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>
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,
32 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
33 + if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
35 + count = ext4_free_inodes_count(sb, gdp);
36 + percpu_counter_sub(&sbi->s_freeinodes_counter,
39 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
42 @@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
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))
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",
54 + if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
55 + percpu_counter_sub(&sbi->s_freeclusters_counter,
57 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
60 @@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
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,
67 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
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)
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,
89 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
90 + if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
92 + count = ext4_free_inodes_count(sb, gdp);
93 + percpu_counter_sub(&sbi->s_freeinodes_counter,
96 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
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);
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)) {
113 + count = ext4_free_inodes_count(sb, desc);
114 + percpu_counter_sub(&sbi->s_freeinodes_counter,
117 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
120 @@ -321,6 +338,12 @@ out:
123 ext4_error(sb, "bit already cleared for inode %lu", ino);
124 + if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
126 + count = ext4_free_inodes_count(sb, gdp);
127 + percpu_counter_sub(&sbi->s_freeinodes_counter,
130 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
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);
145 @@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
146 * corrupt and update bb_free using bitmap value
149 + if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
150 + percpu_counter_sub(&sbi->s_freeclusters_counter,
152 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
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.",
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);