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 }
