Check in v2 version of "ext4: Punch hole and DAX fixes"
[ext4-patch-queue.git] / decrement-counters-on-bitmap-error
blob6978e26f6306e3f34b0c1a802c210963c9e6f269
1 ext4: decrement free clusters/inodes counters when block group declared bad
3 From: Namjae Jeon <namjae.jeon@samsung.com>
5 We should decrement free clusters counter when block bitmap is marked
6 as corrupt and free inodes counter when the allocation bitmap is
7 marked as corrupt to avoid misunderstanding due to incorrect available
8 size in statfs result.  User can get immediately ENOSPC error from
9 write begin without reaching for the writepages.
11 Cc: Darrick J. Wong<darrick.wong@oracle.com>
12 Reported-by: Amit Sahrawat <amit.sahrawat83@gmail.com>
13 Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
14 Signed-off-by: Ashish Sangwan <a.sangwan@samsung.com>
15 ---
16  fs/ext4/balloc.c  | 16 ++++++++++++++++
17  fs/ext4/ialloc.c  | 23 +++++++++++++++++++++++
18  fs/ext4/mballoc.c |  8 ++++++++
19  3 files changed, 47 insertions(+)
21 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
22 index 0762d14..fca3820 100644
23 --- a/fs/ext4/balloc.c
24 +++ b/fs/ext4/balloc.c
25 @@ -194,7 +194,16 @@ static void ext4_init_block_bitmap(struct super_block *sb,
26         if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
27                 ext4_error(sb, "Checksum bad for group %u", block_group);
28                 grp = ext4_get_group_info(sb, block_group);
29 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
30 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
31 +                                          grp->bb_free);
32                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
33 +               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
34 +                       int count;
35 +                       count = ext4_free_inodes_count(sb, gdp);
36 +                       percpu_counter_sub(&sbi->s_freeinodes_counter,
37 +                                          count);
38 +               }
39                 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
40                 return;
41         }
42 @@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
43  {
44         ext4_fsblk_t    blk;
45         struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
46 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
48         if (buffer_verified(bh))
49                 return;
50 @@ -369,6 +379,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
51                 ext4_unlock_group(sb, block_group);
52                 ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
53                            block_group, blk);
54 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
55 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
56 +                                          grp->bb_free);
57                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
58                 return;
59         }
60 @@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
61                         desc, bh))) {
62                 ext4_unlock_group(sb, block_group);
63                 ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
64 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
65 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
66 +                                          grp->bb_free);
67                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
68                 return;
69         }
70 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
71 index 0ee59a6..a87455d 100644
72 --- a/fs/ext4/ialloc.c
73 +++ b/fs/ext4/ialloc.c
74 @@ -71,6 +71,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
75                                        struct ext4_group_desc *gdp)
76  {
77         struct ext4_group_info *grp;
78 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
79         J_ASSERT_BH(bh, buffer_locked(bh));
81         /* If checksum is bad mark all blocks and inodes use to prevent
82 @@ -78,7 +79,16 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
83         if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
84                 ext4_error(sb, "Checksum bad for group %u", block_group);
85                 grp = ext4_get_group_info(sb, block_group);
86 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
87 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
88 +                                          grp->bb_free);
89                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
90 +               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
91 +                       int count;
92 +                       count = ext4_free_inodes_count(sb, gdp);
93 +                       percpu_counter_sub(&sbi->s_freeinodes_counter,
94 +                                          count);
95 +               }
96                 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
97                 return 0;
98         }
99 @@ -116,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
100         struct buffer_head *bh = NULL;
101         ext4_fsblk_t bitmap_blk;
102         struct ext4_group_info *grp;
103 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
105         desc = ext4_get_group_desc(sb, block_group, NULL);
106         if (!desc)
107 @@ -185,6 +196,12 @@ verify:
108                 ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
109                            "inode_bitmap = %llu", block_group, bitmap_blk);
110                 grp = ext4_get_group_info(sb, block_group);
111 +               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
112 +                       int count;
113 +                       count = ext4_free_inodes_count(sb, desc);
114 +                       percpu_counter_sub(&sbi->s_freeinodes_counter,
115 +                                          count);
116 +               }
117                 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
118                 return NULL;
119         }
120 @@ -321,6 +338,12 @@ out:
121                         fatal = err;
122         } else {
123                 ext4_error(sb, "bit already cleared for inode %lu", ino);
124 +               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
125 +                       int count;
126 +                       count = ext4_free_inodes_count(sb, gdp);
127 +                       percpu_counter_sub(&sbi->s_freeinodes_counter,
128 +                                          count);
129 +               }
130                 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
131         }
133 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
134 index 59e3162..7f72f50 100644
135 --- a/fs/ext4/mballoc.c
136 +++ b/fs/ext4/mballoc.c
137 @@ -722,6 +722,7 @@ void ext4_mb_generate_buddy(struct super_block *sb,
138                                 void *buddy, void *bitmap, ext4_group_t group)
140         struct ext4_group_info *grp = ext4_get_group_info(sb, group);
141 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
142         ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
143         ext4_grpblk_t i = 0;
144         ext4_grpblk_t first;
145 @@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
146                  * corrupt and update bb_free using bitmap value
147                  */
148                 grp->bb_free = free;
149 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
150 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
151 +                                          grp->bb_free);
152                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
153         }
154         mb_set_largest_free_order(sb, grp);
155 @@ -1431,6 +1435,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
156                 right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap);
158         if (unlikely(block != -1)) {
159 +               struct ext4_sb_info *sbi = EXT4_SB(sb);
160                 ext4_fsblk_t blocknr;
162                 blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
163 @@ -1441,6 +1446,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
164                                       "freeing already freed block "
165                                       "(bit %u); block bitmap corrupt.",
166                                       block);
167 +               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))
168 +                       percpu_counter_sub(&sbi->s_freeclusters_counter,
169 +                                          e4b->bd_info->bb_free);
170                 /* Mark the block group as corrupt. */
171                 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
172                         &e4b->bd_info->bb_state);