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 c3e87dd3d1709025a079103a0ddd6d7014128d6a
Author: jingfei <[email protected]>
AuthorDate: Fri Jul 4 22:54:43 2025 +0800

    drivers/fs: Control the behavior of FTL by passing oflags during the open 
process.
    
    To save more space (equivalent to the size of one erase sector of
    MTD device) and to achieve faster read and write speeds, a method
    for direct writing was introduced at the FTL layer.
    This can be accomplished simply by using the following oflags during
    the open operation:
    
    1. O_DIRECT. when this flag is passed in, ftl internally uses
       the direct write strategy and no read cache is used in ftl;
       otherwise, each write will be executed with the minimum
       granularity of flash erase sector size which means a
       "sector read back - erase sector - write sector" operation
       is performed by using a read cache buffer in heap.
    
    2. O_SYNC. When this flag is passed in, we assume that the
       flash has been erased in advance and no erasure operation
       will be performed internally within ftl. O_SYNC will take
       effect only when both O_DIRECT and O_SYNC are passed in
       simultaneously.
    
    3. For uniformity, we remapped the mount flag in mount.h and
       unified it with the open flag in fcntl.h. The repetitive
       parts of their definitions were reused, and the remaining
       part of the mount flag redefine to the unused bit of open
       flags.
    
    Signed-off-by: jingfei <[email protected]>
---
 drivers/bch/bchdev_register.c   |  8 ++--
 drivers/bch/bchlib_setup.c      |  5 ++-
 drivers/mtd/ftl.c               | 86 ++++++++++++++++++++++++++++++++++++++++-
 fs/driver/fs_blockproxy.c       |  7 +---
 fs/driver/fs_mtdproxy.c         |  2 +-
 fs/vfs/fs_open.c                |  7 ++--
 include/fcntl.h                 | 46 ++++++++++++----------
 include/nuttx/drivers/drivers.h |  4 +-
 include/nuttx/mtd/mtd.h         | 18 ++++++++-
 include/sys/mount.h             | 21 +++++-----
 10 files changed, 152 insertions(+), 52 deletions(-)

