diff --git a/drivers/mtd/mtd_nandram.c b/drivers/mtd/mtd_nandram.c index a2b96744166..eeb1a477b2f 100644 --- a/drivers/mtd/mtd_nandram.c +++ b/drivers/mtd/mtd_nandram.c @@ -295,7 +295,7 @@ int nand_ram_eraseblock(FAR struct nand_raw_s *raw, off_t block) for (i = start_page; i < end_page; i++) { nand_ram_flash_spare[i].n_erase++; - nand_ram_flash_spare[i].free = 1; + nand_ram_flash_spare[i].free = NAND_RAM_PAGE_FREE; } NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "eraseblock"); @@ -331,12 +331,11 @@ int nand_ram_rawread(FAR struct nand_raw_s *raw, off_t block, struct nand_ram_data_s *read_page_data; struct nand_ram_spare_s *read_page_spare; + ret = OK; read_page = (block << NAND_RAM_LOG_PAGES_PER_BLOCK) + page; read_page_data = nand_ram_flash_data + read_page; read_page_spare = nand_ram_flash_spare + read_page; - ret = OK; - nxmutex_lock(&nand_ram_dev_mut); nand_ram_ins_i++; @@ -362,7 +361,8 @@ int nand_ram_rawread(FAR struct nand_raw_s *raw, off_t block, } else { - memcpy(data, (const void *)read_page_data, NAND_RAM_PAGE_SIZE); + memcpy(data, (const void *)read_page_data->page, + NAND_RAM_PAGE_SIZE); } } @@ -407,12 +407,11 @@ int nand_ram_rawwrite(FAR struct nand_raw_s *raw, off_t block, struct nand_ram_data_s *write_page_data; struct nand_ram_spare_s *write_page_spare; + ret = OK; write_page = (block << NAND_RAM_LOG_PAGES_PER_BLOCK) + page; write_page_data = nand_ram_flash_data + write_page; write_page_spare = nand_ram_flash_spare + write_page; - ret = OK; - nxmutex_lock(&nand_ram_dev_mut); nand_ram_ins_i++; @@ -429,16 +428,17 @@ int nand_ram_rawwrite(FAR struct nand_raw_s *raw, off_t block, } nand_ram_flash_spare[write_page].n_write++; + nand_ram_flash_spare[write_page].free = NAND_RAM_PAGE_WRITTEN; - memset((void *)write_page_data, 0, NAND_RAM_PAGE_SIZE); + memset((void *)write_page_data->page, 0, NAND_RAM_PAGE_SIZE); if (data != NULL) { - memcpy((void *)write_page_data, data, NAND_RAM_PAGE_SIZE); + memcpy((void *)write_page_data->page, data, NAND_RAM_PAGE_SIZE); } if (spare != NULL) { - memcpy((void *)write_page_spare, data, NAND_RAM_PAGE_SIZE); + memcpy((void *)write_page_spare, data, NAND_RAM_SPARE_SIZE); } NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "rawwrite"); diff --git a/fs/mnemofs/mnemofs.c b/fs/mnemofs/mnemofs.c index 5cf0c0fef80..2c022c85c86 100644 --- a/fs/mnemofs/mnemofs.c +++ b/fs/mnemofs/mnemofs.c @@ -116,7 +116,7 @@ static int mnemofs_close(FAR struct file *filep); static ssize_t mnemofs_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t mnemofs_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); + size_t buflen); static off_t mnemofs_seek(FAR struct file *filep, off_t offset, int whence); static int mnemofs_ioctl(FAR struct file *filep, int cmd, @@ -214,10 +214,6 @@ const struct mountpt_operations g_mnemofs_operations = * Private Functions ****************************************************************************/ -/**************************************************************************** - * Public Functions - ****************************************************************************/ - /**************************************************************************** * Name: mnemofs_open * @@ -393,8 +389,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, f->com->off = f->com->sz; } - finfo("[TMP1] %p %p", &sb->of, &f->list); - list_add_tail(&sb->of, &f->list); + list_add_tail(&MFS_OFILES(sb), &f->list); filep->f_priv = f; nxmutex_unlock(&MFS_LOCK(sb)); @@ -471,23 +466,31 @@ static int mnemofs_close(FAR struct file *filep) /* Flushing in-memory data to on-flash journal. */ - ret = mfs_lru_ctzflush(sb, f->com->path, f->com->depth); - if (predict_false(ret < 0)) - { - finfo("Error while flushing file. Ret: %d.", ret); - goto errout_with_lock; - } - + finfo("Original refcount is %u.", f->com->refcount); f->com->refcount--; if (f->com->refcount == 0) { + ret = mnemofs_flush(sb); + if (predict_false(ret < 0)) + { + finfo("Error while flushing. Ret: %d.", ret); + goto errout_with_lock; + } + kmm_free(f->com->path); kmm_free(f->com); - finfo("Refcount is 0, open file structure freed."); + finfo("Open file structure freed."); + + ret = mnemofs_flush(sb); + if (predict_false(ret < 0)) + { + goto errout_with_fcom; + } } +errout_with_fcom: list_delete(&f->list); kmm_free(f); filep->f_priv = NULL; @@ -524,14 +527,14 @@ errout: * * Returned Value: * 0 - OK - * < 0 - Error + * <= 0 - Bytes read. * ****************************************************************************/ static ssize_t mnemofs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { - int ret = 0; + ssize_t ret = 0; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -567,6 +570,11 @@ static ssize_t mnemofs_read(FAR struct file *filep, FAR char *buffer, /* Read data in CTZ from the current offset. */ + buflen = MIN(buflen, f->com->sz - f->com->off); /* TODO: Need to consider + * if this needs to be + * lower down the chain. + */ + ret = mfs_lru_rdfromoff(sb, f->com->off, f->com->path, f->com->depth, buffer, buflen); if (ret < 0) @@ -575,6 +583,8 @@ static ssize_t mnemofs_read(FAR struct file *filep, FAR char *buffer, goto errout_with_lock; } + ret = buflen; + /* Update offset. */ f->com->off += buflen; @@ -602,14 +612,14 @@ errout: * * Returned Value: * 0 - OK - * < 0 - Error + * <= 0 - Bytes written. * ****************************************************************************/ static ssize_t mnemofs_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen) + size_t buflen) { - int ret = OK; + ssize_t ret = OK; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -654,7 +664,8 @@ static ssize_t mnemofs_write(FAR struct file *filep, FAR const char *buffer, /* Update offset and size. */ f->com->off += buflen; - f->com->sz = MAX(f->com->sz, f->com->off); + f->com->sz = MAX(f->com->sz, f->com->off); + ret = buflen; finfo("Offset updated to %u and size to %u", f->com->off, f->com->sz); @@ -688,7 +699,7 @@ errout: * * Returned Value: * 0 - OK - * < 0 - Error + * <= 0 - Final position. * ****************************************************************************/ @@ -752,6 +763,7 @@ static off_t mnemofs_seek(FAR struct file *filep, off_t offset, int whence) } f->com->off = pos; + ret = pos; finfo("Final position %u.", pos); @@ -933,7 +945,7 @@ static int mnemofs_sync(FAR struct file *filep) f = filep->f_priv; DEBUGASSERT(f != NULL); - ret = mfs_lru_ctzflush(sb, f->com->path, f->com->depth); + ret = mnemofs_flush(sb); nxmutex_unlock(&MFS_LOCK(sb)); finfo("Lock released."); @@ -1014,7 +1026,8 @@ static int mnemofs_dup(FAR const struct file *oldp, FAR struct file *newp) /* Add the new upper half to the list of open fds. */ - list_add_tail(&sb->of, &nf->list); + list_add_tail(&MFS_OFILES(sb), &nf->list); + newp->f_priv = nf; finfo("New file descriptor added to the end of the list of open files."); nxmutex_unlock(&MFS_LOCK(sb)); @@ -1139,8 +1152,8 @@ errout: ****************************************************************************/ static int mnemofs_opendir(FAR struct inode *mountpt, - FAR const char *relpath, - FAR struct fs_dirent_s **dir) + FAR const char *relpath, + FAR struct fs_dirent_s **dir) { int ret = OK; int flags; @@ -1287,8 +1300,8 @@ static int mnemofs_closedir(FAR struct inode *mountpt, ****************************************************************************/ static int mnemofs_readdir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir, - FAR struct dirent *entry) + FAR struct fs_dirent_s *dir, + FAR struct dirent *entry) { int ret = OK; FAR struct mfs_sb_s *sb; @@ -1396,7 +1409,7 @@ errout: ****************************************************************************/ static int mnemofs_rewinddir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir) + FAR struct fs_dirent_s *dir) { int ret = OK; FAR struct mfs_sb_s *sb; @@ -1463,12 +1476,15 @@ errout: static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, FAR void** handle) { - int ret = OK; - bool format = false; - FAR char buf[8]; - mfs_t i = 0; - FAR struct mfs_sb_s *sb = NULL; - struct mtd_geometry_s geo; + int ret = OK; + bool format = false; + FAR char buf[8]; + mfs_t i = 0; + mfs_t mnblk1; + mfs_t mnblk2; + mfs_t jrnl_blk; + FAR struct mfs_sb_s *sb = NULL; + struct mtd_geometry_s geo; finfo("Mnemofs bind."); @@ -1516,22 +1532,23 @@ static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, finfo("Lock acquired."); - sb->drv = driver; - sb->pg_sz = geo.blocksize; - sb->blk_sz = geo.erasesize; - sb->n_blks = geo.neraseblocks; - sb->pg_in_blk = MFS_BLKSZ(sb) / sb->pg_sz; + sb->drv = driver; + sb->pg_sz = geo.blocksize; + sb->blk_sz = geo.erasesize; + sb->n_blks = geo.neraseblocks; + sb->pg_in_blk = MFS_BLKSZ(sb) / sb->pg_sz; #ifdef CONFIG_MNEMOFS_JOURNAL_NBLKS - sb->j_nblks = CONFIG_MNEMOFS_JOURNAL_NBLKS; + MFS_JRNL(sb).n_blks = CONFIG_MNEMOFS_JOURNAL_NBLKS; #else - sb->j_nblks = MIN(5, MFS_NBLKS(sb) / 2); + MFS_JRNL(sb).n_blks = MIN(5, MFS_NBLKS(sb) / 2); #endif - sb->log_blk_sz = log2(MFS_BLKSZ(sb)); - sb->log_pg_sz = log2(sb->pg_sz); - sb->log_pg_in_blk = log2(sb->pg_in_blk); - sb->log_n_blks = log2(MFS_NBLKS(sb)); + sb->log_blk_sz = log2(MFS_BLKSZ(sb)); + sb->log_pg_sz = log2(sb->pg_sz); + sb->log_pg_in_blk = log2(sb->pg_in_blk); + sb->log_n_blks = log2(MFS_NBLKS(sb)); + MFS_FLUSH(sb) = false; - list_initialize(&sb->of); + list_initialize(&MFS_OFILES(sb)); sb->rw_buf = kmm_zalloc(MFS_PGSZ(sb)); if (predict_false(sb->rw_buf == NULL)) @@ -1542,8 +1559,6 @@ static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, /* TODO: Print the super block in Block 0. */ srand(time(NULL)); - mfs_ba_init(sb); - mfs_lru_init(sb); if (!strncmp(data, "autoformat", 11)) { @@ -1575,6 +1590,9 @@ static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, else { finfo("Device already formatted.\n"); + + mfs_ba_init(sb); + mfs_lru_init(sb); } } @@ -1587,8 +1605,19 @@ static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, finfo("Force format.\n"); } - ret = mfs_jrnl_fmt(sb, 0, 0); - if (ret != OK) + mfs_ba_fmt(sb); + mfs_lru_init(sb); + + mnblk1 = 0; + mnblk2 = 0; + ret = mfs_jrnl_fmt(sb, &mnblk1, &mnblk2, &jrnl_blk); + if (predict_false(ret < 0)) + { + goto errout_with_sb; + } + + ret = mfs_mn_fmt(sb, mnblk1, mnblk2, jrnl_blk); + if (predict_false(ret < 0)) { goto errout_with_sb; } @@ -1672,7 +1701,7 @@ static int mnemofs_unbind(FAR void *handle, FAR struct inode **driver, static int mnemofs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) { - int ret = OK; + int ret = OK; FAR struct mfs_sb_s *sb; finfo("Mnemofs statfs."); @@ -1728,9 +1757,9 @@ errout: static int mnemofs_unlink(FAR struct inode *mountpt, FAR const char *relpath) { - int ret = OK; - int ret_flags; - mfs_t depth; + int ret = OK; + int ret_flags; + mfs_t depth; FAR struct mfs_sb_s *sb; FAR struct mfs_path_s *path; @@ -1755,7 +1784,7 @@ static int mnemofs_unlink(FAR struct inode *mountpt, FAR const char *relpath) goto errout_with_lock; } - mfs_pitr_rm(sb, path, depth); + mfs_pitr_rm(sb, path, depth, true); mfs_free_patharr(path); @@ -1790,7 +1819,7 @@ errout: ****************************************************************************/ static int mnemofs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, - mode_t mode) + mode_t mode) { int ret = OK; int flags; @@ -1941,7 +1970,7 @@ static int mnemofs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) mfs_pitr_free(&pitr); - mfs_pitr_rm(sb, path, depth); + mfs_pitr_rm(sb, path, depth, true); errout_with_pitr: mfs_free_patharr(path); @@ -2061,7 +2090,7 @@ static int mnemofs_rename(FAR struct inode *mountpt, mfs_pitr_reset(&npitr); - mfs_pitr_rm(sb, npath, ndepth); + mfs_pitr_rm(sb, npath, ndepth, false); } mfs_pitr_adv_tochild(&npitr, npath); @@ -2133,6 +2162,9 @@ static int mnemofs_stat(FAR struct inode *mountpt, FAR const char *relpath, finfo("Lock acquired."); + finfo("Master node: Root (%u, %u), Size %u", MFS_MN(sb).root_ctz.idx_e, + MFS_MN(sb).root_ctz.pg_e, MFS_MN(sb).root_sz); + ret_flags = mfs_get_patharr(sb, relpath, &path, &depth); if ((ret_flags & MFS_EXIST) == 0) { @@ -2187,3 +2219,59 @@ errout: finfo("Ret %d", ret); return ret; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int mnemofs_flush(FAR struct mfs_sb_s *sb) +{ + int ret = OK; + bool change; + + /* Emtpy the LRU, and maybe the journal as well. */ + + finfo("Flush operation started."); + + for (; ; ) + { + change = false; + if (!mfs_lru_isempty(sb)) + { + finfo("LRU needs to be flushed."); + + change = true; + ret = mfs_lru_flush(sb); + if (predict_false(ret < 0)) + { + goto errout; + } + } + + if (!mfs_jrnl_isempty(sb) && + MFS_JRNL(sb).log_cblkidx >= MFS_JRNL_LIM(sb)) + { + finfo("Journal needs to be flushed."); + + change = true; + + ret = mfs_jrnl_flush(sb); + if (predict_false(ret < 0)) + { + goto errout; + } + } + + if (!change) + { + break; + } + + finfo("Finished Iteration."); + } + +errout: + return ret; +} + +/* TODO: Superblock still doesn't exist. Plus bug fixes. */ \ No newline at end of file diff --git a/fs/mnemofs/mnemofs.h b/fs/mnemofs/mnemofs.h index ab6c2476eb9..b9773175951 100644 --- a/fs/mnemofs/mnemofs.h +++ b/fs/mnemofs/mnemofs.h @@ -86,14 +86,17 @@ #define MFS_RWBUF(sb) ((sb)->rw_buf) #define MFS_BA(sb) ((sb)->ba_state) #define MFS_NBLKS(sb) ((sb)->n_blks) +#define MFS_OFILES(sb) ((sb)->of) +#define MFS_FLUSH(sb) ((sb)->flush) #define MFS_NPGS(sb) (MFS_NBLKS(sb) * MFS_PGINBLK(sb)) #define MFS_HASHSZ 16 #define MFS_CTZ_SZ(l) ((l)->sz) -#define MFS_DIRENTSZ(dirent) ((mfs_t) (sizeof(struct mfs_dirent_s) \ - + (dirent)->namelen)) +#define MFS_DIRENTSZ(dirent) ((2 * 2) + 4 + (16 * 3) + 8 + 1 \ + + (dirent)->namelen) -#define MFS_JRNL_LIM(sb) (MFS_JRNL(sb).n_blks) /* TODO: 50-75% */ +#define MFS_JRNL_LIM(sb) (MFS_JRNL(sb).n_blks / 2) +#define MFS_TRAVERSE_INITSZ 8 /**************************************************************************** * Public Types @@ -149,7 +152,7 @@ struct mfs_mn_s { mfs_t pg; /* Only mblk1's pg will be used here. */ mfs_t jrnl_blk; /* Start of journal. */ - mfs_t mblk_idx; + mfs_t mblk_idx; /* Index for next MN entry inside blk. */ struct mfs_ctz_s root_ctz; mfs_t root_sz; struct timespec ts; @@ -170,7 +173,7 @@ struct mfs_jrnl_state_s mfs_t log_sblkidx; /* First jrnl blk index. TODO: jrnlarr > 1 blk. */ mfs_t jrnlarr_pg; mfs_t jrnlarr_pgoff; - uint16_t n_blks; + uint16_t n_blks; /* TODO: Does not include the master node. */ }; struct mfs_sb_s @@ -185,15 +188,14 @@ struct mfs_sb_s uint8_t log_blk_sz; mfs_t n_blks; uint8_t log_n_blks; - mfs_t n_lru; uint16_t pg_in_blk; uint8_t log_pg_in_blk; - uint8_t j_nblks; struct mfs_mn_s mn; /* Master Node */ struct mfs_jrnl_state_s j_state; /* Journal State */ struct mfs_ba_state_s ba_state; /* Block Allocator State */ struct list_node lru; struct list_node of; /* open files. */ + bool flush; }; /* This is for *dir VFS methods. */ @@ -417,6 +419,10 @@ static inline mfs_t mfs_popcnt(mfs_t x) * Public Function Prototypes ****************************************************************************/ +/* mnemofs.c */ + +int mnemofs_flush(FAR struct mfs_sb_s *sb); + /* mnemofs_journal.c */ /**************************************************************************** @@ -459,7 +465,8 @@ int mfs_jrnl_init(FAR struct mfs_sb_s * const sb, mfs_t blk); * ****************************************************************************/ -int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2); +int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t *blk1, mfs_t *blk2, + FAR mfs_t *jrnl_blk); /**************************************************************************** * Name: mfs_jrnl_free @@ -551,7 +558,7 @@ int mfs_jrnl_updatedinfo(FAR const struct mfs_sb_s * const sb, ****************************************************************************/ int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, - const struct mfs_node_s node, + FAR const struct mfs_node_s *node, const struct mfs_ctz_s loc_new, const mfs_t sz_new); /**************************************************************************** @@ -572,8 +579,41 @@ int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, int mfs_jrnl_flush(FAR struct mfs_sb_s * const sb); +/**************************************************************************** + * Name: mfs_jrnl_isempty + * + * Description: + * Check if the journal is empty. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + * Returned Value: + * True is the journal is empty, false otherwise. + * + ****************************************************************************/ + +bool mfs_jrnl_isempty(FAR const struct mfs_sb_s * const sb); + /* mnemofs_blkalloc.c */ +/**************************************************************************** + * Name: mfs_ba_init + * + * Description: + * Formats and initializes the block allocator. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + * Returned Value: + * 0 - OK + * -ENOMEM - No memory left. + * + ****************************************************************************/ + +int mfs_ba_fmt(FAR struct mfs_sb_s * const sb); + /**************************************************************************** * Name: mfs_ba_init * @@ -1172,7 +1212,7 @@ int mfs_ctz_rdfromoff(FAR const struct mfs_sb_s * const sb, mfs_t len, FAR char * buf); /**************************************************************************** - * Name: mfs_ctz_wrtnode_new + * Name: mfs_ctz_wrtnode * * Description: * Write an LRU node to the flash. It also adds a log of it to the journal. @@ -1192,7 +1232,37 @@ int mfs_ctz_rdfromoff(FAR const struct mfs_sb_s * const sb, ****************************************************************************/ int mfs_ctz_wrtnode(FAR struct mfs_sb_s * const sb, - const struct mfs_node_s * const node); + FAR const struct mfs_node_s * const node, + FAR struct mfs_ctz_s *new_loc); + +/**************************************************************************** + * Name: mfs_ctz_travel + * + * Description: + * From CTZ block at page `pg_src` and index `idx_src`, give the page + * number of index `idx_dest`. + * + * The source is preferably the last CTZ block in the CTZ list, but it can + * realistically be any CTZ block in the CTZ list whos position is known. + * However, `idx_dest <= idx_src` has to be followed. Takes O(log(n)) + * complexity to travel. + * + * Input Parameters: + * sb - Superblock instance of the device. + * idx_src - Index of the source ctz block. + * pg_src - Page number of the source ctz block. + * idx_dest - Index of the destination ctz block. + * + * Returned Value: + * The page number corresponding to `idx_dest`. + * + * Assumptions/Limitations: + * `idx_dest <= idx_src`. + * + ****************************************************************************/ + +mfs_t mfs_ctz_travel(FAR const struct mfs_sb_s * const sb, + mfs_t idx_src, mfs_t pg_src, mfs_t idx_dest); /* mnemofs_lru.c */ @@ -1325,7 +1395,10 @@ int mfs_lru_updatedinfo(FAR const struct mfs_sb_s * const sb, int mfs_lru_updatectz(FAR struct mfs_sb_s * sb, FAR struct mfs_path_s * const path, const mfs_t depth, - const struct mfs_ctz_s new_ctz); + const struct mfs_ctz_s new_ctz, mfs_t new_sz); + +bool mfs_lru_isempty(FAR struct mfs_sb_s * const sb); +int mfs_lru_flush(FAR struct mfs_sb_s * const sb); /* mnemofs_master.c */ @@ -1369,7 +1442,8 @@ int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk); * ****************************************************************************/ -int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk); +int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t blk1, + const mfs_t blk2, const mfs_t jrnl_blk); /**************************************************************************** * Name: mfs_mn_move @@ -1394,6 +1468,10 @@ int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk); int mfs_mn_move(FAR struct mfs_sb_s * const sb, struct mfs_ctz_s root, const mfs_t root_sz); +int mfs_mn_sync(FAR struct mfs_sb_s *sb, + FAR struct mfs_path_s * const new_loc, + const mfs_t blk1, const mfs_t blk2, const mfs_t jrnl_blk); + /* mnemofs_fsobj.c */ /**************************************************************************** @@ -1817,7 +1895,10 @@ int mfs_pitr_rmdirent(FAR struct mfs_sb_s * const sb, int mfs_pitr_rm(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, - const mfs_t depth); + const mfs_t depth, bool rm_child); + +int mfs_pitr_traversefs(FAR struct mfs_sb_s * sb, const struct mfs_ctz_s ctz, + int type); #undef EXTERN #ifdef __cplusplus diff --git a/fs/mnemofs/mnemofs_blkalloc.c b/fs/mnemofs/mnemofs_blkalloc.c index 9bc135c6d1c..7c127b48532 100644 --- a/fs/mnemofs/mnemofs_blkalloc.c +++ b/fs/mnemofs/mnemofs_blkalloc.c @@ -236,11 +236,11 @@ static int is_pg_writeable(FAR struct mfs_sb_s * const sb, mfs_t pg, static int is_blk_writeable(FAR struct mfs_sb_s * const sb, const mfs_t blk) { - mfs_t idx; + int blkbad_status; + mfs_t i; + mfs_t pg = MFS_BLK2PG(sb, blk); + mfs_t idx; uint8_t off; - mfs_t pg = MFS_BLK2PG(sb, blk); - mfs_t i; - int blkbad_status; /* Bad block check. */ @@ -279,15 +279,15 @@ static int is_blk_writeable(FAR struct mfs_sb_s * const sb, const mfs_t blk) * Public Functions ****************************************************************************/ -int mfs_ba_init(FAR struct mfs_sb_s * const sb) +int mfs_ba_fmt(FAR struct mfs_sb_s * const sb) { int ret = OK; uint8_t log; -/* We need at least 5 blocks, as one is occupied by superblock, at least - * one for the journal, 2 for journal's master blocks, and at least one for - * actual data. - */ + /* We need at least 5 blocks, as one is occupied by superblock, at least + * one for the journal, 2 for journal's master blocks, and at least one for + * actual data. + */ if (MFS_NBLKS(sb) < 5) { @@ -326,8 +326,6 @@ int mfs_ba_init(FAR struct mfs_sb_s * const sb) goto errout_with_k_del; } - /* TODO: Fill MFS_BA(sb).bmap_upgs after tree traversal. */ - finfo("mnemofs: Block Allocator initialized, starting at page %d.\n", MFS_BLK2PG(sb, MFS_BA(sb).s_blk)); return ret; @@ -339,6 +337,33 @@ errout: return ret; } +int mfs_ba_init(FAR struct mfs_sb_s * const sb) +{ + /* TODO: Ensure journal and master node are initialized before this. */ + + int ret = OK; + + ret = mfs_ba_fmt(sb); + if (predict_false(ret < 0)) + { + goto errout; + } + + /* Traverse the FS tree. */ + + ret = mfs_pitr_traversefs(sb, MFS_MN(sb).root_ctz, MFS_ISDIR); + if (predict_false(ret < 0)) + { + goto errout_with_ba; + } + +errout_with_ba: + mfs_ba_free(sb); + +errout: + return ret; +} + void mfs_ba_free(FAR struct mfs_sb_s * const sb) { kmm_free(MFS_BA(sb).k_del); diff --git a/fs/mnemofs/mnemofs_ctz.c b/fs/mnemofs/mnemofs_ctz.c index 9db41c66439..0d6eea664b8 100644 --- a/fs/mnemofs/mnemofs_ctz.c +++ b/fs/mnemofs/mnemofs_ctz.c @@ -122,8 +122,6 @@ static void ctz_off2loc(FAR const struct mfs_sb_s * const sb, mfs_t off, FAR mfs_t *idx, FAR mfs_t *pgoff); static mfs_t ctz_blkdatasz(FAR const struct mfs_sb_s * const sb, const mfs_t idx); -static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, - mfs_t pg_src, mfs_t idx_dest); static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, FAR struct mfs_ctz_s ctz, const mfs_t idx, FAR char *buf); @@ -183,7 +181,7 @@ static mfs_t ctz_idx_nptrs(const mfs_t idx) static void ctz_off2loc(FAR const struct mfs_sb_s * const sb, mfs_t off, FAR mfs_t *idx, FAR mfs_t *pgoff) { - const mfs_t wb = sizeof(mfs_t); + const mfs_t wb = sizeof(mfs_t); const mfs_t den = MFS_PGSZ(sb) - 2 * wb; if (off < den) @@ -234,33 +232,380 @@ static mfs_t ctz_blkdatasz(FAR const struct mfs_sb_s * const sb, } /**************************************************************************** - * Name: ctz_travel + * Name: ctz_copyidxptrs * * Description: - * From CTZ block at page `pg_src` and index `idx_src`, give the page - * number of index `idx_dest`. + * This is used for cases when you want to expand a CTZ list from any point + * in the list. If we want to expand the CTZ list from a particular index, + * say `start_idx`, while keeping all indexes before it untouched, we + * would need to first allocate new blocks on the flash, and then copy + * the pointers to the location. * - * The source is preferably the last CTZ block in the CTZ list, but it can - * realistically be any CTZ block in the CTZ list whos position is known. - * However, `idx_dest <= idx_src` has to be followed. Takes O(log(n)) - * complexity to travel. + * Usage of this function is, the caller needs to first allocate a CTZ + * block (a page on flash), allocate buffer which is the size of a CTZ + * block (a page on flash), and use this method to copy the pointers to the + * buffer, then write the data to the flash. * * Input Parameters: - * sb - Superblock instance of the device. - * idx_src - Index of the source ctz block. - * pg_src - Page number of the source ctz block. - * idx_dest - Index of the destination ctz block. - * - * Returned Value: - * The page number corresponding to `idx_dest`. + * sb - Superblock instance of the device. + * ctz - CTZ list to use as a reference. + * idx - Index of the block who's supposed pointers are to be copied. + * buf - Buffer representing the entire CTZ block where pointers are + * copied to. * * Assumptions/Limitations: - * `idx_dest <= idx_src`. + * This assumes `idx` is not more than `ctz->idx_e + 1`. * ****************************************************************************/ -static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, - mfs_t pg_src, mfs_t idx_dest) +static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_ctz_s ctz, const mfs_t idx, + FAR char *buf) +{ + mfs_t i; + mfs_t n_ptrs; + mfs_t prev_pg; + mfs_t prev_idx; + + if (idx == 0) + { + /* No pointers for first block. */ + + return; + } + + n_ptrs = ctz_idx_nptrs(idx); + + if (idx != ctz.idx_e + 1) + { + /* We travel to the second last "known" CTZ block. */ + + ctz.pg_e = mfs_ctz_travel(sb, ctz.idx_e, ctz.pg_e, idx - 1); + ctz.idx_e = idx - 1; + } + + buf += MFS_PGSZ(sb); /* Go to buf + pg_sz */ + + DEBUGASSERT(idx == ctz.idx_e + 1); + + finfo("Copying %u pointers for CTZ (%u, %u) at index %u.", n_ptrs, + ctz.idx_e, ctz.pg_e, idx); + + for (i = 0; i < n_ptrs; i++) + { + if (predict_false(i == 0)) + { + prev_idx = ctz.idx_e; + prev_pg = ctz.pg_e; + } + else + { + prev_pg = mfs_ctz_travel(sb, prev_idx, prev_pg, prev_idx - 1); + prev_idx--; + } + + ctz.idx_e = prev_idx; + + /* Do buf + pg_sz - (idx * sizeof(mfs_t)) iteratively. */ + + buf -= MFS_CTZ_PTRSZ; + mfs_ser_mfs(prev_pg, buf); + + finfo("Copied %u page number to %uth pointer.", prev_pg, i); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int mfs_ctz_rdfromoff(FAR const struct mfs_sb_s * const sb, + const struct mfs_ctz_s ctz, mfs_t data_off, + mfs_t len, FAR char * buf) +{ + int ret = OK; + mfs_t i; + mfs_t rd_sz; + mfs_t cur_pg; + mfs_t cur_idx; + mfs_t cur_pgoff; + mfs_t end_idx; + mfs_t end_pgoff; + mfs_t pg_rd_sz; + + finfo("Reading (%u, %u) CTZ from %u offset for %u bytes.", ctz.idx_e, + ctz.pg_e, data_off, len); + + if (ctz.idx_e == 0 && ctz.pg_e == 0) + { + goto errout; + } + + ctz_off2loc(sb, data_off + len, &cur_idx, &cur_pgoff); + ctz_off2loc(sb, data_off, &end_idx, &end_pgoff); + + DEBUGASSERT(ctz.idx_e < cur_idx); /* TODO: Need to consider this. For now, there is a temporary fix in read(). */ + if (ctz.idx_e < end_idx) + { + goto errout; + } + + cur_pg = mfs_ctz_travel(sb, ctz.idx_e, ctz.pg_e, cur_idx); + rd_sz = 0; + + if (predict_false(cur_pg == 0)) + { + goto errout; + } + + /* O(n) read by reading in reverse. */ + + finfo("Started reading. Current Idx: %u, End Idx: %u.", cur_idx, end_idx); + + if (cur_idx != end_idx) + { + for (i = cur_idx; i >= end_idx; i--) + { + finfo("Current index %u, Current Page %u.", i, cur_pg); + + if (predict_false(i == cur_idx)) + { + pg_rd_sz = cur_pgoff; + ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, + 0); + cur_pgoff = 0; + } + else if (predict_false(i == end_idx)) + { + pg_rd_sz = ctz_blkdatasz(sb, i) - end_pgoff; + ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, + end_pgoff); + } + else + { + pg_rd_sz = ctz_blkdatasz(sb, i); + ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, + 0); + } + + if (predict_false(ret == 0)) + { + ret = -EINVAL; + goto errout; + } + + buf -= pg_rd_sz; + } + + cur_pg = mfs_ctz_travel(sb, cur_idx, cur_pg, cur_idx - 1); + if (predict_false(cur_pg == 0)) + { + ret = -EINVAL; + goto errout; + } + } + else + { + ret = mfs_read_page(sb, buf, len, cur_pg, end_pgoff); + if (predict_false(ret < 0)) + { + goto errout; + } + + ret = OK; + } + + finfo("Reading finished."); + +errout: + return ret; +} + +int mfs_ctz_wrtnode(FAR struct mfs_sb_s * const sb, + FAR const struct mfs_node_s * const node, + FAR struct mfs_ctz_s *new_loc) +{ + int ret = OK; + bool written = false; + mfs_t prev; + mfs_t rem_sz; + mfs_t new_pg; + mfs_t cur_pg; + mfs_t cur_idx; + mfs_t cur_pgoff; + mfs_t lower; + mfs_t upper; + mfs_t upper_og; + mfs_t lower_upd; + mfs_t upper_upd; + mfs_t del_bytes; + FAR char *buf = NULL; + FAR char *tmp = NULL; + struct mfs_ctz_s ctz; + FAR struct mfs_delta_s *delta; + + finfo("Write LRU node %p at depth %u, with %u delta(s) to flash.", node, + node->depth, list_length(&node->delta)); + + /* Traverse common CTZ blocks. */ + + ctz_off2loc(sb, node->range_min, &cur_idx, &cur_pgoff); + ctz = node->path[node->depth - 1].ctz; + cur_pg = mfs_ctz_travel(sb, ctz.idx_e, ctz.pg_e, cur_idx); + + /* So, till cur_idx - 1, the CTZ blocks are common. */ + + buf = kmm_zalloc(MFS_PGSZ(sb)); + if (predict_false(buf == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + /* Initially, there might be some offset in cur_idx CTZ blocks that is + * unmodified as well. + */ + + finfo("Initial read."); + tmp = buf; + mfs_read_page(sb, tmp, cur_pgoff, cur_pg, 0); + tmp += cur_pgoff; + + /* Modifications. */ + + prev = 0; + rem_sz = node->sz; + lower = node->range_min; + del_bytes = 0; + + /* [lower, upper) range. Two pointer approach. Window gets narrower + * for every delete falling inside it. + */ + + while (rem_sz > 0) + { + upper = MIN(prev + lower + ctz_blkdatasz(sb, cur_idx), rem_sz); + upper_og = upper; + + finfo("Remaining Size %u. Lower %u, Upper %u, Current Offset %u", + rem_sz, lower, upper, tmp - buf); + + /* Retrieving original data. */ + + ret = mfs_ctz_rdfromoff(sb, ctz, lower + del_bytes, upper - lower, + tmp); + if (predict_false(ret < 0)) + { + goto errout_with_buf; + } + + list_for_every_entry(&node->delta, delta, struct mfs_delta_s, list) + { + finfo("Checking delta %p in node %p. Offset %u, bytes %u.", delta, + node, delta->off, delta->n_b); + + lower_upd = MAX(lower, delta->off); + upper_upd = MIN(upper, delta->off + delta->n_b); + + if (lower_upd >= upper_upd) + { + /* Skip this delta. */ + + continue; + } + + if (delta->upd == NULL) + { + finfo("Node type: Delete"); + + /* Delete */ + + del_bytes += upper_upd - lower_upd; + memmove(tmp + (lower_upd - lower), tmp + (upper_upd - lower), + upper - upper_upd); + upper -= upper_upd; + } + else + { + finfo("Node type: Update"); + + /* Update */ + + memcpy(tmp + (lower_upd - lower), + delta->upd + (lower_upd - delta->off), + upper_upd - lower_upd); + } + } + + /* rem_sz check for final write. */ + + if (upper == upper_og || rem_sz == upper - lower) + { + prev = 0; + + /* Time to write a page for new CTZ list. */ + + new_pg = mfs_ba_getpg(sb); + if (predict_false(new_pg == 0)) + { + ret = -ENOSPC; + goto errout_with_buf; + } + + ctz_copyidxptrs(sb, ctz, cur_idx, buf); + + ret = mfs_write_page(sb, buf, MFS_PGSZ(sb), new_pg, 0); + if (predict_false(ret == 0)) + { + ret = -EINVAL; + goto errout_with_buf; + } + + memset(buf, 0, MFS_PGSZ(sb)); + tmp = buf; + ctz.idx_e = cur_idx; + ctz.pg_e = new_pg; + cur_idx++; + + written = true; + + finfo("Written data to page %u.", new_pg); + } + else + { + tmp += upper - lower; + + written = false; + } + + prev = upper - lower; + rem_sz -= upper - lower; + lower = upper; + } + + DEBUGASSERT(written); + + /* TODO: Need to verify for cases where the delete extends outside, etc. */ + + /* Write log. Assumes journal has enough space due to the limit. */ + + finfo("Writing log."); + *new_loc = ctz; + ret = mfs_jrnl_wrlog(sb, node, ctz, node->sz); + if (predict_false(ret < 0)) + { + goto errout_with_buf; + } + +errout_with_buf: + kmm_free(buf); + +errout: + return ret; +} + +mfs_t mfs_ctz_travel(FAR const struct mfs_sb_s * const sb, + mfs_t idx_src, mfs_t pg_src, mfs_t idx_dest) { char buf[4]; mfs_t pg; @@ -315,347 +660,3 @@ static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, return pg; } - -/**************************************************************************** - * Name: ctz_copyidxptrs - * - * Description: - * This is used for cases when you want to expand a CTZ list from any point - * in the list. If we want to expand the CTZ list from a particular index, - * say `start_idx`, while keeping all indexes before it untouched, we - * would need to first allocate new blocks on the flash, and then copy - * the pointers to the location. - * - * Usage of this function is, the caller needs to first allocate a CTZ - * block (a page on flash), allocate buffer which is the size of a CTZ - * block (a page on flash), and use this method to copy the pointers to the - * buffer, then write the data to the flash. - * - * Input Parameters: - * sb - Superblock instance of the device. - * ctz - CTZ list to use as a reference. - * idx - Index of the block who's supposed pointers are to be copied. - * buf - Buffer representing the entire CTZ block where pointers are - * copied to. - * - * Assumptions/Limitations: - * This assumes `idx` is not more than `ctz->idx_e + 1`. - * - ****************************************************************************/ - -static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, - FAR struct mfs_ctz_s ctz, const mfs_t idx, - FAR char *buf) -{ - mfs_t i; - mfs_t n_ptrs; - mfs_t prev_pg; - mfs_t prev_idx; - - if (idx == 0) - { - /* No pointers for first block. */ - - return; - } - - n_ptrs = ctz_idx_nptrs(idx); - - if (idx != ctz.idx_e + 1) - { - /* We travel to the second last "known" CTZ block. */ - - ctz.pg_e = ctz_travel(sb, ctz.idx_e, ctz.pg_e, idx - 1); - ctz.idx_e = idx - 1; - } - - buf += MFS_PGSZ(sb); /* Go to buf + pg_sz */ - - DEBUGASSERT(idx == ctz.idx_e + 1); - - finfo("Copying %u pointers for CTZ (%u, %u) at index %u.", n_ptrs, - ctz.idx_e, ctz.pg_e, idx); - - for (i = 0; i < n_ptrs; i++) - { - if (predict_false(i == 0)) - { - prev_idx = ctz.idx_e; - prev_pg = ctz.pg_e; - } - else - { - prev_pg = ctz_travel(sb, prev_idx, prev_pg, prev_idx - 1); - prev_idx--; - } - - ctz.idx_e = prev_idx; - - /* Do buf + pg_sz - (idx * sizeof(mfs_t)) iteratively. */ - - buf -= MFS_CTZ_PTRSZ; - mfs_ser_mfs(prev_pg, buf); - - finfo("Copied %u page number to %uth pointer.", prev_pg, i); - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -int mfs_ctz_rdfromoff(FAR const struct mfs_sb_s * const sb, - const struct mfs_ctz_s ctz, mfs_t data_off, - mfs_t len, FAR char * buf) -{ - int ret = OK; - mfs_t i; - mfs_t rd_sz; - mfs_t cur_pg; - mfs_t cur_idx; - mfs_t cur_pgoff; - mfs_t end_idx; - mfs_t end_pgoff; - mfs_t pg_rd_sz; - - ctz_off2loc(sb, data_off + len, &cur_idx, &cur_pgoff); - ctz_off2loc(sb, data_off, &end_idx, &end_pgoff); - - if (ctz.idx_e < cur_idx || ctz.idx_e < end_idx) - { - goto errout; - } - - cur_pg = ctz_travel(sb, ctz.idx_e, ctz.pg_e, cur_idx); - rd_sz = 0; - - if (predict_false(cur_pg == 0)) - { - goto errout; - } - - /* O(n) read by reading in reverse. */ - - if (cur_idx != end_idx) - { - for (i = cur_idx; i >= end_idx; i--) - { - if (predict_false(i == cur_idx)) - { - pg_rd_sz = cur_pgoff; - ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, - 0); - cur_pgoff = 0; - } - else if (predict_false(i == end_idx)) - { - pg_rd_sz = ctz_blkdatasz(sb, i) - end_pgoff; - ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, - end_pgoff); - } - else - { - pg_rd_sz = ctz_blkdatasz(sb, i); - ret = mfs_read_page(sb, buf - pg_rd_sz, pg_rd_sz, cur_pg, - 0); - } - - if (predict_false(ret == 0)) - { - ret = -EINVAL; - goto errout; - } - - buf -= pg_rd_sz; - } - - cur_pg = ctz_travel(sb, cur_idx, cur_pg, cur_idx - 1); - - if (predict_false(cur_pg == 0)) - { - ret = -EINVAL; - goto errout; - } - } - else - { - ret = mfs_read_page(sb, buf, len, cur_pg, end_pgoff); - - if (predict_false(ret == 0)) - { - ret = -EINVAL; - goto errout; - } - } - -errout: - return ret; -} - -int mfs_ctz_wrtnode(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_node_s * const node) -{ - int ret = OK; - bool written = false; - mfs_t prev; - mfs_t rem_sz; - mfs_t new_pg; - mfs_t cur_pg; - mfs_t cur_idx; - mfs_t cur_pgoff; - mfs_t lower; - mfs_t upper; - mfs_t upper_og; - mfs_t lower_upd; - mfs_t upper_upd; - mfs_t del_bytes; - FAR char *buf = NULL; - FAR char *tmp = NULL; - struct mfs_ctz_s ctz; - FAR struct mfs_delta_s *delta; - - /* Traverse common CTZ blocks. */ - - ctz_off2loc(sb, node->range_min, &cur_idx, &cur_pgoff); - ctz = node->path[node->depth - 1].ctz; - cur_pg = ctz_travel(sb, ctz.idx_e, ctz.pg_e, cur_idx); - - /* So, till cur_idx - 1, the CTZ blocks are common. */ - - buf = kmm_zalloc(MFS_PGSZ(sb)); - if (predict_false(buf == NULL)) - { - ret = -ENOMEM; - goto errout; - } - - /* Initially, there might be some offset in cur_idx CTZ blocks that is - * unmodified as well. - */ - - tmp = buf; - mfs_read_page(sb, tmp, cur_pgoff, cur_pg, 0); - tmp += cur_pgoff; - - /* Modifications. */ - - prev = 0; - rem_sz = node->sz; - lower = node->range_min; - del_bytes = 0; - - /* [lower, upper) range. Two pointer approach. Window gets narrower - * for every delete falling inside it. - */ - - while (rem_sz > 0) - { - upper = MIN(prev + lower + ctz_blkdatasz(sb, cur_idx), rem_sz); - upper_og = upper; - - list_for_every_entry(&node->delta, delta, struct mfs_delta_s, list) - { - if (delta->upd == NULL) - { - /* Delete */ - - lower_upd = MAX(lower, delta->off); - upper_upd = MIN(upper, delta->off + delta->n_b); - - if (lower_upd >= upper_upd) - { - /* Skip this delta. */ - - continue; - } - else - { - del_bytes += upper_upd - lower_upd; - memmove(tmp + lower_upd, tmp + upper_upd, - upper - upper_upd); - upper -= upper_upd; - } - } - else - { - /* Update */ - - ret = mfs_ctz_rdfromoff(sb, ctz, lower, upper - lower, - tmp); - if (predict_false(ret < 0)) - { - goto errout_with_buf; - } - } - } - - /* rem_sz check for final write. */ - - if (upper == upper_og || rem_sz == upper - lower) - { - prev = 0; - - /* Time to write a page for new CTZ list. */ - - new_pg = mfs_ba_getpg(sb); - if (predict_false(new_pg == 0)) - { - ret = -ENOSPC; - goto errout_with_buf; - } - - ctz_copyidxptrs(sb, ctz, cur_idx, buf); - ret = mfs_write_page(sb, buf, MFS_PGSZ(sb), new_pg, 0); - if (predict_false(ret == 0)) - { - ret = -EINVAL; - goto errout_with_buf; - } - - memset(buf, 0, MFS_PGSZ(sb)); - tmp = buf; - cur_idx++; - - written = true; - } - else - { - tmp += upper - lower; - - written = false; - } - - prev = upper - lower; - rem_sz -= upper - lower; - lower = upper; - } - - DEBUGASSERT(written); - - /* TODO: Need to verify for cases where the delete extends outside, etc. */ - - /* Write log. */ - - ctz.idx_e = cur_idx; - ctz.pg_e = new_pg; - ret = mfs_jrnl_wrlog(sb, *node, ctz, node->sz); - if (predict_false(ret < 0)) - { - goto errout_with_buf; - } - - if (MFS_JRNL(sb).log_cblkidx >= MFS_JRNL_LIM(sb)) - { - ret = mfs_jrnl_flush(sb); - if (predict_false(ret < 0)) - { - goto errout_with_buf; - } - } - -errout_with_buf: - kmm_free(buf); - -errout: - return ret; -} diff --git a/fs/mnemofs/mnemofs_fsobj.c b/fs/mnemofs/mnemofs_fsobj.c index 1d5fbd5e079..121c15aa416 100644 --- a/fs/mnemofs/mnemofs_fsobj.c +++ b/fs/mnemofs/mnemofs_fsobj.c @@ -85,6 +85,7 @@ static const char *next_child(FAR const char *relpath); static const char *last_child(FAR const char *relpath); static FAR char *mfs_ser_dirent(FAR const struct mfs_dirent_s * const x, FAR char * const out); + static FAR const char *mfs_deser_dirent(FAR const char * const in, FAR struct mfs_dirent_s * const x); @@ -285,11 +286,87 @@ static FAR const char *mfs_deser_dirent(FAR const char * const in, return i; } +int pitr_traverse(FAR struct mfs_sb_s *sb, FAR struct mfs_path_s *path, + mfs_t depth, FAR mfs_t *cap) +{ + int ret = OK; + mfs_t i; + mfs_t pg; + struct mfs_pitr_s pitr; + struct mfs_ctz_s ctz; + FAR struct mfs_dirent_s *dirent = NULL; + + /* TODO: Double traversal can be made faster into a single traversal. */ + + ctz = path[depth - 1].ctz; + + if (ctz.idx_e == 0 && ctz.pg_e == 0) + { + /* Not a valid one. TODO: Does this happens? */ + + goto errout; + } + + for (i = ctz.idx_e; i > 0; i--) + { + mfs_ba_markusedpg(sb, pg); + + pg = mfs_ctz_travel(sb, i, pg, i - 1); + if (pg == 0) + { + break; + } + } + + memset(path + depth, 0, *cap - depth); + + if (depth == *cap) + { + *cap = (*cap * 3) / 2; /* Don't want to double it for memory. */ + + path = kmm_realloc(path, (*cap) * sizeof(struct mfs_path_s)); + if (predict_false(path == NULL)) + { + ret = -ENOMEM; + goto errout; + } + } + + mfs_pitr_init(sb, path, depth, &pitr, true); + + while (true) + { + mfs_pitr_readdirent(sb, path, &pitr, &dirent); + if (dirent == NULL) + { + break; + } + + if (S_ISDIR(dirent->mode)) + { + path[(depth + 1) - 1].ctz = dirent->ctz; + + ret = pitr_traverse(sb, path, depth + 1, cap); + if (predict_false(ret < 0)) + { + mfs_free_dirent(dirent); + goto errout; + } + } + + mfs_pitr_adv_bydirent(&pitr, dirent); + mfs_free_dirent(dirent); + } + +errout: + return ret; +} + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ -FAR const char * mfs_path2childname(FAR const char *relpath) +FAR const char *mfs_path2childname(FAR const char *relpath) { FAR const char *last = relpath + strlen(relpath) - 1; @@ -317,9 +394,9 @@ mfs_t mfs_get_fsz(FAR struct mfs_sb_s * const sb, { sz = MFS_MN(sb).root_sz; /* Updated size. */ -/* Journal updated to the root creates a new master node entry. TODO - * this and moving of the journal. - */ + /* Journal updated to the root creates a new master node entry. TODO + * this and moving of the journal. + */ finfo("File size got as %u for root.", sz); return sz; @@ -362,11 +439,6 @@ bool mfs_searchfopen(FAR const struct mfs_sb_s * const sb, continue; } - /* TODO: Ensure when an LRU's delta is flushed to the journal, the - * new location is updated in the LRU AND the open files, if it is - * open. - */ - if (mfs_path_eq(&ofd->com->path[depth - 1], &path[depth - 1])) { return true; @@ -400,7 +472,7 @@ int mfs_pitr_rmdirent(FAR struct mfs_sb_s * const sb, int mfs_pitr_rm(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, - const mfs_t depth) + const mfs_t depth, bool rm_child) { int ret = OK; struct mfs_pitr_s pitr; @@ -408,7 +480,23 @@ int mfs_pitr_rm(FAR struct mfs_sb_s * const sb, mfs_pitr_init(sb, path, depth, &pitr, true); mfs_pitr_readdirent(sb, path, &pitr, &dirent); + ret = mfs_pitr_rmdirent(sb, path, depth, &pitr, dirent); + if (predict_false(ret < 0)) + { + goto errout; + } + + if (rm_child) + { + ret = mfs_lru_del(sb, 0, path[depth - 1].sz, path, depth); + if (predict_false(ret < 0)) + { + goto errout; + } + } + +errout: mfs_free_dirent(dirent); mfs_pitr_free(&pitr); @@ -558,9 +646,9 @@ int mfs_pitr_readdirent(FAR const struct mfs_sb_s * const sb, *dirent = d; DEBUGASSERT(pitr->depth == 0 || strcmp(d->name, "")); finfo("Read direntry at %u offset, %u depth for CTZ (%u, %u). " \ - "Direntry name: \"%s\" with name length %u.", + "Direntry name: \"%.*s\" with name length %u and size %u.", pitr->c_off, pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, - d->name, d->namelen); + d->namelen, d->name, d->namelen, d->sz); return ret; @@ -584,7 +672,7 @@ int mfs_pitr_adv(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s *path, FAR struct mfs_pitr_s * const pitr) { - int ret = OK; + int ret = OK; FAR struct mfs_dirent_s *dirent; ret = mfs_pitr_readdirent(sb, path, pitr, &dirent); @@ -613,11 +701,11 @@ static int search_ctz_by_name(FAR const struct mfs_sb_s * const sb, /* Applies LRU updates. */ - int ret = OK; - uint16_t name_hash; - struct mfs_pitr_s pitr; + int ret = OK; + bool found = false; + uint16_t name_hash; + struct mfs_pitr_s pitr; FAR struct mfs_dirent_s *nd; - bool found = false; *dirent = NULL; @@ -864,7 +952,7 @@ int mfs_pitr_appenddirent(FAR struct mfs_sb_s * const sb, goto errout; } - /* TOFO: If the parent directory is newly formed (ie. size is 0), then + /* TODO: If the parent directory is newly formed (ie. size is 0), then * allocate space for it. This can be done better. Just allocate page when * its created and added first to LRU, and then add a check to ensure it * doesn't get re-allocated when written. A field like "new" would be @@ -891,12 +979,12 @@ int mfs_pitr_appendnew(FAR struct mfs_sb_s * const sb, { /* Depth is depth of the child to be appended. */ - int ret = OK; - struct timespec ts; + int ret = OK; FAR const char *cur = last_child(relpath); FAR const char *next = next_child(cur); - FAR struct mfs_dirent_s *d = NULL; - const mfs_t len = *next == 0 ? next - cur : next - cur - 1; + const mfs_t len = *next == 0 ? next - cur : next - cur - 1; + struct timespec ts; + FAR struct mfs_dirent_s *d = NULL; DEBUGASSERT(depth > 0); @@ -942,3 +1030,34 @@ errout_with_d: errout: return ret; } + +/* Only for initialization of the block allocator. */ + +int mfs_pitr_traversefs(FAR struct mfs_sb_s * sb, const struct mfs_ctz_s ctz, + int type) +{ + /* type takes in MFS_ISFILE & MFS_ISDIR. */ + + int ret = OK; + mfs_t capacity; + FAR struct mfs_path_s *path = NULL; + + capacity = MFS_TRAVERSE_INITSZ; + path = kmm_zalloc(capacity * sizeof(struct mfs_path_s)); + if (predict_false(path == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + path[0].off = 0; + path[0].ctz = MFS_MN(sb).root_ctz; + path[0].sz = MFS_MN(sb).root_sz; + + ret = pitr_traverse(sb, path, 0, &capacity); + + mfs_free_patharr(path); + +errout: + return ret; +} diff --git a/fs/mnemofs/mnemofs_journal.c b/fs/mnemofs/mnemofs_journal.c index 907bb6f1ea2..a62214a82f0 100644 --- a/fs/mnemofs/mnemofs_journal.c +++ b/fs/mnemofs/mnemofs_journal.c @@ -483,13 +483,13 @@ errout: return ret; } -int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) +int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, FAR mfs_t *blk1, + FAR mfs_t *blk2, FAR mfs_t *jrnl_blk) { int i; int ret = OK; mfs_t sz; mfs_t pg; - mfs_t mn; mfs_t blk; mfs_t n_pgs; mfs_t rem_sz; @@ -509,26 +509,26 @@ int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) goto errout; } - if (blk1 == 0 && blk2 == 0) + if (*blk1 == 0 && *blk2 == 0) { - blk1 = mfs_ba_getblk(sb); + *blk1 = mfs_ba_getblk(sb); if (predict_false(blk1 == 0)) { ret = -ENOSPC; goto errout_with_buf; } - finfo("Allocated Master Block 1: %d.", blk1); + finfo("Allocated Master Block 1: %d.", *blk1); - blk2 = mfs_ba_getblk(sb); + *blk2 = mfs_ba_getblk(sb); if (predict_false(blk2 == 0)) { ret = -ENOSPC; goto errout_with_buf; } - finfo("Allocated Master Block 1: %d.", blk2); - finfo("New locations for Master Blocks %d & %d.", blk1, blk2); + finfo("Allocated Master Block 1: %d.", *blk2); + finfo("New locations for Master Blocks %d & %d.", *blk1, *blk2); } tmp = buf; @@ -548,8 +548,8 @@ int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) finfo("Allocated Journal Block %d at Block %d.", i, alloc_blk); } - tmp = mfs_ser_mfs(blk1, tmp); - tmp = mfs_ser_mfs(blk2, tmp); + tmp = mfs_ser_mfs(*blk1, tmp); + tmp = mfs_ser_mfs(*blk2, tmp); finfo("All Journal Blocks allocated."); @@ -576,26 +576,15 @@ int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) finfo("Written magic sequence, size and journal array into the journal."); MFS_JRNL(sb).n_logs = 0; + MFS_JRNL(sb).n_blks = CONFIG_MNEMOFS_JOURNAL_NBLKS; MFS_JRNL(sb).log_cpg = pg; MFS_JRNL(sb).log_cblkidx = 0; MFS_JRNL(sb).log_spg = MFS_JRNL(sb).log_cpg; MFS_JRNL(sb).log_sblkidx = MFS_JRNL(sb).log_cblkidx; MFS_JRNL(sb).jrnlarr_pg = MFS_BLK2PG(sb, blk); MFS_JRNL(sb).jrnlarr_pgoff = MFS_JRNL_SUFFIXSZ; - MFS_JRNL(sb).n_blks = CONFIG_MNEMOFS_JOURNAL_NBLKS; - MFS_JRNL(sb).mblk1 = blk1; - MFS_JRNL(sb).mblk2 = blk2; - - /* Master node */ - - mn = mfs_mn_fmt(sb, blk); - if (predict_false(mn == 0)) - { - ret = -ENOSPC; - goto errout_with_buf; - } - - /* TODO: Write master node's location in blk1, blk2. */ + MFS_JRNL(sb).mblk1 = *blk1; + MFS_JRNL(sb).mblk2 = *blk2; errout_with_buf: kmm_free(buf); @@ -659,7 +648,7 @@ int mfs_jrnl_updatedinfo(FAR const struct mfs_sb_s * const sb, mfs_t blkidx; mfs_t counter = 0; mfs_t pg_in_block; - struct jrnl_log_s tmplog; + struct jrnl_log_s tmplog; /* TODO: Allow optional filling of updated timestamps, etc. */ @@ -707,19 +696,19 @@ errout: } int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, - const struct mfs_node_s node, + FAR const struct mfs_node_s *node, const struct mfs_ctz_s loc_new, const mfs_t sz_new) { - int ret = OK; - mfs_t i; - mfs_t n_pgs; - mfs_t wr_sz; - mfs_t jrnl_pg; - mfs_t jrnl_blk; - FAR char *buf = NULL; - FAR char *tmp = NULL; - const mfs_t log_sz = sizeof(mfs_t) + MFS_LOGSZ(node.depth); - struct jrnl_log_s log; + int ret = OK; + mfs_t i; + mfs_t n_pgs; + mfs_t wr_sz; + mfs_t jrnl_pg; + mfs_t jrnl_blk; + FAR char *buf = NULL; + FAR char *tmp = NULL; + const mfs_t log_sz = sizeof(mfs_t) + MFS_LOGSZ(node->depth); + struct jrnl_log_s log; buf = kmm_zalloc(log_sz); /* For size before log. */ if (predict_false(buf == NULL)) @@ -730,16 +719,16 @@ int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, /* Serialize */ - log.depth = node.depth; - log.sz_new = node.depth; + log.depth = node->depth; + log.sz_new = sz_new; log.loc_new = loc_new; - log.st_mtim_new = node.st_mtim; - log.st_atim_new = node.st_atim; - log.st_ctim_new = node.st_ctim; - log.path = node.path; /* Fine as temporarily usage. */ + log.st_mtim_new = node->st_mtim; + log.st_atim_new = node->st_atim; + log.st_ctim_new = node->st_ctim; + log.path = node->path; /* Fine as temporarily usage. */ tmp = buf; - tmp = mfs_ser_mfs(log_sz - sizeof(mfs_t), tmp); + tmp = mfs_ser_mfs(log_sz - sizeof(mfs_t), tmp); /* First 4 bytes have sz */ tmp = ser_log(&log, tmp); /* Store */ @@ -820,7 +809,200 @@ errout: int mfs_jrnl_flush(FAR struct mfs_sb_s * const sb) { - /* TODO */ + /* When a file or a directory is deleted. + * + * It will be modified to an entry in the LRU which details the deletion + * of all bytes from the child... as in, offset 0, deleted bytes is the + * size of the file. + * + * The new "location" can be used as (0, 0) to signify a deletion, even in + * its journal log. + * + * Also ensure if the size gets updated to 0. + * + * Then the flush operation problem will be solved for removal of files or + * directories. + * + * Move operation will not empty the child, but only the parent from the + * old parent. + */ - return OK; + /* Time complexity is going to be horrendous. Hint: O(n^2). HOWEVER, as + * littlefs points out....if n is constant, it's essentially a O(k), or + * O(1) :D + */ + + /* TODO: Need to consider how the LRU and Journal interact with each other + * for newly created fs object's entries. + */ + + /* We're using updatectz to update the LRU inside the journal. Think + * about how that might affect the iteration attempts. + */ + + int ret = OK; + mfs_t blkidx = MFS_JRNL(sb).log_sblkidx; + mfs_t log_itr = 0; + mfs_t pg_in_blk = MFS_JRNL(sb).log_spg \ + % MFS_PGINBLK(sb); + mfs_t tmp_blkidx; + mfs_t tmp_pg_in_blk; + mfs_t mn_blk1; + mfs_t mn_blk2; + mfs_t i; + mfs_t jrnl_blk; + mfs_t blk; + struct jrnl_log_s log; + struct jrnl_log_s tmp_log; + FAR struct mfs_path_s *path = NULL; + struct mfs_jrnl_state_s j_state; + struct mfs_mn_s mn_state; + + while (log_itr < MFS_JRNL(sb).n_logs) + { + ret = jrnl_rdlog(sb, &blkidx, &pg_in_blk, &log); + if (predict_false(ret < 0)) + { + DEBUGASSERT(ret != -ENOSPC); /* While condition is sufficient. */ + goto errout; + } + + if (log.loc_new.pg_e == 0 && log.loc_new.idx_e == 0) + { + /* Entry is deleted, do not bother with it. */ + + break; + } + + tmp_blkidx = blkidx; + tmp_pg_in_blk = pg_in_blk; + + path = kmm_zalloc(log.depth * sizeof(struct mfs_path_s)); + if (predict_false(path == NULL)) + { + goto errout; + } + + memcpy(path, log.path, log.depth * sizeof(struct mfs_path_s)); + path[log.depth - 1].ctz = log.loc_new; + + for (; ; ) + { + ret = jrnl_rdlog(sb, &tmp_blkidx, &tmp_pg_in_blk, &tmp_log); + if (ret == -ENOSPC) + { + break; + } + else if (predict_false(ret < 0)) + { + jrnl_log_free(&log); + goto errout; + } + + if (tmp_log.depth > log.depth) + { + jrnl_log_free(&tmp_log); + continue; + } + + if (!mfs_path_eq(&path[tmp_log.depth - 1], + &tmp_log.path[tmp_log.depth - 1])) + { + jrnl_log_free(&tmp_log); + continue; + } + + path[tmp_log.depth - 1] = tmp_log.path[tmp_log.depth - 1]; + + if (tmp_log.loc_new.pg_e == 0 && tmp_log.loc_new.idx_e == 0) + { + /* Entry is deleted, do not bother with it. */ + + break; + } + } + + if (log.depth == 1) + { + MFS_MN(sb).root_ctz = path[log.depth - 1].ctz; + MFS_MN(sb).root_sz = path[log.depth - 1].sz; + + /* TODO: Other parameters. */ + } + else + { + ret = mfs_lru_updatectz(sb, path, log.depth, + path[log.depth - 1].ctz, + path[log.depth - 1].sz); + if (predict_false(ret < 0)) + { + mfs_free_patharr(path); + jrnl_log_free(&log); + goto errout; + } + } + + mfs_free_patharr(path); + jrnl_log_free(&log); + } + + if (MFS_MN(sb).mblk_idx == MFS_PGINBLK(sb)) + { + mn_blk1 = 0; + mn_blk2 = 0; + } + else + { + /* FUTURE TODO: Save the two block numbers in master node structure to + * be faster. + */ + + mn_blk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); + mn_blk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); + } + + /* Reallocate journal. */ + + j_state = MFS_JRNL(sb); + mn_state = MFS_MN(sb); + + ret = mfs_jrnl_fmt(sb, &mn_blk1, &mn_blk2, &jrnl_blk); + if (predict_false(ret < 0)) + { + MFS_JRNL(sb) = j_state; + goto errout; + } + + /* Write master node entry. */ + + ret = mfs_mn_sync(sb, &path[0], mn_blk1, mn_blk2, jrnl_blk); + if (predict_false(ret < 0)) + { + MFS_MN(sb) = mn_state; + goto errout; + } + + /* Mark all old blocks of journal (and master blocks) as deletable. */ + + for (i = 0; i < MFS_JRNL(sb).n_blks + 2; i++) + { + blk = mfs_jrnl_blkidx2blk(sb, i); + mfs_ba_blkmarkdel(sb, blk); + } + + /* Delete outdated blocks. */ + + ret = mfs_ba_delmarked(sb); + if (predict_false(ret < 0)) + { + goto errout; + } + +errout: + return ret; +} + +bool mfs_jrnl_isempty(FAR const struct mfs_sb_s * const sb) +{ + return MFS_JRNL(sb).n_logs == 0; } diff --git a/fs/mnemofs/mnemofs_lru.c b/fs/mnemofs/mnemofs_lru.c index a0965e439c3..bfd310ce016 100644 --- a/fs/mnemofs/mnemofs_lru.c +++ b/fs/mnemofs/mnemofs_lru.c @@ -97,11 +97,12 @@ static void lru_nodesearch(FAR const struct mfs_sb_s * const sb, FAR const struct mfs_path_s * const path, const mfs_t depth, FAR struct mfs_node_s **node); static bool lru_islrufull(FAR struct mfs_sb_s * const sb); -static bool lru_isnodefull(FAR struct mfs_node_s *node); +static bool lru_isnodefull(FAR struct mfs_sb_s * const sb, + FAR struct mfs_node_s *node); static int lru_nodeflush(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, const mfs_t depth, FAR struct mfs_node_s *node, - bool clean_node); + bool rm_node); static int lru_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, mfs_t bytes, int op, FAR struct mfs_path_s * const path, @@ -109,6 +110,7 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, static int lru_updatesz(FAR struct mfs_sb_s * sb, FAR struct mfs_path_s * const path, const mfs_t depth, const mfs_t new_sz); +static void lru_node_free(FAR struct mfs_node_s *node); /**************************************************************************** * Private Data @@ -214,11 +216,15 @@ static void lru_nodesearch(FAR const struct mfs_sb_s * const sb, * true - LRU is full * false - LRU is not full. * + * Assumptions/Limitations: + * When the journal is being flushed, LRU memory limiters will be turned + * off. + * ****************************************************************************/ static bool lru_islrufull(FAR struct mfs_sb_s * const sb) { - return sb->n_lru == CONFIG_MNEMOFS_NLRU; + return !MFS_FLUSH(sb) && list_length(&MFS_LRU(sb)) == CONFIG_MNEMOFS_NLRU; } /**************************************************************************** @@ -234,11 +240,16 @@ static bool lru_islrufull(FAR struct mfs_sb_s * const sb) * true - LRU node is full * false - LRU node is not full. * + * Assumptions/Limitations: + * When the journal is being flushed, LRU memory limiters will be turned + * off. + * ****************************************************************************/ -static bool lru_isnodefull(FAR struct mfs_node_s *node) +static bool lru_isnodefull(FAR struct mfs_sb_s * const sb, + FAR struct mfs_node_s *node) { - return node->n_list == CONFIG_MNEMOFS_NLRUDELTA; + return !MFS_FLUSH(sb) && node->n_list == CONFIG_MNEMOFS_NLRUDELTA; } /**************************************************************************** @@ -263,15 +274,16 @@ static void lru_free_delta(FAR struct mfs_delta_s *delta) * * Description: * Clear out the deltas in a node by writing them to the flash, and adding - * a log about it to the journal. + * a log about it to the journal. Does not flush the journal, and assumes + * enough space is in the journal to handle a log. * * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Depth of `path`. - * node - LRU node to flush. - * clean_node - To remove node out of LRU (true), or just clear the - * deltas (false). + * sb - Superblock instance of the device. + * path - CTZ representation of the relpath. + * depth - Depth of `path`. + * node - LRU node to flush. + * rm_node - To remove node out of LRU (true), or just clear the deltas + * (false). * * Returned Value: * 0 - OK @@ -282,39 +294,59 @@ static void lru_free_delta(FAR struct mfs_delta_s *delta) static int lru_nodeflush(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, const mfs_t depth, FAR struct mfs_node_s *node, - bool clean_node) + bool rm_node) { int ret = OK; + struct mfs_ctz_s loc; FAR struct mfs_delta_s *delta = NULL; FAR struct mfs_delta_s *tmp = NULL; if (predict_false(node == NULL)) { - return -ENOMEM; + return -EINVAL; } - /* TODO: Implement effct of clean_node. */ - - ret = mfs_ctz_wrtnode(sb, node); + ret = mfs_ctz_wrtnode(sb, node, &loc); if (predict_false(ret < 0)) { goto errout; } - /* Reset node stats. */ - - node->range_max = 0; - node->range_min = UINT32_MAX; - /* Free deltas after flush. */ - list_for_every_entry_safe(&node->list, delta, tmp, struct mfs_delta_s, + finfo("Removing Deltas."); + + list_for_every_entry_safe(&node->delta, delta, tmp, struct mfs_delta_s, list) { list_delete_init(&delta->list); lru_free_delta(delta); } + if (rm_node) + { + finfo("Deleting node. Old size: %u.", list_length(&MFS_LRU(sb))); + list_delete_init(&node->list); + finfo("Deleted node. New size: %u.", list_length(&MFS_LRU(sb))); + } + else + { + /* Reset node stats. */ + + finfo("Resetting node."); + memset(node, 0, sizeof(struct mfs_node_s)); + node->range_min = UINT32_MAX; + } + + finfo("Updating CTZ in parent."); + ret = mfs_lru_updatectz(sb, node->path, node->depth, loc, node->sz); + + if (rm_node) + { + finfo("Freeing node."); + lru_node_free(node); + } + errout: return ret; } @@ -353,6 +385,8 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, FAR struct mfs_node_s *last_node = NULL; FAR struct mfs_delta_s *delta = NULL; + DEBUGASSERT(depth > 0); + lru_nodesearch(sb, path, depth, &node); if (node == NULL) @@ -394,20 +428,24 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, struct mfs_node_s, list); list_delete_init(&last_node->list); list_add_tail(&MFS_LRU(sb), &node->list); - finfo("LRU flushing node complete, now only %u nodes", sb->n_lru); + finfo("LRU flushing node complete, now only %u nodes", + list_length(&MFS_LRU(sb))); } else { list_add_tail(&MFS_LRU(sb), &node->list); - sb->n_lru++; - finfo("Node inserted into LRU, and it now %u node(s).", sb->n_lru); + finfo("Node inserted into LRU, and it now %u node(s).", + list_length(&MFS_LRU(sb))); } } - else if (found && lru_isnodefull(node)) + else if (found && lru_isnodefull(sb, node)) { - /* Node flush writes to the flash and journal. */ + /* This can be optimized further if needed, but for now, for saftey of + * the data, I think it's better to flush the entire thing. It won't + * flush ALL of it, just, whatever's required. + */ - ret = lru_nodeflush(sb, path, depth, node, false); + ret = mnemofs_flush(sb); if (predict_false(ret < 0)) { goto errout_with_node; @@ -563,12 +601,13 @@ static int lru_updatesz(FAR struct mfs_sb_s * sb, mfs_ser_mfs(new_sz, buf); /* This function will be used by mfs_lru_wr itself, but given that if - * there is no change in size, this won't cause an infinite loop, this - * should be fine. + * there is no change in size, this won't cause an infinite loop (or, in + * reality, a recursion till it reaches the top of the tree), this should + * be fine. */ ret = mfs_lru_wr(sb, path[depth - 2].off + offsetof(struct mfs_dirent_s, - sz), sizeof(mfs_t), path, depth, buf); + sz), sizeof(mfs_t), path, depth - 1, buf); if (predict_false(ret < 0)) { goto errout; @@ -580,22 +619,220 @@ errout: return ret; } +static void lru_node_free(FAR struct mfs_node_s *node) +{ + mfs_free_patharr(node->path); + kmm_free(node); +} + +static bool lru_sort_cmp(FAR struct mfs_node_s * const node, + FAR struct mfs_node_s * const pivot) +{ + return node->depth < pivot->depth; +} + +static void lru_sort(FAR struct mfs_sb_s * const sb, + FAR struct list_node *left, + FAR struct list_node *right) +{ + FAR struct mfs_node_s *node = NULL; + FAR struct mfs_node_s *next = NULL; + FAR struct mfs_node_s *pivot = NULL; + FAR struct list_node *aend = NULL; /* After end. */ + FAR struct list_node *bfirst = NULL; /* Before first. */ + + if (left == right) + { + return; + } + + /* If left or right is NULL, it means that refers to MFS_LRU(sb). */ + + aend = right->next; + bfirst = left->prev; + + node = list_container_of(left, struct mfs_node_s, list); + pivot = list_container_of(right, struct mfs_node_s, list); + + if (node->list.next == &pivot->list) + { + /* Only two items in the window...node and pivot, so insertion sort. */ + + if (lru_sort_cmp(node, pivot)) + { + /* Add node after the pivot. */ + + list_delete_init(&node->list); + list_add_after(&pivot->list, &node->list); + + DEBUGASSERT(pivot->list.prev == bfirst); + } + + DEBUGASSERT(!lru_sort_cmp(node, pivot)); + + return; + } + + list_for_every_entry_safe_from(&MFS_LRU(sb), node, next, struct mfs_node_s, + list) + { + if (node == pivot) + { + break; + } + + if (lru_sort_cmp(node, pivot)) + { + /* Add node after the pivot. */ + + list_delete_init(&node->list); + list_add_after(&pivot->list, &node->list); + } + } + + if (bfirst->next != &pivot->list) + { + lru_sort(sb, bfirst->next, pivot->list.prev); + } + + if (aend->prev != &pivot->list) + { + lru_sort(sb, pivot->list.next, aend->prev); + } +} + /**************************************************************************** * Public Functions ****************************************************************************/ -int mfs_lru_ctzflush(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, const mfs_t depth) +int mfs_lru_flush(FAR struct mfs_sb_s * const sb) { - struct mfs_node_s *node = NULL; + int ret = OK; + FAR struct mfs_node_s *tmp = NULL; + FAR struct mfs_node_s *tmp2 = NULL; + FAR struct mfs_node_s *node = NULL; + FAR struct mfs_node_s *next = NULL; - lru_nodesearch(sb, path, depth, &node); - if (node == NULL) +/* Modified quick sort in linked lists. What is wanted is like inverted + * topological sort, but all the files (no children) are at the front, + * their depths don't matter. BUT, when it comes to directories, they need + * to be sorted in a decreasing order of their depths to reduce updates due + * to CoW. This will trickle up to the root, such that the root will be the + * last to get updated, and then the master node. + * + * However, since passing the mode all the way requires a lot of change, and + * is a redundant piece of information in most cases, the quick sort can + * simply be done on the basis of depth, and this adventure can be left as a + * TOOD. + * + * This involves recursion, but given the LRU size is a constant, the depth + * of recursion will be log2(n). For an LRU size of even 128 (which is quite + * big), the stack depth for this will be 7. + */ + + finfo("Sorting the LRU. No. of nodes: %u.", list_length(&MFS_LRU(sb))); + + lru_sort(sb, MFS_LRU(sb).next, MFS_LRU(sb).prev); + MFS_FLUSH(sb) = true; + + list_for_every_entry_safe(&MFS_LRU(sb), node, next, struct mfs_node_s, + list) { - return OK; + finfo("Current node depth: %u.", node->depth); + + if (node->depth != 1) + { + finfo("Checking for parent."); + + /* Ensuring parent is either present, or inserted into the LRU. + * No need of doing this before removing current node from LRU, + * however, this allows us to possibly skip allocating path again + * after freeing the current node. + */ + + /* We can not rely on normal LRU node insertions, as they will + * not be inserted in a sorted manner, and would need the entire + * LRU to be sorted again, so we insert it manually. + */ + + lru_nodesearch(sb, node->path, node->depth - 1, &tmp); + + if (tmp == NULL) + { + finfo("Adding parent to LRU"); + + tmp = kmm_zalloc(sizeof(struct mfs_node_s)); + if (predict_false(tmp == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + tmp->range_max = 0; + tmp->range_min = UINT32_MAX; + + /* TODO: Time fields. in tmp. */ + + tmp->depth = node->depth - 1; + tmp->path = kmm_zalloc((node->depth - 1) + * sizeof(struct mfs_path_s)); + if (predict_false(tmp->path == NULL)) + { + ret = -ENOMEM; + goto errout_with_tmp; + } + + memcpy(tmp->path, node->path, + sizeof(struct mfs_path_s) * tmp->depth); + list_initialize(&tmp->list); + list_initialize(&tmp->delta); + + /* Insert into sorted. */ + + list_for_every_entry(&MFS_LRU(sb), tmp2, struct mfs_node_s, + list) + { + if (!lru_sort_cmp(tmp, tmp2)) + { + list_add_before(&tmp2->list, &tmp->list); + + if (tmp2->list.prev == &node->list) + { + next = tmp2; + } + + break; + } + } + } + else + { + finfo("Parent already in LRU."); + } + } + else + { + finfo("Root node from LRU."); + } + + /* Parent gets updated inside the LRU in the function below. */ + + finfo("Flushing node."); + ret = lru_nodeflush(sb, node->path, node->depth, node, true); + if (predict_true(ret < 0)) + { + goto errout; + } } - return lru_nodeflush(sb, path, depth, node, true); + return ret; + +errout_with_tmp: + lru_node_free(node); + +errout: + MFS_FLUSH(sb) = false; + return ret; } int mfs_lru_del(FAR struct mfs_sb_s * const sb, const mfs_t data_off, @@ -615,7 +852,6 @@ int mfs_lru_wr(FAR struct mfs_sb_s * const sb, const mfs_t data_off, void mfs_lru_init(FAR struct mfs_sb_s * const sb) { list_initialize(&MFS_LRU(sb)); - sb->n_lru = 0; finfo("LRU Initialized\n"); } @@ -639,23 +875,24 @@ int mfs_lru_rdfromoff(FAR const struct mfs_sb_s * const sb, FAR struct mfs_node_s *node = NULL; FAR struct mfs_delta_s *delta = NULL; - lru_nodesearch(sb, path, depth, &node); - if (node == NULL) - { - goto errout; - } - /* Node is NOT supposed to be freed by the caller, it's a reference to * the actual node in the LRU and freeing it could break the entire LRU. */ tmp = buf; - ctz = node->path[node->depth - 1].ctz; + ctz = path[depth - 1].ctz; lower = data_off; upper_og = lower + buflen; upper = upper_og; rem_sz = buflen; + lru_nodesearch(sb, path, depth, &node); + if (node == NULL) + { + mfs_ctz_rdfromoff(sb, ctz, 0, buflen, tmp); + goto errout; + } + while (rem_sz > 0) { mfs_ctz_rdfromoff(sb, ctz, lower, rem_sz, tmp); @@ -773,34 +1010,57 @@ int mfs_lru_updatedinfo(FAR const struct mfs_sb_s * const sb, int mfs_lru_updatectz(FAR struct mfs_sb_s * sb, FAR struct mfs_path_s * const path, const mfs_t depth, - const struct mfs_ctz_s new_ctz) + const struct mfs_ctz_s new_ctz, mfs_t new_sz) { int ret = OK; char buf[sizeof(struct mfs_ctz_s)]; FAR struct mfs_node_s *node = NULL; + /* TODO: Other attributes like time stamps to be updated as well. */ + list_for_every_entry(&MFS_LRU(sb), node, struct mfs_node_s, list) { if (node->depth >= depth && - mfs_ctz_eq(&node->path[depth - 1].ctz, &path[depth - 1].ctz) && - node->path[depth - 1].sz == path[depth - 1].sz) + mfs_ctz_eq(&node->path[depth - 1].ctz, &path[depth - 1].ctz)) { node->path[depth - 1].ctz = new_ctz; + node->path[depth - 1].sz = path[depth - 1].sz; } } + if (depth == 1) + { + MFS_MN(sb).root_sz = new_sz; + MFS_MN(sb).root_ctz = new_ctz; + + goto errout; + } + + /* Write to LRU. */ + memset(buf, 0, sizeof(struct mfs_ctz_s)); mfs_ser_ctz(&new_ctz, buf); - ret = mfs_lru_wr(sb, path[depth - 1].off + offsetof(struct mfs_dirent_s, - ctz), sizeof(struct mfs_ctz_s), path, depth, buf); + ctz), sizeof(struct mfs_ctz_s), path, depth - 1, buf); + if (predict_false(ret < 0)) + { + goto errout; + } + + ret = lru_updatesz(sb, path, depth, new_sz); if (predict_false(ret < 0)) { goto errout; } path[depth - 1].ctz = new_ctz; + path[depth - 1].sz = new_sz; errout: return ret; } + +bool mfs_lru_isempty(FAR struct mfs_sb_s * const sb) +{ + return list_length(&MFS_LRU(sb)) == 0; +} diff --git a/fs/mnemofs/mnemofs_master.c b/fs/mnemofs/mnemofs_master.c index 7f5b0ebacad..517df69a6f1 100644 --- a/fs/mnemofs/mnemofs_master.c +++ b/fs/mnemofs/mnemofs_master.c @@ -100,7 +100,7 @@ static FAR char *ser_mn(const struct mfs_mn_s mn, FAR char * const out); static FAR const char *deser_mn(FAR const char * const in, - FAR struct mfs_mn_s *mn, FAR uint8_t *hash); + FAR struct mfs_mn_s *mn, FAR uint16_t *hash); /**************************************************************************** * Private Data @@ -141,7 +141,9 @@ static FAR char *ser_mn(const struct mfs_mn_s mn, FAR char * const out) tmp = mfs_ser_ctz(&mn.root_ctz, tmp); tmp = mfs_ser_mfs(mn.root_sz, tmp); tmp = mfs_ser_timespec(&mn.ts, tmp); - tmp = mfs_ser_8(mfs_arrhash(out, tmp - out), tmp); + tmp = mfs_ser_16(mfs_hash(out, tmp - out), tmp); + + /* TODO: Update this, and the make a macro for size of MN. */ return tmp; } @@ -166,7 +168,7 @@ static FAR char *ser_mn(const struct mfs_mn_s mn, FAR char * const out) ****************************************************************************/ static FAR const char *deser_mn(FAR const char * const in, - FAR struct mfs_mn_s *mn, FAR uint8_t *hash) + FAR struct mfs_mn_s *mn, FAR uint16_t *hash) { FAR const char *tmp = in; @@ -175,7 +177,9 @@ static FAR const char *deser_mn(FAR const char * const in, tmp = mfs_deser_ctz(tmp, &mn->root_ctz); tmp = mfs_deser_mfs(tmp, &mn->root_sz); tmp = mfs_deser_timespec(tmp, &mn->ts); - tmp = mfs_deser_8(tmp, hash); + tmp = mfs_deser_16(tmp, hash); + + /* TODO: Update this, and the make a macro for size of MN. */ return tmp; } @@ -192,15 +196,14 @@ int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) mfs_t mblk2; mfs_t jrnl_blk_tmp; bool found = false; - uint8_t hash; + uint16_t hash; struct mfs_mn_s mn; const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); char buftmp[4]; char buf[sz + 1]; - mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); - mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); - + mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); + mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); mn.jrnl_blk = mn.jrnl_blk; mn.mblk_idx = 0; mn.pg = MFS_BLK2PG(sb, mblk1); @@ -238,7 +241,6 @@ int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) } else { - mn.mblk_idx--; mn.pg--; } @@ -247,7 +249,7 @@ int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) /* Deserialize. */ deser_mn(buf, &mn, &hash); - if (hash != mfs_arrhash(buf, sz)) + if (hash != mfs_hash(buf, sz)) { ret = -EINVAL; goto errout; @@ -263,12 +265,11 @@ errout: return ret; } -int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) +int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t mblk1, + const mfs_t mblk2, const mfs_t jrnl_blk) { int ret = OK; mfs_t pg; - mfs_t mblk1; - mfs_t mblk2; struct mfs_mn_s mn; struct timespec ts; const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); @@ -278,9 +279,6 @@ int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) memset(buf, 0, sz + 1); - mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); - mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); - pg = mfs_ba_getpg(sb); if (predict_false(pg == 0)) { @@ -318,6 +316,7 @@ int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) goto errout; } + mn.mblk_idx = 1; MFS_MN(sb) = mn; finfo("Master node written. Now at page %d, timestamp %lld.%.9ld.", MFS_MN(sb).pg, (long long)MFS_MN(sb).ts.tv_sec, @@ -346,9 +345,9 @@ int mfs_mn_move(FAR struct mfs_sb_s * const sb, struct mfs_ctz_s root, mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); mn = MFS_MN(sb); - mn.root_ctz = root; + mn.root_ctz = root; mn.root_sz = root_sz; - mn.mblk_idx++; + mn.mblk_idx++; /* TODO */ mn.pg++; ser_mn(mn, buf); @@ -364,3 +363,55 @@ int mfs_mn_move(FAR struct mfs_sb_s * const sb, struct mfs_ctz_s root, errout: return ret; } + +int mfs_mn_sync(FAR struct mfs_sb_s *sb, + FAR struct mfs_path_s * const new_loc, + const mfs_t blk1, const mfs_t blk2, const mfs_t jrnl_blk) +{ + int ret = OK; + struct timespec ts; + struct mfs_mn_s mn; + const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); + char buf[sz + 1]; + + mn = MFS_MN(sb); + + clock_gettime(CLOCK_REALTIME, &ts); + + if (mn.mblk_idx == MFS_PGINBLK(sb)) + { + /* New blocks have been already allocated by the journal. */ + + mn.mblk_idx = 0; + mn.pg = MFS_BLK2PG(sb, blk1); + } + + mn.ts = ts; + mn.root_sz = new_loc->sz; + mn.root_ctz = new_loc->ctz; + mn.root_mode = 0777 | S_IFDIR; + + /* TODO: Root timestamps. */ + + /* Serialize. */ + + ser_mn(mn, buf); + + ret = mfs_write_page(sb, buf, sz, MFS_BLK2PG(sb, blk1) + mn.mblk_idx, 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + ret = mfs_write_page(sb, buf, sz, MFS_BLK2PG(sb, blk2) + mn.mblk_idx, 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + mn.mblk_idx++; + MFS_MN(sb) = mn; + +errout: + return ret; +} diff --git a/fs/mnemofs/mnemofs_rw.c b/fs/mnemofs/mnemofs_rw.c index 20ef4331ce8..6250ea9f157 100644 --- a/fs/mnemofs/mnemofs_rw.c +++ b/fs/mnemofs/mnemofs_rw.c @@ -53,6 +53,8 @@ * Included Files ****************************************************************************/ +#include + #include "mnemofs.h" /**************************************************************************** @@ -118,10 +120,10 @@ ssize_t mfs_write_page(FAR const struct mfs_sb_s * const sb, return -EINVAL; } - mempcpy(MFS_RWBUF(sb) + pgoff, data, datalen); + memcpy(MFS_RWBUF(sb) + pgoff, data, MIN(datalen, MFS_PGSZ(sb) - pgoff)); ret = MTD_BWRITE(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); - if (ret < 0) + if (predict_false(ret < 0)) { goto errout_with_reset; } @@ -144,12 +146,12 @@ ssize_t mfs_read_page(FAR const struct mfs_sb_s * const sb, } ret = MTD_BREAD(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); - if (ret < 0) + if (predict_false(ret < 0)) { goto errout_with_reset; } - memcpy(data, MFS_RWBUF(sb) + pgoff, datalen); + memcpy(data, MFS_RWBUF(sb) + pgoff, MIN(datalen, MFS_PGSZ(sb) - pgoff)); errout_with_reset: memset(MFS_RWBUF(sb), 0, MFS_PGSZ(sb)); diff --git a/fs/mnemofs/mnemofs_util.c b/fs/mnemofs/mnemofs_util.c index a9b1efe032a..e977ea35301 100644 --- a/fs/mnemofs/mnemofs_util.c +++ b/fs/mnemofs/mnemofs_util.c @@ -88,8 +88,8 @@ uint8_t mfs_arrhash(FAR const char *arr, ssize_t len) { - ssize_t l = 0; - ssize_t r = len - 1; + ssize_t l = 0; + ssize_t r = len - 1; uint16_t hash = 0; /* TODO: Change the array checksum to be 16 bit long. */ @@ -109,8 +109,8 @@ uint8_t mfs_arrhash(FAR const char *arr, ssize_t len) uint16_t mfs_hash(FAR const char *arr, ssize_t len) { - ssize_t l = 0; - ssize_t r = len - 1; + ssize_t l = 0; + ssize_t r = len - 1; uint32_t hash = 0; /* TODO: Change the array checksum to be 16 bit long. */