• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 699d448eee4b991acafaae4e4f8222be332d6837 Mon Sep 17 00:00:00 2001
2From: Theodore Ts'o <tytso@mit.edu>
3Date: Thu, 9 Dec 2021 10:55:54 -0500
4Subject: [PATCH] libext2fs: don't old the CACHE_MTX while doing I/O
5
6A report a deadlock problem caused by I/O errors (caused by e2fsck's
7error handler trying to write to a bad block to perform a forced
8rewrite) uncovered that we were holding the CACHE_MTX while doing read
9operations.  This serialized read operations which destroyed the
10performance benefits from doing parallel bitmap loading (or the
11parallel e2fsck processing under development).
12
13So restructure the code in unix_read_blk64() so that the read is
14always done into the user-provided buffer, and then copied into the
15cache afterwards.
16
17Signed-off-by: Theodore Ts'o <tytso@mit.edu>
18---
19 lib/ext2fs/unix_io.c | 38 +++++++++++++-------------------------
20 1 file changed, 13 insertions(+), 25 deletions(-)
21
22diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
23index 50ac737..e53db33 100644
24--- a/lib/ext2fs/unix_io.c
25+++ b/lib/ext2fs/unix_io.c
26@@ -977,8 +977,8 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
27 			       int count, void *buf)
28 {
29 	struct unix_private_data *data;
30-	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
31-	errcode_t	retval = 0;
32+	struct unix_cache *cache;
33+	errcode_t	retval;
34 	char		*cp;
35 	int		i, j;
36
37@@ -1005,7 +1005,7 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
38 	mutex_lock(data, CACHE_MTX);
39 	while (count > 0) {
40 		/* If it's in the cache, use it! */
41-		if ((cache = find_cached_block(data, block, &reuse[0]))) {
42+		if ((cache = find_cached_block(data, block, NULL))) {
43 #ifdef DEBUG
44 			printf("Using cached block %lu\n", block);
45 #endif
46@@ -1015,47 +1015,35 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
47 			cp += channel->block_size;
48 			continue;
49 		}
50-		if (count == 1) {
51-			/*
52-			 * Special case where we read directly into the
53-			 * cache buffer; important in the O_DIRECT case
54-			 */
55-			cache = reuse[0];
56-			reuse_cache(channel, data, cache, block);
57-			if ((retval = raw_read_blk(channel, data, block, 1,
58-						   cache->buf))) {
59-				cache->in_use = 0;
60-				break;
61-			}
62-			memcpy(cp, cache->buf, channel->block_size);
63-			retval = 0;
64-			break;
65-		}
66
67 		/*
68 		 * Find the number of uncached blocks so we can do a
69 		 * single read request
70 		 */
71 		for (i=1; i < count; i++)
72-			if (find_cached_block(data, block+i, &reuse[i]))
73+			if (find_cached_block(data, block+i, NULL))
74 				break;
75 #ifdef DEBUG
76 		printf("Reading %d blocks starting at %lu\n", i, block);
77 #endif
78+		mutex_unlock(data, CACHE_MTX);
79 		if ((retval = raw_read_blk(channel, data, block, i, cp)))
80-			break;
81+			return retval;
82+		mutex_lock(data, CACHE_MTX);
83
84 		/* Save the results in the cache */
85 		for (j=0; j < i; j++) {
86+			if (!find_cached_block(data, block, &cache)) {
87+				reuse_cache(channel, data, cache, block);
88+				memcpy(cache->buf, cp, channel->block_size);
89+			}
90 			count--;
91-			cache = reuse[j];
92-			reuse_cache(channel, data, cache, block++);
93-			memcpy(cache->buf, cp, channel->block_size);
94+			block++;
95 			cp += channel->block_size;
96 		}
97 	}
98 	mutex_unlock(data, CACHE_MTX);
99-	return retval;
100+	return 0;
101 #endif /* NO_IO_CACHE */
102 }
103
104--
1051.8.3.1
106
107