diff --git a/drivers/bch/bchdev_register.c b/drivers/bch/bchdev_register.c
index 849f0e47577..5e9390273bb 100644
--- a/drivers/bch/bchdev_register.c
+++ b/drivers/bch/bchdev_register.c
@@ -50,17 +50,17 @@
  ****************************************************************************/
 
 int bchdev_register(FAR const char *blkdev, FAR const char *chardev,
-                    bool readonly)
+                    int oflags)
 {
   FAR void *handle;
   int ret;
 
-  finfo("blkdev=\"%s\" chardev=\"%s\" readonly=%c\n",
-        blkdev, chardev, readonly ? 'T' : 'F');
+  finfo("blkdev=\"%s\" chardev=\"%s\" oflags=0x%x\n",
+        blkdev, chardev, oflags);
 
   /* Setup the BCH lib functions */
 
-  ret = bchlib_setup(blkdev, readonly, &handle);
+  ret = bchlib_setup(blkdev, oflags, &handle);
   if (ret < 0)
     {
       ferr("ERROR: bchlib_setup failed: %d\n", -ret);
diff --git a/drivers/bch/bchlib_setup.c b/drivers/bch/bchlib_setup.c
index a78f2329ec5..7030699db24 100644
--- a/drivers/bch/bchlib_setup.c
+++ b/drivers/bch/bchlib_setup.c
@@ -55,10 +55,11 @@
  *
  ****************************************************************************/
 
-int bchlib_setup(FAR const char *blkdev, bool readonly, FAR void **handle)
+int bchlib_setup(FAR const char *blkdev, int oflags, FAR void **handle)
 {
   FAR struct bchlib_s *bch;
   struct geometry geo;
+  bool readonly = (oflags & O_WROK) == 0;
   int ret;
 
   DEBUGASSERT(blkdev);
@@ -74,7 +75,7 @@ int bchlib_setup(FAR const char *blkdev, bool readonly, FAR 
void **handle)
 
   /* Open the block driver */
 
-  ret = open_blockdriver(blkdev, readonly ? MS_RDONLY : 0, &bch->inode);
+  ret = open_blockdriver(blkdev, oflags, &bch->inode);
   if (ret < 0)
     {
       ferr("ERROR: Failed to open driver %s: %d\n", blkdev, -ret);
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 51c0f63736c..ace0eeb2c53 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -39,6 +39,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/fs/fs.h>
@@ -77,6 +78,7 @@ struct ftl_struct_s
   uint16_t              refs;     /* Number of references */
   bool                  unlinked; /* The driver has been unlinked */
   FAR uint8_t          *eblock;   /* One, in-memory erase block */
+  int                   oflags;
 
   /* The nand block map between logic block and physical block */
 
@@ -96,6 +98,9 @@ static ssize_t ftl_read(FAR struct inode *inode, FAR unsigned 
char *buffer,
                  blkcnt_t start_sector, unsigned int nsectors);
 static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer,
                  off_t startblock, size_t nblocks);
+static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev,
+                                FAR const uint8_t *buffer,
+                                off_t startblock, size_t nblocks);
 static ssize_t ftl_write(FAR struct inode *inode,
                  FAR const unsigned char *buffer, blkcnt_t start_sector,
                  unsigned int nsectors);
@@ -474,6 +479,74 @@ static int ftl_alloc_eblock(FAR struct ftl_struct_s *dev)
   return dev->eblock != NULL ? OK : -ENOMEM;
 }
 
+/****************************************************************************
+ * Name: ftl_flush_direct
+ *
+ * Description: Write the specified number of sectors without cache
+ *
+ ****************************************************************************/
+
+static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev,
+                                FAR const uint8_t *buffer,
+                                off_t startblock, size_t nblocks)
+{
+  size_t blocksize = dev->geo.blocksize;
+  off_t starteraseblock;
+  off_t offset;
+  ssize_t ret;
+  size_t count;
+
+  while (nblocks)
+    {
+      starteraseblock = startblock / dev->blkper;
+      offset = startblock & (dev->blkper - 1);
+      count = MIN(dev->blkper - offset, nblocks);
+
+      if (offset == 0 && dev->mtd->erase != NULL && !(dev->oflags & O_SYNC))
+        {
+          ret = ftl_mtd_erase(dev, starteraseblock);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      if (dev->lptable == NULL)
+        {
+          ret = MTD_BWRITE(dev->mtd, startblock, count, buffer);
+          if (ret != count)
+            {
+              ferr("ERROR: Write block %"PRIdOFF" failed: %zd\n",
+                   startblock, ret);
+              return ret;
+            }
+        }
+      else
+        {
+          if (starteraseblock >= dev->lpcount)
+            {
+              return -ENOSPC;
+            }
+
+          ret = MTD_BWRITE(dev->mtd,
+                           dev->lptable[starteraseblock] * dev->blkper
+                           + offset, count, buffer);
+          if (ret != count)
+            {
+              MTD_MARKBAD(dev->mtd, dev->lptable[starteraseblock]);
+              ftl_update_map(dev, starteraseblock);
+              continue;
+            }
+        }
+
+      nblocks -= count;
+      startblock += count;
+      buffer += count * blocksize;
+    }
+
+  return nblocks;
+}
+
 static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer,
                          off_t startblock, size_t nblocks)
 {
@@ -488,6 +561,13 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t 
*buffer,
   int    nbytes;
   int    ret;
 
+  if (dev->oflags & O_DIRECT)
+    {
+      /* Direct write mode */
+
+      return ftl_flush_direct(dev, buffer, startblock, nblocks);
+    }
+
   /* Get the aligned block.  Here is is assumed: (1) The number of R/W blocks
    * per erase block is a power of 2, and (2) the erase begins with that same
    * alignment.
@@ -803,7 +883,8 @@ static int ftl_unlink(FAR struct inode *inode)
  *
  ****************************************************************************/
 
-int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd)
+int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd,
+                           int oflags)
 {
   struct ftl_struct_s *dev;
   int ret = -ENOMEM;
@@ -825,6 +906,7 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct 
mtd_dev_s *mtd)
       /* Initialize the FTL device structure */
 
       dev->mtd = mtd;
