Mercurial > hg > aboriginal
comparison sources/patches/linux-fixext4.patch @ 1556:1a5d8dbc5a19
John Spencer reported ext4 filesystem corruption, which seems to have been a problem in the kernel since 3.6.3. Backporting a few patches to try to address it.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 13 Nov 2012 07:27:25 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1555:c734d53d271a | 1556:1a5d8dbc5a19 |
---|---|
1 commit f2a09af645b762f8230e7eba7fee3b6f7e6e96e7 | |
2 Author: Yongqiang Yang <xiaoqiangnk@gmail.com> | |
3 Date: Sun Sep 23 23:16:03 2012 -0400 | |
4 | |
5 ext4: check free inode count before allocating an inode | |
6 | |
7 Recently, I ecountered some corrupted filesystems in which some | |
8 groups' free inode counts were 65535, it seemed that free inode | |
9 count was overflow. This patch teaches ext4 to check free inode | |
10 count before allocaing an inode. | |
11 | |
12 Signed-off-by: Yongqiang Yang <xiaoqiangnk@gmail.com> | |
13 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
14 | |
15 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c | |
16 index 26154b8..fa36372 100644 | |
17 --- a/fs/ext4/ialloc.c | |
18 +++ b/fs/ext4/ialloc.c | |
19 @@ -697,6 +697,15 @@ got_group: | |
20 if (!gdp) | |
21 goto fail; | |
22 | |
23 + /* | |
24 + * Check free inodes count before loading bitmap. | |
25 + */ | |
26 + if (ext4_free_inodes_count(sb, gdp) == 0) { | |
27 + if (++group == ngroups) | |
28 + group = 0; | |
29 + continue; | |
30 + } | |
31 + | |
32 brelse(inode_bitmap_bh); | |
33 inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); | |
34 if (!inode_bitmap_bh) | |
35 commit 79f1ba49569e5aec919b653c55b03274c2331701 | |
36 Author: Tao Ma <boyu.mt@taobao.com> | |
37 Date: Mon Oct 22 00:34:32 2012 -0400 | |
38 | |
39 ext4: Checksum the block bitmap properly with bigalloc enabled | |
40 | |
41 In mke2fs, we only checksum the whole bitmap block and it is right. | |
42 While in the kernel, we use EXT4_BLOCKS_PER_GROUP to indicate the | |
43 size of the checksumed bitmap which is wrong when we enable bigalloc. | |
44 The right size should be EXT4_CLUSTERS_PER_GROUP and this patch fixes | |
45 it. | |
46 | |
47 Also as every caller of ext4_block_bitmap_csum_set and | |
48 ext4_block_bitmap_csum_verify pass in EXT4_BLOCKS_PER_GROUP(sb)/8, | |
49 we'd better removes this parameter and sets it in the function itself. | |
50 | |
51 Signed-off-by: Tao Ma <boyu.mt@taobao.com> | |
52 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
53 Reviewed-by: Lukas Czerner <lczerner@redhat.com> | |
54 Cc: stable@vger.kernel.org | |
55 | |
56 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c | |
57 index 1b50890..cf18217 100644 | |
58 --- a/fs/ext4/balloc.c | |
59 +++ b/fs/ext4/balloc.c | |
60 @@ -174,8 +174,7 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | |
61 ext4_free_inodes_set(sb, gdp, 0); | |
62 ext4_itable_unused_set(sb, gdp, 0); | |
63 memset(bh->b_data, 0xff, sb->s_blocksize); | |
64 - ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | |
65 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
66 + ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); | |
67 return; | |
68 } | |
69 memset(bh->b_data, 0, sb->s_blocksize); | |
70 @@ -212,8 +211,7 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | |
71 */ | |
72 ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), | |
73 sb->s_blocksize * 8, bh->b_data); | |
74 - ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | |
75 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
76 + ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); | |
77 ext4_group_desc_csum_set(sb, block_group, gdp); | |
78 } | |
79 | |
80 @@ -350,7 +348,7 @@ void ext4_validate_block_bitmap(struct super_block *sb, | |
81 return; | |
82 } | |
83 if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, | |
84 - desc, bh, EXT4_BLOCKS_PER_GROUP(sb) / 8))) { | |
85 + desc, bh))) { | |
86 ext4_unlock_group(sb, block_group); | |
87 ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); | |
88 return; | |
89 diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c | |
90 index 5c2d181..3285aa5 100644 | |
91 --- a/fs/ext4/bitmap.c | |
92 +++ b/fs/ext4/bitmap.c | |
93 @@ -58,11 +58,12 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | |
94 | |
95 int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | |
96 struct ext4_group_desc *gdp, | |
97 - struct buffer_head *bh, int sz) | |
98 + struct buffer_head *bh) | |
99 { | |
100 __u32 hi; | |
101 __u32 provided, calculated; | |
102 struct ext4_sb_info *sbi = EXT4_SB(sb); | |
103 + int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8; | |
104 | |
105 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | |
106 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | |
107 @@ -84,8 +85,9 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | |
108 | |
109 void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | |
110 struct ext4_group_desc *gdp, | |
111 - struct buffer_head *bh, int sz) | |
112 + struct buffer_head *bh) | |
113 { | |
114 + int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8; | |
115 __u32 csum; | |
116 struct ext4_sb_info *sbi = EXT4_SB(sb); | |
117 | |
118 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h | |
119 index 78971cf..3c20de1 100644 | |
120 --- a/fs/ext4/ext4.h | |
121 +++ b/fs/ext4/ext4.h | |
122 @@ -1882,10 +1882,10 @@ int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | |
123 struct buffer_head *bh, int sz); | |
124 void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | |
125 struct ext4_group_desc *gdp, | |
126 - struct buffer_head *bh, int sz); | |
127 + struct buffer_head *bh); | |
128 int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | |
129 struct ext4_group_desc *gdp, | |
130 - struct buffer_head *bh, int sz); | |
131 + struct buffer_head *bh); | |
132 | |
133 /* balloc.c */ | |
134 extern void ext4_validate_block_bitmap(struct super_block *sb, | |
135 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c | |
136 index fa36372..4facdd2 100644 | |
137 --- a/fs/ext4/ialloc.c | |
138 +++ b/fs/ext4/ialloc.c | |
139 @@ -762,9 +762,7 @@ got: | |
140 ext4_free_group_clusters_set(sb, gdp, | |
141 ext4_free_clusters_after_init(sb, group, gdp)); | |
142 ext4_block_bitmap_csum_set(sb, group, gdp, | |
143 - block_bitmap_bh, | |
144 - EXT4_BLOCKS_PER_GROUP(sb) / | |
145 - 8); | |
146 + block_bitmap_bh); | |
147 ext4_group_desc_csum_set(sb, group, gdp); | |
148 } | |
149 ext4_unlock_group(sb, group); | |
150 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c | |
151 index a415465..eb1e385 100644 | |
152 --- a/fs/ext4/mballoc.c | |
153 +++ b/fs/ext4/mballoc.c | |
154 @@ -2805,8 +2805,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |
155 } | |
156 len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; | |
157 ext4_free_group_clusters_set(sb, gdp, len); | |
158 - ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh, | |
159 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
160 + ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh); | |
161 ext4_group_desc_csum_set(sb, ac->ac_b_ex.fe_group, gdp); | |
162 | |
163 ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | |
164 @@ -4666,8 +4665,7 @@ do_more: | |
165 | |
166 ret = ext4_free_group_clusters(sb, gdp) + count_clusters; | |
167 ext4_free_group_clusters_set(sb, gdp, ret); | |
168 - ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh, | |
169 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
170 + ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh); | |
171 ext4_group_desc_csum_set(sb, block_group, gdp); | |
172 ext4_unlock_group(sb, block_group); | |
173 percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); | |
174 @@ -4811,8 +4809,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, | |
175 mb_free_blocks(NULL, &e4b, bit, count); | |
176 blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); | |
177 ext4_free_group_clusters_set(sb, desc, blk_free_count); | |
178 - ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh, | |
179 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
180 + ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh); | |
181 ext4_group_desc_csum_set(sb, block_group, desc); | |
182 ext4_unlock_group(sb, block_group); | |
183 percpu_counter_add(&sbi->s_freeclusters_counter, | |
184 diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c | |
185 index 7a75e10..47bf06a 100644 | |
186 --- a/fs/ext4/resize.c | |
187 +++ b/fs/ext4/resize.c | |
188 @@ -1212,8 +1212,7 @@ static int ext4_set_bitmap_checksums(struct super_block *sb, | |
189 bh = ext4_get_bitmap(sb, group_data->block_bitmap); | |
190 if (!bh) | |
191 return -EIO; | |
192 - ext4_block_bitmap_csum_set(sb, group, gdp, bh, | |
193 - EXT4_BLOCKS_PER_GROUP(sb) / 8); | |
194 + ext4_block_bitmap_csum_set(sb, group, gdp, bh); | |
195 brelse(bh); | |
196 | |
197 return 0; | |
198 commit ffb5387e85d528fb6d0d924abfa3fbf0fc484071 | |
199 Author: Eric Sandeen <sandeen@redhat.com> | |
200 Date: Sun Oct 28 22:24:57 2012 -0400 | |
201 | |
202 ext4: fix unjournaled inode bitmap modification | |
203 | |
204 commit 119c0d4460b001e44b41dcf73dc6ee794b98bd31 changed | |
205 ext4_new_inode() such that the inode bitmap was being modified | |
206 outside a transaction, which could lead to corruption, and was | |
207 discovered when journal_checksum found a bad checksum in the | |
208 journal during log replay. | |
209 | |
210 Nix ran into this when using the journal_async_commit mount | |
211 option, which enables journal checksumming. The ensuing | |
212 journal replay failures due to the bad checksums led to | |
213 filesystem corruption reported as the now infamous | |
214 "Apparent serious progressive ext4 data corruption bug" | |
215 | |
216 [ Changed by tytso to only call ext4_journal_get_write_access() only | |
217 when we're fairly certain that we're going to allocate the inode. ] | |
218 | |
219 I've tested this by mounting with journal_checksum and | |
220 running fsstress then dropping power; I've also tested by | |
221 hacking DM to create snapshots w/o first quiescing, which | |
222 allows me to test journal replay repeatedly w/o actually | |
223 power-cycling the box. Without the patch I hit a journal | |
224 checksum error every time. With this fix it survives | |
225 many iterations. | |
226 | |
227 Reported-by: Nix <nix@esperi.org.uk> | |
228 Signed-off-by: Eric Sandeen <sandeen@redhat.com> | |
229 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
230 Cc: stable@vger.kernel.org | |
231 | |
232 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c | |
233 index 4facdd2..3a100e7 100644 | |
234 --- a/fs/ext4/ialloc.c | |
235 +++ b/fs/ext4/ialloc.c | |
236 @@ -725,6 +725,10 @@ repeat_in_this_group: | |
237 "inode=%lu", ino + 1); | |
238 continue; | |
239 } | |
240 + BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); | |
241 + err = ext4_journal_get_write_access(handle, inode_bitmap_bh); | |
242 + if (err) | |
243 + goto fail; | |
244 ext4_lock_group(sb, group); | |
245 ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data); | |
246 ext4_unlock_group(sb, group); | |
247 @@ -738,6 +742,11 @@ repeat_in_this_group: | |
248 goto out; | |
249 | |
250 got: | |
251 + BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); | |
252 + err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); | |
253 + if (err) | |
254 + goto fail; | |
255 + | |
256 /* We may have to initialize the block bitmap if it isn't already */ | |
257 if (ext4_has_group_desc_csum(sb) && | |
258 gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | |
259 @@ -771,11 +780,6 @@ got: | |
260 goto fail; | |
261 } | |
262 | |
263 - BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); | |
264 - err = ext4_journal_get_write_access(handle, inode_bitmap_bh); | |
265 - if (err) | |
266 - goto fail; | |
267 - | |
268 BUFFER_TRACE(group_desc_bh, "get_write_access"); | |
269 err = ext4_journal_get_write_access(handle, group_desc_bh); | |
270 if (err) | |
271 @@ -823,11 +827,6 @@ got: | |
272 } | |
273 ext4_unlock_group(sb, group); | |
274 | |
275 - BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); | |
276 - err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); | |
277 - if (err) | |
278 - goto fail; | |
279 - | |
280 BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); | |
281 err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); | |
282 if (err) |