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

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

commit 0d50f01d8a2ebbf2526efa887a7537e0a7ab35df
Author: chao an <[email protected]>
AuthorDate: Wed Oct 28 15:31:45 2026 +0800

    drivers/misc: Preserve rwbuffer data on flush errors
    
    rwb_wrflush() logged failed or short write-buffer flushes but still reset 
the
    buffer, which could drop dirty data while rwb_flush() reported success.
    Propagate flush and padding-read errors so the dirty buffer is kept for a
    later retry.
    
    Signed-off-by: chao an <[email protected]>
---
 drivers/misc/rwbuffer.c | 54 ++++++++++++++++++++++++++++++++++++++++---------
 drivers/mtd/ftl.c       |  7 ++++---
 2 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/rwbuffer.c b/drivers/misc/rwbuffer.c
index 97e24843711..7480a5996af 100644
--- a/drivers/misc/rwbuffer.c
+++ b/drivers/misc/rwbuffer.c
@@ -135,9 +135,9 @@ static inline void rwb_resetwrbuffer(FAR struct rwbuffer_s 
*rwb)
  ****************************************************************************/
 
 #ifdef CONFIG_DRVR_WRITEBUFFER
-static void rwb_wrflush(FAR struct rwbuffer_s *rwb)
+static int rwb_wrflush(FAR struct rwbuffer_s *rwb)
 {
-  int ret;
+  ssize_t ret;
 
   if (rwb->wrnblocks > 0)
     {
@@ -151,9 +151,20 @@ static void rwb_wrflush(FAR struct rwbuffer_s *rwb)
       padblocks = rwb->wrnblocks % rwb->wralignblocks;
       if (padblocks)
         {
+          ssize_t nread;
+
           padblocks = rwb->wralignblocks - padblocks;
-          rwb_read_(rwb, rwb->wrblockstart + rwb->wrnblocks, padblocks,
-                    &rwb->wrbuffer[rwb->wrnblocks * rwb->blocksize]);
+          nread = rwb_read_(rwb, rwb->wrblockstart + rwb->wrnblocks,
+                            padblocks,
+                            &rwb->wrbuffer[rwb->wrnblocks *
+                                           rwb->blocksize]);
+          if (nread < 0 || nread != padblocks)
+            {
+              ret = nread < 0 ? nread : -EIO;
+              ferr("ERROR: Error padding write buffer: %zd\n", ret);
+              return ret;
+            }
+
           rwb->wrnblocks += padblocks;
         }
 
@@ -164,13 +175,17 @@ static void rwb_wrflush(FAR struct rwbuffer_s *rwb)
 
       ret = rwb->wrflush(rwb->dev, rwb->wrbuffer, rwb->wrblockstart,
                          rwb->wrnblocks);
-      if (ret != rwb->wrnblocks)
+      if (ret < 0 || ret != rwb->wrnblocks)
         {
-          ferr("ERROR: Error flushing write buffer: %d\n", ret);
+          ret = ret < 0 ? ret : -EIO;
+          ferr("ERROR: Error flushing write buffer: %zd\n", ret);
+          return ret;
         }
 
       rwb_resetwrbuffer(rwb);
     }
+
+  return OK;
 }
 #endif
 
@@ -184,6 +199,7 @@ static void rwb_wrtimeout(FAR void *arg)
   /* The following assumes that the size of a pointer is 4-bytes or less */
 
   FAR struct rwbuffer_s *rwb = (FAR struct rwbuffer_s *)arg;
+
   DEBUGASSERT(rwb != NULL);
 
   finfo("Timeout!\n");
@@ -212,6 +228,7 @@ static void rwb_wrstarttimeout(FAR struct rwbuffer_s *rwb)
    */
 
   int ticks = MSEC2TICK(CONFIG_DRVR_WRDELAY);
+
   work_queue(LPWORK, &rwb->work, rwb_wrtimeout, rwb, ticks);
 #endif
 }
@@ -239,6 +256,7 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
                                off_t startblock, uint32_t nblocks,
                                FAR const uint8_t *wrbuffer)
 {
+  ssize_t ret;
   uint32_t nwritten = nblocks;
 
   /* Write writebuffer Logic */
@@ -331,7 +349,8 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
 
   if (nblocks > rwb->wrmaxblocks)
     {
-      ssize_t ret = rwb->wrflush(rwb->dev, wrbuffer, startblock, nblocks);
+      ret = rwb->wrflush(rwb->dev, wrbuffer, startblock, nblocks);
+
       if (ret < 0)
         {
           return ret;
@@ -347,7 +366,11 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
 
       /* Flush the write buffer */
 
-      rwb_wrflush(rwb);
+      ret = rwb_wrflush(rwb);
+      if (ret < 0)
+        {
+          return ret;
+        }
 
       /* Get the alignment padding of startblock, and read the contents
        * of the padding area, ensure that wrblockstart is aligned
@@ -357,7 +380,12 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
       padblocks = startblock % rwb->wralignblocks;
       rwb->wrblockstart = startblock - padblocks;
       rwb->wrnblocks = padblocks;
-      rwb_read_(rwb, rwb->wrblockstart, padblocks, rwb->wrbuffer);
+      ret = rwb_read_(rwb, rwb->wrblockstart, padblocks, rwb->wrbuffer);
+      if (ret < 0 || ret != padblocks)
+        {
+          rwb->wrnblocks = 0;
+          return ret < 0 ? ret : -EIO;
+        }
 
       if (remain > rwb->wrmaxblocks - padblocks)
         {
@@ -935,6 +963,7 @@ static ssize_t rwb_read_(FAR struct rwbuffer_s *rwb, off_t 
startblock,
               if (startblock >= rwb->rhblockstart && startblock < bufferend)
                 {
                   size_t rdblocks = bufferend - startblock;
+
                   if (rdblocks > remaining)
                     {
                       rdblocks = remaining;
@@ -1271,8 +1300,13 @@ int rwb_flush(FAR struct rwbuffer_s *rwb)
   int ret;
 
   ret = rwb_lock(&rwb->wrlock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
   rwb_wrcanceltimeout(rwb);
-  rwb_wrflush(rwb);
+  ret = rwb_wrflush(rwb);
   rwb_unlock(&rwb->wrlock);
 
   return ret;
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 2d50ac28f0e..24d85119020 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -240,12 +240,13 @@ static int ftl_open(FAR struct inode *inode)
 static int ftl_close(FAR struct inode *inode)
 {
   FAR struct ftl_struct_s *dev;
+  int ret = OK;
 
   DEBUGASSERT(inode->i_private);
   dev = inode->i_private;
 
 #ifdef CONFIG_FTL_WRITEBUFFER
-  rwb_flush(&dev->rwb);
+  ret = rwb_flush(&dev->rwb);
 #endif
 
   if (--dev->refs == 0 && dev->unlinked)
@@ -261,7 +262,7 @@ static int ftl_close(FAR struct inode *inode)
       kmm_free(dev);
     }
 
-  return OK;
+  return ret;
 }
 
 /****************************************************************************
@@ -869,7 +870,7 @@ static int ftl_ioctl(FAR struct inode *inode, int cmd, 
unsigned long arg)
   if (cmd == BIOC_FLUSH)
     {
 #ifdef CONFIG_FTL_WRITEBUFFER
-      rwb_flush(&dev->rwb);
+      return rwb_flush(&dev->rwb);
 #endif
     }
 

Reply via email to