diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-08-26 13:22:27 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-08-26 13:22:27 -0400 |
commit | f632265d0ffb5acf331252d98c64939849d96bb2 (patch) | |
tree | 31187d9a726bf1ca6ca12e26ad8e7c609eaf4d8b /fs/super.c | |
parent | 7d94784293096c0a46897acdb83be5abd9278ece (diff) | |
parent | da5cabf80e2433131bf0ed8993abc0f7ea618c73 (diff) |
Merge commit 'v2.6.36-rc1' into HEAD
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/fs/super.c b/fs/super.c index 5c35bc7a499e..9674ab2c8718 100644 --- a/fs/super.c +++ b/fs/super.c @@ -305,8 +305,13 @@ retry: if (s) { up_write(&s->s_umount); destroy_super(s); + s = NULL; } down_write(&old->s_umount); + if (unlikely(!(old->s_flags & MS_BORN))) { + deactivate_locked_super(old); + goto retry; + } return old; } } @@ -358,10 +363,10 @@ EXPORT_SYMBOL(drop_super); */ void sync_supers(void) { - struct super_block *sb, *n; + struct super_block *sb, *p = NULL; spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { + list_for_each_entry(sb, &super_blocks, s_list) { if (list_empty(&sb->s_instances)) continue; if (sb->s_op->write_super && sb->s_dirt) { @@ -374,9 +379,13 @@ void sync_supers(void) up_read(&sb->s_umount); spin_lock(&sb_lock); - __put_super(sb); + if (p) + __put_super(p); + p = sb; } } + if (p) + __put_super(p); spin_unlock(&sb_lock); } @@ -390,10 +399,10 @@ void sync_supers(void) */ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) { - struct super_block *sb, *n; + struct super_block *sb, *p = NULL; spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { + list_for_each_entry(sb, &super_blocks, s_list) { if (list_empty(&sb->s_instances)) continue; sb->s_count++; @@ -405,8 +414,12 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) up_read(&sb->s_umount); spin_lock(&sb_lock); - __put_super(sb); + if (p) + __put_super(p); + p = sb; } + if (p) + __put_super(p); spin_unlock(&sb_lock); } @@ -568,10 +581,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) static void do_emergency_remount(struct work_struct *work) { - struct super_block *sb, *n; + struct super_block *sb, *p = NULL; spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { + list_for_each_entry(sb, &super_blocks, s_list) { if (list_empty(&sb->s_instances)) continue; sb->s_count++; @@ -585,8 +598,12 @@ static void do_emergency_remount(struct work_struct *work) } up_write(&sb->s_umount); spin_lock(&sb_lock); - __put_super(sb); + if (p) + __put_super(p); + p = sb; } + if (p) + __put_super(p); spin_unlock(&sb_lock); kfree(work); printk("Emergency Remount complete\n"); @@ -767,7 +784,16 @@ int get_sb_bdev(struct file_system_type *fs_type, goto error_bdev; } + /* + * s_umount nests inside bd_mutex during + * __invalidate_device(). close_bdev_exclusive() + * acquires bd_mutex and can't be called under + * s_umount. Drop s_umount temporarily. This is safe + * as we're holding an active reference. + */ + up_write(&s->s_umount); close_bdev_exclusive(bdev, mode); + down_write(&s->s_umount); } else { char b[BDEVNAME_SIZE]; @@ -903,6 +929,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void goto out_free_secdata; BUG_ON(!mnt->mnt_sb); WARN_ON(!mnt->mnt_sb->s_bdi); + mnt->mnt_sb->s_flags |= MS_BORN; error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); if (error) |