1From 8625b843ab9e1327dcb83b025951f97c971175e0 Mon Sep 17 00:00:00 2001 2From: Wenchao Hao <haowenchao@huawei.com> 3Date: Fri, 11 Nov 2022 12:22:08 +0800 4Subject: [PATCH] unix_io.c: fix deadlock problem in unix_write_blk64 5 6We will release CACHE_MTX lock, when enter e2fsck_handle_write_error. 7 8stack: 9(gdb) bt 100 0x0000ffffa740bc34 in ?? () from /usr/lib64/libc.so.6 111 0x0000ffffa7412024 in pthread_mutex_lock () from /usr/lib64/libc.so.6 122 0x0000ffffa7654e54 in mutex_lock (kind=CACHE_MTX, data=0xaaaaf5c98f30) at unix_io.c:151 133 unix_write_blk64 (channel=0xaaaaf5c98e60, block=2, count=4, buf=0xaaaaf5c9d170) at unix_io.c:1092 144 0x0000ffffa762e610 in ext2fs_flush2 (flags=0, fs=0xaaaaf5c98cc0) at closefs.c:401 155 ext2fs_flush2 (fs=0xaaaaf5c98cc0, flags=0) at closefs.c:279 166 0x0000ffffa762eb14 in ext2fs_close2 (fs=fs@entry=0xaaaaf5c98cc0, flags=flags@entry=0) at closefs.c:510 177 0x0000ffffa762eba4 in ext2fs_close_free (fs_ptr=fs_ptr@entry=0xffffc8cbab30) at closefs.c:472 188 0x0000aaaadcc39bd8 in preenhalt (ctx=ctx@entry=0xaaaaf5c98460) at util.c:365 199 0x0000aaaadcc3bc5c in e2fsck_handle_write_error (channel=<optimized out>, block=262152, count=<optimized out>, data=<optimized out>, size=<optimized out>, actual=<optimized out>, error=5) 20 at ehandler.c:114 2110 0x0000ffffa7655044 in reuse_cache (block=262206, cache=0xaaaaf5c98f80, data=0xaaaaf5c98f30, channel=0xaaaaf5c98e60) at unix_io.c:583 2211 unix_write_blk64 (channel=0xaaaaf5c98e60, block=262206, count=<optimized out>, buf=<optimized out>) at unix_io.c:1097 2312 0x0000aaaadcc3702c in ll_rw_block (rw=rw@entry=1, op_flags=op_flags@entry=0, nr=<optimized out>, nr@entry=1, bhp=0xffffc8cbac60, bhp@entry=0xffffc8cbac58) at journal.c:184 2413 0x0000aaaadcc375e8 in brelse (bh=<optimized out>, bh@entry=0xaaaaf5cac4a0) at journal.c:217 2514 0x0000aaaadcc3ebe0 in do_one_pass (journal=journal@entry=0xaaaaf5c9f590, info=info@entry=0xffffc8cbad60, pass=pass@entry=PASS_REPLAY) at recovery.c:693 2615 0x0000aaaadcc3ee74 in jbd2_journal_recover (journal=0xaaaaf5c9f590) at recovery.c:310 2716 0x0000aaaadcc386a8 in recover_ext3_journal (ctx=0xaaaaf5c98460) at journal.c:1653 2817 e2fsck_run_ext3_journal (ctx=0xaaaaf5c98460) at journal.c:1706 2918 0x0000aaaadcc207e0 in main (argc=<optimized out>, argv=<optimized out>) at unix.c:1791 30 31Signed-off-by: zhanchengbin <zhanchengbin1@huawei.com> 32Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com> 33--- 34 lib/ext2fs/unix_io.c | 63 +++++++++++++++++++++++++++++++++++++--------------- 35 1 file changed, 45 insertions(+), 18 deletions(-) 36 37diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c 38index c326f57..a7ab772 100644 39--- a/lib/ext2fs/unix_io.c 40+++ b/lib/ext2fs/unix_io.c 41@@ -210,7 +210,8 @@ static char *safe_getenv(const char *arg) 42 static errcode_t raw_read_blk(io_channel channel, 43 struct unix_private_data *data, 44 unsigned long long block, 45- int count, void *bufv) 46+ int count, void *bufv, 47+ int cache_lock) 48 { 49 errcode_t retval; 50 ssize_t size; 51@@ -331,16 +332,22 @@ error_unlock: 52 mutex_unlock(data, BOUNCE_MTX); 53 if (actual >= 0 && actual < size) 54 memset((char *) buf+actual, 0, size-actual); 55- if (channel->read_error) 56+ if (channel->read_error) { 57+ if (cache_lock) 58+ mutex_unlock(data, CACHE_MTX); 59 retval = (channel->read_error)(channel, block, count, buf, 60 size, actual, retval); 61+ if (cache_lock) 62+ mutex_lock(data, CACHE_MTX); 63+ } 64 return retval; 65 } 66 67 static errcode_t raw_write_blk(io_channel channel, 68 struct unix_private_data *data, 69 unsigned long long block, 70- int count, const void *bufv) 71+ int count, const void *bufv, 72+ int cache_lock) 73 { 74 ssize_t size; 75 ext2_loff_t location; 76@@ -482,9 +489,14 @@ bounce_write: 77 error_unlock: 78 mutex_unlock(data, BOUNCE_MTX); 79 error_out: 80- if (channel->write_error) 81+ if (channel->write_error) { 82+ if (cache_lock) 83+ mutex_unlock(data, CACHE_MTX); 84 retval = (channel->write_error)(channel, block, count, buf, 85 size, actual, retval); 86+ if (cache_lock) 87+ mutex_lock(data, CACHE_MTX); 88+ } 89 return retval; 90 } 91 92@@ -576,16 +588,22 @@ static struct unix_cache *find_cached_block(struct unix_private_data *data, 93 /* 94 * Reuse a particular cache entry for another block. 95 */ 96-static void reuse_cache(io_channel channel, struct unix_private_data *data, 97+static errcode_t reuse_cache(io_channel channel, struct unix_private_data *data, 98 struct unix_cache *cache, unsigned long long block) 99 { 100- if (cache->dirty && cache->in_use) 101- raw_write_blk(channel, data, cache->block, 1, cache->buf); 102+ errcode_t retval = 0; 103+ if (cache->dirty && cache->in_use) { 104+ retval = raw_write_blk(channel, data, cache->block, 1, cache->buf, 1); 105+ if (retval) 106+ return retval; 107+ } 108 109 cache->in_use = 1; 110 cache->dirty = 0; 111 cache->block = block; 112 cache->access_time = ++data->access_time; 113+ 114+ return retval; 115 } 116 117 #define FLUSH_INVALIDATE 0x01 118@@ -616,7 +634,8 @@ static errcode_t flush_cached_blocks(io_channel channel, 119 continue; 120 121 retval = raw_write_blk(channel, data, 122- cache->block, 1, cache->buf); 123+ cache->block, 1, cache->buf, 124+ !(flags & FLUSH_NOLOCK)); 125 if (retval) 126 retval2 = retval; 127 else 128@@ -984,10 +1003,10 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 129 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 130 131 #ifdef NO_IO_CACHE 132- return raw_read_blk(channel, data, block, count, buf); 133+ return raw_read_blk(channel, data, block, count, buf, 0); 134 #else 135 if (data->flags & IO_FLAG_NOCACHE) 136- return raw_read_blk(channel, data, block, count, buf); 137+ return raw_read_blk(channel, data, block, count, buf, 0); 138 /* 139 * If we're doing an odd-sized read or a very large read, 140 * flush out the cache and then do a direct read. 141@@ -995,7 +1014,7 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 142 if (count < 0 || count > WRITE_DIRECT_SIZE) { 143 if ((retval = flush_cached_blocks(channel, data, 0))) 144 return retval; 145- return raw_read_blk(channel, data, block, count, buf); 146+ return raw_read_blk(channel, data, block, count, buf, 0); 147 } 148 149 cp = buf; 150@@ -1024,14 +1043,18 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 151 printf("Reading %d blocks starting at %lu\n", i, block); 152 #endif 153 mutex_unlock(data, CACHE_MTX); 154- if ((retval = raw_read_blk(channel, data, block, i, cp))) 155+ if ((retval = raw_read_blk(channel, data, block, i, cp, 0))) 156 return retval; 157 mutex_lock(data, CACHE_MTX); 158 159 /* Save the results in the cache */ 160 for (j=0; j < i; j++) { 161 if (!find_cached_block(data, block, &cache)) { 162- reuse_cache(channel, data, cache, block); 163+ retval = reuse_cache(channel, data, cache, block); 164+ if (retval) { 165+ mutex_unlock(data, CACHE_MTX); 166+ return retval; 167+ } 168 memcpy(cache->buf, cp, channel->block_size); 169 } 170 count--; 171@@ -1064,10 +1087,10 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 172 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 173 174 #ifdef NO_IO_CACHE 175- return raw_write_blk(channel, data, block, count, buf); 176+ return raw_write_blk(channel, data, block, count, buf, 0); 177 #else 178 if (data->flags & IO_FLAG_NOCACHE) 179- return raw_write_blk(channel, data, block, count, buf); 180+ return raw_write_blk(channel, data, block, count, buf, 0); 181 /* 182 * If we're doing an odd-sized write or a very large write, 183 * flush out the cache completely and then do a direct write. 184@@ -1076,7 +1099,7 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 185 if ((retval = flush_cached_blocks(channel, data, 186 FLUSH_INVALIDATE))) 187 return retval; 188- return raw_write_blk(channel, data, block, count, buf); 189+ return raw_write_blk(channel, data, block, count, buf, 0); 190 } 191 192 /* 193@@ -1086,7 +1109,7 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 194 */ 195 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 196 if (writethrough) 197- retval = raw_write_blk(channel, data, block, count, buf); 198+ retval = raw_write_blk(channel, data, block, count, buf, 0); 199 200 cp = buf; 201 mutex_lock(data, CACHE_MTX); 202@@ -1094,7 +1117,11 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 203 cache = find_cached_block(data, block, &reuse); 204 if (!cache) { 205 cache = reuse; 206- reuse_cache(channel, data, cache, block); 207+ retval = reuse_cache(channel, data, cache, block); 208+ if (retval) { 209+ mutex_unlock(data, CACHE_MTX); 210+ return retval; 211+ } 212 } 213 if (cache->buf != cp) 214 memcpy(cache->buf, cp, channel->block_size); 215-- 2161.8.3.1 217 218