You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/03/13 16:11:48 UTC

(nuttx) 02/02: mtd_config_fs : optimize nvs

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 3b7936304183d505f15a3a270fc39277f9da8e60
Author: xucheng5 <xu...@xiaomi.com>
AuthorDate: Wed Dec 20 11:45:27 2023 +0800

    mtd_config_fs : optimize nvs
    
    Signed-off-by: xucheng5 <xu...@xiaomi.com>
---
 drivers/mtd/mtd_config_fs.c | 156 +++++++++++++++++++++++++++++---------------
 1 file changed, 104 insertions(+), 52 deletions(-)

diff --git a/drivers/mtd/mtd_config_fs.c b/drivers/mtd/mtd_config_fs.c
index ad2d3ca2b0..f1f8079f5f 100644
--- a/drivers/mtd/mtd_config_fs.c
+++ b/drivers/mtd/mtd_config_fs.c
@@ -81,11 +81,8 @@
 
 #define NVS_SPECIAL_ATE_ID              0xffffffff
 
-#ifdef CONFIG_MTD_WRITE_ALIGN_SIZE
 #define NVS_ALIGN_SIZE                  CONFIG_MTD_WRITE_ALIGN_SIZE
-#else
-#define NVS_ALIGN_SIZE                  4
-#endif
+#define NVS_ALIGN_UP(x)                 (((x) + NVS_ALIGN_SIZE - 1) & ~(NVS_ALIGN_SIZE - 1))
 
 /****************************************************************************
  * Private Types
@@ -116,11 +113,15 @@ begin_packed_struct struct nvs_ate
   uint16_t key_len;      /* Key string len */
   uint8_t  part;         /* Part of a multipart data - future extension */
   uint8_t  crc8;         /* Crc8 check of the ate entry */
-#if CONFIG_MTD_WRITE_ALIGN_SIZE > 4
-  uint8_t  padding[NVS_ALIGN_SIZE - 4];  /* padding for align */
+#if CONFIG_MTD_WRITE_ALIGN_SIZE <= 4
+  /* stay compatible with situation which align byte be 1 */
+
+  uint8_t  expired[NVS_ALIGN_SIZE];
+  uint8_t  reserved[4 - NVS_ALIGN_SIZE];
+#else
+  uint8_t  padding[NVS_ALIGN_UP(12) - 12];
+  uint8_t  expired[NVS_ALIGN_SIZE];
 #endif
-  uint8_t  expired;      /* 0xFF-newest entry, others-old entry */
-  uint8_t  reserved[NVS_ALIGN_SIZE - 1];
 } end_packed_struct;
 
 /****************************************************************************
@@ -163,19 +164,6 @@ static const struct file_operations g_mtdnvs_fops =
  * Private Functions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: nvs_al_size
- ****************************************************************************/
-
-static inline size_t nvs_al_size(size_t len)
-{
-#ifdef CONFIG_MTD_WRITE_ALIGN_SIZE
-  return (len + (NVS_ALIGN_SIZE - 1U)) & ~(NVS_ALIGN_SIZE - 1U);
-#else
-  return len;
-#endif
-}
-
 /****************************************************************************
  * Name: nvs_fnv_hash
  ****************************************************************************/
@@ -599,6 +587,40 @@ static int nvs_close_ate_valid(FAR struct nvs_fs *fs,
   return 1;
 }
 
