diff --git a/fs/mnemofs/mnemofs.h b/fs/mnemofs/mnemofs.h index 7511d22203..df1d1040b3 100644 --- a/fs/mnemofs/mnemofs.h +++ b/fs/mnemofs/mnemofs.h @@ -1303,6 +1303,27 @@ void mfs_lru_updatedsz(FAR struct mfs_sb_s * const sb, /* mnemofs_master.c */ +/**************************************************************************** + * Name: mfs_mn_init + * + * Description: + * Initialize master node by reading from the flash. + * + * Input Parameters: + * sb - Superblock instance of the device. + * jrnl_blk - First block of the journal. + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + * Assumptions/Limitations: + * The journal will have to be initialized before this. + * + ****************************************************************************/ + +int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk); + /**************************************************************************** * Name: mfs_mn_fmt * @@ -1324,6 +1345,29 @@ void mfs_lru_updatedsz(FAR struct mfs_sb_s * const sb, int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk); +/**************************************************************************** + * Name: mfs_mn_move + * + * Description: + * Move the master node. + * + * Input Parameters: + * sb - Superblock instance of the device. + * root - New location of the root of the file system. + * root_sz - New size of the CTZ list of the root of the file syste. + * + * Returned Value: + * 0 - OK + * < 0 - Error + * + * Assumptions/Limitations: + * This is called when the root is updated to a new location. + * + ****************************************************************************/ + +int mfs_mn_move(FAR struct mfs_sb_s * const sb, struct mfs_ctz_s root, + const mfs_t root_sz); + /* mnemofs_fsobj.c */ /**************************************************************************** diff --git a/fs/mnemofs/mnemofs_master.c b/fs/mnemofs/mnemofs_master.c index b971671b1a..3f94720aa8 100644 --- a/fs/mnemofs/mnemofs_master.c +++ b/fs/mnemofs/mnemofs_master.c @@ -97,6 +97,11 @@ * Private Function Prototypes ****************************************************************************/ +static FAR char *ser_mn(const struct mfs_mn_s mn, + FAR char * const out); +static FAR const char *deser_mn(FAR const char * const in, + FAR struct mfs_mn_s *mn, FAR uint8_t *hash); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -109,13 +114,253 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: ser_mn + * + * Description: + * Serialize master node. + * + * Input Parameters: + * mn - Master node. + * out - Out buffer. + * + * Returned Value: + * Pointer to the end of the serialized data in `out`. + * + * Assumptions/Limitations: + * Out should contain enough space for `mn` and 1 byte extra for the hash. + * + ****************************************************************************/ + +static FAR char *ser_mn(const struct mfs_mn_s mn, FAR char * const out) +{ + FAR char *tmp = out; + + tmp = mfs_ser_mfs(mn.jrnl_blk, tmp); + tmp = mfs_ser_mfs(mn.mblk_idx, tmp); + tmp = mfs_ser_ctz(&mn.root_ctz, tmp); + tmp = mfs_ser_mfs(mn.root_sz, tmp); + tmp = mfs_ser_timespec(&mn.ts, tmp); + tmp = mfs_ser_8(mfs_arrhash(out, tmp - out), tmp); + + return tmp; +} + +/**************************************************************************** + * Name: ser_mn + * + * Description: + * Deserialize master node. + * + * Input Parameters: + * in - In buffer. + * mn - Master node to populate. + * hash - Stored hash (of serialized data) to populate. + * + * Returned Value: + * Pointer to the end of the serialized data in `in`. + * + * Assumptions/Limitations: + * In should contain enough space for `mn` and 1 byte extra for the hash. + * + ****************************************************************************/ + +static FAR const char *deser_mn(FAR const char * const in, + FAR struct mfs_mn_s *mn, FAR uint8_t *hash) +{ + FAR const char *tmp = in; + + tmp = mfs_deser_mfs(tmp, &mn->jrnl_blk); + tmp = mfs_deser_mfs(tmp, &mn->mblk_idx); + tmp = mfs_deser_ctz(tmp, &mn->root_ctz); + tmp = mfs_deser_mfs(tmp, &mn->root_sz); + tmp = mfs_deser_timespec(tmp, &mn->ts); + tmp = mfs_deser_8(tmp, hash); + + return tmp; +} + /**************************************************************************** * Public Functions ****************************************************************************/ +int mfs_mn_init(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) +{ + int ret = OK; + mfs_t i = 0; + mfs_t mblk1; + mfs_t mblk2; + mfs_t jrnl_blk_tmp; + bool found = false; + uint8_t hash; + struct mfs_mn_s mn; + const mfs_t sz = sizeof(struct mfs_mn_s) - sizeof(mn.pg); + char buftmp[4]; + char buf[sz + 1]; + + mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); + mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); + + mn.jrnl_blk = mn.jrnl_blk; + mn.mblk_idx = 0; + mn.pg = MFS_BLK2PG(sb, mblk1); + + for (i = 0; i < MFS_PGINBLK(sb); i++) + { + mfs_read_page(sb, buftmp, 4, mn.pg, 0); + mfs_deser_mfs(buftmp, &jrnl_blk_tmp); + + if (jrnl_blk_tmp == 0) + { + break; + } + + if (jrnl_blk_tmp != jrnl_blk) + { + break; + } + + found = true; + mn.mblk_idx++; + mn.pg++; + } + + if (found == false) + { + ret = -EINVAL; + goto errout; + } + + if (i == MFS_PGINBLK(sb)) + { + ret = -ENOSPC; + goto errout; + } + else + { + mn.mblk_idx--; + mn.pg--; + } + + mfs_read_page(sb, buf, sz + 1, mn.pg, 0); + + /* Deserialize. */ + + deser_mn(buf, &mn, &hash); + if (hash != mfs_arrhash(buf, sz)) + { + ret = -EINVAL; + goto errout; + } + + /* FUTURE TODO: Recovery in case of hash not matching, or page not + * readable. + */ + + MFS_MN(sb) = mn; + +errout: + return ret; +} + int mfs_mn_fmt(FAR struct mfs_sb_s * const sb, const mfs_t jrnl_blk) { - /* TODO */ + 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; - return OK; + clock_gettime(CLOCK_REALTIME, &ts); + + memset(buf, 0, sz + 1); + + mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); + mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); + + pg = mfs_ba_getpg(sb); + if (predict_false(pg == 0)) + { + ret = -ENOSPC; + goto errout; + } + + finfo("Root formatted to be at Page %u", pg); + + mn.root_ctz.idx_e = 0; + mn.root_ctz.pg_e = pg; + mn.jrnl_blk = jrnl_blk; + mn.mblk_idx = 0; + mn.pg = MFS_BLK2PG(sb, mblk1); + mn.root_sz = 0; + mn.ts = ts; + mn.root_st_atim = ts; + mn.root_st_ctim = ts; + mn.root_st_mtim = ts; + mn.root_mode = 0777 | S_IFDIR; + + /* Serialize. */ + + ser_mn(mn, buf); + + ret = mfs_write_page(sb, buf, sz, MFS_BLK2PG(sb, mblk1), 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + ret = mfs_write_page(sb, buf, sz, MFS_BLK2PG(sb, mblk2), 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + MFS_MN(sb) = mn; + finfo("Master node written. Now at page %d, timestamp %lld.%.9ld.", + MFS_MN(sb).pg, (long long)MFS_MN(sb).ts.tv_sec, + MFS_MN(sb).ts.tv_nsec); + +errout: + return ret; +} + +int mfs_mn_move(FAR struct mfs_sb_s * const sb, struct mfs_ctz_s root, + const mfs_t root_sz) +{ + int ret = OK; + 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]; + + if (MFS_MN(sb).mblk_idx == MFS_PGINBLK(sb) - 1) + { + /* TODO: Move journal. Master blocks are full. */ + } + + mblk1 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks); + mblk2 = mfs_jrnl_blkidx2blk(sb, MFS_JRNL(sb).n_blks + 1); + mn = MFS_MN(sb); + + mn.root_ctz = root; + mn.root_sz = root_sz; + mn.mblk_idx++; + mn.pg++; + + ser_mn(mn, buf); + + ret = mfs_write_page(sb, buf, sz + 1, mn.pg, 0); + if (predict_false(ret < 0)) + { + goto errout; + } + + MFS_MN(sb) = mn; + +errout: + return ret; } diff --git a/fs/mnemofs/mnemofs_rw.c b/fs/mnemofs/mnemofs_rw.c index 306051d5b2..4a01e8aec9 100644 --- a/fs/mnemofs/mnemofs_rw.c +++ b/fs/mnemofs/mnemofs_rw.c @@ -93,22 +93,48 @@ int mfs_markbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk) return MTD_ISBAD(MFS_MTD(sb), blk); } +/* NOTE: These functions do not update the block allocator's state nor do + * they enforce it. + */ + ssize_t mfs_write_page(FAR const struct mfs_sb_s * const sb, FAR const char *data, const mfs_t datalen, const off_t page, const mfs_t pgoff) { - /* TODO */ + int ret = OK; - return OK; + mempcpy(MFS_RWBUF(sb) + pgoff, data, datalen); + + ret = MTD_BWRITE(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); + if (ret < 0) + { + goto errout_with_reset; + } + +errout_with_reset: + memset(MFS_RWBUF(sb), 0, MFS_PGSZ(sb)); + + return ret; } ssize_t mfs_read_page(FAR const struct mfs_sb_s * const sb, FAR char *data, const mfs_t datalen, const off_t page, const mfs_t pgoff) { - /* TODO */ + int ret = OK; - return OK; + ret = MTD_BREAD(MFS_MTD(sb), page, 1, MFS_RWBUF(sb)); + if (ret < 0) + { + goto errout_with_reset; + } + + memcpy(data, MFS_RWBUF(sb) + pgoff, datalen); + +errout_with_reset: + memset(MFS_RWBUF(sb), 0, MFS_PGSZ(sb)); + + return ret; } int mfs_erase_blk(FAR const struct mfs_sb_s * const sb, const off_t blk)