aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <jaxboe@fusionio.com>2011-03-17 11:13:12 +0100
committerPaul Gortmaker <paul.gortmaker@windriver.com>2012-08-17 15:34:58 -0400
commitbc661f5d238569cae7ca9da01e12451b7785fb01 (patch)
treea8a49679d74ca6c609dd0971c2046de97466b687
parent075c4ced91c551cdc2e9bb99b1697c3d54be106e (diff)
fs: assign sb->s_bdi to default_backing_dev_info if the bdi is going away
commit 95f28604a65b1c40b6c6cd95e58439cd7ded3add upstream. We don't have proper reference counting for this yet, so we run into cases where the device is pulled and we OOPS on flushing the fs data. This happens even though the dirty inodes have already been migrated to the default_backing_dev_info. Reported-by: Torsten Hilbrich <torsten.hilbrich@secunet.com> Tested-by: Torsten Hilbrich <torsten.hilbrich@secunet.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
-rw-r--r--fs/super.c2
-rw-r--r--fs/sync.c4
-rw-r--r--mm/backing-dev.c2
3 files changed, 5 insertions, 3 deletions
diff --git a/fs/super.c b/fs/super.c
index 53040a673bf..7123fa728af 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -64,6 +64,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
goto out;
}
INIT_LIST_HEAD(&s->s_files);
+ s->s_bdi = &default_backing_dev_info;
INIT_LIST_HEAD(&s->s_instances);
INIT_HLIST_HEAD(&s->s_anon);
INIT_LIST_HEAD(&s->s_inodes);
@@ -962,6 +963,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);
+ WARN_ON(mnt->mnt_sb->s_bdi == &default_backing_dev_info);
mnt->mnt_sb->s_flags |= MS_BORN;
error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
diff --git a/fs/sync.c b/fs/sync.c
index 92b228176f7..5281fb372d5 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -33,7 +33,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
* This should be safe, as we require bdi backing to actually
* write out data in the first place
*/
- if (!sb->s_bdi || sb->s_bdi == &noop_backing_dev_info)
+ if (sb->s_bdi == &noop_backing_dev_info)
return 0;
if (sb->s_qcop && sb->s_qcop->quota_sync)
@@ -110,7 +110,7 @@ restart:
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
- if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi)
+ if (!(sb->s_flags & MS_RDONLY) && sb->s_root)
__sync_filesystem(sb, wait);
up_read(&sb->s_umount);
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 707d0dc6da0..7bd17d294b8 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -634,7 +634,7 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
spin_lock(&sb_lock);
list_for_each_entry(sb, &super_blocks, s_list) {
if (sb->s_bdi == bdi)
- sb->s_bdi = NULL;
+ sb->s_bdi = &default_backing_dev_info;
}
spin_unlock(&sb_lock);
}