+/****************************************************************************
+ * Name: nvs_flash_write_multi_blk
+ *
+ * Description:
+ *   Store multi align block in flash
+ *
+ * Returned Value:
+ *   number of bytes at the end of addr which is left to write next time.
+ *   zero indicates all bytes were written . On error returns -ERRNO code.
+ ****************************************************************************/
+
+int nvs_flash_write_multi_blk(FAR struct nvs_fs *fs, const uint8_t *addr,
+                              size_t size)
+{
+  size_t blk_cnt;
+  int left;
+  int rc;
+
+  blk_cnt = size / NVS_ALIGN_SIZE;
+  left    = size % NVS_ALIGN_SIZE;
+
+  if (blk_cnt)
+    {
+      rc = nvs_flash_data_wrt(fs, addr, size - left);
+      if (rc)
+        {
+          ferr("Write multi data value failed, rc=%d\n", rc);
+          return rc;
+        }
+    }
+
+  return left;
+}
+
 /****************************************************************************
  * Name: nvs_flash_wrt_entry
  *
@@ -613,8 +635,9 @@ static int nvs_flash_wrt_entry(FAR struct nvs_fs *fs, uint32_t id,
 {
   int rc;
   struct nvs_ate entry;
-  uint16_t total;
-  uint8_t *tmp;
+  uint16_t left;
+  uint16_t copy_len = 0;
+  uint8_t buf[NVS_ALIGN_SIZE];
 
   memset(&entry, fs->erasestate, sizeof(entry));
   entry.id = id;
@@ -624,37 +647,65 @@ static int nvs_flash_wrt_entry(FAR struct nvs_fs *fs, uint32_t id,
 
   nvs_ate_crc8_update(&entry);
 
-  /* Let's sew key and data into one, key comes first, then data */
+  /* Let's save key and data into one, key comes first, then data */
 
-  total = nvs_al_size(key_size + len);
-  tmp = kmm_malloc(total);
-  if (tmp == NULL)
+  rc = nvs_flash_write_multi_blk(fs, key, key_size);
+  if (rc < 0)
     {
-      ferr("malloc size %u failed\n", total);
-      return -ENOMEM;
+      return rc;
     }
 
-  memcpy(tmp, key, key_size);
-  memcpy(tmp + key_size, data, len);
-  memset(tmp + key_size + len, fs->erasestate, total - key_size - len);
-
-  rc = nvs_flash_data_wrt(fs, tmp, total);
   if (rc)
     {
-      ferr("Write value failed, rc=%d\n", rc);
-      kmm_free(tmp);
+      /* Write align block which inlcude part key + part data */
+
+      left = rc;
+      memset(buf, fs->erasestate, NVS_ALIGN_SIZE);
+
+      copy_len = (left + len) <= NVS_ALIGN_SIZE ?
+                  len : (NVS_ALIGN_SIZE - left);
+
+      memcpy(buf, key + key_size - left, left);
+      memcpy(buf + left, data, copy_len);
+      rc = nvs_flash_data_wrt(fs, buf, NVS_ALIGN_SIZE);
+      if (rc)
+        {
+          ferr("Write value failed, rc=%d\n", rc);
+          return rc;
+        }
+    }
+
+  rc = nvs_flash_write_multi_blk(fs, data + copy_len,  len - copy_len);
+  if (rc < 0)
+    {
       return rc;
     }
 
+  if (rc)
+    {
+      /* Add padding at the end of data */
+
+      left = rc;
+      memset(buf, fs->erasestate, NVS_ALIGN_SIZE);
+      memcpy(buf, data + len - left, left);
+
+      rc = nvs_flash_data_wrt(fs, buf, NVS_ALIGN_SIZE);
+      if (rc)
+        {
+          ferr("Write value failed, rc=%d\n", rc);
+          return rc;
+        }
+    }
+
+  /* Last, let's save entry to flash */
+
   rc = nvs_flash_ate_wrt(fs, &entry);
   if (rc)
     {
       ferr("Write ate failed, rc=%d\n", rc);
-      kmm_free(tmp);
       return rc;
     }
 
-  kmm_free(tmp);
   return 0;
 }
 
@@ -699,7 +750,7 @@ static int nvs_recover_last_ate(FAR struct nvs_fs *fs,
 
           data_end_addr &= ADDR_BLOCK_MASK;
           data_end_addr += end_ate.offset +
-                           nvs_al_size(end_ate.key_len + end_ate.len);
+                           NVS_ALIGN_UP(end_ate.key_len + end_ate.len);
           *addr = ate_end_addr;
         }
 
@@ -945,7 +996,7 @@ static int nvs_gc(FAR struct nvs_fs *fs)
           return rc;
         }
 
