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/11/07 06:59:28 UTC

(nuttx) branch master updated: fs: add merge partitions support

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


The following commit(s) were added to refs/heads/master by this push:
     new 929bbf0be8 fs: add merge partitions support
929bbf0be8 is described below

commit 929bbf0be8fe9c20cb586272857dbd0c843f128b
Author: wanggang26 <wa...@xiaomi.com>
AuthorDate: Fri Oct 25 10:09:15 2024 +0800

    fs: add merge partitions support
    
    Usage example for merging the factory partition and reserve
    partition into the merge partition:
    register_merge_blockdriver("/dev/merge", "/dev/factory", "/dev/reserve",
    NULL)
    
    Signed-off-by: wanggang26 <wa...@xiaomi.com>
---
 fs/driver/CMakeLists.txt  |   1 +
 fs/driver/Make.defs       |   2 +
 fs/driver/fs_blockmerge.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++
 include/nuttx/fs/fs.h     |  28 ++++
 4 files changed, 362 insertions(+)

diff --git a/fs/driver/CMakeLists.txt b/fs/driver/CMakeLists.txt
index 74d4381b5e..d54c2ae03b 100644
--- a/fs/driver/CMakeLists.txt
+++ b/fs/driver/CMakeLists.txt
@@ -36,6 +36,7 @@ if(NOT CONFIG_DISABLE_MOUNTPOINT)
     fs_closeblockdriver.c
     fs_blockpartition.c
     fs_findmtddriver.c
+    fs_blockmerge.c
     fs_closemtddriver.c)
 
   if(CONFIG_MTD)
diff --git a/fs/driver/Make.defs b/fs/driver/Make.defs
index 452b933930..626d5e22cc 100644
--- a/fs/driver/Make.defs
+++ b/fs/driver/Make.defs
@@ -29,6 +29,8 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
 CSRCS += fs_registerblockdriver.c fs_unregisterblockdriver.c
 CSRCS += fs_findblockdriver.c fs_openblockdriver.c fs_closeblockdriver.c
 CSRCS += fs_blockpartition.c fs_findmtddriver.c fs_closemtddriver.c
+CSRCS += fs_blockmerge.c
+
 
 ifeq ($(CONFIG_MTD),y)
 CSRCS += fs_registermtddriver.c fs_unregistermtddriver.c
