add patch improve-code-readability-in-ext4_iget
[ext4-patch-queue.git] / fix-race-with-setting-bitmap-corrupted
blobb2faa11e5bc3075fccff4cb3bd466a23b45d07e8
1 ext4: fix race when setting the bitmap corrupted flag
3 From: Wang Shilong <wshilong@ddn.com>
5 Whenever we hit block or inode bitmap corruptions we set
6 bit and then reduce this block group free inode/clusters
7 counter to expose right available space.
9 However some of ext4_mark_group_bitmap_corrupted() is called
10 inside group spinlock, some are not, this could make it happen
11 that we double reduce one block group free counters from system.
13 Always hold group spinlock for it could fix it, but it looks
14 a little heavy, we could use test_and_set_bit() to fix race
15 problems here.
17 Signed-off-by: Wang Shilong <wshilong@ddn.com>
18 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
19 Cc: stable@vger.kernel.org
20 ---
21  fs/ext4/super.c | 22 +++++++++++-----------
22  1 file changed, 11 insertions(+), 11 deletions(-)
24 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
25 index c1c5c87..d6fa6cf 100644
26 --- a/fs/ext4/super.c
27 +++ b/fs/ext4/super.c
28 @@ -770,26 +770,26 @@ void ext4_mark_group_bitmap_corrupted(struct super_block *sb,
29         struct ext4_sb_info *sbi = EXT4_SB(sb);
30         struct ext4_group_info *grp = ext4_get_group_info(sb, group);
31         struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
32 +       int ret;
34 -       if ((flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) &&
35 -           !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) {
36 -               percpu_counter_sub(&sbi->s_freeclusters_counter,
37 -                                       grp->bb_free);
38 -               set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
39 -                       &grp->bb_state);
40 +       if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) {
41 +               ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
42 +                                           &grp->bb_state);
43 +               if (!ret)
44 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
45 +                                          grp->bb_free);
46         }
48 -       if ((flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) &&
49 -           !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
50 -               if (gdp) {
51 +       if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) {
52 +               ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
53 +                                           &grp->bb_state);
54 +               if (!ret && gdp) {
55                         int count;
57                         count = ext4_free_inodes_count(sb, gdp);
58                         percpu_counter_sub(&sbi->s_freeinodes_counter,
59                                            count);
60                 }
61 -               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
62 -                       &grp->bb_state);
63         }
64  }
66 -- 
67 1.8.3.1