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
*