aboutsummaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-01-03 21:01:29 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2012-01-03 22:53:10 -0500
commitdabe0dc194d5d56d379a8994fff47392744b6491 (patch)
tree16696a688d5b6386c6183cc6137807af38e1d9d1 /fs/super.c
parentcf31e70d6cf93f19fe9bf1144966ef40991ac723 (diff)
vfs: fix the rest of sget() races
unfortunately, just checking MS_BORN after having grabbed ->s_umount in sget() is not enough; places that pick superblock from a list and grab s_umount shared need the same check in addition to checking for ->s_root; otherwise three-way race between failing mount, sget() and such list-walker can leave us with list-walker coming *second*, when temporary active ref grabbed by sget() (to be dropped when sget() notices that original mount has failed by checking MS_BORN) has lead to deactivate_locked_super() from failing ->mount() *not* doing ->kill_sb() and just releasing ->s_umount. Once sget() gets through and notices that MS_BORN had never been set it will drop the active ref and fs will be shut down and kicked out of all lists, but it's too late for something like sync_supers(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/fs/super.c b/fs/super.c
index bab11bad13ba..0413f51a9f0f 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -337,7 +337,7 @@ bool grab_super_passive(struct super_block *sb)
337 spin_unlock(&sb_lock); 337 spin_unlock(&sb_lock);
338 338
339 if (down_read_trylock(&sb->s_umount)) { 339 if (down_read_trylock(&sb->s_umount)) {
340 if (sb->s_root) 340 if (sb->s_root && (sb->s_flags & MS_BORN))
341 return true; 341 return true;
342 up_read(&sb->s_umount); 342 up_read(&sb->s_umount);
343 } 343 }
@@ -505,7 +505,7 @@ void sync_supers(void)
505 spin_unlock(&sb_lock); 505 spin_unlock(&sb_lock);
506 506
507 down_read(&sb->s_umount); 507 down_read(&sb->s_umount);
508 if (sb->s_root && sb->s_dirt) 508 if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN))
509 sb->s_op->write_super(sb); 509 sb->s_op->write_super(sb);
510 up_read(&sb->s_umount); 510 up_read(&sb->s_umount);
511 511
@@ -540,7 +540,7 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg)
540 spin_unlock(&sb_lock); 540 spin_unlock(&sb_lock);
541 541
542 down_read(&sb->s_umount); 542 down_read(&sb->s_umount);
543 if (sb->s_root) 543 if (sb->s_root && (sb->s_flags & MS_BORN))
544 f(sb, arg); 544 f(sb, arg);
545 up_read(&sb->s_umount); 545 up_read(&sb->s_umount);
546 546
@@ -575,7 +575,7 @@ void iterate_supers_type(struct file_system_type *type,
575 spin_unlock(&sb_lock); 575 spin_unlock(&sb_lock);
576 576
577 down_read(&sb->s_umount); 577 down_read(&sb->s_umount);
578 if (sb->s_root) 578 if (sb->s_root && (sb->s_flags & MS_BORN))
579 f(sb, arg); 579 f(sb, arg);
580 up_read(&sb->s_umount); 580 up_read(&sb->s_umount);
581 581
@@ -616,7 +616,7 @@ rescan:
616 spin_unlock(&sb_lock); 616 spin_unlock(&sb_lock);
617 down_read(&sb->s_umount); 617 down_read(&sb->s_umount);
618 /* still alive? */ 618 /* still alive? */
619 if (sb->s_root) 619 if (sb->s_root && (sb->s_flags & MS_BORN))
620 return sb; 620 return sb;
621 up_read(&sb->s_umount); 621 up_read(&sb->s_umount);
622 /* nope, got unmounted */ 622 /* nope, got unmounted */
@@ -676,7 +676,7 @@ rescan:
676 spin_unlock(&sb_lock); 676 spin_unlock(&sb_lock);
677 down_read(&sb->s_umount); 677 down_read(&sb->s_umount);
678 /* still alive? */ 678 /* still alive? */
679 if (sb->s_root) 679 if (sb->s_root && (sb->s_flags & MS_BORN))
680 return sb; 680 return sb;
681 up_read(&sb->s_umount); 681 up_read(&sb->s_umount);
682 /* nope, got unmounted */ 682 /* nope, got unmounted */
@@ -763,7 +763,8 @@ static void do_emergency_remount(struct work_struct *work)
763 sb->s_count++; 763 sb->s_count++;
764 spin_unlock(&sb_lock); 764 spin_unlock(&sb_lock);
765 down_write(&sb->s_umount); 765 down_write(&sb->s_umount);
766 if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) { 766 if (sb->s_root && sb->s_bdev && (sb->s_flags & MS_BORN) &&
767 !(sb->s_flags & MS_RDONLY)) {
767 /* 768 /*
768 * What lock protects sb->s_flags?? 769 * What lock protects sb->s_flags??
769 */ 770 */
@@ -1146,6 +1147,11 @@ int freeze_super(struct super_block *sb)
1146 return -EBUSY; 1147 return -EBUSY;
1147 } 1148 }
1148 1149
1150 if (!(sb->s_flags & MS_BORN)) {
1151 up_write(&sb->s_umount);
1152 return 0; /* sic - it's "nothing to do" */
1153 }
1154
1149 if (sb->s_flags & MS_RDONLY) { 1155 if (sb->s_flags & MS_RDONLY) {
1150 sb->s_frozen = SB_FREEZE_TRANS; 1156 sb->s_frozen = SB_FREEZE_TRANS;
1151 smp_wmb(); 1157 smp_wmb();