acassis commented on code in PR #12661:
URL: https://github.com/apache/nuttx/pull/12661#discussion_r1672525348


##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -111,18 +122,416 @@
  * 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)

Review Comment:
   ```suggestion
                              FAR mfs_t *idx, FAR uint8_t *off)



##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -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);

Review Comment:
   ```suggestion
                                      FAR mfs_t *idx, FAR uint8_t *off);



##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -111,18 +122,416 @@
  * 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;
+
+/* We need atleast 5 blocks, as one is occupied by superblock, atleast

Review Comment:
   ```suggestion
   /* We need at least 5 blocks, as one is occupied by superblock, at least



##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -111,18 +122,416 @@
  * 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;
+
+/* We need atleast 5 blocks, as one is occupied by superblock, atleast
+ * one for the journal, 2 for journal's master blocks, and atleast 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));
 
-  return OK;
+  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;
+        }
+    }
+

Review Comment:
   Maybe add a debug warn msg if !found



##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -111,18 +122,416 @@
  * 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;
+
+/* We need atleast 5 blocks, as one is occupied by superblock, atleast
+ * one for the journal, 2 for journal's master blocks, and atleast 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));
 
-  return OK;
+  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;
+        }
+    }
+
+  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));
+      return ret;
+    }
+  else
+    {
+      return ret;

Review Comment:
   Add debug warn ?



##########
fs/mnemofs/mnemofs_blkalloc.c:
##########
@@ -111,18 +122,416 @@
  * 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;
+
+/* We need atleast 5 blocks, as one is occupied by superblock, atleast
+ * one for the journal, 2 for journal's master blocks, and atleast one for

Review Comment:
   ```suggestion
    * one for the journal, 2 for journal's master blocks, and at least one for



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to