fs/mnemofs: Refactor path logic, direntry size bug fix, open free bug fix

Refactoring path logic to prevent logic flaws, direntry size bug fix to allow proper direntry traversal, open free bug fix to prevent memory leak after close.

Signed-off-by: Saurav Pal <resyfer.dev@gmail.com>
This commit is contained in:
Saurav Pal 2024-08-08 16:38:56 +00:00 committed by Alin Jerpelea
parent 01bac59cb7
commit 0be6dfb552
14 changed files with 2208 additions and 1635 deletions

2
.gitignore vendored
View file

@ -66,4 +66,4 @@ tools/gdb/__pycache__
/build
.ccls-cache
compile_commands.json
imx9-sdimage.img
imx9-sdimage.img

View file

@ -25,6 +25,7 @@
* Included Files
****************************************************************************/
#include <debug.h>
#include <stddef.h>
#include <nuttx/compiler.h>
@ -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);

View file

@ -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
{

View file

@ -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;
}

View file

@ -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

View file

@ -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++)

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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