提交 d251ed27 编写于 作者: A Al Viro

ubifs: fix sget races

* allocate ubifs_info in ->mount(), fill it enough for sb_test() and
set ->s_fs_info to it in set() callback passed to sget().
* do *not* free it in ->put_super(); do that in ->kill_sb() after we'd
done kill_anon_super().
* don't free it in ubifs_fill_super() either - deactivate_locked_super()
done by caller when ubifs_fill_super() returns an error will take care
of that sucker.
* get rid of kludge with passing ubi to ubifs_fill_super() in ->s_fs_info;
we only need it in alloc_ubifs_info(), so ubifs_fill_super() will need
only ubifs_info.  Which it will find in ->s_fs_info just fine, no need to
reassign anything...

As the result, sb_test() becomes safe to apply to all superblocks that
can be found by sget() (and a kludge with temporary use of ->s_fs_info
to store a pointer to very different structure goes away).
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
上级 b1c27ab3
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
...@@ -1848,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb) ...@@ -1848,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb)
bdi_destroy(&c->bdi); bdi_destroy(&c->bdi);
ubi_close_volume(c->ubi); ubi_close_volume(c->ubi);
mutex_unlock(&c->umount_mutex); mutex_unlock(&c->umount_mutex);
kfree(c);
} }
static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
...@@ -2020,21 +2019,16 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) ...@@ -2020,21 +2019,16 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
static int ubifs_fill_super(struct super_block *sb, void *data, int silent) static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct ubi_volume_desc *ubi = sb->s_fs_info; struct ubifs_info *c = sb->s_fs_info;
struct ubifs_info *c;
struct inode *root; struct inode *root;
int err; int err;
c = alloc_ubifs_info(ubi);
if (!c)
return -ENOMEM;
c->vfs_sb = sb; c->vfs_sb = sb;
/* Re-open the UBI device in read-write mode */ /* Re-open the UBI device in read-write mode */
c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
if (IS_ERR(c->ubi)) { if (IS_ERR(c->ubi)) {
err = PTR_ERR(c->ubi); err = PTR_ERR(c->ubi);
goto out_free; goto out;
} }
/* /*
...@@ -2100,24 +2094,29 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2100,24 +2094,29 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
bdi_destroy(&c->bdi); bdi_destroy(&c->bdi);
out_close: out_close:
ubi_close_volume(c->ubi); ubi_close_volume(c->ubi);
out_free: out:
kfree(c);
return err; return err;
} }
static int sb_test(struct super_block *sb, void *data) static int sb_test(struct super_block *sb, void *data)
{ {
dev_t *dev = data; struct ubifs_info *c1 = data;
struct ubifs_info *c = sb->s_fs_info; struct ubifs_info *c = sb->s_fs_info;
return c->vi.cdev == *dev; return c->vi.cdev == c1->vi.cdev;
}
static int sb_set(struct super_block *sb, void *data)
{
sb->s_fs_info = data;
return set_anon_super(sb, NULL);
} }
static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
const char *name, void *data) const char *name, void *data)
{ {
struct ubi_volume_desc *ubi; struct ubi_volume_desc *ubi;
struct ubi_volume_info vi; struct ubifs_info *c;
struct super_block *sb; struct super_block *sb;
int err; int err;
...@@ -2134,19 +2133,24 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2134,19 +2133,24 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
name, (int)PTR_ERR(ubi)); name, (int)PTR_ERR(ubi));
return ERR_CAST(ubi); return ERR_CAST(ubi);
} }
ubi_get_volume_info(ubi, &vi);
dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); c = alloc_ubifs_info(ubi);
if (!c) {
err = -ENOMEM;
goto out_close;
}
dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); sb = sget(fs_type, sb_test, sb_set, c);
if (IS_ERR(sb)) { if (IS_ERR(sb)) {
err = PTR_ERR(sb); err = PTR_ERR(sb);
goto out_close; kfree(c);
} }
if (sb->s_root) { if (sb->s_root) {
struct ubifs_info *c1 = sb->s_fs_info; struct ubifs_info *c1 = sb->s_fs_info;
kfree(c);
/* A new mount point for already mounted UBIFS */ /* A new mount point for already mounted UBIFS */
dbg_gen("this ubi volume is already mounted"); dbg_gen("this ubi volume is already mounted");
if (!!(flags & MS_RDONLY) != c1->ro_mount) { if (!!(flags & MS_RDONLY) != c1->ro_mount) {
...@@ -2155,11 +2159,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2155,11 +2159,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
} }
} else { } else {
sb->s_flags = flags; sb->s_flags = flags;
/*
* Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
* replaced by 'c'.
*/
sb->s_fs_info = ubi;
err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
if (err) if (err)
goto out_deact; goto out_deact;
...@@ -2179,11 +2178,18 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2179,11 +2178,18 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
return ERR_PTR(err); return ERR_PTR(err);
} }
static void kill_ubifs_super(struct super_block *s)
{
struct ubifs_info *c = s->s_fs_info;
kill_anon_super(s);
kfree(c);
}
static struct file_system_type ubifs_fs_type = { static struct file_system_type ubifs_fs_type = {
.name = "ubifs", .name = "ubifs",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.mount = ubifs_mount, .mount = ubifs_mount,
.kill_sb = kill_anon_super, .kill_sb = kill_ubifs_super,
}; };
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部