diff --git a/.gitignore b/.gitignore index fa38fadba3c..030babedd6a 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,4 @@ tools/gdb/__pycache__ /build .ccls-cache compile_commands.json -imx9-sdimage.img +imx9-sdimage.img \ No newline at end of file diff --git a/drivers/mtd/mtd_nandram.c b/drivers/mtd/mtd_nandram.c index cfaaef7366e..a2b96744166 100644 --- a/drivers/mtd/mtd_nandram.c +++ b/drivers/mtd/mtd_nandram.c @@ -25,6 +25,7 @@ * Included Files ****************************************************************************/ +#include #include #include @@ -89,8 +90,8 @@ #else -#define NAND_RAM_LOG -#define NAND_RAM_STATUS_LOG +#define NAND_RAM_LOG(str, ...) +#define NAND_RAM_STATUS_LOG(str, ...) #endif /* CONFIG_MTD_NAND_RAM_DEBUG */ @@ -197,10 +198,12 @@ static void nand_ram_storage_status(void) static inline void nand_ram_status(void) { +#ifdef CONFIG_MTD_NAND_RAM_DEBUG if (nand_ram_ins_i % NAND_RAM_STATUS_LEVEL == 0) { nand_ram_storage_status(); } +#endif } /**************************************************************************** @@ -353,12 +356,19 @@ int nand_ram_rawread(FAR struct nand_raw_s *raw, off_t block, if (data != NULL) { - memcpy(data, (const void *)read_page_data, NAND_RAM_PAGE_SIZE); + if (nand_ram_flash_spare[read_page].free == NAND_RAM_PAGE_FREE) + { + memset(data, 0, NAND_RAM_PAGE_SIZE); + } + else + { + memcpy(data, (const void *)read_page_data, NAND_RAM_PAGE_SIZE); + } } if (spare != NULL) { - memcpy(spare, (const void *)read_page_spare, NAND_RAM_PAGE_SIZE); + memcpy(spare, (const void *)read_page_spare, NAND_RAM_SPARE_SIZE); } NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "rawread"); @@ -420,6 +430,7 @@ int nand_ram_rawwrite(FAR struct nand_raw_s *raw, off_t block, nand_ram_flash_spare[write_page].n_write++; + memset((void *)write_page_data, 0, NAND_RAM_PAGE_SIZE); if (data != NULL) { memcpy((void *)write_page_data, data, NAND_RAM_PAGE_SIZE); diff --git a/drivers/mtd/mtd_nandwrapper.c b/drivers/mtd/mtd_nandwrapper.c index 83e6bbc9862..4c84340069a 100644 --- a/drivers/mtd/mtd_nandwrapper.c +++ b/drivers/mtd/mtd_nandwrapper.c @@ -328,7 +328,7 @@ int nand_wrapper_isbad(FAR struct mtd_dev_s *dev, off_t block) nxmutex_lock(&nand_wrapper_dev_mut); nand_wrapper_ins_i++; - NAND_WRAPPER_LOG("[UPPER %lu | %s] Blocks: %d\n", + NAND_WRAPPER_LOG("[UPPER %lu | %s] Block: %d\n", nand_wrapper_ins_i, "isbad", block); DEBUGASSERT(nand_dev && nand_dev->under.mtd.isbad); @@ -336,8 +336,8 @@ int nand_wrapper_isbad(FAR struct mtd_dev_s *dev, off_t block) if (ret >= 0) { - NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n", - nand_wrapper_ins_i, "isbad"); + NAND_WRAPPER_LOG("[UPPER %lu | %s] Done %d\n", + nand_wrapper_ins_i, "isbad", ret); } else { diff --git a/fs/mnemofs/mnemofs.c b/fs/mnemofs/mnemofs.c index 2009098fa3a..5cf0c0fef80 100644 --- a/fs/mnemofs/mnemofs.c +++ b/fs/mnemofs/mnemofs.c @@ -120,25 +120,25 @@ static ssize_t mnemofs_write(FAR struct file *filep, FAR const char *buffer, static off_t mnemofs_seek(FAR struct file *filep, off_t offset, int whence); static int mnemofs_ioctl(FAR struct file *filep, int cmd, - unsigned long arg); + unsigned long arg); static int mnemofs_truncate(FAR struct file *filep, off_t length); static int mnemofs_sync(FAR struct file *filep); static int mnemofs_dup(FAR const struct file *oldp, - FAR struct file *newp); + FAR struct file *newp); static int mnemofs_fstat(FAR const struct file *filep, - FAR struct stat *buf); + FAR struct stat *buf); 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); static int mnemofs_closedir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); 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); static int mnemofs_rewinddir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir); + FAR struct fs_dirent_s *dir); static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, FAR void** handle); @@ -151,9 +151,9 @@ static int mnemofs_statfs(FAR struct inode *mountpt, static int mnemofs_unlink(FAR struct inode *mountpt, FAR const char *relpath); static int mnemofs_mkdir(FAR struct inode *mountpt, - FAR const char *relpath, mode_t mode); + FAR const char *relpath, mode_t mode); static int mnemofs_rmdir(FAR struct inode *mountpt, - FAR const char *relpath); + FAR const char *relpath); static int mnemofs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, FAR const char *newrelpath); @@ -250,11 +250,11 @@ const struct mountpt_operations g_mnemofs_operations = static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { - int ret = OK; - int flags; - struct mfs_pitr_s pitr; + int ret = OK; + int flags; FAR const char *child = NULL; FAR struct inode *inode; + struct mfs_pitr_s pitr; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; FAR struct mfs_ocom_s *fcom; @@ -298,7 +298,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, /* Check creation flags. */ flags = mfs_get_patharr(sb, relpath, &f->com->path, &f->com->depth); - if ((flags & MFS_NEXIST) != 0) + if ((flags & MFS_EXIST) == 0) { if ((flags & MFS_P_ISDIR) != 0) { @@ -307,8 +307,10 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, /* Add direntry to parent's directory file. */ f->com->new_ent = true; + mfs_pitr_init(sb, f->com->path, f->com->depth, &pitr, true); child = mfs_path2childname(relpath); + finfo("Child is: %s.", child); mfs_pitr_appendnew(sb, f->com->path, f->com->depth, &pitr, child, mode); mfs_pitr_free(&pitr); @@ -347,7 +349,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, /* TODO: Update mtime and atime. */ mfs_pitr_init(sb, f->com->path, f->com->depth, &pitr, true); - mfs_pitr_readdirent(sb, &pitr, &dirent); + mfs_pitr_readdirent(sb, f->com->path, &pitr, &dirent); if (dirent != NULL) { @@ -367,7 +369,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, mfs_pitr_free(&pitr); - finfo("Direntry is read and processed."); + finfo("Direntry processing done."); /* Check Offset flags. */ @@ -378,8 +380,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, * then it's truncated. Else, the truncate flag is ignored. */ - ret = mfs_lru_del(sb, 0, f->com->sz, f->com->sz, f->com->path, - f->com->depth); + ret = mfs_lru_del(sb, 0, f->com->sz, f->com->path, f->com->depth); if (predict_false(ret < 0)) { finfo("Error while truncating file. Ret: %d.", ret); @@ -392,8 +393,7 @@ static int mnemofs_open(FAR struct file *filep, FAR const char *relpath, f->com->off = f->com->sz; } - finfo("Offset flags are set."); - + finfo("[TMP1] %p %p", &sb->of, &f->list); list_add_tail(&sb->of, &f->list); filep->f_priv = f; @@ -446,7 +446,7 @@ errout: static int mnemofs_close(FAR struct file *filep) { - int ret = OK; + int ret = OK; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -471,7 +471,7 @@ 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, f->com->sz); + ret = mfs_lru_ctzflush(sb, f->com->path, f->com->depth); if (predict_false(ret < 0)) { finfo("Error while flushing file. Ret: %d.", ret); @@ -480,17 +480,18 @@ static int mnemofs_close(FAR struct file *filep) f->com->refcount--; - if (predict_true(f->com->refcount != 0)) + if (f->com->refcount == 0) { kmm_free(f->com->path); kmm_free(f->com); - kmm_free(f); finfo("Refcount is 0, open file structure freed."); } list_delete(&f->list); + kmm_free(f); filep->f_priv = NULL; + finfo("File entry removed from the open files list."); errout_with_lock: @@ -530,7 +531,7 @@ errout: static ssize_t mnemofs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { - int ret = 0; + int ret = 0; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -643,8 +644,8 @@ static ssize_t mnemofs_write(FAR struct file *filep, FAR const char *buffer, /* Write data to CTZ at the current offset. */ - ret = mfs_lru_wr(sb, f->com->off, buflen, f->com->sz, f->com->path, - f->com->depth, buffer); + ret = mfs_lru_wr(sb, f->com->off, buflen, f->com->path, f->com->depth, + buffer); if (ret < 0) { goto errout_with_lock; @@ -693,8 +694,8 @@ errout: static off_t mnemofs_seek(FAR struct file *filep, off_t offset, int whence) { - int ret = OK; - mfs_t pos; + int ret = OK; + mfs_t pos; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -782,7 +783,7 @@ errout: static int mnemofs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { - int ret = OK; + int ret = OK; FAR struct inode *inode; FAR struct inode *drv; FAR struct mfs_sb_s *sb; @@ -844,7 +845,7 @@ errout: static int mnemofs_truncate(FAR struct file *filep, off_t length) { - int ret = OK; + int ret = OK; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -869,8 +870,8 @@ static int mnemofs_truncate(FAR struct file *filep, off_t length) if (length < f->com->sz) { - ret = mfs_lru_del(sb, length, f->com->sz - length, f->com->sz, - f->com->path, f->com->depth); + ret = mfs_lru_del(sb, length, f->com->sz - length, f->com->path, + f->com->depth); if (predict_false(ret < 0)) { finfo("Error during truncate. Ret: %d.", ret); @@ -932,7 +933,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, f->com->sz); + ret = mfs_lru_ctzflush(sb, f->com->path, f->com->depth); nxmutex_unlock(&MFS_LOCK(sb)); finfo("Lock released."); @@ -966,7 +967,7 @@ errout: static int mnemofs_dup(FAR const struct file *oldp, FAR struct file *newp) { - int ret = OK; + int ret = OK; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *of; @@ -1055,8 +1056,8 @@ errout: static int mnemofs_fstat(FAR const struct file *filep, FAR struct stat *buf) { - int ret = OK; - struct mfs_pitr_s pitr; + int ret = OK; + struct mfs_pitr_s pitr; FAR struct inode *inode; FAR struct mfs_sb_s *sb; FAR struct mfs_ofd_s *f; @@ -1081,9 +1082,10 @@ static int mnemofs_fstat(FAR const struct file *filep, FAR struct stat *buf) DEBUGASSERT(f != NULL); mfs_pitr_init(sb, f->com->path, f->com->depth, &pitr, true); - mfs_pitr_adv_tochild(&pitr, f->com->path, f->com->depth); - mfs_pitr_readdirent(sb, &pitr, &dirent); + mfs_pitr_adv_tochild(&pitr, f->com->path); + mfs_pitr_readdirent(sb, f->com->path, &pitr, &dirent); mfs_pitr_free(&pitr); + DEBUGASSERT(dirent != NULL); buf->st_mode = dirent->mode; @@ -1169,11 +1171,17 @@ static int mnemofs_opendir(FAR struct inode *mountpt, goto errout_with_lock; } + ret = mfs_lru_updatedinfo(sb, path, depth); + if (predict_false(ret < 0)) + { + goto errout_with_path; + } + pitr = kmm_zalloc(sizeof(*pitr)); if (predict_false(pitr == NULL)) { ret = -ENOMEM; - goto errout_with_lock; + goto errout_with_path; } fsdirent = kmm_zalloc(sizeof(*fsdirent)); @@ -1183,7 +1191,12 @@ static int mnemofs_opendir(FAR struct inode *mountpt, goto errout_with_pitr; } - mfs_pitr_init(sb, path, depth, pitr, false); + ret = mfs_pitr_init(sb, path, depth, pitr, false); + if (predict_false(ret < 0)) + { + finfo("Failed PITR initialization."); + goto errout_with_fsdirent; + } fsdirent->idx = 0; fsdirent->path = path; @@ -1199,9 +1212,15 @@ static int mnemofs_opendir(FAR struct inode *mountpt, finfo("Lock released."); return ret; +errout_with_fsdirent: + kmm_free(fsdirent); + errout_with_pitr: kmm_free(pitr); +errout_with_path: + mfs_free_patharr(path); + errout_with_lock: nxmutex_unlock(&MFS_LOCK(sb)); finfo("Lock released."); @@ -1271,8 +1290,8 @@ static int mnemofs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir, FAR struct dirent *entry) { - int ret = OK; - FAR struct mfs_sb_s *sb; + int ret = OK; + FAR struct mfs_sb_s *sb; FAR struct mfs_dirent_s *dirent; FAR struct mfs_fsdirent *fsdirent = (FAR struct mfs_fsdirent *) dir; @@ -1311,13 +1330,19 @@ static int mnemofs_readdir(FAR struct inode *mountpt, /* Regular direntries from here. */ - /* Here lies the `unlink` and `rmdir` bug, as sync can only update the - * current CTZ. + /* TODO: Need to think why *exactly* below line is needed. The LRU node + * seems to contain wrong size during opendir, but updating it here + * updates it to correct size, even though this updatedinfo is also + * called in opendir? */ - /* mfs_pitr_sync(sb, fsdirent->pitr, fsdirent->path, fsdirent->depth); */ + ret = mfs_lru_updatedinfo(sb, fsdirent->path, fsdirent->depth); + if (predict_false(ret < 0)) + { + goto errout_with_lock; + } - mfs_pitr_readdirent(sb, fsdirent->pitr, &dirent); + ret = mfs_pitr_readdirent(sb, fsdirent->path, fsdirent->pitr, &dirent); if (predict_false(ret < 0)) { goto errout_with_lock; @@ -1333,10 +1358,13 @@ static int mnemofs_readdir(FAR struct inode *mountpt, } memset(entry->d_name, 0, NAME_MAX + 1); - memcpy(entry->d_name, dirent->name, NAME_MAX); + memcpy(entry->d_name, dirent->name, dirent->namelen); entry->d_type = (S_ISDIR(dirent->mode) ? DTYPE_DIRECTORY: DTYPE_FILE); - mfs_pitr_adv(sb, fsdirent->pitr); + finfo("Size of direntry %u, current off %u.", MFS_DIRENTSZ(dirent), + fsdirent->pitr->c_off); + + mfs_pitr_adv_bydirent(fsdirent->pitr, dirent); mfs_free_dirent(dirent); errout_with_lock: @@ -1370,7 +1398,7 @@ errout: static int mnemofs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) { - int ret = OK; + int ret = OK; FAR struct mfs_sb_s *sb; struct mfs_fsdirent *fsdirent = (struct mfs_fsdirent *) dir; @@ -1503,6 +1531,8 @@ static int mnemofs_bind(FAR struct inode *driver, FAR const void *data, sb->log_pg_in_blk = log2(sb->pg_in_blk); sb->log_n_blks = log2(MFS_NBLKS(sb)); + list_initialize(&sb->of); + sb->rw_buf = kmm_zalloc(MFS_PGSZ(sb)); if (predict_false(sb->rw_buf == NULL)) { @@ -1762,11 +1792,10 @@ errout: static int mnemofs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, mode_t mode) { - int ret = OK; - int flags; - mfs_t depth; - FAR const char *child; - struct mfs_pitr_s pitr; + int ret = OK; + int flags; + mfs_t depth; + struct mfs_pitr_s pitr; FAR struct mfs_sb_s *sb; FAR struct mfs_path_s *path; @@ -1787,7 +1816,14 @@ static int mnemofs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, finfo("Lock acquired."); flags = mfs_get_patharr(sb, relpath, &path, &depth); - if ((flags & MFS_NEXIST) == 0) + if ((flags & MFS_EXIST) != 0) + { + finfo("File exists."); + + ret = -EEXIST; + goto errout_with_path; + } + else { if ((flags & MFS_P_EXIST) != 0) { @@ -1800,29 +1836,25 @@ static int mnemofs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, else { ret = -ENOTDIR; - goto errout_with_lock; + goto errout_with_path; } } else { ret = -ENOENT; - goto errout_with_lock; + goto errout_with_path; } } - else - { - ret = -EEXIST; - goto errout_with_lock; - } + memset(&path[depth - 1], 0, sizeof(struct mfs_path_s)); mfs_pitr_init(sb, path, depth, &pitr, true); - child = relpath; - finfo("Mode %x", mode); - ret = mfs_pitr_appendnew(sb, path, depth, &pitr, child, mode); + /* The last incomplete direntry will be added by mfs_pitr_appendnew. */ + + ret = mfs_pitr_appendnew(sb, path, depth, &pitr, relpath, mode); if (predict_false(ret < 0)) { - goto errout_with_pitr; + goto errout_with_path; } mfs_pitr_free(&pitr); @@ -1837,10 +1869,11 @@ static int mnemofs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, finfo("Mnemofs mkdir exited with ret %d.", ret); return ret; -errout_with_pitr: +errout_with_path: + mfs_free_patharr(path); + mfs_pitr_free(&pitr); -errout_with_lock: nxmutex_unlock(&MFS_LOCK(sb)); finfo("Lock released."); @@ -1869,10 +1902,10 @@ errout: static int mnemofs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) { - int ret = OK; - int flags; - mfs_t depth; - struct mfs_pitr_s pitr; + int ret = OK; + int flags; + mfs_t depth; + struct mfs_pitr_s pitr; FAR struct mfs_sb_s *sb; FAR struct mfs_path_s *path; @@ -1898,9 +1931,9 @@ static int mnemofs_rmdir(FAR struct inode *mountpt, FAR const char *relpath) } mfs_pitr_init(sb, path, depth, &pitr, true); - mfs_pitr_adv_tochild(&pitr, path, depth); + mfs_pitr_adv_tochild(&pitr, path); - if (!mfs_obj_isempty(sb, &pitr)) + if (!mfs_obj_isempty(sb, path, &pitr)) { ret = -ENOTEMPTY; goto errout_with_pitr; @@ -1948,16 +1981,16 @@ static int mnemofs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, FAR const char *newrelpath) { - int ret = OK; - int oflags; - int nflags; - bool nexists; - bool odir = false; - bool ndir = false; - mfs_t odepth; - mfs_t ndepth; - struct mfs_pitr_s opitr; - struct mfs_pitr_s npitr; + int ret = OK; + int oflags; + int nflags; + bool nexists; + bool odir = false; + bool ndir = false; + mfs_t odepth; + mfs_t ndepth; + struct mfs_pitr_s opitr; + struct mfs_pitr_s npitr; FAR struct mfs_sb_s *sb; FAR struct mfs_path_s *opath; FAR struct mfs_path_s *npath; @@ -1978,7 +2011,7 @@ static int mnemofs_rename(FAR struct inode *mountpt, finfo("Lock acquired."); oflags = mfs_get_patharr(sb, oldrelpath, &opath, &odepth); - if ((oflags & MFS_NEXIST) != 0) + if ((oflags & MFS_EXIST) == 0) { ret = -ENOENT; goto errout_with_opath; @@ -1991,9 +2024,9 @@ static int mnemofs_rename(FAR struct inode *mountpt, goto errout_with_npath; } - odir = ((oflags & MFS_ISDIR) != 0); - ndir = ((nflags & MFS_ISDIR) != 0); - nexists = ((nflags & MFS_NEXIST) == 0); + odir = ((oflags & MFS_ISDIR) != 0); + ndir = ((nflags & MFS_ISDIR) != 0); + nexists = ((nflags & MFS_EXIST) != 0); if (nexists && odir && !ndir) { @@ -2016,11 +2049,11 @@ static int mnemofs_rename(FAR struct inode *mountpt, if (nexists) { - mfs_pitr_adv_tochild(&opitr, opath, odepth); - mfs_pitr_adv_tochild(&npitr, npath, ndepth); + mfs_pitr_adv_tochild(&opitr, opath); + mfs_pitr_adv_tochild(&npitr, npath); - mfs_pitr_readdirent(sb, &opitr, &odirent); - if (ndir && !mfs_obj_isempty(sb, &npitr)) + mfs_pitr_readdirent(sb, opath, &opitr, &odirent); + if (ndir && !mfs_obj_isempty(sb, npath, &npitr)) { ret = -ENOTEMPTY; goto errout_with_pitr; @@ -2031,7 +2064,7 @@ static int mnemofs_rename(FAR struct inode *mountpt, mfs_pitr_rm(sb, npath, ndepth); } - mfs_pitr_adv_tochild(&npitr, npath, ndepth); + mfs_pitr_adv_tochild(&npitr, npath); mfs_pitr_appenddirent(sb, npath, ndepth, &npitr, odirent); mfs_pitr_rmdirent(sb, opath, odepth, &opitr, odirent); @@ -2086,7 +2119,7 @@ static int mnemofs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct mfs_path_s *path; FAR struct mfs_dirent_s *dirent = NULL; - finfo("Mnemofs stat for path %s.", relpath); + finfo("Mnemofs stat for path \"%s\".", relpath); DEBUGASSERT(mountpt != NULL); sb = mountpt->i_private; @@ -2101,26 +2134,33 @@ static int mnemofs_stat(FAR struct inode *mountpt, FAR const char *relpath, finfo("Lock acquired."); ret_flags = mfs_get_patharr(sb, relpath, &path, &depth); - if (ret_flags & MFS_NEXIST) + if ((ret_flags & MFS_EXIST) == 0) { ret = -ENOENT; - goto errout_with_lock; + goto errout_with_path; } - finfo("Got path array. Depth %u for path \"%s\"", depth, relpath); + finfo("Got path array. Depth %u for path \"%s\". Return flags %u.", depth, + relpath, ret_flags); - mfs_pitr_init(sb, path, depth, &pitr, true); - mfs_pitr_adv_tochild(&pitr, path, depth); - - ret = mfs_pitr_readdirent(sb, &pitr, &dirent); + ret = mfs_lru_updatedinfo(sb, path, depth); if (predict_false(ret < 0)) { - goto errout_with_lock; + goto errout_with_path; + } + + mfs_pitr_init(sb, path, depth, &pitr, true); + mfs_pitr_adv_tochild(&pitr, path); + + ret = mfs_pitr_readdirent(sb, path, &pitr, &dirent); + if (predict_false(ret < 0)) + { + goto errout_with_path; } else if (dirent == NULL) { ret = -ENOENT; - goto errout_with_lock; + goto errout_with_path; } finfo("Read stats."); @@ -2136,13 +2176,14 @@ static int mnemofs_stat(FAR struct inode *mountpt, FAR const char *relpath, mfs_free_dirent(dirent); mfs_pitr_free(&pitr); + +errout_with_path: mfs_free_patharr(path); -errout_with_lock: finfo("Lock released."); nxmutex_unlock(&MFS_LOCK(sb)); errout: - finfo("ret %d", ret); + finfo("Ret %d", ret); return ret; } diff --git a/fs/mnemofs/mnemofs.h b/fs/mnemofs/mnemofs.h index df1d1040b3c..ab6c2476eb9 100644 --- a/fs/mnemofs/mnemofs.h +++ b/fs/mnemofs/mnemofs.h @@ -88,9 +88,12 @@ #define MFS_NBLKS(sb) ((sb)->n_blks) #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) (sizeof(struct mfs_dirent_s) \ - + (dirent)->namelen) +#define MFS_DIRENTSZ(dirent) ((mfs_t) (sizeof(struct mfs_dirent_s) \ + + (dirent)->namelen)) + +#define MFS_JRNL_LIM(sb) (MFS_JRNL(sb).n_blks) /* TODO: 50-75% */ /**************************************************************************** * Public Types @@ -112,7 +115,7 @@ enum MFS_PATH_FLAGS { MFS_ISDIR = (1 << 0), /* Path is a directory. */ MFS_ISFILE = (1 << 1), /* Path is a file. */ - MFS_NEXIST = (1 << 2), /* Path No Exist */ + MFS_EXIST = (1 << 2), /* Path Exists */ MFS_FINPATH = (1 << 3), /* File in midele of path before bottom most * child. Not reachable. */ @@ -227,7 +230,10 @@ struct mfs_node_s mfs_t sz; mfs_t range_min; mfs_t range_max; - FAR struct mfs_path_s path[]; + struct timespec st_mtim; + struct timespec st_atim; + struct timespec st_ctim; + FAR struct mfs_path_s *path; }; /* Common Part Open File Descriptor */ @@ -253,9 +259,9 @@ struct mfs_ofd_s struct mfs_dirent_s { - uint8_t name_hash; /* Should be at start to improve efficiency. */ - mfs_t sz; + uint16_t name_hash; /* Should be at start to improve efficiency. */ uint16_t mode; + mfs_t sz; struct timespec st_atim; /* Time of last access */ struct timespec st_mtim; /* Time of last modification */ struct timespec st_ctim; /* Time of last status change */ @@ -271,9 +277,12 @@ struct mfs_pitr_s struct mfs_path_s p; /* Parent representation */ mfs_t depth; mfs_t c_off; /* Current offset. */ - mfs_t sz; /* Parent's size. */ }; +/* TODO: depth >= 1 */ + +/* IMP TODO: sizeof(x) != size of buffer required to store it. Need to fix. */ + /**************************************************************************** * Public Data ****************************************************************************/ @@ -410,55 +419,6 @@ static inline mfs_t mfs_popcnt(mfs_t x) /* mnemofs_journal.c */ -/**************************************************************************** - * Name: mfs_jrnl_newlog - * - * Description: - * Add a new log to the journal. - * - * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Length of path. - * new_ctz - The updated location. - * - * Returned Value: - * 0 - OK - * < 0 - Error - * - * Assumptions/Limitations: - * Assumes the CTZ list to be updated is `path[depth - 1].ctz`. - * - ****************************************************************************/ - -int mfs_jrnl_newlog(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, const struct mfs_ctz_s new_ctz); - -/**************************************************************************** - * Name: mfs_jrnl_updatepath - * - * Description: - * Updates the path of a CTZ list by applies all changes from the journal. - * - * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Length of path. - * - * Returned Value: - * 0 - OK - * < 0 - Error - * - * Assumptions/Limitations: - * Assumes the CTZ list to be updated is `path[depth - 1].ctz`. - * - ****************************************************************************/ - -int mfs_jrnl_updatepath(FAR const struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, - const mfs_t depth); - /**************************************************************************** * Name: mfs_jrnl_init * @@ -501,6 +461,19 @@ 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); +/**************************************************************************** + * Name: mfs_jrnl_free + * + * Description: + * Free the journal. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + ****************************************************************************/ + +void mfs_jrnl_free(FAR struct mfs_sb_s * const sb); + /**************************************************************************** * Name: mfs_jrnl_blkidx2blk * @@ -525,17 +498,79 @@ mfs_t mfs_jrnl_blkidx2blk(FAR const struct mfs_sb_s * const sb, const mfs_t blk_idx); /**************************************************************************** - * Name: mfs_jrnl_free + * Name: mfs_jrnl_updatedinfo * * Description: - * Free the journal. + * Update the path information from the journal. + * + * Input Parameters: + * sb - Superblock instance of the device. + * path - "Base state" path. + * depth - Path depth. + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + * Assumptions/Limitations: + * This applies updates over data that is already gathered from the data + * section of the flash. The data section is the "base state" over which + * the updates in the journal are applied. + * + ****************************************************************************/ + +int mfs_jrnl_updatedinfo(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth); + +/**************************************************************************** + * Name: mfs_jrnl_wrlog + * + * Description: + * Write a log for LRU node when its popped from the LRU. + * + * Input Parameters: + * sb - Superblock instance of the device. + * node - LRU node. + * loc_new - New location of the CTZ skip list. + * sz_new - New size of the CTZ skip list. + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + * Assumptions/Limitations: + * When a node from LRU is flushed, it's written to the data in any space + * that is available according to the block allocator, and the new location + * is recorded as a log along with the old location. Any log of this same + * CTZ skip list in the journal will use this "snapshot" of the location, + * ie. the updated path will be used until another log of the same CTZ + * skip list is stored, after which the path will be updated again, and + * so on. + * + ****************************************************************************/ + +int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, + const struct mfs_node_s node, + const struct mfs_ctz_s loc_new, const mfs_t sz_new); + +/**************************************************************************** + * Name: mfs_jrnl_flush + * + * Description: + * Flush the entire journal. This is the entry point of the entire flush + * operation and includes messing with the master node as well. * * Input Parameters: * sb - Superblock instance of the device. * + * Returned Value: + * 0 - OK + * < 0 - Error + * ****************************************************************************/ -void mfs_jrnl_free(FAR struct mfs_sb_s * const sb); +int mfs_jrnl_flush(FAR struct mfs_sb_s * const sb); /* mnemofs_blkalloc.c */ @@ -639,12 +674,16 @@ void mfs_ba_blkmarkdel(FAR struct mfs_sb_s * const sb, mfs_t blk); * Input Parameters: * sb - Superblock instance of the device. * + * Returned Value: + * 0 - OK + * < 0 - Error + * * Assumptions/Limitations: * This assumes a locked environment when called. * ****************************************************************************/ -void mfs_ba_delmarked(FAR struct mfs_sb_s * const sb); +int mfs_ba_delmarked(FAR struct mfs_sb_s * const sb); /**************************************************************************** * Name: mfs_ba_markusedpg @@ -847,6 +886,10 @@ int mfs_erase_nblks(FAR const struct mfs_sb_s * const sb, const off_t blk, uint8_t mfs_arrhash(FAR const char *arr, ssize_t len); +/* TODO: Put below in place of above. */ + +uint16_t mfs_hash(FAR const char *arr, ssize_t len); + /**************************************************************************** * Name: mfs_ser_8 * @@ -990,6 +1033,12 @@ FAR char *mfs_ser_ctz(FAR const struct mfs_ctz_s * const x, FAR const char *mfs_deser_ctz(FAR const char * const in, FAR struct mfs_ctz_s * const x); +FAR char *mfs_ser_path(FAR const struct mfs_path_s * const x, + FAR char * const out); + +FAR const char *mfs_deser_path(FAR const char * const in, + FAR struct mfs_path_s * const x); + /**************************************************************************** * Name: mfs_ser_timespec * @@ -1080,7 +1129,7 @@ mfs_t mfs_v2n(mfs_t n); * Name: mfs_set_msb * * Description: - * Set the least significant of the most significant unset bits. + * The mosr significant set bit location. * * Input Parameters: * n - Number. @@ -1092,146 +1141,61 @@ mfs_t mfs_v2n(mfs_t n); mfs_t mfs_set_msb(mfs_t n); +bool mfs_ctz_eq(FAR const struct mfs_ctz_s * const a, + FAR const struct mfs_ctz_s * const b); + +bool mfs_path_eq(FAR const struct mfs_path_s * const a, + FAR const struct mfs_path_s * const b); + /* mnemofs_ctz.c */ /**************************************************************************** - * Name: mfs_ctz_rdfromoff + * Name: mfs_ctz_rdfromoff_new * * Description: - * Read data from data offset in a CTZ list. This includes updates from the - * journal. The ctz list is taken as the last element in the path, got - * using `path[depth - 1]`. + * Read from a specific offset into the data in a CTZ file. New version. * * Input Parameters: * sb - Superblock instance of the device. - * data_off - Data offset into the CTZ list. - * path - CTZ representation of the relpath. - * depth - Depth of the path. - * buf - Buffer will be populated with the contents. - * buflen - Length of `buf`. - * - * Returned Value: - * 0 - OK - * < 0 - Error + * ctz - CTZ list. + * data_off - Offset into the data. + * len - Length of the buffer. + * buf - Buffer to store read contents. * * Assumptions/Limitations: - * This updates the value of path to reflect the latest location. + * The CTZ list provided should be the updated location from the journal. * ****************************************************************************/ -int mfs_ctz_rdfromoff(FAR struct mfs_sb_s * const sb, mfs_t data_off, - FAR struct mfs_path_s * const path, const mfs_t depth, - FAR char *buf, mfs_t buflen); +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); /**************************************************************************** - * Name: mfs_ctz_wrtooff + * Name: mfs_ctz_wrtnode_new * * Description: - * Replace `o_bytes` of data from CTZ list with `n_bytes` of data from - * `buf` at CTZ data offset `data_off`. - * - * In mnemofs, the CTZ lists are all stored in a Copy On Write manner. - * Hence to update a CTZ list, the common CTZ blocks will be kept as it is, - * then in the CTZ block containing `data_off`, the bytes appearing before - * `data_off` (which remain unchanged) will be copied to the new CTZ block - * then `n_bytes` of content from `buf` will follow, and then the data from - * `data_off + o_bytes` will follow (both these will be copied to new - * CTZ blocks as well due to Copy On Write). - * - * The new location will be written to the journal upon success as well. + * Write an LRU node to the flash. It also adds a log of it to the journal. * * Input Parameters: - * sb - Superblock instance of the device. - * data_off - Data offset into the CTZ list. - * o_bytes - Number of bytes in old CTZ list from `data_off` that will be - * replaced. - * n_bytes - Number of bytes in new CTZ list from `data_off` that will be - * replacing `o_bytes`. - * o_ctz_sz - The size in bytes of the old CTZ list. - * path - CTZ representation of the relpath. - * depth - Depth of the path. - * buf - Buffer that contains the data to be replaced in CTZ list. - * ctz - CTZ list to be updated with the new position. - * - * Returned Value: - * 0 - OK - * < 0 - Error + * sb - Superblock instance of the device. + * node - LRU node * * Assumptions/Limitations: - * This updates the value of path to reflect the latest location.s + * - Assumes path is updated by journal. This will also write corresponding + * journal log. + * + * - This is the most computationally heavy part of the entire file system + * from a human POV, and one of the most for MCU or computer (as init + * methods are heavier). * ****************************************************************************/ -int mfs_ctz_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - mfs_t o_bytes, const mfs_t n_bytes, - mfs_t o_ctz_sz, FAR struct mfs_path_s * const path, - const mfs_t depth, FAR const char *buf, - FAR struct mfs_ctz_s *ctz); - -/**************************************************************************** - * Name: mfs_ctz_nwrtooff - * - * Description: - * Write deltas of an LRU node to flash. - * - * Input Parameters: - * sb - Superblock instance of the device. - * node - LRU Node. - * path - CTZ representation of the relpath. - * depth - Depth of path. - * ctz_sz - Number of bytes in the data of the CTZ list. - * new_ctz - New CTZ location - * - ****************************************************************************/ - -int mfs_ctz_nwrtooff(FAR struct mfs_sb_s * const sb, - FAR struct mfs_node_s *node, - FAR struct mfs_path_s * const path, const mfs_t depth, - const mfs_t ctz_sz, FAR struct mfs_ctz_s *new_ctz); +int mfs_ctz_wrtnode(FAR struct mfs_sb_s * const sb, + const struct mfs_node_s * const node); /* mnemofs_lru.c */ -/**************************************************************************** - * Name: mfs_lru_del - * - * Description: - * Delete instruction to LRU. - * - * Input Parameters: - * sb - Superblock instance of the device. - * off - Offset into the data. - * bytes - Number of bytes to delete. - * ctz_sz - Number of bytes in the data of the CTZ list. - * path - CTZ representation of the relpath. - * depth - Depth of path. - * - ****************************************************************************/ - -int mfs_lru_del(FAR struct mfs_sb_s * const sb, const mfs_t off, - mfs_t bytes, mfs_t ctz_sz, - FAR struct mfs_path_s * const path, const mfs_t depth); - -/**************************************************************************** - * Name: mfs_lru_wr - * - * Description: - * Write to LRU - * - * Input Parameters: - * sb - Superblock instance of the device. - * data_off - Offset into the data. - * bytes - Number of bytes to delete. - * ctz_sz - Number of bytes in the data of the CTZ list. - * path - CTZ representation of the relpath. - * depth - Depth of path. - * buf - Buffer. - * - ****************************************************************************/ - -int mfs_lru_wr(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - mfs_t bytes, mfs_t ctz_sz, FAR struct mfs_path_s * const path, - const mfs_t depth, FAR const char *buf); - /**************************************************************************** * Name: mfs_lru_ctzflush * @@ -1242,13 +1206,63 @@ int mfs_lru_wr(FAR struct mfs_sb_s * const sb, const mfs_t data_off, * sb - Superblock instance of the device. * path - CTZ representation of the relpath. * depth - Depth of path. - * ctz_sz - Size of the CTZ file. * ****************************************************************************/ int mfs_lru_ctzflush(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, const mfs_t depth, - const mfs_t ctz_sz); + FAR struct mfs_path_s * const path, const mfs_t depth); + +/**************************************************************************** + * Name: mfs_lru_del + * + * Description: + * Delete instruction to LRU. + * + * Input Parameters: + * sb - Superblock instance of the device. + * off - Offset into the data. + * bytes - Number of bytes to delete. + * path - CTZ representation of the relpath. + * depth - Depth of path. + * + ****************************************************************************/ + +int mfs_lru_del(FAR struct mfs_sb_s * const sb, const mfs_t data_off, + mfs_t bytes, FAR struct mfs_path_s * const path, + const mfs_t depth); + +/**************************************************************************** + * Name: mfs_lru_wr + * + * Description: + * Write to LRU + * + * Input Parameters: + * sb - Superblock instance of the device. + * data_off - Offset into the data. + * bytes - Number of bytes to delete. + * path - CTZ representation of the relpath. + * depth - Depth of path. + * buf - Buffer. + * + ****************************************************************************/ + +int mfs_lru_wr(FAR struct mfs_sb_s * const sb, const mfs_t data_off, + mfs_t bytes, FAR struct mfs_path_s * const path, + const mfs_t depth, FAR const char *buf); + +/**************************************************************************** + * Name: mfs_lru_init + * + * Description: + * Initialize LRU. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + ****************************************************************************/ + +void mfs_lru_init(FAR struct mfs_sb_s * const sb); /**************************************************************************** * Name: mfs_lru_rdfromoff @@ -1266,40 +1280,52 @@ int mfs_lru_ctzflush(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -int mfs_lru_rdfromoff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, +int mfs_lru_rdfromoff(FAR const struct mfs_sb_s * const sb, + const mfs_t data_off, FAR struct mfs_path_s * const path, const mfs_t depth, FAR char *buf, const mfs_t buflen); /**************************************************************************** - * Name: mfs_lru_init + * Name: mfs_lru_updatedinfo * * Description: - * Initialize LRU. + * Update information of the path. * * Input Parameters: - * sb - Superblock instance of the device. + * sb - Superblock instance of the device. + * path - CTZ representation of the relpath. + * depth - Depth of path. + * + * Assumptions/Limitations: + * The will update path. * ****************************************************************************/ -void mfs_lru_init(FAR struct mfs_sb_s * const sb); +int mfs_lru_updatedinfo(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth); /**************************************************************************** - * Name: mfs_lru_updatedsz + * Name: mfs_lru_updatectz * * Description: - * Update size of a CTZ list. + * Update CTZ location of an fs object. * * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Depth of path. - * n_sz - New size. + * sb - Superblock instance of the device. + * path - Old CTZ representation of the relpath. + * depth - Depth of path. + * new_ctz - New CTZ location. + * + * Assumptions/Limitations: + * The update the CTZ portion of the direntry in the parent. + * This updates the path as well. * ****************************************************************************/ -void mfs_lru_updatedsz(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, mfs_t *n_sz); +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); /* mnemofs_master.c */ @@ -1436,8 +1462,8 @@ mfs_t mfs_get_fsz(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -int mfs_get_patharr(FAR struct mfs_sb_s *const sb, - FAR const char *relpath, FAR struct mfs_path_s **path, +int mfs_get_patharr(FAR const struct mfs_sb_s * const sb, + FAR const char * relpath, FAR struct mfs_path_s **path, FAR mfs_t *depth); /**************************************************************************** @@ -1472,7 +1498,8 @@ void mfs_free_patharr(FAR struct mfs_path_s *path); ****************************************************************************/ bool mfs_obj_isempty(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr); + FAR struct mfs_path_s *path, + FAR struct mfs_pitr_s * const pitr); /**************************************************************************** * Name: mfs_pitr_init @@ -1509,9 +1536,9 @@ bool mfs_obj_isempty(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -void mfs_pitr_init(FAR struct mfs_sb_s * const sb, +int mfs_pitr_init(FAR const struct mfs_sb_s * const sb, FAR const struct mfs_path_s * const path, - const mfs_t depth, FAR struct mfs_pitr_s *pitr, + const mfs_t depth, FAR struct mfs_pitr_s * const pitr, bool child); /**************************************************************************** @@ -1529,7 +1556,7 @@ void mfs_pitr_init(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -void mfs_pitr_free(FAR struct mfs_pitr_s * const pitr); +void mfs_pitr_free(FAR const struct mfs_pitr_s * const pitr); /**************************************************************************** * Name: mfs_pitr_adv @@ -1547,11 +1574,12 @@ void mfs_pitr_free(FAR struct mfs_pitr_s * const pitr); * ****************************************************************************/ -void mfs_pitr_adv(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr); +int mfs_pitr_adv(FAR struct mfs_sb_s * const sb, + FAR struct mfs_path_s *path, + FAR struct mfs_pitr_s * const pitr); /**************************************************************************** - * Name: mfs_pitr_adv_dirent + * Name: mfs_pitr_adv_bydirent * * Description: * Advance a pitr to the next direntry by using current direntry. @@ -1567,8 +1595,8 @@ void mfs_pitr_adv(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -void mfs_pitr_adv_dirent(FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_dirent_s * const dirent); +void mfs_pitr_adv_bydirent(FAR struct mfs_pitr_s * const pitr, + FAR const struct mfs_dirent_s * const dirent); /**************************************************************************** * Name: mfs_pitr_adv_off @@ -1598,7 +1626,6 @@ void mfs_pitr_adv_off(FAR struct mfs_pitr_s * const pitr, * Input Parameters: * pitr - Parent iterator. * path - CTZ representation of the relpath - * depth - Depth of path. * * Assumptions/Limitations: * This assumes that the pitr is initialized for the immediate parent of the @@ -1607,8 +1634,7 @@ void mfs_pitr_adv_off(FAR struct mfs_pitr_s * const pitr, ****************************************************************************/ void mfs_pitr_adv_tochild(FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_path_s * const path, - const mfs_t depth); + FAR const struct mfs_path_s * const path); /**************************************************************************** * Name: mfs_pitr_reset @@ -1623,30 +1649,6 @@ void mfs_pitr_adv_tochild(FAR struct mfs_pitr_s * const pitr, void mfs_pitr_reset(FAR struct mfs_pitr_s * const pitr); -/**************************************************************************** - * Name: mfs_pitr_sync - * - * Description: - * Sync a pitr. - * - * In mnemofs, when moving between locked contexts, it may happen that a - * a CTZ is moved to some place is between. This updates the location by - * reading the journal to check for any related logs in the journal. - * Updates contained in the LRU do not update the location of a CTZ list. - * - * Input Parameters: - * sb - Superblock instance of the device. - * pitr - Parent iterator. - * path - CTZ representation of the relpath - * depth - Depth of path. - * - ****************************************************************************/ - -void mfs_pitr_sync(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_path_s * const path, - const mfs_t depth); - /**************************************************************************** * Name: mfs_pitr_readdirent * @@ -1667,7 +1669,8 @@ void mfs_pitr_sync(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -int mfs_pitr_readdirent(FAR struct mfs_sb_s * const sb, +int mfs_pitr_readdirent(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s *path, FAR struct mfs_pitr_s * const pitr, FAR struct mfs_dirent_s **dirent); @@ -1734,7 +1737,7 @@ bool mfs_searchfopen(FAR const struct mfs_sb_s * const sb, int mfs_pitr_appenddirent(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, const mfs_t depth, - FAR const struct mfs_pitr_s * const pitr, + FAR struct mfs_pitr_s * const pitr, FAR const struct mfs_dirent_s * const dirent); /**************************************************************************** @@ -1745,24 +1748,27 @@ int mfs_pitr_appenddirent(FAR struct mfs_sb_s * const sb, * initialized in pitr. This creates the direntry. * * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Depth of path. - * pitr - Parent Iterator. - * dirent - Directory entry to be added. - * mode - Mode of the file/directory. + * sb - Superblock instance of the device. + * path - CTZ representation of the relpath. + * depth - Depth of path. + * pitr - Parent Iterator. + * relpath - Relative path of the fs object. + * mode - Mode of the file/directory. * * Returned Value: * 0 - OK * < 0 - Error * + * Assumptions/Limitations: + * This assumes that the fs object desired to be appended appears at the + * end of the entire relpath. + * ****************************************************************************/ int mfs_pitr_appendnew(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, - const mfs_t depth, - FAR const struct mfs_pitr_s * const pitr, - FAR const char * const child_name, const mode_t mode); + FAR struct mfs_path_s * const path, const mfs_t depth, + FAR struct mfs_pitr_s * const pitr, + FAR const char * const relpath, const mode_t mode); /**************************************************************************** * Name: mfs_pitr_rmdirent diff --git a/fs/mnemofs/mnemofs_blkalloc.c b/fs/mnemofs/mnemofs_blkalloc.c index 254675995f4..9bc135c6d1c 100644 --- a/fs/mnemofs/mnemofs_blkalloc.c +++ b/fs/mnemofs/mnemofs_blkalloc.c @@ -91,7 +91,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define BMAP_GET(bmap, idx, off) ((bmap)[(idx)] & (1 << (off))) +#define BMAP_GET(bmap, idx, off) (((bmap)[(idx)] & (1 << (off))) != 0) #define BMAP_SET(bmap, idx, off) ((bmap)[(idx)] |= (1 << (off))) #define DEL_ARR_BLK(sb, blk) (MFS_BA((sb)).k_del[(blk) * sizeof(size_t)]) #define DEL_ARR_PG(sb, pg) (DEL_ARR_BLK(sb, MFS_PG2BLK((sb), (pg)))) @@ -134,14 +134,8 @@ static int is_blk_writeable(FAR struct mfs_sb_s * const sb, * idx - Populated later with the index of page in MFS_BA(sb).bmap_upgs * off - Populated later with the offset of page in MFS_BA(sb).bmap_upgs * - * Returned Value: - * MFS_BLK_BAD - If the block of the page is a bad block. - * MFS_PG_USED - If the page is being used. - * MFS_BLK_ERASABLE - If page can be allocated, but block needs erase. - * MFS_PG_FREE - If the page is free. - * * Assumptions/Limitations: - * Does not check validity of the page number. + * Does not check validity of the index. * ****************************************************************************/ @@ -503,13 +497,28 @@ void mfs_ba_pgmarkdel(FAR struct mfs_sb_s * const sb, mfs_t pg) void mfs_ba_blkmarkdel(FAR struct mfs_sb_s * const sb, mfs_t blk) { - mfs_erase_blk(sb, blk); - DEL_ARR_BLK(sb, blk) = 0; + DEL_ARR_BLK(sb, blk) = MFS_PGINBLK(sb); } -void mfs_ba_delmarked(FAR struct mfs_sb_s * const sb) +int mfs_ba_delmarked(FAR struct mfs_sb_s * const sb) { - /* TODO */ + int ret = OK; + mfs_t i; + + for (i = 1; i < MFS_NBLKS(sb); i++) + { + if (DEL_ARR_BLK(sb, i) == MFS_PGINBLK(sb)) + { + ret = mfs_erase_blk(sb, i); + + if (ret != OK) + { + return ret; + } + } + } + + return ret; } /* Mark a page as being used. Used by master node during initial format and @@ -517,15 +526,16 @@ void mfs_ba_delmarked(FAR struct mfs_sb_s * const sb) void mfs_ba_markusedpg(FAR struct mfs_sb_s * const sb, mfs_t pg) { - mfs_t idx; + mfs_t idx; uint8_t off; + pg2bmap(pg, &idx, &off); BMAP_SET(MFS_BA(sb).bmap_upgs, idx, off); /* Set as used */ } void mfs_ba_markusedblk(FAR struct mfs_sb_s * const sb, mfs_t blk) { - mfs_t i = 0; + mfs_t i = 0; mfs_t pg = MFS_BLK2PG(sb, blk); for (i = 0; i < MFS_PGINBLK(sb); i++) diff --git a/fs/mnemofs/mnemofs_ctz.c b/fs/mnemofs/mnemofs_ctz.c index f24111f34eb..9db41c66439 100644 --- a/fs/mnemofs/mnemofs_ctz.c +++ b/fs/mnemofs/mnemofs_ctz.c @@ -157,7 +157,11 @@ static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, static mfs_t ctz_idx_nptrs(const mfs_t idx) { - return idx == 0 ? 0 : mfs_ctz(idx) + 1; + mfs_t ret; + + ret = (idx == 0) ? 0 : mfs_ctz(idx) + 1; + finfo("Number of pointers for %u index is %u.", idx, ret); + return ret; } /**************************************************************************** @@ -179,17 +183,29 @@ 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 den = MFS_PGSZ(sb) - 8; - if (off < MFS_PGSZ(sb)) + const mfs_t wb = sizeof(mfs_t); + const mfs_t den = MFS_PGSZ(sb) - 2 * wb; + + if (off < den) { *idx = 0; *pgoff = off; return; } - *idx = floor((off - 4 * (__builtin_popcount((off / den) - 1) + 2)) - / den); - *pgoff = off - den * (*idx) - 4 * __builtin_popcount(*idx); + if (idx != NULL) + { + *idx = (off - wb * (__builtin_popcount((off / den) - 1) + 2)) / den; + } + + if (pgoff != NULL) + { + *pgoff = off - den * (*idx) - wb * __builtin_popcount(*idx) + - (ctz_idx_nptrs(*idx) * wb); + } + + finfo("Offset %u. Calculated index %u and page offset %u.", off, *idx, + *pgoff); } /**************************************************************************** @@ -210,7 +226,11 @@ static void ctz_off2loc(FAR const struct mfs_sb_s * const sb, mfs_t off, static mfs_t ctz_blkdatasz(FAR const struct mfs_sb_s * const sb, const mfs_t idx) { - return MFS_PGSZ(sb) - (ctz_idx_nptrs(idx) * MFS_LOGPGSZ(sb)); + mfs_t ret; + + ret = MFS_PGSZ(sb) - (ctz_idx_nptrs(idx) * MFS_LOGPGSZ(sb)); + finfo("Block data size for index %u is %u.", idx, ret); + return ret; } /**************************************************************************** @@ -261,6 +281,11 @@ static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, mfs_read_page(sb, buf, 4, pg, MFS_PGSZ(sb) - (4 * pow)); mfs_deser_mfs(buf, &pg); idx -= (1 << pow); + + if (pg == 0) + { + return 0; + } } if (idx == idx_dest) @@ -278,8 +303,16 @@ static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, mfs_deser_mfs(buf, &pg); idx -= (1 << pow); diff -= (1 << pow); + + if (pg == 0) + { + return 0; + } } + finfo("Travel from index %u at page %u to index %u at page %u.", idx_src, + pg_src, idx_dest, pg); + return pg; } @@ -299,11 +332,11 @@ static mfs_t ctz_travel(FAR const struct mfs_sb_s * const sb, mfs_t idx_src, * 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. + * 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`. @@ -330,12 +363,19 @@ static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, 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)) @@ -355,6 +395,8 @@ static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, buf -= MFS_CTZ_PTRSZ; mfs_ser_mfs(prev_pg, buf); + + finfo("Copied %u page number to %uth pointer.", prev_pg, i); } } @@ -362,70 +404,123 @@ static void ctz_copyidxptrs(FAR const struct mfs_sb_s * const sb, * Public Functions ****************************************************************************/ -int mfs_ctz_rdfromoff(FAR struct mfs_sb_s * const sb, mfs_t data_off, - FAR struct mfs_path_s * const path, const mfs_t depth, - FAR char *buf, mfs_t buflen) +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 sz; - mfs_t pg; - mfs_t idx; - mfs_t off; - struct mfs_ctz_s ctz; + 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; - /* Get updated location from the journal */ + ctz_off2loc(sb, data_off + len, &cur_idx, &cur_pgoff); + ctz_off2loc(sb, data_off, &end_idx, &end_pgoff); - finfo("Journal upd!"); - DEBUGASSERT(depth > 0); - mfs_jrnl_updatepath(sb, path, depth); - ctz = path[depth - 1].ctz; - - ctz_off2loc(sb, data_off, &idx, &off); - - /* TODO: Make the traversal in reverse direction. It would cause - * a lot less traversals. - */ - - while (idx <= ctz.idx_e && off - data_off < buflen) + if (ctz.idx_e < cur_idx || ctz.idx_e < end_idx) { - sz = ctz_blkdatasz(sb, idx); - pg = ctz_travel(sb, ctz.idx_e, ctz.pg_e, idx); - - ret = mfs_read_page(sb, buf, sz, pg, off); - if (predict_false(ret < 0)) - { - return ret; - } - - off = 0; - idx++; - buf += sz; + 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_nwrtooff(FAR struct mfs_sb_s * const sb, - FAR struct mfs_node_s *node, - FAR struct mfs_path_s * const path, const mfs_t depth, - const mfs_t ctz_sz, FAR struct mfs_ctz_s *new_ctz) +int mfs_ctz_wrtnode(FAR struct mfs_sb_s * const sb, + FAR const struct mfs_node_s * const node) { - int ret = OK; - bool del; - mfs_t pg; - mfs_t sz; - mfs_t inc; - mfs_t idx; - mfs_t bytes; - mfs_t pgoff; - mfs_t itr_min; - mfs_t itr_max; - mfs_t neg_off; /* Negative offset due to delete. */ - FAR char *buf = NULL; - const mfs_t range_min = node->range_min; - const mfs_t range_max = node->range_max; + 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 = NULL; + 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)) @@ -434,338 +529,133 @@ int mfs_ctz_nwrtooff(FAR struct mfs_sb_s * const sb, goto errout; } - /* CoW of items in block before range_min */ + /* Initially, there might be some offset in cur_idx CTZ blocks that is + * unmodified as well. + */ - ctz_off2loc(sb, range_min, &idx, &pgoff); - DEBUGASSERT(depth > 0); - pg = ctz_travel(sb, path[depth - 1].ctz.idx_e, path[depth - 1].ctz.pg_e, - idx); - if (predict_false(pg == 0)) + 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) { - ret = -EINVAL; - goto errout_with_buf; - } - - ctz.idx_e = idx - 1; - ctz.pg_e = pg; - mfs_read_page(sb, buf, pgoff, pg, pgoff); - - /* Updates */ - - bytes = range_min; - itr_max = range_min; - neg_off = 0; - del = false; - - while (bytes < range_max) - { - if (!del) - { - memset(buf, 0, MFS_PGSZ(sb)); - sz = ctz_blkdatasz(sb, ctz.idx_e + 1); - itr_min = itr_max; - itr_max += sz; - ctz_copyidxptrs(sb, ctz, ctz.idx_e + 1, buf); - } - else - { - inc = itr_max - itr_min; - itr_min = itr_max; - itr_min = sz - inc; - } - - del = false; - mfs_ctz_rdfromoff(sb, itr_min + neg_off, path, depth, buf + pgoff, sz); + 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->off + delta->n_b <= itr_min || itr_max <= delta->off) - { - /* Out of range */ - - continue; - } - - inc = MIN(itr_max, delta->off + delta->n_b) - delta->off; - - if (delta->upd != NULL) - { - /* Update */ - - memcpy(buf + pgoff + (delta->off - itr_min), delta->upd, inc); - } - else + if (delta->upd == NULL) { /* Delete */ - memmove(buf + pgoff + (delta->off - itr_min), - buf + pgoff + (delta->off - itr_min) + inc, - itr_max - (delta->off + inc)); - itr_max -= inc; - neg_off += inc; - del = true; + 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; + } } } - bytes += itr_max - itr_min; + /* rem_sz check for final write. */ - if (!del) + if (upper == upper_og || rem_sz == upper - lower) { - pgoff = 0; - pg = mfs_ba_getpg(sb); - if (pg == 0) + 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; } - mfs_write_page(sb, buf, MFS_PGSZ(sb), pg, 0); - ctz.pg_e = pg; - ctz.idx_e++; + 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 { - pgoff += itr_max - itr_min; + tmp += upper - lower; + + written = false; } + + prev = upper - lower; + rem_sz -= upper - lower; + lower = upper; } - /* Copy rest of the file. */ + DEBUGASSERT(written); - if (del) + /* 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)) { - mfs_ctz_rdfromoff(sb, itr_max + neg_off, path, depth, buf + pgoff, - sz - pgoff); - pg = mfs_ba_getpg(sb); - if (pg == 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)) { - ret = -ENOSPC; goto errout_with_buf; } - - mfs_write_page(sb, buf, MFS_PGSZ(sb), pg, 0); - ctz.pg_e = pg; - ctz.idx_e++; - itr_max += sz - pgoff; - pgoff = 0; } - while (bytes < ctz_sz) - { - sz = ctz_blkdatasz(sb, ctz.idx_e + 1); - mfs_ctz_rdfromoff(sb, itr_max + neg_off, path, depth, buf, - MIN(MFS_PGSZ(sb), ctz_sz - bytes)); - pg = mfs_ba_getpg(sb); - if (pg == 0) - { - ret = -ENOSPC; - goto errout_with_buf; - } - - mfs_write_page(sb, buf, MFS_PGSZ(sb), pg, 0); - bytes += MIN(MFS_PGSZ(sb), ctz_sz - bytes); - } - - /* TODO: Check for cases where delete, but no further data at the end. - * , which might cause an infinite loop. - */ - errout_with_buf: kmm_free(buf); errout: return ret; } - -int mfs_ctz_wrtooff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - mfs_t o_bytes, const mfs_t n_bytes, - mfs_t o_ctz_sz, FAR struct mfs_path_s * const path, - const mfs_t depth, FAR const char *buf, - FAR struct mfs_ctz_s *ctz) -{ - int ret = OK; - bool partial; - mfs_t partial_bytes; /* Bytes partially filled. */ - mfs_t pg; - mfs_t off; - mfs_t idx; - mfs_t bytes; - mfs_t o_pg; - mfs_t o_off; - mfs_t o_idx; - mfs_t o_rembytes; - mfs_t o_data_off; - mfs_t n_pg; - mfs_t n_data_off; - mfs_t ctz_blk_datasz; - FAR char *data; - struct mfs_ctz_s o_ctz; - struct mfs_ctz_s n_ctz; - - data = kmm_zalloc(MFS_PGSZ(sb)); - if (predict_false(data == NULL)) - { - ret = -ENOMEM; - goto errout; - } - - /* Get updated location from the journal. */ - - DEBUGASSERT(depth > 0); - mfs_jrnl_updatepath(sb, path, depth); - o_ctz = path[depth - 1].ctz; - - /* TODO: Make the traversal in reverse direction. It would cause - * a lot less traversals. - */ - - ctz_off2loc(sb, data_off, &idx, &off); - - /* Reach the common part. */ - - if (idx != 0 && off != 0) - { - pg = ctz_travel(sb, o_ctz.idx_e, o_ctz.pg_e, idx - 1); - n_ctz.idx_e = idx - 1; - n_ctz.pg_e = pg; - } - else - { - pg = o_ctz.pg_e; - n_ctz.idx_e = 0; - n_ctz.pg_e = pg; - finfo("CTZ: %u %u %u", pg, n_ctz.idx_e, n_ctz.pg_e); - } - - /* Add new data from buf. */ - - partial = false; - o_rembytes = o_ctz_sz - (data_off + o_bytes); - bytes = data_off; - if (n_bytes != 0) - { - while (bytes < data_off + n_bytes) - { - n_pg = mfs_ba_getpg(sb); - if (n_pg) - { - ret = -ENOSPC; - goto errout_with_data; - } - - ctz_copyidxptrs(sb, n_ctz, idx, data); /* Handles idx == 0. */ - ctz_blk_datasz = ctz_blkdatasz(sb, idx); - - if (predict_false(off != 0)) - { - /* This happens at max for the first iteration of the loop. */ - - mfs_read_page(sb, data, off, - ctz_travel(sb, o_ctz.idx_e, o_ctz.pg_e, idx), 0); - bytes += off; - } - - memcpy(data + off, buf + bytes, - MIN(ctz_blk_datasz - off, n_bytes - bytes)); - if (n_bytes - bytes < ctz_blk_datasz - off && o_rembytes != 0) - { - partial = true; - partial_bytes = n_bytes - bytes; - } - else - { - bytes += ctz_blk_datasz - off; - } - - if (predict_false(off != 0)) - { - /* This happens at max for the first iteration of the loop. */ - - off = 0; - } - - if (predict_true(!partial)) - { - mfs_write_page(sb, data, MFS_PGSZ(sb), n_pg, 0); - n_ctz.idx_e = idx; - n_ctz.pg_e = pg; - } - else - { - /* In this case, we have a situation where there is still - * some empty area left in the page, and there is some data - * that is waiting to be fit in there, so we won't write it - * to the flash JUST yet. We'll fill in the rest of the data - * and THEN write it. - * - * It's okay to leave the loop as this case will happen, if at - * all, on the last iteration of the loop. - */ - - n_ctz.idx_e = idx; - n_ctz.pg_e = pg; - break; - } - - idx++; - - memset(data, 0, MFS_PGSZ(sb)); - } - } - - o_data_off = data_off + o_bytes; - n_data_off = data_off + n_bytes; - - /* Completing partially filled data, if present. */ - - if (partial) - { - ctz_off2loc(sb, o_data_off, &o_idx, &o_off); - o_pg = ctz_travel(sb, o_ctz.idx_e, o_ctz.pg_e, o_idx); - mfs_read_page(sb, data + partial_bytes, - ctz_blkdatasz(sb, n_ctz.idx_e) - partial_bytes, o_pg, - o_off); - mfs_write_page(sb, data, MFS_PGSZ(sb), n_ctz.pg_e, 0); - - o_data_off += partial_bytes; - n_data_off += partial_bytes; - partial_bytes = 0; - partial = false; - } - - /* Adding old bytes in. */ - - while (o_data_off < o_ctz_sz) - { - memset(data, 0, MFS_PGSZ(sb)); - - pg = mfs_ba_getpg(sb); - if (predict_false(pg == 0)) - { - ret = -ENOSPC; - goto errout_with_data; - } - - ctz_blk_datasz = ctz_blkdatasz(sb, n_ctz.idx_e + 1); - ctz_copyidxptrs(sb, n_ctz, n_ctz.idx_e + 1, data); - - mfs_ctz_rdfromoff(sb, o_data_off, path, depth, data, ctz_blk_datasz); - mfs_write_page(sb, data, MFS_PGSZ(sb), pg, 0); - - n_ctz.idx_e++; - n_ctz.pg_e = pg; - - o_data_off += ctz_blk_datasz; - } - - mfs_jrnl_newlog(sb, path, depth, n_ctz); - - /* path is not updated to point to the new ctz. This is upto the caller. */ - - *ctz = n_ctz; - -errout_with_data: - kmm_free(data); - -errout: - return ret; -} diff --git a/fs/mnemofs/mnemofs_fsobj.c b/fs/mnemofs/mnemofs_fsobj.c index aea7ccd51db..1d5fbd5e079 100644 --- a/fs/mnemofs/mnemofs_fsobj.c +++ b/fs/mnemofs/mnemofs_fsobj.c @@ -63,6 +63,7 @@ ****************************************************************************/ #include +#include #include #include "mnemofs.h" @@ -81,15 +82,27 @@ static mfs_t nobjs_in_path(FAR const char * relpath); 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); +static int search_ctz_by_name(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth, FAR const char * const name, + const mfs_t namelen, FAR mfs_t *off, + FAR struct mfs_dirent_s **dirent); + /**************************************************************************** * Private Data ****************************************************************************/ +const struct mfs_path_s empty_fsobj = +{ + 0 +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -117,6 +130,14 @@ static mfs_t nobjs_in_path(FAR const char *relpath) { mfs_t count; + /* If mount point is "/hi", then operations on "/hi/bye" and "/hi/hello/a" + * give respective relpaths as "bye" and "hello/a". Since mnemofs counts + * the root as 1 FS object, these respectively contain 2 and 3 FS objects + * in the path. The last FS object might be a file or a directory, but + * everything else is a directory. The number of FS objects in the path + * is the depth of the FS object the path refers to. + */ + if (*relpath == 0) { return 1; @@ -124,7 +145,7 @@ static mfs_t nobjs_in_path(FAR const char *relpath) count = 2; - while (*relpath == 0) + while (*relpath != 0) { if (*relpath == '/') { @@ -138,7 +159,7 @@ static mfs_t nobjs_in_path(FAR const char *relpath) } /**************************************************************************** - * Name: nobjs_in_path + * Name: next_child * * Description: * Give the pointer to next child that appears in the path. @@ -164,7 +185,38 @@ static const char *next_child(FAR const char *relpath) relpath++; } - return NULL; + return relpath; +} + +/**************************************************************************** + * Name: next_child + * + * Description: + * Give the pointer to next child that appears in the path. + * + * Input Parameters: + * relpath - Relative Path. + * + * Returned Value: + * The pointer to the next child. This is not allocated, but points to the + * inside relpath itself. + * + ****************************************************************************/ + +static const char *last_child(FAR const char *relpath) +{ + const mfs_t len = strlen(relpath); + mfs_t i; + + for (i = len - 1; i > 0; i--) + { + if (relpath[i - 1] == '/') + { + return relpath + i; + } + } + + return relpath; } /**************************************************************************** @@ -187,9 +239,9 @@ static FAR char *mfs_ser_dirent(FAR const struct mfs_dirent_s * const x, { FAR char *o = out; - o = mfs_ser_8(x->name_hash, o); + o = mfs_ser_16(x->name_hash, o); + o = mfs_ser_16(x->mode, o); o = mfs_ser_mfs(x->sz, o); - o = mfs_ser_mfs((mfs_t) x->mode, o); o = mfs_ser_timespec(&x->st_atim, o); o = mfs_ser_timespec(&x->st_mtim, o); o = mfs_ser_timespec(&x->st_ctim, o); @@ -220,9 +272,9 @@ static FAR const char *mfs_deser_dirent(FAR const char * const in, { FAR const char *i = in; - i = mfs_deser_8(i, &x->name_hash); + i = mfs_deser_16(i, &x->name_hash); + i = mfs_deser_16(i, &x->mode); i = mfs_deser_mfs(i, &x->sz); - i = mfs_deser_mfs(i, (mfs_t *) &x->mode); i = mfs_deser_timespec(i, &x->st_atim); i = mfs_deser_timespec(i, &x->st_mtim); i = mfs_deser_timespec(i, &x->st_ctim); @@ -263,8 +315,7 @@ mfs_t mfs_get_fsz(FAR struct mfs_sb_s * const sb, } else if (depth == 1) { - sz = MFS_MN(sb).root_sz; - mfs_lru_updatedsz(sb, path, depth, &sz); + 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. @@ -277,356 +328,20 @@ mfs_t mfs_get_fsz(FAR struct mfs_sb_s * const sb, return path[depth - 1].sz; } -int mfs_get_patharr(FAR struct mfs_sb_s *const sb, - FAR const char *relpath, FAR struct mfs_path_s **path, - FAR mfs_t *depth) -{ - int ret; - bool found; - bool isfile; - mfs_t sz; - mfs_t idx; - uint8_t hash; - const mfs_t len = nobjs_in_path(relpath); - FAR const char *next; - struct mfs_pitr_s pitr; - FAR struct mfs_dirent_s *dirent; - - ret = 0; - idx = 0; - isfile = false; - found = true; - - *path = kmm_zalloc(len * sizeof(struct mfs_ctz_s)); - if (predict_false(*path == NULL)) - { - return -ENOMEM; - } - - *depth = len; - (*path)[idx].ctz = MFS_MN(sb).root_ctz; - (*path)[idx].off = 0; - (*path)[idx].sz = mfs_get_fsz(sb, *path, 1); - - finfo("Path \"%s\" depth %u.", relpath, len); - - if (len == 1) - { - ret |= MFS_P_EXIST | MFS_P_ISDIR | MFS_ISDIR; - goto errout; - } - else if (len == 2) - { - ret |= MFS_P_EXIST | MFS_P_ISDIR; - } - - for (idx = 1; idx < len; idx++) - { - mfs_pitr_init(sb, *path, idx - 1, &pitr, false); - - if (predict_false(idx == 1)) - { - next = relpath; - } - else - { - next = next_child(relpath); - } - - sz = next - relpath; - hash = mfs_arrhash(relpath, sz); - - for (; ; ) - { - mfs_pitr_readdirent(sb, &pitr, &dirent); - if (predict_false(dirent == NULL)) - { - found = false; - ret |= MFS_NEXIST; - break; - } - - if (dirent->name_hash == hash && - !strncmp(dirent->name, relpath, sz)) - { - (*path)[idx - 1].ctz = dirent->ctz; - (*path)[idx - 1].off = pitr.c_off; - (*path)[idx - 1].sz = dirent->sz; - - mfs_free_dirent(dirent); - - if (len >= 2 && idx == len - 2) - { - ret |= MFS_P_EXIST; - ret |= (S_ISDIR(dirent->mode) ? MFS_P_ISDIR : - (MFS_FINPATH | MFS_NEXIST)); - } - else if (idx == len - 1) - { - ret |= (S_ISDIR(dirent->mode) ? MFS_ISDIR : MFS_ISFILE); - } - else - { - ret |= (S_ISDIR(dirent->mode) ? 0 : - (MFS_FINPATH | MFS_NEXIST)); - } - - break; - } - - if (!S_ISDIR(dirent->mode)) - { - isfile = true; - } - - mfs_pitr_adv_dirent(&pitr, dirent); - - mfs_free_dirent(dirent); - - if (isfile) - { - /* At max, only the last element is allowed to be a file. */ - - break; - } - } - - mfs_pitr_free(&pitr); - - if (!found) - { - break; - } - - relpath = next; - finfo("Next path \"%s\"", relpath); - } - -errout: - finfo("Path array for \"%s\", returned flags: %u.", relpath, ret); - return ret; -} - -void mfs_free_patharr(FAR struct mfs_path_s *path) -{ - kmm_free(path); -} - bool mfs_obj_isempty(FAR struct mfs_sb_s * const sb, + FAR struct mfs_path_s *path, FAR struct mfs_pitr_s * const pitr) { + bool ret; FAR struct mfs_dirent_s *dirent = NULL; - bool ret; - mfs_pitr_readdirent(sb, pitr, &dirent); + mfs_pitr_readdirent(sb, path, pitr, &dirent); ret = (dirent->sz == 0); mfs_free_dirent(dirent); return ret; } -void mfs_pitr_init(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, FAR struct mfs_pitr_s *pitr, - bool child) -{ - const uint8_t diff = child ? 1 : 0; - mfs_t p_depth; - - if (predict_false(depth < diff)) - { - return; - } - - p_depth = depth - diff; - - if (p_depth == 0) - { - /* Master Node */ - - pitr->sz = 0; - memset(&pitr->p, 0, sizeof(pitr->p)); - } - else - { - pitr->p.ctz = path[p_depth - 1].ctz; - pitr->sz = path[p_depth - 1].sz; - } - - pitr->depth = p_depth; - pitr->c_off = 0; - - finfo("Pitr initialized for parent CTZ at (%u, %u) at" - " depth %u for file size %u.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->depth, pitr->sz); -} - -void mfs_pitr_free(FAR struct mfs_pitr_s * const pitr) -{ - finfo("Pitr for CTZ (%u, %u) at depth %u freed.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->depth); - - memset(pitr, 0, sizeof(*pitr)); -} - -void mfs_pitr_adv(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr) -{ - FAR struct mfs_dirent_s *dirent; - - mfs_pitr_readdirent(sb, pitr, &dirent); - mfs_pitr_adv_dirent(pitr, dirent); - mfs_free_dirent(dirent); - - finfo("Pitr for CTZ (%u, %u) advanced to offset %u.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->c_off); -} - -void mfs_pitr_adv_dirent(FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_dirent_s * const dirent) -{ - pitr->c_off += MFS_DIRENTSZ(dirent); - - finfo("Pitr for CTZ (%u, %u) advanced to offset %u using dirent.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->c_off); -} - -void mfs_pitr_adv_off(FAR struct mfs_pitr_s * const pitr, - const mfs_t off) -{ - pitr->c_off += off; - - finfo("Pitr for CTZ (%u, %u) advanced to offset %u by offset %u.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->c_off, off); -} - -void mfs_pitr_adv_tochild(FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_path_s * const path, - const mfs_t depth) -{ - if (pitr->depth == 0) - { - return; - } - - pitr->c_off = path[depth - 1].off; - - finfo("Pitr for CTZ (%u, %u) at depth %u advanced to offset %u.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, depth, path[depth - 1].off); -} - -void mfs_pitr_reset(FAR struct mfs_pitr_s * const pitr) -{ - pitr->c_off = 0; - - finfo("Pitr for CTZ (%u, %u) reset.", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e); -} - -void mfs_pitr_sync(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr, - FAR const struct mfs_path_s * const path, - const mfs_t depth) -{ - finfo("Pitr for CTZ (%u, %u) syncing...", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e); - - /* TODO: mfs_jrnl_updatectz(sb, &pitr->p.ctz, pitr->depth); */ - - pitr->sz = mfs_get_fsz(sb, path, depth - 1); - - DEBUGASSERT(depth == pitr->depth); - - finfo("New location is (%u, %u).", - pitr->p.ctz.idx_e, pitr->p.ctz.pg_e); -} - -int mfs_pitr_readdirent(FAR struct mfs_sb_s * const sb, - FAR struct mfs_pitr_s * const pitr, - FAR struct mfs_dirent_s **dirent) -{ - int ret = OK; - mfs_t sz = 0; - const mfs_t len = sizeof(struct mfs_dirent_s) - + NAME_MAX + 1; - char dirent_data[len]; - struct mfs_dirent_s *dirent_rd = NULL; - - /* No harm in reading more. The namelen will stop all the included - * unnecessary characters during deserialization, and if there are none, - * the rest will be just empty. - */ - - memset(dirent_data, 0, len); - - *dirent = NULL; - - dirent_rd = kmm_zalloc(len); - if (predict_false(dirent_rd == NULL)) - { - goto errout; - } - - if (pitr->depth == 0) - { - dirent_rd->ctz = MFS_MN(sb).root_ctz; - dirent_rd->mode = MFS_MN(sb).root_mode; - dirent_rd->st_atim = MFS_MN(sb).root_st_atim; - dirent_rd->st_ctim = MFS_MN(sb).root_st_ctim; - dirent_rd->st_mtim = MFS_MN(sb).root_st_mtim; - dirent_rd->mode = MFS_MN(sb).root_mode; - dirent_rd->sz = MFS_MN(sb).root_sz; - dirent_rd->namelen = 1; - dirent_rd->name_hash = 0; - - memcpy(dirent_rd->name, "", 2); - } - else - { - mfs_lru_rdfromoff(sb, pitr->c_off, &pitr->p, pitr->depth, - dirent_data, len); - mfs_deser_dirent(dirent_data, dirent_rd); - - finfo("Got direntry with name %s", dirent_rd->name); - } - - sz = MFS_DIRENTSZ(dirent_rd); - if (dirent_rd->namelen == 0) - { - /* Not found direntry. */ - - goto errout_with_dirent_rd; - } - - *dirent = kmm_zalloc(sz); - if (predict_false(*dirent == NULL)) - { - ret = -ENOMEM; - goto errout_with_dirent_rd; - } - - memcpy(*dirent, dirent_rd, sz); - -errout_with_dirent_rd: - kmm_free(dirent_rd); - - if (ret < 0) - { - finfo("Direntry could not be allocated."); - } - else if (*dirent == NULL) - { - finfo("No direntry found."); - } - else - { - finfo("Reading direntry done for %s.", (*dirent)->name); - } - -errout: - return ret; -} - void mfs_free_dirent(FAR struct mfs_dirent_s *dirent) { kmm_free(dirent); @@ -652,9 +367,7 @@ bool mfs_searchfopen(FAR const struct mfs_sb_s * const sb, * open. */ - if (ofd->com->path[depth - 1].off == path[depth - 1].off && - ofd->com->path[depth - 1].ctz.pg_e == path[depth - 1].ctz.pg_e && - ofd->com->path[depth - 1].ctz.idx_e == path[depth - 1].ctz.idx_e) + if (mfs_path_eq(&ofd->com->path[depth - 1], &path[depth - 1])) { return true; } @@ -663,106 +376,21 @@ bool mfs_searchfopen(FAR const struct mfs_sb_s * const sb, return false; } -int mfs_pitr_appendnew(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, - const mfs_t depth, - FAR const struct mfs_pitr_s * const pitr, - FAR const char * const child_name, - const mode_t mode) -{ - int ret = OK; - mfs_t len; - mfs_t pg; - struct mfs_dirent_s *dirent = NULL; - struct timespec ts; - - len = strlen(child_name); - - dirent = kmm_zalloc(sizeof(*dirent) + len); - if (predict_false(dirent == NULL)) - { - return -ENOMEM; - } - - clock_gettime(CLOCK_REALTIME, &ts); - - /* TODO: Confirm if creation for directory in VFS gives true for - * S_ISDIR(). - */ - - pg = mfs_ba_getpg(sb); - if (predict_false(pg == 0)) - { - return -ENOSPC; - } - - dirent->sz = 0; - dirent->mode = mode; - dirent->ctz.pg_e = pg; - dirent->ctz.idx_e = 0; - dirent->st_atim = ts; - dirent->st_mtim = ts; - dirent->st_ctim = ts; - dirent->namelen = len; - strncpy(dirent->name, child_name, len); - - ret = mfs_pitr_appenddirent(sb, path, depth, pitr, dirent); - finfo("New direntry %p with name \"%s\" appended to CTZ (%u, %u) " - "at offset %u depth %u.", - dirent, dirent->name, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, - pitr->c_off, pitr->depth); - - mfs_free_dirent(dirent); - - return ret; -} - -int mfs_pitr_appenddirent(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, - const mfs_t depth, - FAR const struct mfs_pitr_s * const pitr, - FAR const struct mfs_dirent_s * const dirent) -{ - int ret = OK; - const mfs_t len = MFS_DIRENTSZ(dirent); - char dirent_data[len]; - struct mfs_pitr_s p_pitr; - FAR struct mfs_dirent_s *p_dirent = NULL; - - memset(dirent_data, 0, len); - mfs_ser_dirent(dirent, dirent_data); - - mfs_pitr_init(sb, path, depth - 1, &p_pitr, true); - mfs_pitr_adv_tochild(&p_pitr, path, depth - 1); - mfs_pitr_readdirent(sb, &p_pitr, &p_dirent); - - ret = mfs_lru_wr(sb, p_dirent->sz, len, p_dirent->sz, path, depth - 1, - dirent_data); - - mfs_free_dirent(p_dirent); - mfs_pitr_free(&p_pitr); - - finfo("Appended direntry for \"%s\" at depth %u.", dirent->name, depth); - - return ret; -} - int mfs_pitr_rmdirent(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, const mfs_t depth, FAR struct mfs_pitr_s * const pitr, FAR const struct mfs_dirent_s * const dirent) { + int ret = OK; + struct mfs_pitr_s p_pitr; FAR struct mfs_dirent_s *p_dirent = NULL; - struct mfs_pitr_s p_pitr; - int ret = OK; mfs_pitr_init(sb, path, depth - 1, &p_pitr, true); - mfs_pitr_adv_tochild(&p_pitr, path, depth - 1); - mfs_pitr_readdirent(sb, &p_pitr, &p_dirent); + mfs_pitr_adv_tochild(&p_pitr, path); + mfs_pitr_readdirent(sb, path, &p_pitr, &p_dirent); - ret = mfs_lru_del(sb, pitr->c_off, MFS_DIRENTSZ(dirent), p_dirent->sz, - path, depth); + ret = mfs_lru_del(sb, pitr->c_off, MFS_DIRENTSZ(dirent), path, depth); mfs_free_dirent(p_dirent); mfs_pitr_free(&p_pitr); @@ -774,15 +402,543 @@ int mfs_pitr_rm(FAR struct mfs_sb_s * const sb, FAR struct mfs_path_s * const path, const mfs_t depth) { - int ret = OK; - struct mfs_pitr_s pitr; + int ret = OK; + struct mfs_pitr_s pitr; FAR struct mfs_dirent_s *dirent = NULL; mfs_pitr_init(sb, path, depth, &pitr, true); - mfs_pitr_readdirent(sb, &pitr, &dirent); + mfs_pitr_readdirent(sb, path, &pitr, &dirent); ret = mfs_pitr_rmdirent(sb, path, depth, &pitr, dirent); mfs_free_dirent(dirent); mfs_pitr_free(&pitr); return ret; } + +int mfs_pitr_init(FAR const struct mfs_sb_s * const sb, + FAR const struct mfs_path_s * const path, + const mfs_t depth, FAR struct mfs_pitr_s * const pitr, + bool child) +{ + /* Ensure updated CTZ location from the journal before this. */ + + int ret = OK; + const int diff = child ? 1 : 0; + const mfs_t p_depth = depth - diff; + + if (predict_false(depth < diff)) + { + ret = -EINVAL; + goto errout; + } + + pitr->c_off = 0; + pitr->depth = p_depth; + + if (predict_true(p_depth != 0)) + { + pitr->p = path[p_depth - 1]; + } + else + { + /* 0 or gabage value is fine for master node, not required. */ + + pitr->p.ctz.idx_e = 0; + pitr->p.ctz.pg_e = 0; + pitr->p.off = 0; + pitr->p.sz = 1; /* For 1 traversal to get root. */ + } + + finfo("Pitr initialized at depth %u, with CTZ (%u, %u) and size %u.", + p_depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->p.sz); + +errout: + return ret; +} + +void mfs_pitr_free(FAR const struct mfs_pitr_s * const pitr) +{ + finfo("Pitr at depth %u with CTZ (%u, %u) freed.", + pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e); +} + +void mfs_pitr_adv_off(FAR struct mfs_pitr_s * const pitr, + const mfs_t off) +{ + pitr->c_off += off; + + finfo("Pitr at depth %u with CTZ (%u, %u) advanced by %u to %u offset.", + pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, off, pitr->c_off); +} + +void mfs_pitr_adv_bydirent(FAR struct mfs_pitr_s * const pitr, + FAR const struct mfs_dirent_s * const dirent) +{ + mfs_pitr_adv_off(pitr, MFS_DIRENTSZ(dirent)); + + finfo("Pitr at depth %u with CTZ (%u, %u) advanced by %u to %u offset.", + pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, + MFS_DIRENTSZ(dirent), pitr->c_off); +} + +void mfs_pitr_adv_tochild(FAR struct mfs_pitr_s * const pitr, + FAR const struct mfs_path_s * const path) +{ + /* (pitr->depth + 1) - 1 is the child's index. */ + + pitr->c_off = path[pitr->depth].off; + + finfo("Pitr at depth %u with CTZ (%u, %u) advanced to %u offset.", + pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->c_off); +} + +int mfs_pitr_readdirent(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s *path, + FAR struct mfs_pitr_s * const pitr, + FAR struct mfs_dirent_s **dirent) +{ + int ret = OK; + mfs_t sz; + const mfs_t len = sizeof(struct mfs_dirent_s) \ + + NAME_MAX + 1; + char rd[len]; + FAR struct mfs_dirent_s *d = NULL; + FAR struct mfs_dirent_s *tmp = NULL; + + if (dirent == NULL) + { + return ret; + } + + *dirent = NULL; + memset(rd, 0, len); + + d = kmm_zalloc(len); + if (predict_false(d == NULL)) + { + ret = -ENOMEM; + goto errout; + } + else if (pitr->c_off >= pitr->p.sz) + { + goto errout_with_d; + } + else if (pitr->depth == 0) + { + d->name[0] = 0; + d->namelen = 0; + d->ctz = MFS_MN(sb).root_ctz; + d->mode = MFS_MN(sb).root_mode; + d->name_hash = mfs_hash(d->name, d->namelen); + d->st_atim = MFS_MN(sb).root_st_atim; + d->st_ctim = MFS_MN(sb).root_st_ctim; + d->st_mtim = MFS_MN(sb).root_st_mtim; + d->sz = MFS_MN(sb).root_sz; + + pitr->c_off = 1; /* To prevent infinite loop. */ + } + else + { + ret = mfs_lru_rdfromoff(sb, pitr->c_off, path, pitr->depth, rd, len); + if (predict_false(ret < 0)) + { + goto errout_with_d; + } + + mfs_deser_dirent(rd, d); + } + + sz = MFS_DIRENTSZ(d); + tmp = kmm_realloc(d, sz); + if (predict_true(tmp != NULL)) + { + d = tmp; + } + + *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.", + pitr->c_off, pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, + d->name, d->namelen); + + return ret; + +errout_with_d: + kmm_free(d); + + if (ret < 0) + { + finfo("Direntry could not be allocated."); + } + else if (*dirent == NULL) + { + finfo("No direntry found."); + } + +errout: + return ret; +} + +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; + FAR struct mfs_dirent_s *dirent; + + ret = mfs_pitr_readdirent(sb, path, pitr, &dirent); + if (predict_false(ret < 0)) + { + goto errout; + } + + mfs_pitr_adv_bydirent(pitr, dirent); + mfs_free_dirent(dirent); + + finfo("Pitr for CTZ (%u, %u) advanced to offset %u.", + pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, pitr->c_off); + +errout: + return ret; +} + +static int search_ctz_by_name(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth, FAR const char * const name, + const mfs_t namelen, FAR mfs_t *off, + FAR struct mfs_dirent_s **dirent) +{ + /* NOTE: depth is of the parent here. */ + + /* Applies LRU updates. */ + + int ret = OK; + uint16_t name_hash; + struct mfs_pitr_s pitr; + FAR struct mfs_dirent_s *nd; + bool found = false; + + *dirent = NULL; + + if (depth == 0) + { + DEBUGASSERT(namelen == 0); + + nd = kmm_zalloc(sizeof(struct mfs_dirent_s)); + if (predict_false(nd == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + *off = 0; + nd->namelen = namelen; + nd->ctz = MFS_MN(sb).root_ctz; + nd->mode = MFS_MN(sb).root_mode; + nd->name_hash = mfs_hash(nd->name, nd->namelen); + nd->st_atim = MFS_MN(sb).root_st_atim; + nd->st_ctim = MFS_MN(sb).root_st_ctim; + nd->st_mtim = MFS_MN(sb).root_st_mtim; + nd->sz = MFS_MN(sb).root_sz; + + *dirent = nd; + goto errout; + } + + name_hash = mfs_hash(name, namelen); + + ret = mfs_lru_updatedinfo(sb, path, depth); + if (predict_false(ret < 0)) + { + goto errout; + } + + ret = mfs_pitr_init(sb, path, depth, &pitr, false); + if (predict_false(ret < 0)) + { + goto errout; + } + + for (; ; ) + { + /* Readdirent takes care of LRU updates. */ + + ret = mfs_pitr_readdirent(sb, path, &pitr, &nd); + if (predict_false(ret < 0 || nd == NULL)) + { + ret = -ENONET; + goto errout; + } + + if (nd->name_hash == name_hash && + !strncmp(nd->name, name, MIN(nd->namelen, namelen))) + { + found = true; + path[depth].sz = nd->sz; + path[depth].ctz = nd->ctz; + path[depth].off = pitr.c_off; + *off = pitr.c_off; + break; + } + + mfs_pitr_adv_bydirent(&pitr, nd); + mfs_free_dirent(nd); + } + +errout: + if (found) + { + finfo("Searched \"%.*s\" direntry inside CTZ (%u, %u) at depth %u," + " size %u.", namelen, name, path[depth - 1].ctz.idx_e, + path[depth - 1].ctz.pg_e, depth, path[depth - 1].sz); + *dirent = nd; + } + else + { + ret = -ENOENT; + finfo("Can not find requested direntry in parent. Ret: %d.", ret); + } + + return ret; +} + +int mfs_get_patharr(FAR const struct mfs_sb_s * const sb, + FAR const char * relpath, FAR struct mfs_path_s **path, + FAR mfs_t *depth) +{ + int ret = OK; + int ret_flags = 0; + mfs_t i; + mfs_t sz; + mfs_t off; + mfs_t n_objs; + mfs_t name_len; + FAR const char *cur = NULL; + FAR const char *next = NULL; + struct mfs_ctz_s ctz; + FAR struct mfs_path_s *np = NULL; + FAR struct mfs_dirent_s *dirent = NULL; + + *path = NULL; + n_objs = nobjs_in_path(relpath); + np = kmm_zalloc(n_objs * sizeof(struct mfs_path_s)); + if (predict_false(np == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + ctz = MFS_MN(sb).root_ctz; + sz = MFS_MN(sb).root_sz; + np[0].sz = sz; + np[0].ctz = ctz; + np[0].off = 0; + cur = relpath; + next = next_child(cur); + name_len = *next == 0 ? next - cur : next - cur - 1; + + if (predict_false(n_objs == 1)) + { + ret_flags |= MFS_ISDIR | MFS_EXIST; + + /* This will not go into the loop. */ + } + else if (predict_false(n_objs == 2)) + { + ret_flags |= MFS_P_EXIST | MFS_P_ISDIR; + } + + /* MFS_MN(sb).root_* is always up to date, no need for journal update. */ + + for (i = 1; i < n_objs; i++) + { + /* np[i] is the fs object at depth i + 1. */ + + /* Need to update journal for every level in the path as, for eg., the + * child can be deleted, etc. Same goes for LRU, which is taken care of + * by search_ctz_by_name function. + */ + + ret = search_ctz_by_name(sb, np, i, cur, name_len, &off, &dirent); + if (predict_false(ret < 0)) + { + goto errout_with_ret_flags; + } + + if (i < n_objs - 2 && !S_ISDIR(dirent->mode)) + { + ret_flags |= MFS_FINPATH; + goto errout_with_ret_flags; + } + else if (i == n_objs - 2) + { + ret_flags |= MFS_P_EXIST; + if (S_ISDIR(dirent->mode)) + { + ret_flags |= MFS_P_ISDIR; + } + else + { + ret_flags |= MFS_FINPATH; + goto errout_with_ret_flags; + } + } + else /* if (i == n_objs - 1) */ + { + ret_flags |= MFS_EXIST; + if (S_ISDIR(dirent->mode)) + { + ret_flags |= MFS_ISDIR; + } + else + { + ret_flags |= MFS_ISFILE; + } + } + + np[i].ctz = dirent->ctz; + np[i].off = off; + np[i].sz = dirent->sz; + + ctz = dirent->ctz; + + mfs_free_dirent(dirent); + + cur = next; + next = next_child(cur); + name_len = *next == 0 ? next - cur : next - cur - 1; + } + + ret = ret_flags; + *depth = n_objs; + *path = np; + + finfo("Got path array with flags %u, depth %u.", ret, n_objs); + return ret; + +errout_with_ret_flags: + ret = ret_flags; + *depth = n_objs; + *path = np; + + /* mfs_free_patharr(np) : All callers will free np (ie. path) when done + * with it. + */ + +errout: + finfo("Got path array with flags %u, depth %u.", ret, n_objs); + return ret; +} + +void mfs_free_patharr(FAR struct mfs_path_s *path) +{ + kmm_free(path); +} + +void mfs_pitr_reset(FAR struct mfs_pitr_s * const pitr) +{ + pitr->c_off = 0; + + finfo("Pitr for CTZ (%u, %u) reset.", + pitr->p.ctz.idx_e, pitr->p.ctz.pg_e); +} + +int mfs_pitr_appenddirent(FAR struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth, + FAR struct mfs_pitr_s * const pitr, + FAR const struct mfs_dirent_s * const dirent) +{ + /* Depth is depth of the child to be appended. */ + + int ret = OK; + const mfs_t len = MFS_DIRENTSZ(dirent); + char wd[len]; + + if (pitr->depth == 0) + { + /* Root is the only child of the master node. */ + + ret = -EINVAL; + goto errout; + } + + /* TOFO: 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 + * helpful in the LRU node for this. + */ + + memset(wd, 0, len); + + mfs_ser_dirent(dirent, wd); + ret = mfs_lru_wr(sb, pitr->p.sz, len, path, pitr->depth, wd); + if (predict_false(ret < 0)) + { + goto errout; + } + +errout: + return ret; +} + +int mfs_pitr_appendnew(FAR struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, const mfs_t depth, + FAR struct mfs_pitr_s * const pitr, + FAR const char * const relpath, const mode_t mode) +{ + /* Depth is depth of the child to be appended. */ + + int ret = OK; + struct timespec ts; + 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; + + DEBUGASSERT(depth > 0); + + d = kmm_zalloc(sizeof(struct mfs_dirent_s) + len); + if (predict_false(d == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + clock_gettime(CLOCK_REALTIME, &ts); + + d->ctz = empty_fsobj.ctz; + d->mode = mode; + d->st_atim = ts; + d->st_mtim = ts; + d->st_ctim = ts; + d->namelen = len; + strncpy(d->name, cur, d->namelen); + d->name_hash = mfs_hash(d->name, d->namelen); + d->sz = 0; + + /* Add the new direntry in this path. */ + + path[depth - 1].ctz = d->ctz; + path[depth - 1].off = pitr->p.sz; + path[depth - 1].sz = d->sz; + + ret = mfs_pitr_appenddirent(sb, path, depth, pitr, d); + if (predict_false(ret < 0)) + { + goto errout_with_d; + } + + finfo("Direntry appended to Pitr with %u depth, and CTZ (%u, %u). " \ + "Direntry name: \"%.*s\" with name length %u at offset %u.", + pitr->depth, pitr->p.ctz.idx_e, pitr->p.ctz.pg_e, d->namelen, + d->name, d->namelen, path[depth - 1].off); + +errout_with_d: + mfs_free_dirent(d); + +errout: + return ret; +} diff --git a/fs/mnemofs/mnemofs_journal.c b/fs/mnemofs/mnemofs_journal.c index 2fdc6d2d1bc..907bb6f1ea2 100644 --- a/fs/mnemofs/mnemofs_journal.c +++ b/fs/mnemofs/mnemofs_journal.c @@ -87,6 +87,11 @@ * Pre-processor Definitions ****************************************************************************/ +#define MFS_JRNL_SUFFIXSZ (8 + 2) /* 8 byte magic sequence + no. of blks */ +#define MFS_LOGSZ(depth) (sizeof(mfs_t) * 2 + sizeof(struct mfs_ctz_s) + \ + sizeof(struct mfs_path_s) * depth + \ + sizeof(struct timespec) * 3 + sizeof(uint16_t)) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -97,26 +102,35 @@ * search methods of higher functions. */ -/* There is a byte-long hash that follows this on-flash. */ +/* New journal log structure being phased in. */ struct jrnl_log_s { - mfs_t depth; - struct mfs_ctz_s new; - FAR struct mfs_ctz_s path[]; + /* A field denoting the size of the below elements is added here on-flash. + */ + + mfs_t depth; + mfs_t sz_new; + struct mfs_ctz_s loc_new; + struct timespec st_mtim_new; + struct timespec st_atim_new; + struct timespec st_ctim_new; + FAR struct mfs_path_s *path; + uint16_t hash; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -static int jrnl_wrlog(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, const struct mfs_ctz_s new_ctz); -static int jrnl_rdlog(FAR const struct mfs_sb_s * const sb, mfs_t pg, - mfs_t idx, FAR mfs_t *new_pg, FAR mfs_t *new_idx, - FAR struct jrnl_log_s **log); -static void jrnl_log_free(FAR struct jrnl_log_s *log); +static int jrnl_rdlog(FAR const struct mfs_sb_s *const sb, + FAR mfs_t *blkidx, FAR mfs_t *pg_in_blk, + FAR struct jrnl_log_s *log); + +FAR static const char *deser_log(FAR const char * const in, + FAR struct jrnl_log_s * const x); +FAR static char *ser_log(FAR const struct jrnl_log_s * const x, + FAR char * const out); /**************************************************************************** * Private Data @@ -131,102 +145,143 @@ static void jrnl_log_free(FAR struct jrnl_log_s *log); ****************************************************************************/ /**************************************************************************** - * Name: jrnl_wrlog + * Name: jrnl_rdlog * * Description: - * Appends a log to the journal. + * Read a log to the journal from given location, and update location to + * point to next log location. * * Input Parameters: - * sb - Superblock instance of the device. - * path - CTZ representation of the relpath. - * depth - Length of path. - * new_ctz - The updated location. + * sb - Superblock instance of the device. + * blkidx - Journal Block Index of the current block. + * pg_in_blk - Page offset in the block. + * log - To populate with the log. * * Returned Value: * 0 - OK * < 0 - Error * * Assumptions/Limitations: - * Assumes the CTZ list to be updated is `path[depth - 1].ctz`. + * This function does NOT care about start of the journal, or even, if + * the initial requested area is inside the journal. It will malfunction + * if not used properly. Usually this is used in an iterative manner, and + * hence the first time blkidx and pg_in_blk are initialized, they should + * be derived from the values in MFS_JRNL(sb) respectively. + * + * This updates the blkidx and pg_in_blk to point to the next log, and + * returns an -ENOSPC when end of journal is reached in traversal. + * + * Free the log after use. * ****************************************************************************/ -static int jrnl_wrlog(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, const struct mfs_ctz_s new_ctz) +static int jrnl_rdlog(FAR const struct mfs_sb_s *const sb, + FAR mfs_t *blkidx, FAR mfs_t *pg_in_blk, + FAR struct jrnl_log_s *log) { - int ret = OK; - mfs_t i; - mfs_t pg; - mfs_t idx; - mfs_t sz; - mfs_t blk; - mfs_t n_pgs; - mfs_t rem_sz; - FAR char *tmp; - FAR char *buf = NULL; + int ret = OK; + char tmp[4]; + mfs_t i; + mfs_t len; + mfs_t n_pgs; + mfs_t rd_sz; + mfs_t log_sz; + mfs_t jrnl_pg; + mfs_t jrnl_blk; + FAR char *buf = NULL; + FAR char *buftmp = NULL; - /* FUTURE TODO: Group logs together. Common hash and a prefix for number - * of logs together. - */ + DEBUGASSERT(*pg_in_blk % MFS_PGSZ(sb) == 0); - /* Serialize. */ + jrnl_blk = mfs_jrnl_blkidx2blk(sb, *blkidx); + jrnl_pg = MFS_BLK2PG(sb, jrnl_blk) + *pg_in_blk; - sz = sizeof(struct jrnl_log_s) + depth * sizeof(struct mfs_ctz_s) + 1; - buf = kmm_zalloc(sz); + /* First 4 bytes contain the size of the entire log. */ + + ret = mfs_read_page(sb, tmp, 4, jrnl_pg, 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + mfs_deser_mfs(tmp, &log_sz); + n_pgs = MFS_CEILDIVIDE(log_sz, MFS_PGSZ(sb)); + + buf = kmm_zalloc(log_sz); if (predict_false(buf == NULL)) { ret = -ENOMEM; goto errout; } - tmp = buf; - tmp = mfs_ser_mfs(depth, tmp); - tmp = mfs_ser_ctz(&new_ctz, tmp); - for (i = 0; i < depth; i++) + buftmp = buf; + rd_sz = 0; + for (i = 0; i < n_pgs && rd_sz < log_sz; i++) { - tmp = mfs_ser_ctz(&path[i].ctz, tmp); - } + /* This if-statement exists to remove calculation behind + * MIN(MFS_PGSZ(sb), log_sz - rd_sz) + */ - tmp = mfs_ser_8(mfs_arrhash(buf, sz - 1), tmp); /* Hash */ - - /* Write. */ - - pg = MFS_JRNL(sb).log_cpg; - idx = MFS_JRNL(sb).log_cblkidx; - blk = MFS_PG2BLK(sb, pg); - n_pgs = (sz + (MFS_PGSZ(sb) - 1)) / MFS_PGSZ(sb); /* Ceil */ - tmp = buf; - - for (i = 0; i < n_pgs; i++) - { - rem_sz = MIN(MFS_PGSZ(sb), buf + sz - tmp); - ret = mfs_write_page(sb, tmp, rem_sz, pg, 0); - if (predict_false(ret < 0)) + if (i == 0 && i != n_pgs - 1) { + ret = mfs_read_page(sb, buftmp, MFS_PGSZ(sb), jrnl_pg, + sizeof(mfs_t)); + len = MFS_PGSZ(sb); + } + else if (i == 0) + { + ret = mfs_read_page(sb, buftmp, log_sz, jrnl_pg, sizeof(mfs_t)); + len = log_sz; + } + else if (i == n_pgs - 1) + { + ret = mfs_read_page(sb, buftmp, log_sz - rd_sz, jrnl_pg, 0); + len = log_sz - rd_sz; + } + else + { + ret = mfs_read_page(sb, buftmp, MFS_PGSZ(sb), jrnl_pg, 0); + len = MFS_PGSZ(sb); + } + + buftmp += len; + rd_sz += len; + + if (predict_false(ret == 0)) + { + ret = -EINVAL; /* TODO: Need to check when this occurs. */ goto errout_with_buf; } - pg++; + /* Move to next block if needed. */ - if (pg - MFS_BLK2PG(sb, blk) >= MFS_PGINBLK(sb)) + jrnl_pg++; + if (jrnl_pg - MFS_BLK2PG(sb, jrnl_blk) >= MFS_PGINBLK(sb)) { - idx++; - if (idx >= MFS_JRNL(sb).n_blks) + (*blkidx)++; + + if (*blkidx >= MFS_JRNL(sb).n_blks) { - /* TODO: Time for journal flushing and moving. */ + /* Not finished reading log yet, and the journal is over. */ + + ret = -ENOSPC; + goto errout_with_buf; } - blk = mfs_jrnl_blkidx2blk(sb, idx); - pg = MFS_BLK2PG(sb, blk); + jrnl_blk = mfs_jrnl_blkidx2blk(sb, *blkidx); + jrnl_pg = MFS_BLK2PG(sb, jrnl_blk); } - - tmp += rem_sz; } - MFS_JRNL(sb).log_cpg = pg; - MFS_JRNL(sb).log_cblkidx = idx; - MFS_JRNL(sb).n_logs += 1; + if (predict_false(deser_log(buf, log) == NULL)) + { + ret = -ENOMEM; + goto errout_with_buf; + } + + /* blkidx has been up to date throughout the program. */ + + *pg_in_blk = jrnl_pg - MFS_BLK2PG(sb, jrnl_blk); errout_with_buf: kmm_free(buf); @@ -236,217 +291,128 @@ errout: } /**************************************************************************** - * Name: jrnl_rdlog + * Name: ser_log * * Description: - * Read a log to the journal from given location. + * Serialize a log. * * Input Parameters: - * sb - Superblock instance of the device. - * pg - Page number of the start of the log. - * idx - Index of the start of the log. - * new_pg - Page number of the start of the next log. - * new_idx - Index of the start of the next log. - * log - To populate with the log. + * n - Log to serialize + * out - Output array where to serialize. * * Returned Value: - * 0 - OK - * < 0 - Error + * Pointer to byte after the end of serialized value. * * Assumptions/Limitations: - * This assumes that at any possibly attainable locations in the journal, - * there will atleast be 4 bytes of data left in that page to read. + * This assumes the out buffer has enough space to hold the inline path. * - * Everything stored in the journal blocks is multiple of 4, and any block - * size is a power of 2, so any block size greater than 4 should also be a - * multiple of 4. - * - * Free the log after use. + * This doesn't require the hash to be pre-calculated. * ****************************************************************************/ -static int jrnl_rdlog(FAR const struct mfs_sb_s * const sb, mfs_t pg, - mfs_t idx, FAR mfs_t *new_pg, FAR mfs_t *new_idx, - FAR struct jrnl_log_s **log) +FAR static char *ser_log(FAR const struct jrnl_log_s * const x, + FAR char * const out) { - int ret = OK; - char buftmp[4]; - mfs_t n_pgs; - mfs_t i; - mfs_t sz; - mfs_t blk; - mfs_t depth; - mfs_t rem_sz; - uint8_t hash; - FAR char *buf = NULL; - FAR char *tmp; - FAR const char *tmp2; + char *o = out; + mfs_t i = 0; - blk = MFS_PG2BLK(sb, pg); + o = mfs_ser_mfs(x->depth, o); + o = mfs_ser_mfs(x->sz_new, o); + o = mfs_ser_ctz(&x->loc_new, o); + o = mfs_ser_timespec(&x->st_mtim_new, o); + o = mfs_ser_timespec(&x->st_atim_new, o); + o = mfs_ser_timespec(&x->st_ctim_new, o); - /* Read depth. */ - - mfs_read_page(sb, buftmp, 5, pg, 0); - mfs_deser_mfs(buftmp, &depth); - - sz = sizeof(struct jrnl_log_s) + (depth * sizeof(struct mfs_ctz_s)) + 1; - buf = kmm_zalloc(sz); - if (predict_false(buf == NULL)) + for (i = 0; i < x->depth; i++) { - ret = -ENOMEM; - goto errout; + o = mfs_ser_path(&x->path[i], o); } - *log = kmm_zalloc(sz - 1); - if (predict_false(*log == NULL)) + o = mfs_ser_16(mfs_hash(out, o - out), o); + return o; +} + +/**************************************************************************** + * Name: deser_log + * + * Description: + * Deserialize a log. + * + * Input Parameters: + * in - Input array from where to deserialize. + * n - Log to deserialize + * + * Returned Value: + * NULL - Error. + * Pointer to byte after the end of serialized value. + * + * Assumptions/Limitations: + * This allocates space for the path, and the log should freed after use. + * + ****************************************************************************/ + +FAR static const char *deser_log(FAR const char * const in, + FAR struct jrnl_log_s * const x) +{ + mfs_t k = 0; + const char *i = in; + + i = mfs_deser_mfs(i, &x->depth); + i = mfs_deser_mfs(i, &x->sz_new); + i = mfs_deser_ctz(i, &x->loc_new); + i = mfs_deser_timespec(i, &x->st_mtim_new); + i = mfs_deser_timespec(i, &x->st_atim_new); + i = mfs_deser_timespec(i, &x->st_ctim_new); + + /* Allocates path. Deallocate using mfs_jrnl_log_free. */ + + x->path = kmm_zalloc(sizeof(struct jrnl_log_s) * x->depth); + if (predict_false(x->path == NULL)) { - goto errout_with_buf; + return NULL; } - /* Read the log. */ - - n_pgs = (sz + (MFS_PGSZ(sb) - 1)) / MFS_PGSZ(sb); - tmp = buf; - - for (i = 0; i < n_pgs; i++) + for (k = 0; k < x->depth; k++) { - rem_sz = MIN(MFS_PGSZ(sb), buf + sz - tmp); - ret = mfs_read_page(sb, tmp, rem_sz, pg, 0); - if (predict_false(ret < 0)) - { - goto errout_with_log; - } - - pg++; - - if (pg - MFS_BLK2PG(sb, blk) >= MFS_PGINBLK(sb)) - { - idx++; - if (idx >= MFS_JRNL(sb).n_blks) - { - /* TODO: Time for journal flushing and moving. */ - } - - blk = mfs_jrnl_blkidx2blk(sb, idx); - pg = MFS_BLK2PG(sb, blk); - } - - tmp += rem_sz; + i = mfs_deser_path(i, &x->path[k]); } - /* Deserialize */ - - tmp2 = buf; - tmp2 = mfs_deser_ctz(tmp2, &(*log)->new); - for (i = 0; i < depth; i++) - { - tmp2 = mfs_deser_ctz(tmp2, &(*log)->path[i]); - } - - tmp2 = mfs_deser_8(tmp2, &hash); - - if (hash != mfs_arrhash(buf, sz - 1)) - { - ret = -EINVAL; - goto errout_with_log; - } - - *new_pg = pg; - *new_idx = idx; - - kmm_free(buf); - return ret; - -errout_with_log: - kmm_free(*log); - *log = NULL; - -errout_with_buf: - kmm_free(buf); - -errout: - return ret; + i = mfs_deser_16(i, &x->hash); + return i; } /**************************************************************************** * Name: jrnl_log_free * * Description: - * Free a log. + * Free the log. * * Input Parameters: - * log - Journal log. + * log - Log + * + * Assumptions/Limitations: + * This allocates space for the path, and the log should freed after use. * ****************************************************************************/ -static void jrnl_log_free(FAR struct jrnl_log_s *log) +static void jrnl_log_free(FAR const struct jrnl_log_s * const log) { - kmm_free(log); + free(log->path); } /**************************************************************************** * Public Functions ****************************************************************************/ -int mfs_jrnl_newlog(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, const struct mfs_ctz_s new_ctz) -{ - return jrnl_wrlog(sb, path, depth, new_ctz); -} - -int mfs_jrnl_updatepath(FAR const struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, - const mfs_t depth) -{ - int ret = OK; - mfs_t k; - mfs_t pg; - mfs_t idx; - struct jrnl_log_s *log; - - idx = MFS_JRNL(sb).log_sblkidx; - pg = MFS_JRNL(sb).log_spg; - - for (k = 0; k < MFS_JRNL(sb).n_logs; k++) - { - ret = jrnl_rdlog(sb, pg, idx, &pg, &idx, &log); - if (predict_false(ret < 0)) - { - return ret; - } - - if (log->depth > depth) - { - continue; - } - - if (depth == 0 || - (log->path[log->depth - 1].pg_e == path[log->depth - 1].ctz.pg_e && - log->path[log->depth - 1].idx_e == path[log->depth - 1].ctz.idx_e)) - { - path[log->depth].ctz = log->new; - } - - jrnl_log_free(log); - } - - /* TODO: Create an update offset function in ctz.c to update the offsets - * of path. - */ - - return ret; -} - int mfs_jrnl_init(FAR struct mfs_sb_s * const sb, mfs_t blk) { - mfs_t pg; - FAR char *buf = NULL; - char buftmp[2]; - int ret = OK; - mfs_t sz; - mfs_t idx; - FAR struct jrnl_log_s *log = NULL; + char buftmp[2]; + int ret = OK; + mfs_t sz; + mfs_t blkidx; + mfs_t pg_in_blk; + FAR char *buf = NULL; + FAR struct jrnl_log_s *log = NULL; /* Magic sequence is already used to find the block, so not required. */ @@ -459,28 +425,44 @@ int mfs_jrnl_init(FAR struct mfs_sb_s * const sb, mfs_t blk) goto errout; } - sz = 8 + 2 + ((CONFIG_MNEMOFS_JOURNAL_NBLKS + 2) * 4); - pg = (sz + (MFS_PGSZ(sb) - 1)) / MFS_PGSZ(sb); + sz = MFS_JRNL_SUFFIXSZ + ((CONFIG_MNEMOFS_JOURNAL_NBLKS + 2) * 4); - MFS_JRNL(sb).log_cpg = pg; - MFS_JRNL(sb).log_cblkidx = 0; + MFS_JRNL(sb).log_cpg = (sz + (MFS_PGSZ(sb) - 1)) / MFS_PGSZ(sb); MFS_JRNL(sb).log_spg = MFS_JRNL(sb).log_cpg; + MFS_JRNL(sb).log_cblkidx = 0; MFS_JRNL(sb).log_sblkidx = MFS_JRNL(sb).log_cblkidx; MFS_JRNL(sb).jrnlarr_pg = 0; - MFS_JRNL(sb).jrnlarr_pgoff = 8 + 2; + MFS_JRNL(sb).jrnlarr_pgoff = MFS_JRNL_SUFFIXSZ; /* Number of logs */ - idx = 0; MFS_JRNL(sb).n_logs = 0; - while (idx < MFS_JRNL(sb).n_logs) + blkidx = MFS_JRNL(sb).log_sblkidx; + pg_in_blk = MFS_JRNL(sb).log_spg % MFS_PGINBLK(sb); + + while (true) { - jrnl_rdlog(sb, pg, idx, &pg, &idx, &log); + /* TODO: Update this to new read log. */ - /* Assumes checking the depth is enough to check if it's empty. */ - - if (log->depth == 0) + ret = jrnl_rdlog(sb, &blkidx, &pg_in_blk, log); + if (predict_false(ret < 0 && ret != -ENOSPC)) { + goto errout; + } + else if (ret == -ENOSPC) + { + ret = OK; + break; + } + + /* Assumes checking the depth is enough to check if it's empty, as + * theoretically there are no blocks with depth 0, as root has a + * depth of 1. + */ + + if (!log || log->depth == 0) + { + DEBUGASSERT(!log || log->path == NULL); break; } @@ -501,13 +483,6 @@ errout: return ret; } -void mfs_jrnl_free(FAR struct mfs_sb_s * const sb) -{ - /* TODO: Flush entire journal here. */ - - finfo("Journal Freed."); -} - int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) { int i; @@ -524,7 +499,7 @@ int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) /* Write magic sequence, size of jrnlarr, and then the jrnlarr. */ - sz = 8 + 2 + ((CONFIG_MNEMOFS_JOURNAL_NBLKS + 2) * 4); + sz = MFS_JRNL_SUFFIXSZ + ((CONFIG_MNEMOFS_JOURNAL_NBLKS + 2) * 4); n_pgs = (sz + (MFS_PGSZ(sb) - 1)) / MFS_PGSZ(sb); buf = kmm_zalloc(sz); @@ -606,7 +581,7 @@ int mfs_jrnl_fmt(FAR struct mfs_sb_s * const sb, mfs_t blk1, mfs_t blk2) 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 = 8 + 2; + 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; @@ -629,14 +604,20 @@ errout: return ret; } +void mfs_jrnl_free(FAR struct mfs_sb_s * const sb) +{ + mfs_jrnl_flush(sb); + finfo("Journal Freed."); +} + mfs_t mfs_jrnl_blkidx2blk(FAR const struct mfs_sb_s * const sb, const mfs_t blk_idx) { - int ret = OK; + int ret = OK; mfs_t pg; - mfs_t pgoff; - mfs_t blk; mfs_t idx; + mfs_t blk; + mfs_t pgoff; char buf[4]; pg = MFS_JRNL(sb).jrnlarr_pg; @@ -669,3 +650,177 @@ mfs_t mfs_jrnl_blkidx2blk(FAR const struct mfs_sb_s * const sb, return idx; } + +int mfs_jrnl_updatedinfo(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth) +{ + int ret = OK; + mfs_t blkidx; + mfs_t counter = 0; + mfs_t pg_in_block; + struct jrnl_log_s tmplog; + + /* TODO: Allow optional filling of updated timestamps, etc. */ + + DEBUGASSERT(depth > 0); + + blkidx = MFS_JRNL(sb).log_sblkidx; + pg_in_block = MFS_JRNL(sb).log_spg % MFS_PGINBLK(sb); + + while (blkidx < MFS_JRNL(sb).n_blks && counter < MFS_JRNL(sb).n_logs) + { + ret = jrnl_rdlog(sb, &blkidx, &pg_in_block, &tmplog); + if (predict_false(ret < 0 && ret != -ENOSPC)) + { + goto errout; + } + else if (ret == -ENOSPC) + { + break; + } + + DEBUGASSERT(tmplog.depth > 0); + + if (tmplog.depth > depth) + { + /* Not suitable. */ + } + else + { + DEBUGASSERT(tmplog.depth > 0); + + if (mfs_path_eq(&tmplog.path[tmplog.depth - 1], + &path[tmplog.depth - 1])) + { + path[tmplog.depth - 1].ctz = tmplog.loc_new; + path[tmplog.depth - 1].sz = tmplog.sz_new; + } + } + + jrnl_log_free(&tmplog); + counter++; + } + +errout: + return ret; +} + +int mfs_jrnl_wrlog(FAR struct mfs_sb_s * const sb, + 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; + + buf = kmm_zalloc(log_sz); /* For size before log. */ + if (predict_false(buf == NULL)) + { + ret = -ENOMEM; + goto errout; + } + + /* Serialize */ + + log.depth = node.depth; + log.sz_new = node.depth; + 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. */ + + tmp = buf; + tmp = mfs_ser_mfs(log_sz - sizeof(mfs_t), tmp); + tmp = ser_log(&log, tmp); + + /* Store */ + + n_pgs = MFS_CEILDIVIDE(log_sz, MFS_PGSZ(sb)); + jrnl_blk = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).log_cblkidx); + jrnl_pg = MFS_JRNL(sb).log_cpg; + tmp = buf; + wr_sz = 0; + for (i = 0; i < n_pgs && wr_sz < log_sz; i++) + { + /* This if-statement exists to remove calculation behind + * MIN(MFS_PGSZ(sb), log_sz - wr_sz) + */ + + if (i == 0 && i == n_pgs - 1) + { + ret = mfs_write_page(sb, tmp, log_sz, jrnl_pg, 0); + wr_sz += log_sz; + tmp += log_sz; + } + else if (i == 0) + { + ret = mfs_write_page(sb, tmp, MFS_PGSZ(sb), jrnl_pg, 0); + wr_sz += MFS_PGSZ(sb); + tmp += MFS_PGSZ(sb); + } + else if (i == n_pgs - 1) + { + ret = mfs_write_page(sb, tmp, log_sz - wr_sz, jrnl_pg, 0); + wr_sz += MFS_PGSZ(sb); + tmp += MFS_PGSZ(sb); + } + else + { + ret = mfs_write_page(sb, tmp, MFS_PGSZ(sb), jrnl_pg, 0); + wr_sz += MFS_PGSZ(sb); + tmp += MFS_PGSZ(sb); + } + + if (predict_false(ret == 0)) + { + ret = -EINVAL; + goto errout_with_buf; + } + + /* Move to next block if needed. */ + + jrnl_pg++; + if (jrnl_pg - MFS_BLK2PG(sb, jrnl_blk) == MFS_PGINBLK(sb)) + { + MFS_JRNL(sb).log_cblkidx++; + + if (MFS_JRNL(sb).log_cblkidx == MFS_JRNL(sb).n_blks) + { + /* Not finished reading log yet, and the journal is over. */ + + ret = -ENOSPC; + goto errout_with_buf; + } + + jrnl_blk = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).log_cblkidx); + jrnl_pg = MFS_BLK2PG(sb, jrnl_blk); + } + } + + /* MFS_JRNL(sb).log_cblkidx is up to date */ + + MFS_JRNL(sb).log_cpg = jrnl_pg; + MFS_JRNL(sb).n_logs++; + +errout_with_buf: + kmm_free(buf); + +errout: + return ret; +} + +int mfs_jrnl_flush(FAR struct mfs_sb_s * const sb) +{ + /* TODO */ + + return OK; +} diff --git a/fs/mnemofs/mnemofs_lru.c b/fs/mnemofs/mnemofs_lru.c index a1b032e44dd..a0965e439c3 100644 --- a/fs/mnemofs/mnemofs_lru.c +++ b/fs/mnemofs/mnemofs_lru.c @@ -93,15 +93,22 @@ enum * Private Function Prototypes ****************************************************************************/ -static void lru_nodesearch(FAR struct mfs_sb_s * const sb, +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 int lru_nodeflush(FAR struct mfs_sb_s * const sb, +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); +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, + const mfs_t depth, FAR const char *buf); +static int lru_updatesz(FAR struct mfs_sb_s * sb, FAR struct mfs_path_s * const path, - const mfs_t depth, const mfs_t ctz_sz, - FAR struct mfs_node_s *node, bool clean_node); + const mfs_t depth, const mfs_t new_sz); /**************************************************************************** * Private Data @@ -129,58 +136,69 @@ static int lru_nodeflush(FAR struct mfs_sb_s * const sb, * ****************************************************************************/ -static void lru_nodesearch(FAR struct mfs_sb_s * const sb, +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) { - bool found; - mfs_t i; + bool found = false; + mfs_t i; FAR struct mfs_node_s *n; *node = NULL; + list_for_every_entry(&MFS_LRU(sb), n, struct mfs_node_s, list) { - if (n == NULL) - { - break; - } + /* We need this loop to specifically check the parents in case these + * entries are all new, and have not been allocated any pages for + * being stored in the flash. Also we know that the root (depth 1) will + * be at least common in their paths. + */ + + DEBUGASSERT(depth > 0); - found = true; if (n->depth != depth) { continue; } - if (depth != 0) + found = true; + for (i = n->depth; i >= 1 && found; i--) { - for (i = depth - 1; i + 1 > 0; i--) /* i + 1 prevents underflow. */ + if (path[i - 1].ctz.idx_e == 0 && path[i - 1].ctz.pg_e == 0 && + mfs_ctz_eq(&n->path[i - 1].ctz, &path[i - 1].ctz) && + n->path[i - 1].off == path[i - 1].off) { - if (n->path[i].off == path[i].off && - n->path[i].ctz.idx_e == path[i].ctz.idx_e && - n->path[i].ctz.pg_e == path[i].ctz.pg_e) - { - /* OK */ - } - else - { - found = false; - break; - } + /* OK */ + } + else if (path[i - 1].ctz.pg_e != 0 && + mfs_ctz_eq(&n->path[i - 1].ctz, &path[i - 1].ctz)) + { + /* OK */ + } + else + { + found = false; } } if (found) { - finfo("Node search ended with match of node %p at depth %u" - " for CTZ of %u original size with range [%u, %u).", n, - n->depth, n->sz, n->range_min, n->range_max); *node = n; - return; + break; } } - *node = NULL; - finfo("Node search ended without match."); + if (found) + { + finfo("Node search ended with match of node %p at depth %u" + " for CTZ of %u size with range [%u, %u).", n, n->depth, n->sz, + n->range_min, n->range_max); + } + else + { + finfo("Node search ended without match."); + *node = NULL; + } } /**************************************************************************** @@ -190,7 +208,7 @@ static void lru_nodesearch(FAR struct mfs_sb_s * const sb, * Check whether the number of nodes in the LRU has reaches its limit. * * Input Parameters: - * sb - Superblock instance of the device. + * sb - Superblock instance of the device. * * Returned Value: * true - LRU is full @@ -223,6 +241,17 @@ static bool lru_isnodefull(FAR struct mfs_node_s *node) return node->n_list == CONFIG_MNEMOFS_NLRUDELTA; } +/**************************************************************************** + * Name: lru_free_delta + * + * Description: + * Free a node's delta. + * + * Input Parameters: + * delta - LRU delta. + * + ****************************************************************************/ + static void lru_free_delta(FAR struct mfs_delta_s *delta) { kmm_free(delta->upd); @@ -252,10 +281,10 @@ 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, const mfs_t ctz_sz, - FAR struct mfs_node_s *node, bool clean_node) + const mfs_t depth, FAR struct mfs_node_s *node, + bool clean_node) { - int ret = OK; + int ret = OK; FAR struct mfs_delta_s *delta = NULL; FAR struct mfs_delta_s *tmp = NULL; @@ -264,8 +293,9 @@ static int lru_nodeflush(FAR struct mfs_sb_s * const sb, return -ENOMEM; } - ret = mfs_ctz_nwrtooff(sb, node, path, depth, ctz_sz, - &path[depth - 1].ctz); + /* TODO: Implement effct of clean_node. */ + + ret = mfs_ctz_wrtnode(sb, node); if (predict_false(ret < 0)) { goto errout; @@ -289,13 +319,36 @@ errout: return ret; } -static int lru_wrtooff(FAR struct mfs_sb_s * const sb, - const mfs_t data_off, mfs_t bytes, mfs_t ctz_sz, - int op, FAR struct mfs_path_s * const path, - const mfs_t depth, FAR const char *buf) +/**************************************************************************** + * Name: lru_wrtooff + * + * Description: + * Write to offset in LRU. + * + * Input Parameters: + * sb - Superblock instance of the device. + * data_off - Offset into the data in the CTZ skip list. + * bytes - Number of bytes to write. + * ctz_sz - Size of the CTZ skip list. + * op - Operation (MFS_LRU_UPD or MFS_LRU_DEL). + * path - CTZ representation of the path. + * depth - Depth of path. + * buf - Buffer containing data. + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + ****************************************************************************/ + +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, const mfs_t depth, + FAR const char *buf) { - int ret = OK; - bool found = true; + int ret = OK; + bool found = true; + mfs_t old_sz; FAR struct mfs_node_s *node = NULL; FAR struct mfs_node_s *last_node = NULL; FAR struct mfs_delta_s *delta = NULL; @@ -304,14 +357,23 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, if (node == NULL) { - node = kmm_zalloc(sizeof(*node) + (depth * sizeof(struct mfs_path_s))); + node = kmm_zalloc(sizeof(*node)); if (predict_false(node == NULL)) { + found = false; ret = -ENOMEM; goto errout; } - node->sz = ctz_sz; + node->path = kmm_zalloc(depth * sizeof(struct mfs_path_s)); + if (predict_false(node->path == NULL)) + { + found = false; + ret = -ENOMEM; + goto errout_with_node; + } + + node->sz = path[depth - 1].sz; node->depth = depth; node->n_list = 0; node->range_max = 0; @@ -320,7 +382,7 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, memcpy(node->path, path, depth * sizeof(struct mfs_path_s)); found = false; - finfo("Node not found, allocated, ready to be inserted into LRU."); + finfo("Node not found. Allocated at %p.", node); } if (!found) @@ -345,7 +407,7 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, { /* Node flush writes to the flash and journal. */ - ret = lru_nodeflush(sb, path, depth, ctz_sz, node, false); + ret = lru_nodeflush(sb, path, depth, node, false); if (predict_false(ret < 0)) { goto errout_with_node; @@ -373,7 +435,8 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, goto errout_with_delta; } - finfo("Delta is of the update type, has %u bytes of updates." , bytes); + finfo("Delta is of the update type, has %u bytes at offset %u.", + bytes, data_off); } delta->n_b = bytes; @@ -385,21 +448,37 @@ static int lru_wrtooff(FAR struct mfs_sb_s * const sb, } node->n_list++; - node->range_min = MIN(node->range_min, data_off); - node->range_max = MAX(node->range_max, data_off + bytes); + node->range_min = MIN(node->range_min, data_off); + node->range_max = MAX(node->range_max, data_off + bytes); - finfo("Delta attached to node. Now there are %lu nodes and the node has" - " %lu deltas. Node with range [%u, %u).", list_length(&MFS_LRU(sb)), - list_length(&node->delta), node->range_min, node->range_max); + old_sz = node->sz; + node->sz = MAX(node->range_max, path[depth - 1].sz); + node->path[node->depth - 1].sz = node->sz; + + if (old_sz != node->sz) + { + ret = lru_updatesz(sb, node->path, node->depth, node->sz); + if (predict_false(ret < 0)) + { + goto errout_with_delta; + } + } + + finfo("Delta attached to node %p. Now there are %lu nodes and the node has" + " %lu deltas. Node with range [%u, %u).", node, + list_length(&MFS_LRU(sb)), list_length(&node->delta), + node->range_min, node->range_max); return ret; errout_with_delta: + list_delete(&delta->list); kmm_free(delta); errout_with_node: if (!found && node != NULL) { + list_delete(&node->list); kmm_free(node); } @@ -407,13 +486,106 @@ errout: return ret; } +/**************************************************************************** + * Name: lru_updatesz + * + * Description: + * Updates size of an fs object in its parent. + * + * Input Parameters: + * sb - Superblock instance of the device. + * path - CTZ representation of the path. + * depth - Depth of path. + * new_sz - New size + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + * Assumptions/Limitations: + * Adds an entry for the target's parent to update the child's size, and + * updates the size in path of everyone that has this child. + * + ****************************************************************************/ + +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) +{ + int ret = OK; + struct mfs_node_s *n = NULL; + mfs_t i; + bool found; + char buf[sizeof(mfs_t)]; + + DEBUGASSERT(depth > 0); + + list_for_every_entry(&MFS_LRU(sb), n, struct mfs_node_s, list) + { + if (n->depth < depth) + { + continue; + } + + found = false; + for (i = depth; i >= 1; i--) + { + if (path[i - 1].ctz.idx_e == 0 && path[i - 1].ctz.pg_e == 0 && + mfs_ctz_eq(&n->path[i - 1].ctz, &path[i - 1].ctz) && + n->path[i - 1].off == path[i - 1].off) + { + found = true; + } + else if (path[i - 1].ctz.pg_e != 0 && + mfs_ctz_eq(&n->path[i - 1].ctz, &path[i - 1].ctz)) + { + found = true; + } + else + { + break; + } + } + + if (found) + { + n->path[depth - 1].sz = new_sz; + } + } + + if (depth == 1) + { + MFS_MN(sb).root_sz = new_sz; + goto errout; + } + + memset(buf, 0, sizeof(mfs_t)); + 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. + */ + + ret = mfs_lru_wr(sb, path[depth - 2].off + offsetof(struct mfs_dirent_s, + sz), sizeof(mfs_t), path, depth, buf); + if (predict_false(ret < 0)) + { + goto errout; + } + + path[depth - 1].sz = new_sz; + +errout: + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ int mfs_lru_ctzflush(FAR struct mfs_sb_s * const sb, - FAR struct mfs_path_s * const path, const mfs_t depth, - const mfs_t ctz_sz) + FAR struct mfs_path_s * const path, const mfs_t depth) { struct mfs_node_s *node = NULL; @@ -423,111 +595,21 @@ int mfs_lru_ctzflush(FAR struct mfs_sb_s * const sb, return OK; } - return lru_nodeflush(sb, path, depth, ctz_sz, node, true); + return lru_nodeflush(sb, path, depth, node, true); } int mfs_lru_del(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - mfs_t bytes, mfs_t ctz_sz, - FAR struct mfs_path_s * const path, const mfs_t depth) + mfs_t bytes, FAR struct mfs_path_s * const path, + const mfs_t depth) { - return lru_wrtooff(sb, data_off, bytes, ctz_sz, MFS_LRU_DEL, path, depth, - NULL); + return lru_wrtooff(sb, data_off, bytes, MFS_LRU_DEL, path, depth, NULL); } int mfs_lru_wr(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - mfs_t bytes, mfs_t ctz_sz, FAR struct mfs_path_s * const path, + mfs_t bytes, FAR struct mfs_path_s * const path, const mfs_t depth, FAR const char *buf) { - return lru_wrtooff(sb, data_off, bytes, ctz_sz, MFS_LRU_UPD, path, depth, - buf); -} - -int mfs_lru_rdfromoff(FAR struct mfs_sb_s * const sb, const mfs_t data_off, - FAR struct mfs_path_s * const path, const mfs_t depth, - FAR char *buf, const mfs_t buflen) -{ - int ret = OK; - mfs_t s; - mfs_t e; - mfs_t end; - mfs_t start; - mfs_t del_b; - FAR struct mfs_node_s *node = NULL; - FAR struct mfs_delta_s *delta = NULL; - - finfo("Reading from offset %u, %u bytes", data_off, buflen); - - ret = mfs_ctz_rdfromoff(sb, data_off, path, depth, buf, buflen); - if (predict_false(ret < 0)) - { - goto errout; - } - - lru_nodesearch(sb, path, depth, &node); - if (node == NULL) - { - goto errout; - } - - start = data_off; - end = data_off + buflen; - del_b = 0; - - do - { - list_for_every_entry(&node->delta, delta, struct mfs_delta_s, list) - { - if (delta->upd) - { - s = MAX(delta->off, start); - e = MIN(delta->off + delta->n_b, end); - - if (s >= e) - { - continue; - } - - memcpy(buf + (s - data_off), delta->upd + (s - delta->off), - e - s); - } - else - { - s = MAX(delta->off, start); - e = MIN(delta->off + delta->n_b, end); - - if (s >= end) - { - continue; - } - - if (e <= start) - { - del_b += delta->n_b; - s = data_off + delta->n_b; - e = end; - memmove(buf, buf + delta->n_b, - buflen - delta->n_b); - e = data_off + buflen - delta->n_b; - } - else - { - del_b += e - s; - memmove(buf + s, buf + e, buflen - (e - s)); - e = data_off + buflen - (e - s); - } - } - - start = s; - end = e; - } - - start = end; - end = data_off + buflen; - } - while (start != end); - -errout: - return ret; + return lru_wrtooff(sb, data_off, bytes, MFS_LRU_UPD, path, depth, buf); } void mfs_lru_init(FAR struct mfs_sb_s * const sb) @@ -538,53 +620,187 @@ void mfs_lru_init(FAR struct mfs_sb_s * const sb) finfo("LRU Initialized\n"); } -void mfs_lru_updatedsz(FAR struct mfs_sb_s * const sb, - FAR const struct mfs_path_s * const path, - const mfs_t depth, mfs_t *n_sz) +int mfs_lru_rdfromoff(FAR const struct mfs_sb_s * const sb, + const mfs_t data_off, + FAR struct mfs_path_s * const path, const mfs_t depth, + FAR char *buf, const mfs_t buflen) { - mfs_t o_sz; - FAR struct mfs_node_s *node = NULL; - FAR struct mfs_delta_s *delta = NULL; + /* Requires updated path from the journal. */ - if (depth == 0) - { - /* Master node */ - - o_sz = 0; - } - - if (depth == 1) - { - /* Root node. */ - - o_sz = MFS_MN(sb).root_sz; - } - else - { - o_sz = path[depth - 1].sz; - } - - *n_sz = o_sz; + int ret = OK; + mfs_t upper; + mfs_t lower; + mfs_t rem_sz; + mfs_t upper_og; + mfs_t upper_upd; + mfs_t lower_upd; + FAR char *tmp; + struct mfs_ctz_s ctz; + FAR struct mfs_node_s *node = NULL; + FAR struct mfs_delta_s *delta = NULL; lru_nodesearch(sb, path, depth, &node); if (node == NULL) { - finfo("No updates for file size, with depth %u.", depth); - return; + goto errout; } - list_for_every_entry(&node->delta, delta, struct mfs_delta_s, list) + /* 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; + lower = data_off; + upper_og = lower + buflen; + upper = upper_og; + rem_sz = buflen; + + while (rem_sz > 0) { - finfo("depth %u %u %u %p", depth, delta->n_b, delta->off, delta->upd); - if (delta->upd == NULL) + mfs_ctz_rdfromoff(sb, ctz, lower, rem_sz, tmp); + + list_for_every_entry(&node->delta, delta, struct mfs_delta_s, list) { - *n_sz -= MIN((*n_sz) - delta->off, delta->n_b); + 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) + { + /* Outside range */ + } + else + { + memmove(tmp + (lower - lower_upd), + tmp + (upper_upd - lower), upper - upper_upd); + + upper -= (upper_upd - lower_upd); + } + } + else + { + /* Update */ + + lower_upd = MAX(lower, delta->off); + upper_upd = MIN(upper, delta->off + delta->n_b); + + if (lower_upd >= upper_upd) + { + /* Outside range */ + } + else + { + memcpy(tmp + (lower_upd - lower), + delta->upd + (lower_upd - delta->off), + upper_upd - lower_upd); + } + } } - else + + tmp += upper - lower; + rem_sz -= upper - lower; + lower = upper; + upper = upper_og; + } + +errout: + return ret; +} + +int mfs_lru_updatedinfo(FAR const struct mfs_sb_s * const sb, + FAR struct mfs_path_s * const path, + const mfs_t depth) +{ + int ret = OK; + bool found; + mfs_t i; + FAR struct mfs_node_s *node = NULL; + + DEBUGASSERT(depth > 0); + + list_for_every_entry(&MFS_LRU(sb), node, struct mfs_node_s, list) + { + /* TODO: When a directory is newly created, and still in the LRU, its + * CTZ is (0, 0), and this can match others as well if at same depth, + * so, in these cases, match the parents, and so on up. + */ + + DEBUGASSERT(node->depth > 0); + + if (node->depth > depth) { - *n_sz = MAX(*n_sz, delta->off + delta->n_b); + continue; + } + + /* We need this loop to specifically check the parents in case these + * entries are all new, and have not been allocated any pages for + * being stored in the flash. Also we know that the root (depth 1) will + * be at least common in their paths. + */ + + found = true; + for (i = node->depth; i >= 1 && found; i--) + { + if (path[i - 1].ctz.idx_e == 0 && path[i - 1].ctz.pg_e == 0 && + mfs_ctz_eq(&node->path[i - 1].ctz, &path[i - 1].ctz) && + node->path[i - 1].off == path[i - 1].off) + { + /* OK */ + } + else if (path[i - 1].ctz.pg_e != 0 && + mfs_ctz_eq(&node->path[i - 1].ctz, &path[i - 1].ctz)) + { + /* OK */ + } + else + { + found = false; + } + } + + if (found) + { + path[node->depth - 1].sz = node->path[node->depth - 1].sz; } } - finfo("Updated file size is %u with depth %u.", *n_sz, depth); + return ret; +} + +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) +{ + int ret = OK; + char buf[sizeof(struct mfs_ctz_s)]; + FAR struct mfs_node_s *node = NULL; + + 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) + { + node->path[depth - 1].ctz = new_ctz; + } + } + + 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); + if (predict_false(ret < 0)) + { + goto errout; + } + + path[depth - 1].ctz = new_ctz; + +errout: + return ret; } diff --git a/fs/mnemofs/mnemofs_master.c b/fs/mnemofs/mnemofs_master.c index 3f94720aa83..7f5b0ebacad 100644 --- a/fs/mnemofs/mnemofs_master.c +++ b/fs/mnemofs/mnemofs_master.c @@ -186,15 +186,15 @@ static FAR const char *deser_mn(FAR const char * const in, int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) { - int ret = OK; - mfs_t i = 0; + int ret = OK; + mfs_t i = 0; mfs_t mblk1; mfs_t mblk2; mfs_t jrnl_blk_tmp; - bool found = false; + bool found = false; uint8_t hash; struct mfs_mn_s mn; - const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); + const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); char buftmp[4]; char buf[sz + 1]; @@ -265,14 +265,14 @@ errout: int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) { - int ret = OK; + int ret = OK; mfs_t pg; mfs_t mblk1; mfs_t mblk2; struct mfs_mn_s mn; - const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); - char buf[sz + 1]; struct timespec ts; + const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); + char buf[sz + 1]; clock_gettime(CLOCK_REALTIME, &ts); diff --git a/fs/mnemofs/mnemofs_rw.c b/fs/mnemofs/mnemofs_rw.c index 4a01e8aec99..20ef4331ce8 100644 --- a/fs/mnemofs/mnemofs_rw.c +++ b/fs/mnemofs/mnemofs_rw.c @@ -85,12 +85,22 @@ int mfs_isbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk) { + if (predict_false(blk > MFS_NBLKS(sb))) + { + return -EINVAL; + } + return MTD_ISBAD(MFS_MTD(sb), blk); } int mfs_markbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk) { - return MTD_ISBAD(MFS_MTD(sb), blk); + if (predict_false(blk > MFS_NBLKS(sb))) + { + return -EINVAL; + } + + return MTD_MARKBAD(MFS_MTD(sb), blk); } /* NOTE: These functions do not update the block allocator's state nor do @@ -103,6 +113,11 @@ ssize_t mfs_write_page(FAR const struct mfs_sb_s * const sb, { int ret = OK; + if (predict_false(page > MFS_NPGS(sb) || pgoff >= MFS_PGSZ(sb))) + { + return -EINVAL; + } + mempcpy(MFS_RWBUF(sb) + pgoff, data, datalen); ret = MTD_BWRITE(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); @@ -123,6 +138,11 @@ ssize_t mfs_read_page(FAR const struct mfs_sb_s * const sb, { int ret = OK; + if (predict_false(page > MFS_NPGS(sb) || pgoff >= MFS_PGSZ(sb))) + { + return -EINVAL; + } + ret = MTD_BREAD(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); if (ret < 0) { @@ -139,11 +159,21 @@ errout_with_reset: int mfs_erase_blk(FAR const struct mfs_sb_s * const sb, const off_t blk) { + if (predict_false(blk > MFS_NBLKS(sb))) + { + return -EINVAL; + } + return MTD_ERASE(MFS_MTD(sb), blk, 1); } int mfs_erase_nblks(FAR const struct mfs_sb_s * const sb, const off_t blk, const size_t n) { + if (predict_false(blk + n > MFS_NBLKS(sb))) + { + return -EINVAL; + } + return MTD_ERASE(MFS_MTD(sb), blk, n); } diff --git a/fs/mnemofs/mnemofs_util.c b/fs/mnemofs/mnemofs_util.c index 0815bd352e7..a9b1efe032a 100644 --- a/fs/mnemofs/mnemofs_util.c +++ b/fs/mnemofs/mnemofs_util.c @@ -92,6 +92,8 @@ uint8_t mfs_arrhash(FAR const char *arr, ssize_t len) ssize_t r = len - 1; uint16_t hash = 0; + /* TODO: Change the array checksum to be 16 bit long. */ + while (l <= r) { hash += arr[l] * arr[r] * (l + 1) * (r + 1); @@ -105,6 +107,27 @@ uint8_t mfs_arrhash(FAR const char *arr, ssize_t len) return hash % (1 << 8); } +uint16_t mfs_hash(FAR const char *arr, ssize_t len) +{ + ssize_t l = 0; + ssize_t r = len - 1; + uint32_t hash = 0; + + /* TODO: Change the array checksum to be 16 bit long. */ + + while (l <= r) + { + hash += arr[l] * arr[r] * (l + 1) * (r + 1); + l++; + r--; + hash %= (1 << MFS_HASHSZ); + } + + finfo("Hash calculated for size %ld to be %u.", len, hash); + + return hash; +} + FAR char *mfs_ser_8(const uint8_t n, FAR char * const out) { *out = n; @@ -189,6 +212,28 @@ FAR const char *mfs_deser_ctz(FAR const char * const in, return i; } +FAR char *mfs_ser_path(FAR const struct mfs_path_s * const x, + FAR char * const out) +{ + char *o = out; + + o = mfs_ser_ctz(&x->ctz, o); + o = mfs_ser_mfs(x->off, o); + o = mfs_ser_mfs(x->sz, o); + return o; +} + +FAR const char *mfs_deser_path(FAR const char * const in, + FAR struct mfs_path_s * const x) +{ + const char *i = in; + + i = mfs_deser_ctz(i, &x->ctz); + i = mfs_deser_mfs(i, &x->off); + i = mfs_deser_mfs(i, &x->sz); + return i; +} + FAR char *mfs_ser_timespec(FAR const struct timespec * const x, FAR char * const out) { @@ -225,3 +270,16 @@ mfs_t mfs_set_msb(mfs_t n) { return 31 - mfs_clz(n); } + +bool mfs_ctz_eq(FAR const struct mfs_ctz_s * const a, + FAR const struct mfs_ctz_s * const b) +{ + return a->idx_e == b->idx_e && a->pg_e == b->pg_e; +} + +bool mfs_path_eq(FAR const struct mfs_path_s * const a, + FAR const struct mfs_path_s * const b) +{ + return mfs_ctz_eq(&a->ctz, &b->ctz) && (a->off == b->off) + && (a->sz == b->sz); +} diff --git a/include/nuttx/mtd/nand_ram.h b/include/nuttx/mtd/nand_ram.h index 5229882e42b..c3483ed06ac 100644 --- a/include/nuttx/mtd/nand_ram.h +++ b/include/nuttx/mtd/nand_ram.h @@ -43,14 +43,14 @@ #define NAND_RAM_SIZE NAND_RAM_MB(CONFIG_MTD_NAND_RAM_SIZE) -#define NAND_RAM_LOG_PAGES_PER_BLOCK ((uint32_t) 7) -#define NAND_RAM_PAGE_SIZE ((uint32_t) (1 << 9)) /* 512 B */ -#define NAND_RAM_SPARE_SIZE ((uint32_t) (1 << 4)) /* 16 B */ +#define NAND_RAM_LOG_PAGES_PER_BLOCK ((uint32_t) 4) +#define NAND_RAM_PAGE_SIZE ((uint32_t) (1 << 7)) +#define NAND_RAM_SPARE_SIZE ((uint32_t) (1 << 3)) +#define NAND_RAM_BLOCK_SIZE ((uint32_t) ((1 << NAND_RAM_LOG_PAGES_PER_BLOCK) * NAND_RAM_PAGE_SIZE)) #define NAND_RAM_N_PAGES ((uint32_t) NAND_RAM_SIZE / NAND_RAM_PAGE_SIZE) #define NAND_RAM_TOTAL_PAGE_SIZE ((uint32_t) (NAND_RAM_PAGE_SIZE + NAND_RAM_SPARE_SIZE)) -#define NAND_RAM_PAGES_PER_BLOCK ((uint32_t) (NAND_RAM_BLOCK_SIZE / NAND_RAM_PAGE_SIZE)) -#define NAND_RAM_N_BLOCKS ((uint32_t) (NAND_RAM_N_PAGES / NAND_RAM_PAGES_PER_BLOCK)) -#define NAND_RAM_BLOCK_SIZE ((uint32_t) ((1 << NAND_RAM_LOG_PAGES_PER_BLOCK) * NAND_RAM_PAGE_SIZE)) +#define NAND_RAM_PAGES_PER_BLOCK ((uint32_t) (1 << (NAND_RAM_LOG_PAGES_PER_BLOCK))) +#define NAND_RAM_N_BLOCKS ((uint32_t) (NAND_RAM_SIZE / (NAND_RAM_PAGES_PER_BLOCK * NAND_RAM_PAGE_SIZE))) #define NAND_RAM_PAGE_WRITTEN 0 #define NAND_RAM_PAGE_FREE 1