aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Shilong <wshilong@ddn.com>2018-07-29 17:27:45 -0400
committerTheodore Ts'o <tytso@mit.edu>2018-07-29 17:27:45 -0400
commit9af0b3d1257756394ebbd06b14937b557e3a756b (patch)
tree5ed219a153d49a4691ea5d2f729d742e80a69173
parentf39b3f45dbcb0343822cce31ea7636ad66e60bc2 (diff)
ext4: fix race when setting the bitmap corrupted flag
Whenever we hit block or inode bitmap corruptions we set bit and then reduce this block group free inode/clusters counter to expose right available space. However some of ext4_mark_group_bitmap_corrupted() is called inside group spinlock, some are not, this could make it happen that we double reduce one block group free counters from system. Always hold group spinlock for it could fix it, but it looks a little heavy, we could use test_and_set_bit() to fix race problems here. Signed-off-by: Wang Shilong <wshilong@ddn.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@vger.kernel.org
-rw-r--r--fs/ext4/super.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d4a218ba626c..f7750bc5b85a 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -795,26 +795,26 @@ void ext4_mark_group_bitmap_corrupted(struct super_block *sb,
795 struct ext4_sb_info *sbi = EXT4_SB(sb); 795 struct ext4_sb_info *sbi = EXT4_SB(sb);
796 struct ext4_group_info *grp = ext4_get_group_info(sb, group); 796 struct ext4_group_info *grp = ext4_get_group_info(sb, group);
797 struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); 797 struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
798 int ret;
798 799
799 if ((flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) && 800 if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) {
800 !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) { 801 ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
801 percpu_counter_sub(&sbi->s_freeclusters_counter, 802 &grp->bb_state);
802 grp->bb_free); 803 if (!ret)
803 set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, 804 percpu_counter_sub(&sbi->s_freeclusters_counter,
804 &grp->bb_state); 805 grp->bb_free);
805 } 806 }
806 807
807 if ((flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) && 808 if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) {
808 !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { 809 ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
809 if (gdp) { 810 &grp->bb_state);
811 if (!ret && gdp) {
810 int count; 812 int count;
811 813
812 count = ext4_free_inodes_count(sb, gdp); 814 count = ext4_free_inodes_count(sb, gdp);
813 percpu_counter_sub(&sbi->s_freeinodes_counter, 815 percpu_counter_sub(&sbi->s_freeinodes_counter,
814 count); 816 count);
815 } 817 }
816 set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
817 &grp->bb_state);
818 } 818 }
819} 819}
820 820