aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/ext4.h
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-05-01 08:50:38 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-05-01 08:50:38 -0400
commit8df9675f8b498d0bfa1f0b5b06f56bf1ff366dd5 (patch)
tree38fd56a82049f50b4d774af47b9d39f116071755 /fs/ext4/ext4.h
parent9ca92389c5312a51e819c15c762f0abdc7f3129b (diff)
ext4: Avoid races caused by on-line resizing and SMP memory reordering
Ext4's on-line resizing adds a new block group and then, only at the last step adjusts s_groups_count. However, it's possible on SMP systems that another CPU could see the updated the s_group_count and not see the newly initialized data structures for the just-added block group. For this reason, it's important to insert a SMP read barrier after reading s_groups_count and before reading any (for example) the new block group descriptors allowed by the increased value of s_groups_count. Unfortunately, we rather blatently violate this locking protocol documented in fs/ext4/resize.c. Fortunately, (1) on-line resizes happen relatively rarely, and (2) it seems rare that the filesystem code will immediately try to use just-added block group before any memory ordering issues resolve themselves. So apparently problems here are relatively hard to hit, since ext3 has been vulnerable to the same issue for years with no one apparently complaining. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/ext4.h')
-rw-r--r--fs/ext4/ext4.h12
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index d0f15ef56de1..02ec44bf38e6 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1228,6 +1228,18 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
1228 return grp_info[indexv][indexh]; 1228 return grp_info[indexv][indexh];
1229} 1229}
1230 1230
1231/*
1232 * Reading s_groups_count requires using smp_rmb() afterwards. See
1233 * the locking protocol documented in the comments of ext4_group_add()
1234 * in resize.c
1235 */
1236static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
1237{
1238 ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
1239
1240 smp_rmb();
1241 return ngroups;
1242}
1231 1243
1232static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi, 1244static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
1233 ext4_group_t block_group) 1245 ext4_group_t block_group)