+      dev->oflags = oflags;
 
       /* Get the device geometry. (casting to uintptr_t first eliminates
        * complaints on some architectures where the sizeof long is different
@@ -928,5 +1010,5 @@ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd)
   /* Do the real work by ftl_initialize_by_path */
 
   snprintf(path, DEV_NAME_MAX, "/dev/mtdblock%d", minor);
-  return ftl_initialize_by_path(path, mtd);
+  return ftl_initialize_by_path(path, mtd, O_RDWR);
 }
diff --git a/fs/driver/fs_blockproxy.c b/fs/driver/fs_blockproxy.c
index 77eae6476a3..5e2858a1155 100644
--- a/fs/driver/fs_blockproxy.c
+++ b/fs/driver/fs_blockproxy.c
@@ -149,7 +149,6 @@ int block_proxy(FAR struct file *filep, FAR const char 
*blkdev, int oflags)
 {
   struct file temp;
   FAR char *chardev;
-  bool readonly;
   int ret;
 
   DEBUGASSERT(blkdev);
@@ -163,13 +162,9 @@ int block_proxy(FAR struct file *filep, FAR const char 
*blkdev, int oflags)
       return -ENOMEM;
     }
 
-  /* Should this character driver be read-only? */
-
-  readonly = ((oflags & O_WROK) == 0);
-
   /* Wrap the block driver with an instance of the BCH driver */
 