diff --git a/fs/driver/fs_blockmerge.c b/fs/driver/fs_blockmerge.c
new file mode 100644
index 0000000000..5618b239f4
--- /dev/null
+++ b/fs/driver/fs_blockmerge.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * fs/driver/fs_blockmerge.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <debug.h>
+#include <nuttx/kmalloc.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/fs/partition.h>
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct merge_part_s
+{
+  FAR struct inode *inode;
+  struct geometry geo;
+  char path[PATH_MAX];
+};
+
+struct merge_priv_s
+{
+  size_t npart;
+  struct merge_part_s part[0];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int     merge_open(FAR struct inode *inode);
+static int     merge_close(FAR struct inode *inode);
+static ssize_t merge_read(FAR struct inode *inode, FAR unsigned char *buffer,
+                          blkcnt_t startsector, unsigned int nsectors);
+static ssize_t merge_write(FAR struct inode *inode,
+                           FAR const unsigned char *buffer,
+                           blkcnt_t startsector, unsigned int nsectors);
+static int     merge_geometry(FAR struct inode *inode,
+                              FAR struct geometry *geometry);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct block_operations g_merge_bops =
+{
+  merge_open,     /* open     */
+  merge_close,    /* close    */
+  merge_read,     /* read     */
+  merge_write,    /* write    */
+  merge_geometry, /* geometry */
+  NULL            /* ioctl    */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int merge_open(FAR struct inode *inode)
+{
+  FAR struct merge_priv_s *priv;
+  int ret = 0;
+  size_t i;
+
+  DEBUGASSERT(inode && inode->i_private);
+  priv = inode->i_private;
+
+  for (i = 0; i < priv->npart; i++)
+    {
+      ret = open_blockdriver(priv->part[i].path, 0, &inode);
+      if (ret < 0)
+        {
+          ferr("ERROR: Failed to open block driver for %s\n",
+               priv->part[i].path);
+          goto err_with_open;
+        }
+
+      priv->part[i].inode = inode;
+
+      if (inode->u.i_bops->geometry == NULL ||
+          inode->u.i_bops->geometry(inode, &priv->part[i].geo) < 0 ||
+          priv->part[i].geo.geo_sectorsize <= 0 ||
+          priv->part[i].geo.geo_nsectors <= 0)
+        {
+          ferr("ERROR: Failed to get geometry for %s\n", priv->part[i].path);
+          ret = -EINVAL;
+          goto err_with_inode;
+        }
+
+      if (priv->part[0].geo.geo_sectorsize !=
+          priv->part[i].geo.geo_sectorsize)
+        {
+          ferr("ERROR: Inconsistent sectorsize!\n");
+          ret = -EINVAL;
+          goto err_with_inode;
+        }
+
+      finfo("[%s] nsectors: %" PRIuOFF " sectorsize:%u\n",
+            priv->part[i].path, priv->part[i].geo.geo_nsectors,
+            priv->part[i].geo.geo_sectorsize);
+    }
+
+  return ret;
+
+err_with_inode:
+  close_blockdriver(priv->part[i].inode);
+err_with_open:
+  while (i--)
+    {
+      close_blockdriver(priv->part[i].inode);
+    }
+
+  return ret;
+}
+
+static int merge_close(FAR struct inode *inode)
+{
+  FAR struct merge_priv_s *priv;
+  size_t i;
+
+  DEBUGASSERT(inode && inode->i_private);
+  priv = inode->i_private;
+
+  for (i = 0; i < priv->npart; i++)
+    {
+      int ret = close_blockdriver(priv->part[i].inode);
+      if (ret < 0)
+        {
+          ferr("ERROR: Failed to close block driver for %s\n",
+               priv->part[i].path);
+          return ret;
+        }
+    }
+
+  return OK;
+}
+
+static ssize_t merge_read(FAR struct inode *inode, FAR unsigned char *buffer,
+                          blkcnt_t startsector, unsigned int nsectors)
+{
+  FAR struct merge_priv_s *priv;
+  ssize_t nread = 0;
+  size_t ntotal = 0;
+  size_t i;
+
+  DEBUGASSERT(inode && inode->i_private);
+  priv = inode->i_private;
+
+  for (i = 0; nsectors > 0 && i < priv->npart; i++)
+    {
+      if ((startsector >= priv->part[i].geo.geo_nsectors))
+        {
+          startsector -= priv->part[i].geo.geo_nsectors;
+          continue;
+        }
+
+      inode = priv->part[i].inode;
+      nread = MIN(priv->part[i].geo.geo_nsectors - startsector, nsectors);
+      nread = inode->u.i_bops->read(inode, buffer, startsector, nread);
+      if (nread < 0)
+        {
+          break;
+        }
+
+      buffer += nread * priv->part[i].geo.geo_sectorsize;
+      nsectors -= nread;
+      ntotal += nread;
+      startsector = 0;
+    }
+
+  /* On success, return the number of blocks read */
+
+  return ntotal ? ntotal : nread;
+}
+
+static ssize_t merge_write(FAR struct inode *inode,
+                           FAR const unsigned char *buffer,
+                           blkcnt_t startsector, unsigned int nsectors)
+{
+  FAR struct merge_priv_s *priv;
+  ssize_t nwritten = 0;
+  size_t ntotal = 0;
+  size_t i;
+
+  DEBUGASSERT(inode && inode->i_private);
+  priv = inode->i_private;
+
+  for (i = 0; nsectors > 0 && i < priv->npart; i++)
+    {
+      if (startsector >= priv->part[i].geo.geo_nsectors)
+        {
+          startsector -= priv->part[i].geo.geo_nsectors;
+          continue;
+        }
+
+      inode = priv->part[i].inode;
+      nwritten = MIN(priv->part[i].geo.geo_nsectors - startsector, nsectors);
+      nwritten = inode->u.i_bops->write(inode, buffer, startsector,
+                                        nwritten);
+      if (nwritten < 0)
+        {
+          break;
+        }
+
+      buffer += nwritten * priv->part[i].geo.geo_sectorsize;
+      nsectors -= nwritten;
+      ntotal += nwritten;
+      startsector = 0;
+    }
+
+  /* On success, return the number of blocks written */
+
+  return ntotal ? ntotal : nwritten;
+}
+
+static int merge_geometry(FAR struct inode *inode,
+                          FAR struct geometry *geometry)
+{
+  DEBUGASSERT(inode && inode->i_private);
+
+  if (geometry)
+    {
+      FAR struct merge_priv_s *priv = inode->i_private;
+      size_t i;
+
+      memcpy(geometry, &priv->part[0].geo, sizeof(*geometry));
+      for (i = 1; i < priv->npart; i++)
+        {
+          geometry->geo_nsectors += priv->part[i].geo.geo_nsectors;
+        }
+
+      finfo("nsectors: %" PRIuOFF " sectorsize:%u\n",
+            geometry->geo_nsectors, geometry->geo_sectorsize);
+      return OK;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int register_merge_blockdriver(FAR const char *merge, ...)
+{
+  FAR struct merge_priv_s *priv;
+  FAR const char *name;
+  va_list args;
+  size_t i;
+  int ret;
+
+  va_start(args, merge);
+  for (i = 0; ; i++)
+    {
+      name = va_arg(args, FAR const char *);
+      if (name == NULL)
+        {
+          break;
+        }
+    }
+
+  va_end(args);
+
+  if (i < 2)
+    {
+      ferr("ERROR: invalid number of partitions\n");
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct merge_priv_s) + i *
+                    sizeof(struct merge_part_s));
+  if (priv == NULL)
+    {
+      ferr("ERROR: out of memory\n");
+      return -ENOMEM;
+    }
+
+  priv->npart = i;
+
+  va_start(args, merge);
+  for (i = 0; i < priv->npart; i++)
+    {
+      name = va_arg(args, FAR const char *);
+      strlcpy(priv->part[i].path, name, PATH_MAX);
+    }
+
+  ret = register_blockdriver(merge, &g_merge_bops, 0, priv);
+  if (ret < 0)
+    {
+      ferr("ERROR: register blockdriver failed: %d\n", ret);
+      goto err;
+    }
+
+  va_end(args);
+  return ret;
+
+err:
+  va_end(args);
+  kmm_free(priv);
+  return ret;
+}
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index 1ef0704af5..d9aa023b83 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -653,6 +653,34 @@ int register_blockdriver(FAR const char *path,
                          mode_t mode, FAR void *priv);
 #endif
 
+/****************************************************************************
+ * Name: register_merge_blockdriver
+ *
+ * Description:
+ *   This function registers a block driver that presents a contiguous block
+ * device composed of multiple, non-contiguous partitions.  The partitions
+ * are specified by the variable argument list which has 'nparts' elements.
+ *
+ * Input Parameters:
+ *   merge - The partition name to be merged.
+ *   ...   - The variable argument list for partition names.
+ *
+ *  Usage example for merging the factory partition and reserve partition
+ *  into the merge partition:
+ *
+ * register_merge_blockdriver("/dev/merge", "/dev/factory",
+ *                            "/dev/reserve", NULL);
+ *
+ * Returned Value:
+ *   Zero on success;
+ *   Negated errno value is returned on a failure
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+int register_merge_blockdriver(FAR const char *merge, ...);
+#endif
+
 /****************************************************************************
  * Name: register_blockpartition
  *