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)