[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230131061542.324172-4-tytso@mit.edu>
Date: Tue, 31 Jan 2023 01:15:42 -0500
From: "Theodore Ts'o" <tytso@....edu>
To: Ext4 Developers List <linux-ext4@...r.kernel.org>
Cc: zhanchengbin1@...wei.com, linfeilong@...wei.com,
"Theodore Ts'o" <tytso@....edu>
Subject: [PATCH 3/3] libext2fs: unix_io: fix_potential error path deadlock in flush_cached_blocks()
We can't call the error handler while holding the CACHE_MUTEX (see
previous commit, "libext2fs: unix_io: fix_potential error path
deadlock in reuse_cache()" for details), so first try to write out all
of the dirty blocks in the cache, and then for those where we had
errors, then call the error handler.
Signed-off-by: Theodore Ts'o <tytso@....edu>
---
lib/ext2fs/unix_io.c | 61 ++++++++++++++++++++++++++++++++++----------
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 2e108a2f..353d85af 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -614,31 +614,66 @@ static errcode_t flush_cached_blocks(io_channel channel,
int flags)
{
struct unix_cache *cache;
- errcode_t retval, retval2;
+ errcode_t retval, retval2 = 0;
int i;
+ int errors_found = 0;
- retval2 = 0;
if ((flags & FLUSH_NOLOCK) == 0)
mutex_lock(data, CACHE_MTX);
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
- if (!cache->in_use)
+ if (!cache->in_use || !cache->dirty)
continue;
-
- if (flags & FLUSH_INVALIDATE)
- cache->in_use = 0;
-
- if (!cache->dirty)
- continue;
-
retval = raw_write_blk(channel, data,
- cache->block, 1, cache->buf, 0);
- if (retval)
+ cache->block, 1, cache->buf,
+ RAW_WRITE_NO_HANDLER);
+ if (retval) {
+ cache->write_err = 1;
+ errors_found = 1;
retval2 = retval;
- else
+ } else {
cache->dirty = 0;
+ cache->write_err = 0;
+ if (flags & FLUSH_INVALIDATE)
+ cache->in_use = 0;
+ }
}
if ((flags & FLUSH_NOLOCK) == 0)
mutex_unlock(data, CACHE_MTX);
+retry:
+ while (errors_found) {
+ if ((flags & FLUSH_NOLOCK) == 0)
+ mutex_lock(data, CACHE_MTX);
+ errors_found = 0;
+ for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+ if (!cache->in_use || !cache->write_err)
+ continue;
+ errors_found = 1;
+ if (cache->write_err && channel->write_error) {
+ char *err_buf = NULL;
+ unsigned long long err_block = cache->block;
+
+ cache->dirty = 0;
+ cache->in_use = 0;
+ cache->write_err = 0;
+ if (io_channel_alloc_buf(channel, 0,
+ &err_buf))
+ err_buf = NULL;
+ else
+ memcpy(err_buf, cache->buf,
+ channel->block_size);
+ mutex_unlock(data, CACHE_MTX);
+ (channel->write_error)(channel, err_block,
+ 1, err_buf, channel->block_size, -1,
+ retval2);
+ if (err_buf)
+ ext2fs_free_mem(&err_buf);
+ goto retry;
+ } else
+ cache->write_err = 0;
+ }
+ if ((flags & FLUSH_NOLOCK) == 0)
+ mutex_unlock(data, CACHE_MTX);
+ }
return retval2;
}
#endif /* NO_IO_CACHE */
--
2.31.0
Powered by blists - more mailing lists