diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-05-01 08:50:38 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-05-01 08:50:38 -0400 |
commit | 8df9675f8b498d0bfa1f0b5b06f56bf1ff366dd5 (patch) | |
tree | 38fd56a82049f50b4d774af47b9d39f116071755 /fs/ext4/super.c | |
parent | 9ca92389c5312a51e819c15c762f0abdc7f3129b (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/super.c')
-rw-r--r-- | fs/ext4/super.c | 3 |
1 files changed, 1 insertions, 2 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 68c3a44c4a97..fcd7b24c6df3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -3557,9 +3557,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
3557 | if (test_opt(sb, MINIX_DF)) { | 3557 | if (test_opt(sb, MINIX_DF)) { |
3558 | sbi->s_overhead_last = 0; | 3558 | sbi->s_overhead_last = 0; |
3559 | } else if (sbi->s_blocks_last != ext4_blocks_count(es)) { | 3559 | } else if (sbi->s_blocks_last != ext4_blocks_count(es)) { |
3560 | ext4_group_t ngroups = sbi->s_groups_count, i; | 3560 | ext4_group_t i, ngroups = ext4_get_groups_count(sb); |
3561 | ext4_fsblk_t overhead = 0; | 3561 | ext4_fsblk_t overhead = 0; |
3562 | smp_rmb(); | ||
3563 | 3562 | ||
3564 | /* | 3563 | /* |
3565 | * Compute the overhead (FS structures). This is constant | 3564 | * Compute the overhead (FS structures). This is constant |