-      if (gc_ate.expired != fs->erasestate)
+      if (gc_ate.expired[0] != fs->erasestate)
         {
           /* Deleted or old ate, ignore it */
 
@@ -971,7 +1022,7 @@ static int nvs_gc(FAR struct nvs_fs *fs)
           nvs_ate_crc8_update(&gc_ate);
 
           rc = nvs_flash_block_move(fs, data_addr,
-                                   nvs_al_size(gc_ate.key_len + gc_ate.len));
+                            NVS_ALIGN_UP(gc_ate.key_len + gc_ate.len));
           if (rc)
             {
               return rc;
@@ -1156,8 +1207,8 @@ static int nvs_startup(FAR struct nvs_fs *fs)
           /* Complete write of ate was performed */
 
           fs->data_wra = addr & ADDR_BLOCK_MASK;
-          fs->data_wra += last_ate.offset + nvs_al_size(last_ate.key_len +
-            last_ate.len);
+          fs->data_wra += last_ate.offset +
+                          NVS_ALIGN_UP(last_ate.key_len + last_ate.len);
           finfo("recovered data_wra=0x%" PRIx32 "\n", fs->data_wra);
         }
 
@@ -1316,7 +1367,7 @@ static int nvs_startup(FAR struct nvs_fs *fs)
 
               if (nvs_ate_valid(fs, &second_ate)
                   && second_ate.id == last_ate.id
-                  && second_ate.expired == fs->erasestate)
+                  && second_ate.expired[0] == fs->erasestate)
                 {
                   finfo("same id at 0x%" PRIx32 ", key_len %" PRIu16 ", "
                         "offset %" PRIu16 "\n",
@@ -1432,7 +1483,7 @@ static ssize_t nvs_read_entry(FAR struct nvs_fs *fs, FAR const uint8_t *key,
             {
               /* It is old or deleted, return -ENOENT */
 
-              if (wlk_ate.expired != fs->erasestate)
+              if (wlk_ate.expired[0] != fs->erasestate)
                 {
                   return -ENOENT;
                 }
@@ -1521,13 +1572,14 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
 
   /* Data now contains input data and input key, input key first. */
 
-  data_size = nvs_al_size(key_size + pdata->len);
+  data_size = NVS_ALIGN_UP(key_size + pdata->len);
 
   /* The maximum data size is block size - 3 ate
    * where: 1 ate for data, 1 ate for block close, 1 ate for gc done.
    */
 
-  finfo("key_size=%zu, len=%zu\n", key_size, pdata->len);
+  finfo("key_size=%zu, len=%zu, data_size = %zu\n", key_size,
+                                                    pdata->len, data_size);
 
   if ((data_size > (fs->geo.erasesize - 3 * sizeof(struct nvs_ate))) ||
       ((pdata->len > 0) && (pdata->configdata == NULL)))
@@ -1587,7 +1639,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
         {
           /* If prev ate is expired, it is deleted. */
 
-          if (wlk_ate.expired != fs->erasestate)
+          if (wlk_ate.expired[0] != fs->erasestate)
             {
               /* Skip delete entry as it is already the
                * last one.
@@ -1611,7 +1663,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
             }
         }
       else if (pdata->len == wlk_ate.len &&
-               wlk_ate.expired == fs->erasestate)
+               wlk_ate.expired[0] == fs->erasestate)
         {
           /* Do not try to compare if lengths are not equal
            * or prev one is deleted.
@@ -1658,7 +1710,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
           /* Nvs is changed after gc, we will look for the old ate.
            */
 
-          if (prev_found && wlk_ate.expired == fs->erasestate)
+          if (prev_found && wlk_ate.expired[0] == fs->erasestate)
             {
               finfo("prev entry exists, search for it\n");
 
@@ -1701,7 +1753,7 @@ static ssize_t nvs_write(FAR struct nvs_fs *fs,
            * already expired)
            */
 
-          if (prev_found && wlk_ate.expired == fs->erasestate)
+          if (prev_found && wlk_ate.expired[0] == fs->erasestate)
             {
               rc = nvs_expire_ate(fs, hist_addr);
               finfo("expir prev entry, %" PRIx32 ", rc %d\n",
@@ -1871,7 +1923,7 @@ static int nvs_next(FAR struct nvs_fs *fs,
 
       if (nvs_ate_valid(fs, &step_ate)
           && step_ate.id != NVS_SPECIAL_ATE_ID
-          && step_ate.expired == fs->erasestate)
+          && step_ate.expired[0] == fs->erasestate)
         {
           break;
         }