diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-29 22:20:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-29 22:20:43 -0400 |
commit | 16874b2cb867d3eb63ed838f2847143e11556708 (patch) | |
tree | 3052bd2c5fe3a661ef42dea767d6a782d71c821b /fs | |
parent | 4c834452aad01531db949414f94f817a86348d59 (diff) | |
parent | a93cd4cf86466caa49cfe64607bea7f0bde3f916 (diff) |
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 bugfixes from Ted Ts'o:
"Fix a regression when trying to compile ext4 on older versions gcc.
Fix a number of miscellaneous bugs for punch hole as well as a
long-standing potential double buffer head release when failing a
block allocation for an indirect-mapped file"
* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: Fix hole punching for files with indirect blocks
ext4: Fix block zeroing when punching holes in indirect block files
ext4: decrement free clusters/inodes counters when block group declared bad
fs/mbcache: replace __builtin_log2() with ilog2()
ext4: Fix buffer double free in ext4_alloc_branch()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/balloc.c | 16 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 23 | ||||
-rw-r--r-- | fs/ext4/indirect.c | 24 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 8 | ||||
-rw-r--r-- | fs/mbcache.c | 3 |
5 files changed, 68 insertions, 6 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 0762d143e252..fca382037ddd 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -194,7 +194,16 @@ static void ext4_init_block_bitmap(struct super_block *sb, | |||
194 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { | 194 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
195 | ext4_error(sb, "Checksum bad for group %u", block_group); | 195 | ext4_error(sb, "Checksum bad for group %u", block_group); |
196 | grp = ext4_get_group_info(sb, block_group); | 196 | grp = ext4_get_group_info(sb, block_group); |
197 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | ||
198 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
199 | grp->bb_free); | ||
197 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | 200 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); |
201 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
202 | int count; | ||
203 | count = ext4_free_inodes_count(sb, gdp); | ||
204 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
205 | count); | ||
206 | } | ||
198 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | 207 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); |
199 | return; | 208 | return; |
200 | } | 209 | } |
@@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb, | |||
359 | { | 368 | { |
360 | ext4_fsblk_t blk; | 369 | ext4_fsblk_t blk; |
361 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); | 370 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); |
371 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
362 | 372 | ||
363 | if (buffer_verified(bh)) | 373 | if (buffer_verified(bh)) |
364 | return; | 374 | return; |
@@ -369,6 +379,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb, | |||
369 | ext4_unlock_group(sb, block_group); | 379 | ext4_unlock_group(sb, block_group); |
370 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", | 380 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", |
371 | block_group, blk); | 381 | block_group, blk); |
382 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | ||
383 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
384 | grp->bb_free); | ||
372 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | 385 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); |
373 | return; | 386 | return; |
374 | } | 387 | } |
@@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb, | |||
376 | desc, bh))) { | 389 | desc, bh))) { |
377 | ext4_unlock_group(sb, block_group); | 390 | ext4_unlock_group(sb, block_group); |
378 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); | 391 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); |
392 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | ||
393 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
394 | grp->bb_free); | ||
379 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | 395 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); |
380 | return; | 396 | return; |
381 | } | 397 | } |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 0ee59a6644e2..a87455df38bc 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -71,6 +71,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, | |||
71 | struct ext4_group_desc *gdp) | 71 | struct ext4_group_desc *gdp) |
72 | { | 72 | { |
73 | struct ext4_group_info *grp; | 73 | struct ext4_group_info *grp; |
74 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
74 | J_ASSERT_BH(bh, buffer_locked(bh)); | 75 | J_ASSERT_BH(bh, buffer_locked(bh)); |
75 | 76 | ||
76 | /* If checksum is bad mark all blocks and inodes use to prevent | 77 | /* If checksum is bad mark all blocks and inodes use to prevent |
@@ -78,7 +79,16 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, | |||
78 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { | 79 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
79 | ext4_error(sb, "Checksum bad for group %u", block_group); | 80 | ext4_error(sb, "Checksum bad for group %u", block_group); |
80 | grp = ext4_get_group_info(sb, block_group); | 81 | grp = ext4_get_group_info(sb, block_group); |
82 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | ||
83 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
84 | grp->bb_free); | ||
81 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | 85 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); |
86 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
87 | int count; | ||
88 | count = ext4_free_inodes_count(sb, gdp); | ||
89 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
90 | count); | ||
91 | } | ||
82 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | 92 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); |
83 | return 0; | 93 | return 0; |
84 | } | 94 | } |
@@ -116,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
116 | struct buffer_head *bh = NULL; | 126 | struct buffer_head *bh = NULL; |
117 | ext4_fsblk_t bitmap_blk; | 127 | ext4_fsblk_t bitmap_blk; |
118 | struct ext4_group_info *grp; | 128 | struct ext4_group_info *grp; |
129 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
119 | 130 | ||
120 | desc = ext4_get_group_desc(sb, block_group, NULL); | 131 | desc = ext4_get_group_desc(sb, block_group, NULL); |
121 | if (!desc) | 132 | if (!desc) |
@@ -185,6 +196,12 @@ verify: | |||
185 | ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " | 196 | ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " |
186 | "inode_bitmap = %llu", block_group, bitmap_blk); | 197 | "inode_bitmap = %llu", block_group, bitmap_blk); |
187 | grp = ext4_get_group_info(sb, block_group); | 198 | grp = ext4_get_group_info(sb, block_group); |
199 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
200 | int count; | ||
201 | count = ext4_free_inodes_count(sb, desc); | ||
202 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
203 | count); | ||
204 | } | ||
188 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | 205 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); |
189 | return NULL; | 206 | return NULL; |
190 | } | 207 | } |
@@ -321,6 +338,12 @@ out: | |||
321 | fatal = err; | 338 | fatal = err; |
322 | } else { | 339 | } else { |
323 | ext4_error(sb, "bit already cleared for inode %lu", ino); | 340 | ext4_error(sb, "bit already cleared for inode %lu", ino); |
341 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
342 | int count; | ||
343 | count = ext4_free_inodes_count(sb, gdp); | ||
344 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
345 | count); | ||
346 | } | ||
324 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | 347 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); |
325 | } | 348 | } |
326 | 349 | ||
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 8a57e9fcd1b9..fd69da194826 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
@@ -389,7 +389,13 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
389 | return 0; | 389 | return 0; |
390 | failed: | 390 | failed: |
391 | for (; i >= 0; i--) { | 391 | for (; i >= 0; i--) { |
392 | if (i != indirect_blks && branch[i].bh) | 392 | /* |
393 | * We want to ext4_forget() only freshly allocated indirect | ||
394 | * blocks. Buffer for new_blocks[i-1] is at branch[i].bh and | ||
395 | * buffer at branch[0].bh is indirect block / inode already | ||
396 | * existing before ext4_alloc_branch() was called. | ||
397 | */ | ||
398 | if (i > 0 && i != indirect_blks && branch[i].bh) | ||
393 | ext4_forget(handle, 1, inode, branch[i].bh, | 399 | ext4_forget(handle, 1, inode, branch[i].bh, |
394 | branch[i].bh->b_blocknr); | 400 | branch[i].bh->b_blocknr); |
395 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], | 401 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], |
@@ -1310,16 +1316,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode, | |||
1310 | blk = *i_data; | 1316 | blk = *i_data; |
1311 | if (level > 0) { | 1317 | if (level > 0) { |
1312 | ext4_lblk_t first2; | 1318 | ext4_lblk_t first2; |
1319 | ext4_lblk_t count2; | ||
1320 | |||
1313 | bh = sb_bread(inode->i_sb, le32_to_cpu(blk)); | 1321 | bh = sb_bread(inode->i_sb, le32_to_cpu(blk)); |
1314 | if (!bh) { | 1322 | if (!bh) { |
1315 | EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk), | 1323 | EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk), |
1316 | "Read failure"); | 1324 | "Read failure"); |
1317 | return -EIO; | 1325 | return -EIO; |
1318 | } | 1326 | } |
1319 | first2 = (first > offset) ? first - offset : 0; | 1327 | if (first > offset) { |
1328 | first2 = first - offset; | ||
1329 | count2 = count; | ||
1330 | } else { | ||
1331 | first2 = 0; | ||
1332 | count2 = count - (offset - first); | ||
1333 | } | ||
1320 | ret = free_hole_blocks(handle, inode, bh, | 1334 | ret = free_hole_blocks(handle, inode, bh, |
1321 | (__le32 *)bh->b_data, level - 1, | 1335 | (__le32 *)bh->b_data, level - 1, |
1322 | first2, count - offset, | 1336 | first2, count2, |
1323 | inode->i_sb->s_blocksize >> 2); | 1337 | inode->i_sb->s_blocksize >> 2); |
1324 | if (ret) { | 1338 | if (ret) { |
1325 | brelse(bh); | 1339 | brelse(bh); |
@@ -1329,8 +1343,8 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode, | |||
1329 | if (level == 0 || | 1343 | if (level == 0 || |
1330 | (bh && all_zeroes((__le32 *)bh->b_data, | 1344 | (bh && all_zeroes((__le32 *)bh->b_data, |
1331 | (__le32 *)bh->b_data + addr_per_block))) { | 1345 | (__le32 *)bh->b_data + addr_per_block))) { |
1332 | ext4_free_data(handle, inode, parent_bh, &blk, &blk+1); | 1346 | ext4_free_data(handle, inode, parent_bh, |
1333 | *i_data = 0; | 1347 | i_data, i_data + 1); |
1334 | } | 1348 | } |
1335 | brelse(bh); | 1349 | brelse(bh); |
1336 | bh = NULL; | 1350 | bh = NULL; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 59e31622cc6e..7f72f50a8fa7 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -722,6 +722,7 @@ void ext4_mb_generate_buddy(struct super_block *sb, | |||
722 | void *buddy, void *bitmap, ext4_group_t group) | 722 | void *buddy, void *bitmap, ext4_group_t group) |
723 | { | 723 | { |
724 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | 724 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); |
725 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
725 | ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb); | 726 | ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb); |
726 | ext4_grpblk_t i = 0; | 727 | ext4_grpblk_t i = 0; |
727 | ext4_grpblk_t first; | 728 | ext4_grpblk_t first; |
@@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb, | |||
759 | * corrupt and update bb_free using bitmap value | 760 | * corrupt and update bb_free using bitmap value |
760 | */ | 761 | */ |
761 | grp->bb_free = free; | 762 | grp->bb_free = free; |
763 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | ||
764 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
765 | grp->bb_free); | ||
762 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | 766 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); |
763 | } | 767 | } |
764 | mb_set_largest_free_order(sb, grp); | 768 | mb_set_largest_free_order(sb, grp); |
@@ -1431,6 +1435,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, | |||
1431 | right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap); | 1435 | right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap); |
1432 | 1436 | ||
1433 | if (unlikely(block != -1)) { | 1437 | if (unlikely(block != -1)) { |
1438 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
1434 | ext4_fsblk_t blocknr; | 1439 | ext4_fsblk_t blocknr; |
1435 | 1440 | ||
1436 | blocknr = ext4_group_first_block_no(sb, e4b->bd_group); | 1441 | blocknr = ext4_group_first_block_no(sb, e4b->bd_group); |
@@ -1441,6 +1446,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, | |||
1441 | "freeing already freed block " | 1446 | "freeing already freed block " |
1442 | "(bit %u); block bitmap corrupt.", | 1447 | "(bit %u); block bitmap corrupt.", |
1443 | block); | 1448 | block); |
1449 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)) | ||
1450 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
1451 | e4b->bd_info->bb_free); | ||
1444 | /* Mark the block group as corrupt. */ | 1452 | /* Mark the block group as corrupt. */ |
1445 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, | 1453 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, |
1446 | &e4b->bd_info->bb_state); | 1454 | &e4b->bd_info->bb_state); |
diff --git a/fs/mbcache.c b/fs/mbcache.c index bf166e388f0d..187477ded6b3 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c | |||
@@ -73,6 +73,7 @@ | |||
73 | #include <linux/mbcache.h> | 73 | #include <linux/mbcache.h> |
74 | #include <linux/init.h> | 74 | #include <linux/init.h> |
75 | #include <linux/blockgroup_lock.h> | 75 | #include <linux/blockgroup_lock.h> |
76 | #include <linux/log2.h> | ||
76 | 77 | ||
77 | #ifdef MB_CACHE_DEBUG | 78 | #ifdef MB_CACHE_DEBUG |
78 | # define mb_debug(f...) do { \ | 79 | # define mb_debug(f...) do { \ |
@@ -93,7 +94,7 @@ | |||
93 | 94 | ||
94 | #define MB_CACHE_WRITER ((unsigned short)~0U >> 1) | 95 | #define MB_CACHE_WRITER ((unsigned short)~0U >> 1) |
95 | 96 | ||
96 | #define MB_CACHE_ENTRY_LOCK_BITS __builtin_log2(NR_BG_LOCKS) | 97 | #define MB_CACHE_ENTRY_LOCK_BITS ilog2(NR_BG_LOCKS) |
97 | #define MB_CACHE_ENTRY_LOCK_INDEX(ce) \ | 98 | #define MB_CACHE_ENTRY_LOCK_INDEX(ce) \ |
98 | (hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS)) | 99 | (hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS)) |
99 | 100 | ||