From 6f0daf08eb79620b419b7353d3b66e55055bb08b Mon Sep 17 00:00:00 2001 From: Saurav Pal Date: Wed, 10 Jul 2024 15:14:33 +0000 Subject: [PATCH] fs/mnemofs: Adds Block Allocator Adds Block Allocator logic to mnemofs. Signed-off-by: Saurav Pal --- drivers/mtd/mtd_nandecc.c | 1 + fs/mnemofs/mnemofs.h | 199 +++++++++++++++- fs/mnemofs/mnemofs_blkalloc.c | 418 +++++++++++++++++++++++++++++++++- fs/mnemofs/mnemofs_rw.c | 21 ++ 4 files changed, 634 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/mtd_nandecc.c b/drivers/mtd/mtd_nandecc.c index cfe5ff8b44..5a21a79177 100644 --- a/drivers/mtd/mtd_nandecc.c +++ b/drivers/mtd/mtd_nandecc.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff --git a/fs/mnemofs/mnemofs.h b/fs/mnemofs/mnemofs.h index 7ef33e15a6..93c647e4fd 100644 --- a/fs/mnemofs/mnemofs.h +++ b/fs/mnemofs/mnemofs.h @@ -485,20 +485,128 @@ void mfs_jrnl_free(FAR struct mfs_sb_s * const sb); int mfs_ba_init(FAR struct mfs_sb_s * const sb); /**************************************************************************** - * Name: mfs_ba_free + * Name: mfs_ba_getpg * * Description: - * Free the block allocator + * Returns an allocated page. * * Input Parameters: * sb - Superblock instance of the device. * + * Returned Value: + * 0 - No more space left + * > 0 - Page number + * * Assumptions/Limitations: * This assumes a locked environment when called. * ****************************************************************************/ -void mfs_ba_free(FAR struct mfs_sb_s * const sb); +mfs_t mfs_ba_getpg(FAR struct mfs_sb_s * const sb); + +/**************************************************************************** + * Name: mfs_ba_getblk + * + * Description: + * Returns an allocated block. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + * Returned Value: + * 0 - No more space left + * > 0 - Block number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +mfs_t mfs_ba_getblk(FAR struct mfs_sb_s * const sb); + +/**************************************************************************** + * Name: mfs_ba_pgmarkdel + * + * Description: + * Mark a page as being ready for deletion. + * + * Input Parameters: + * sb - Superblock instance of the device. + * pg - Page number. + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_pgmarkdel(FAR struct mfs_sb_s * const sb, mfs_t pg); + +/**************************************************************************** + * Name: mfs_ba_blkmarkdel + * + * Description: + * Mark a block as being ready for deletion. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block number. + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_blkmarkdel(FAR struct mfs_sb_s * const sb, mfs_t blk); + +/**************************************************************************** + * Name: mfs_ba_delmarked + * + * Description: + * Delete all marked for deletion blocks. + * + * Input Parameters: + * sb - Superblock instance of the device. + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_delmarked(FAR struct mfs_sb_s * const sb); + +/**************************************************************************** + * Name: mfs_ba_markusedpg + * + * Description: + * Marked page as being used. + * + * Input Parameters: + * sb - Superblock instance of the device. + * pg - Page number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_markusedpg(FAR struct mfs_sb_s * const sb, mfs_t pg); + +/**************************************************************************** + * Name: mfs_ba_markusedblk + * + * Description: + * Marked block as being used. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_markusedblk(FAR struct mfs_sb_s * const sb, mfs_t blk); /**************************************************************************** * Name: mfs_ba_getavailpgs @@ -517,8 +625,58 @@ void mfs_ba_free(FAR struct mfs_sb_s * const sb); mfs_t mfs_ba_getavailpgs(FAR const struct mfs_sb_s * const sb); +/**************************************************************************** + * Name: mfs_ba_free + * + * Description: + * Free the block allocator + * + * Input Parameters: + * sb - Superblock instance of the device. + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +void mfs_ba_free(FAR struct mfs_sb_s * const sb); + /* mnemofs_rw.c */ +/**************************************************************************** + * Name: mfs_isbadblk + * + * Description: + * Is a block bad. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block Number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +int mfs_isbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk); + +/**************************************************************************** + * Name: mfs_markbadblk + * + * Description: + * Mark a block as bad. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block Number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +int mfs_markbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk); + /**************************************************************************** * Name: mfs_read_page * @@ -541,6 +699,41 @@ 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); +/**************************************************************************** + * Name: mfs_erase_blk + * + * Description: + * Erase a block. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block Number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +int mfs_erase_blk(FAR const struct mfs_sb_s * const sb, const off_t blk); + +/**************************************************************************** + * Name: mfs_erase_nblks + * + * Description: + * Erase consecutive blocks. + * + * Input Parameters: + * sb - Superblock instance of the device. + * blk - Block Number + * + * Assumptions/Limitations: + * This assumes a locked environment when called. + * + ****************************************************************************/ + +int mfs_erase_nblks(FAR const struct mfs_sb_s * const sb, const off_t blk, + const size_t n); + /* mnemofs_lru.c */ /**************************************************************************** diff --git a/fs/mnemofs/mnemofs_blkalloc.c b/fs/mnemofs/mnemofs_blkalloc.c index 0fc04110b1..254675995f 100644 --- a/fs/mnemofs/mnemofs_blkalloc.c +++ b/fs/mnemofs/mnemofs_blkalloc.c @@ -91,6 +91,11 @@ * Pre-processor Definitions ****************************************************************************/ +#define BMAP_GET(bmap, idx, off) ((bmap)[(idx)] & (1 << (off))) +#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)))) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -99,6 +104,12 @@ * Private Function Prototypes ****************************************************************************/ +static inline void pg2bmap(mfs_t pg, FAR mfs_t *idx, FAR uint8_t *off); +static int is_pg_writeable(FAR struct mfs_sb_s * const sb, mfs_t pg, + FAR mfs_t *idx, FAR uint8_t *off); +static int is_blk_writeable(FAR struct mfs_sb_s * const sb, + const mfs_t blk); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -111,18 +122,421 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: pg2bmap + * + * Description: + * Gets the bitmap location of a page. The page in the bitmap will be in + * bmap[idx] byte at (1 << off) position in the byte. + * + * Input Parameters: + * pg - Page number to check. + * 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. + * + ****************************************************************************/ + +static inline void pg2bmap(mfs_t pg, FAR mfs_t *idx, FAR uint8_t *off) +{ + /* The compiler should automatically use shift operation for division. */ + + *idx = pg / 8; + *off = pg % 8; +} + +/**************************************************************************** + * Name: is_pg_writeable + * + * Description: + * Checks if a page is writeable by checking if the page is either free, or + * it's being used but the entire block is ready for erase. + * + * Input Parameters: + * sb - Superblock instance of the device. + * pg - Page number to check. + * 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. + * -ENOSYS - Not supported. + * + * Assumptions/Limitations: + * Assumes this is run in a locked environment. + * + ****************************************************************************/ + +static int is_pg_writeable(FAR struct mfs_sb_s * const sb, mfs_t pg, + FAR mfs_t *idx, FAR uint8_t *off) +{ + int blkbad_status; + + /* Bad block check. */ + + blkbad_status = mfs_isbadblk(sb, MFS_PG2BLK(sb, pg)); + if (predict_false(blkbad_status == -ENOSYS)) + { + return blkbad_status; + } + + if (predict_false(blkbad_status < 0) || blkbad_status == 1) + { + return MFS_BLK_BAD; + } + + pg2bmap(MFS_BA(sb).c_pg, idx, off); + + if (BMAP_GET(MFS_BA(sb).bmap_upgs, *idx, *off)) + { + if (DEL_ARR_PG(sb, MFS_BA(sb).c_pg) == MFS_PGINBLK(sb)) + { + return MFS_BLK_ERASABLE; + } + else + { + return MFS_PG_USED; + } + } + else + { + return MFS_PG_FREE; + } +} + +/**************************************************************************** + * Name: is_blk_writeable + * + * Description: + * Checks if an entire block is allocatable, either because none of the + * pages in it have been allocated, or because the entire block can be + * erased. + * + * Input Parameters: + * sb - Superblock instance of the device. + * pg - Page number to check. + * 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 is a bad block. + * MFS_BLK_USED - If the block is being used. + * MFS_BLK_ERASABLE - If block can be allocated, but block needs erase. + * MFS_BLK_FREE - If the block is free. + * + * Assumptions/Limitations: + * Assumes this is run in a locked environment. + * + ****************************************************************************/ + +static int is_blk_writeable(FAR struct mfs_sb_s * const sb, const mfs_t blk) +{ + mfs_t idx; + uint8_t off; + mfs_t pg = MFS_BLK2PG(sb, blk); + mfs_t i; + int blkbad_status; + + /* Bad block check. */ + + blkbad_status = mfs_isbadblk(sb, blk); + if (predict_false(blkbad_status == -ENOSYS)) + { + return blkbad_status; + } + + if (predict_false(blkbad_status < 0) || blkbad_status == 1) + { + return MFS_BLK_BAD; + } + + for (i = 0; i < MFS_PGINBLK(sb); i++) + { + pg2bmap(pg + i, &idx, &off); + + if (BMAP_GET(MFS_BA(sb).bmap_upgs, idx, off)) + { + if (DEL_ARR_PG(sb, MFS_BA(sb).c_pg) == MFS_PGINBLK(sb)) + { + return MFS_BLK_ERASABLE; + } + else + { + return MFS_BLK_USED; + } + } + } + + return MFS_BLK_FREE; +} + /**************************************************************************** * Public Functions ****************************************************************************/ int mfs_ba_init(FAR struct mfs_sb_s * const sb) { - /* TODO */ + int ret = OK; + uint8_t log; - return OK; +/* We need at least 5 blocks, as one is occupied by superblock, at least + * one for the journal, 2 for journal's master blocks, and at least one for + * actual data. + */ + + if (MFS_NBLKS(sb) < 5) + { + ret = -ENOSPC; + goto errout; + } + + memset(&MFS_BA(sb), 0, sizeof(MFS_BA(sb))); + + MFS_BA(sb).s_blk = rand() % MFS_NBLKS(sb); + if (MFS_PG2BLK(sb, MFS_BA(sb).s_blk) == sb->sb_blk) + { + MFS_BA(sb).s_blk++; + MFS_BA(sb).s_blk %= MFS_NBLKS(sb); + } + + MFS_BA(sb).c_pg = MFS_BLK2PG(sb, MFS_BA(sb).s_blk); + + log = ceil(log2(MFS_NBLKS(sb))); + + /* MFS_BA(sb).k_del_elemsz = ((log + 7) & (-8)) / 8; */ + + MFS_BA(sb).k_del = kmm_zalloc(sizeof(size_t) * MFS_NBLKS(sb)); + if (!MFS_BA(sb).k_del) + { + ret = -ENOMEM; + goto errout; + } + + MFS_BA(sb).n_bmap_upgs = MFS_UPPER8(MFS_NPGS(sb)); + + MFS_BA(sb).bmap_upgs = kmm_zalloc(MFS_BA(sb).n_bmap_upgs); + if (!MFS_BA(sb).bmap_upgs) + { + ret = -ENOMEM; + goto errout_with_k_del; + } + + /* TODO: Fill MFS_BA(sb).bmap_upgs after tree traversal. */ + + finfo("mnemofs: Block Allocator initialized, starting at page %d.\n", + MFS_BLK2PG(sb, MFS_BA(sb).s_blk)); + return ret; + +errout_with_k_del: + kmm_free(MFS_BA(sb).k_del); + +errout: + return ret; } void mfs_ba_free(FAR struct mfs_sb_s * const sb) +{ + kmm_free(MFS_BA(sb).k_del); + kmm_free(MFS_BA(sb).bmap_upgs); + + finfo("Block Allocator Freed."); +} + +mfs_t mfs_ba_getpg(FAR struct mfs_sb_s * const sb) +{ + bool inc = true; + bool found = false; + mfs_t i = MFS_BA(sb).c_pg; + mfs_t pg = 0; + mfs_t idx; + mfs_t tpgs = MFS_NBLKS(sb) * MFS_PGINBLK(sb); + uint8_t off; + + for (; i != tpgs; i++) + { + switch (is_pg_writeable(sb, MFS_BA(sb).c_pg, &idx, &off)) + { + case MFS_PG_USED: + finfo("Used %d\n", MFS_BA(sb).c_pg); + break; + + case MFS_PG_FREE: + finfo("Free %d\n", MFS_BA(sb).c_pg); + pg = MFS_BA(sb).c_pg; + mfs_ba_markusedpg(sb, pg); + found = true; + break; + + case MFS_BLK_BAD: + finfo("Bad %d\n", MFS_BA(sb).c_pg); + + /* Skip pages to next block. */ + + MFS_BA(sb).c_pg = MFS_BLK2PG(sb, + (MFS_PG2BLK(sb, MFS_BA(sb).c_pg) + 1) % + MFS_NBLKS(sb)); + inc = false; + break; + + case MFS_BLK_ERASABLE: + finfo("Erasable %d\n", MFS_BA(sb).c_pg); + pg = MFS_BA(sb).c_pg; + mfs_erase_blk(sb, MFS_PG2BLK(sb, MFS_BA(sb).c_pg)); + DEL_ARR_PG(sb, MFS_BA(sb).c_pg) = 0; + mfs_ba_markusedpg(sb, pg); + found = true; + break; + + case -ENOSYS: + + /* TODO: Manually check for bad blocks. */ + + return 0; + } + + if (inc) + { + MFS_BA(sb).c_pg++; + MFS_BA(sb).c_pg %= tpgs; + } + else + { + i--; + inc = true; + } + + if (found) + { + break; + } + } + + if (!found) + { + DEBUGASSERT(pg == 0); + finfo("No more pages found. Page: %u.", pg); + } + + return pg; +} + +mfs_t mfs_ba_getblk(FAR struct mfs_sb_s * const sb) +{ + bool found = false; + mfs_t i = 0; + mfs_t blk; + mfs_t ret = 0; + + blk = MFS_PG2BLK(sb, MFS_BA(sb).c_pg); + if (MFS_BA(sb).c_pg % MFS_PGINBLK(sb)) + { + /* Skipped pages are not updated in used. */ + + blk++; + blk %= MFS_NBLKS(sb); + i++; + } + + for (; i < MFS_NBLKS(sb); i++) + { + switch (is_blk_writeable(sb, blk)) + { + case MFS_BLK_BAD: + break; + + case MFS_BLK_USED: + break; + + case MFS_BLK_ERASABLE: + mfs_ba_blkmarkdel(sb, blk); + mfs_ba_markusedblk(sb, blk); + found = true; + break; + + case MFS_BLK_FREE: + mfs_ba_markusedblk(sb, blk); + found = true; + break; + + case -ENOSYS: + + /* TODO: Manually check for bad blocks. */ + + return 0; + } + + if (found) + { + break; + } + + blk++; + blk %= MFS_NBLKS(sb); + } + + if (found) + { + ret = blk; + MFS_BA(sb).c_pg = MFS_BLK2PG(sb, (++blk) % MFS_NBLKS(sb)); + } + + finfo("Block number: %u. Found: %d.", ret, found); + + return ret; +} + +void mfs_ba_pgmarkdel(FAR struct mfs_sb_s * const sb, mfs_t pg) +{ + DEL_ARR_PG(sb, MFS_BA(sb).c_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; +} + +void mfs_ba_delmarked(FAR struct mfs_sb_s * const sb) { /* TODO */ } + +/* Mark a page as being used. Used by master node during initial format and + */ + +void mfs_ba_markusedpg(FAR struct mfs_sb_s * const sb, mfs_t pg) +{ + 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 pg = MFS_BLK2PG(sb, blk); + + for (i = 0; i < MFS_PGINBLK(sb); i++) + { + mfs_ba_markusedpg(sb, pg + i); + } +} + +mfs_t mfs_ba_getavailpgs(FAR const struct mfs_sb_s * const sb) +{ + /* TODO */ + + return 0; +} diff --git a/fs/mnemofs/mnemofs_rw.c b/fs/mnemofs/mnemofs_rw.c index 0607c95bef..ffadd2e771 100644 --- a/fs/mnemofs/mnemofs_rw.c +++ b/fs/mnemofs/mnemofs_rw.c @@ -83,9 +83,30 @@ * Public Functions ****************************************************************************/ +int mfs_isbadblk(FAR const struct mfs_sb_s * const sb, mfs_t blk) +{ + 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); +} + 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) { return OK; } + +int mfs_erase_blk(FAR const struct mfs_sb_s * const sb, const off_t blk) +{ + 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) +{ + return MTD_ERASE(MFS_MTD(sb), blk, n); +}