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