-  ret = bchdev_register(blkdev, chardev, readonly);
+  ret = bchdev_register(blkdev, chardev, oflags);
   if (ret < 0)
     {
       ferr("ERROR: bchdev_register(%s, %s) failed: %d\n",
diff --git a/fs/driver/fs_mtdproxy.c b/fs/driver/fs_mtdproxy.c
index 659cbb6c403..44f9bc84e51 100644
--- a/fs/driver/fs_mtdproxy.c
+++ b/fs/driver/fs_mtdproxy.c
@@ -165,7 +165,7 @@ int mtd_proxy(FAR const char *mtddev, int mountflags,
       goto out_with_blkdev;
     }
 
-  ret = ftl_initialize_by_path(blkdev, mtd->u.i_mtd);
+  ret = ftl_initialize_by_path(blkdev, mtd->u.i_mtd, mountflags);
   inode_release(mtd);
   if (ret < 0)
     {
diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c
index 8cf86b964d6..84fd3f251bc 100644
--- a/fs/vfs/fs_open.c
+++ b/fs/vfs/fs_open.c
@@ -202,10 +202,11 @@ static int file_vopen(FAR struct file *filep, FAR const 
char *path,
       /* Get the file structure of the opened character driver proxy */
 
 #ifdef CONFIG_BCH_DEVICE_READONLY
-      ret = block_proxy(filep, path, O_RDOK);
-#else
-      ret = block_proxy(filep, path, oflags);
+      oflags &= ~O_RDWR;
+      oflags |= O_RDOK;
 #endif
+
+      ret = block_proxy(filep, path, oflags);
 #ifdef CONFIG_FS_NOTIFY
       if (ret >= 0)
         {
diff --git a/include/fcntl.h b/include/fcntl.h
index 4acbb64efba..5be8390ecec 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -38,26 +38,32 @@
 
 /* open flag settings for open() (and related APIs) */
 
-#define O_RDONLY    (1 << 0)        /* Open for read access (only) */
-#define O_RDOK      O_RDONLY        /* Read access is permitted (non-standard) 
*/
-#define O_WRONLY    (1 << 1)        /* Open for write access (only) */
-#define O_WROK      O_WRONLY        /* Write access is permitted 
(non-standard) */
-#define O_RDWR      (O_RDOK|O_WROK) /* Open for both read & write access */
-#define O_CREAT     (1 << 2)        /* Create file/sem/mq object */
-#define O_EXCL      (1 << 3)        /* Name must not exist when opened  */
-#define O_APPEND    (1 << 4)        /* Keep contents, append to end */
-#define O_TRUNC     (1 << 5)        /* Delete contents */
-#define O_NONBLOCK  (1 << 6)        /* Don't wait for data */
-#define O_NDELAY    O_NONBLOCK      /* Synonym for O_NONBLOCK */
-#define O_SYNC      (1 << 7)        /* Synchronize output on write */
-#define O_DSYNC     O_SYNC          /* Equivalent to OSYNC in NuttX */
-#define O_TEXT      (1 << 8)        /* Open the file in text (translated) 
mode. */
-#define O_DIRECT    (1 << 9)        /* Avoid caching, write directly to 
hardware */
-#define O_CLOEXEC   (1 << 10)       /* Close on execute */
-#define O_DIRECTORY (1 << 11)       /* Must be a directory */
-#define O_NOFOLLOW  (1 << 12)       /* Don't follow links */
-#define O_LARGEFILE (1 << 13)       /* Large File */
-#define O_NOATIME   (1 << 18)       /* Don't update the file last access time 
*/
+#define O_RDONLY     (1 << 0)        /* Open for read access (only) */
+#define O_RDOK       O_RDONLY        /* Read access is permitted 
(non-standard) */
+#define O_WRONLY     (1 << 1)        /* Open for write access (only) */
+#define O_WROK       O_WRONLY        /* Write access is permitted 
(non-standard) */
+#define O_RDWR       (O_RDOK|O_WROK) /* Open for both read & write access */
+#define O_CREAT      (1 << 2)        /* Create file/sem/mq object */
+#define O_EXCL       (1 << 3)        /* Name must not exist when opened  */
+#define O_APPEND     (1 << 4)        /* Keep contents, append to end */
+#define O_TRUNC      (1 << 5)        /* Delete contents */
+#define O_NONBLOCK   (1 << 6)        /* Don't wait for data */
+#define O_NDELAY     O_NONBLOCK      /* Synonym for O_NONBLOCK */
+#define O_SYNC       (1 << 7)        /* Synchronize output on write */
+#define O_DSYNC      O_SYNC          /* Equivalent to OSYNC in NuttX */
+#define O_TEXT       (1 << 8)        /* Open the file in text (translated) 
mode. */
+#define O_DIRECT     (1 << 9)        /* Avoid caching, write directly to 
hardware */
+#define O_CLOEXEC    (1 << 10)       /* Close on execute */
+#define O_DIRECTORY  (1 << 11)       /* Must be a directory */
+#define O_NOFOLLOW   (1 << 12)       /* Don't follow links */
+#define O_LARGEFILE  (1 << 13)       /* Large File */
+#define O_RESERVE14  (1 << 14)       /* reserved and used by mount flag : 
MS_NOSUID in mount.h */
+#define O_RESERVE15  (1 << 15)       /* reserved and used by mount flag : 
MS_NODEV in mount.h */
+#define O_RESERVE16  (1 << 16)       /* reserved and used by mount flag : 
MS_DIRSYNC in mount.h */
+#define O_RESERVE17  (1 << 17)       /* reserved and used by mount flag : 
MS_REMOUNT in mount.h */
+#define O_NOATIME    (1 << 18)       /* Don't update the file last access time 
*/
+#define O_RESERVE19  (1 << 19)       /* reserved and used by mount flag : 
MS_MANDLOCK in mount.h */
+#define O_RESERVE20  (1 << 20)       /* reserved and used by mount flag : 
MS_NOEXEC in mount.h */
 
 /* Unsupported, but required open flags */
 
diff --git a/include/nuttx/drivers/drivers.h b/include/nuttx/drivers/drivers.h
index 672242691bd..07c9b005030 100644
--- a/include/nuttx/drivers/drivers.h
+++ b/include/nuttx/drivers/drivers.h
@@ -184,7 +184,7 @@ void devzero_register(void);
  ****************************************************************************/
 
 int bchdev_register(FAR const char *blkdev, FAR const char *chardev,
-                    bool readonly);
+                    int oflags);
 
 /****************************************************************************
  * Name: bchdev_unregister
@@ -211,7 +211,7 @@ int bchdev_unregister(FAR const char *chardev);
  *
  ****************************************************************************/
 
-int bchlib_setup(FAR const char *blkdev, bool readonly, FAR void **handle);
+int bchlib_setup(FAR const char *blkdev, int oflags, FAR void **handle);
 
 /****************************************************************************
  * Name: bchlib_teardown
diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h
index 171f2e583bf..a1c791dbf50 100644
--- a/include/nuttx/mtd/mtd.h
+++ b/include/nuttx/mtd/mtd.h
@@ -298,10 +298,25 @@ FAR struct mtd_dev_s *mtd_rwb_initialize(FAR struct 
mtd_dev_s *mtd);
  * Input Parameters:
  *   path - The block device path.
  *   mtd  - The MTD device that supports the FLASH interface.
+ *   oflags - oflags passed to the ftl layer. Currently, the ftl is affected
+ *            by two oflags:
+ *           1. O_DIRECT when this flag is passed in, ftl internally uses
+ *              the direct write strategy and no read cache is used in ftl;
+ *              otherwise, each write will be executed with the minimum
+ *              granularity of flash erase sector size which means a
+ *              "sector read back - erase sector - write sector" operation
+ *              is performed by using a read cache buffer in heap.
+ *
+ *           2. O_SYNC, when this flag is passed in, we assume that the
+ *              flash has been erased in advance and no erase operation
+ *              will be performed internally within ftl. O_SYNC will take
+ *              effect only when both O_DIRECT and O_SYNC are passed in
+ *              simultaneously
  *
  ****************************************************************************/
 
-int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd);
+int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd,
+                           int oflags);
 
 /****************************************************************************
  * Name: ftl_initialize
@@ -313,7 +328,6 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct 
mtd_dev_s *mtd);
  *   minor - The minor device number.  The MTD block device will be
  *      registered as as /dev/mtdblockN where N is the minor number.
  *   mtd - The MTD device that supports the FLASH interface.
- *
  ****************************************************************************/
 
 int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd);
diff --git a/include/sys/mount.h b/include/sys/mount.h
index 9a1bb82874d..a4e6712aad5 100644
--- a/include/sys/mount.h
+++ b/include/sys/mount.h
@@ -29,6 +29,7 @@
 
 #include <nuttx/compiler.h>
 #include <nuttx/fs/ioctl.h>
+#include <fcntl.h>
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -39,16 +40,16 @@
 
 /* Mount flags */
 
-#define MS_RDONLY       1    /* Mount file system read-only */
-#define MS_NOSUID       2    /* Ignore suid and sgid bits */
-#define MS_NODEV        4    /* Disallow access to device special files */
-#define MS_NOEXEC       8    /* Disallow program execution */
-#define MS_SYNCHRONOUS  16   /* Writes are synced at once */
-#define MS_REMOUNT      32   /* Alter flags of a mounted FS */
-#define MS_MANDLOCK     64   /* Allow mandatory locks on an FS */
-#define MS_DIRSYNC      128  /* Directory modifications are synchronous */
-#define MS_NOSYMFOLLOW  256  /* Do not follow symlinks */
-#define MS_NOATIME      1024 /* Do not update access times. */
+#define MS_RDONLY       O_RDONLY    /* Mount file system read-only */
+#define MS_SYNCHRONOUS  O_SYNC      /* Writes are synced at once */
+#define MS_NOSYMFOLLOW  O_NOFOLLOW  /* Do not follow symlinks */
+#define MS_NOATIME      O_NOATIME   /* Do not update access times. */
+#define MS_NOSUID       O_RESERVE14 /* Ignore suid and sgid bits */
+#define MS_NODEV        O_RESERVE15 /* Disallow access to device special files 
*/
+#define MS_DIRSYNC      O_RESERVE16 /* Directory modifications are synchronous 
*/
+#define MS_REMOUNT      O_RESERVE17 /* Alter flags of a mounted FS */
+#define MS_MANDLOCK     O_RESERVE19 /* Allow mandatory locks on an FS */
+#define MS_NOEXEC       O_RESERVE20 /* Disallow program execution */
 
 /* Un-mount flags
  *

Reply via email to