aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ubifs/super.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-06-12 10:24:33 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-06-12 17:45:34 -0400
commitd251ed271d528afb407cc2ede30923e34cb209a5 (patch)
treeb77e0133453057821ee50956c560013acb467c4c /fs/ubifs/super.c
parentb1c27ab3f93daede979f804afc38b189c2f17c60 (diff)
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: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ubifs/super.c')
-rw-r--r--fs/ubifs/super.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index ddc3b02e8cf0..8c892c2d5300 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1848,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb)
1848 bdi_destroy(&c->bdi); 1848 bdi_destroy(&c->bdi);
1849 ubi_close_volume(c->ubi); 1849 ubi_close_volume(c->ubi);
1850 mutex_unlock(&c->umount_mutex); 1850 mutex_unlock(&c->umount_mutex);
1851 kfree(c);
1852} 1851}
1853 1852
1854static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) 1853static 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 2019
2021static int ubifs_fill_super(struct super_block *sb, void *data, int silent) 2020static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
2022{ 2021{
2023 struct ubi_volume_desc *ubi = sb->s_fs_info; 2022 struct ubifs_info *c = sb->s_fs_info;
2024 struct ubifs_info *c;
2025 struct inode *root; 2023 struct inode *root;
2026 int err; 2024 int err;
2027 2025
2028 c = alloc_ubifs_info(ubi);
2029 if (!c)
2030 return -ENOMEM;
2031
2032 c->vfs_sb = sb; 2026 c->vfs_sb = sb;
2033 /* Re-open the UBI device in read-write mode */ 2027 /* Re-open the UBI device in read-write mode */
2034 c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); 2028 c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
2035 if (IS_ERR(c->ubi)) { 2029 if (IS_ERR(c->ubi)) {
2036 err = PTR_ERR(c->ubi); 2030 err = PTR_ERR(c->ubi);
2037 goto out_free; 2031 goto out;
2038 } 2032 }
2039 2033
2040 /* 2034 /*
@@ -2100,24 +2094,29 @@ out_bdi:
2100 bdi_destroy(&c->bdi); 2094 bdi_destroy(&c->bdi);
2101out_close: 2095out_close:
2102 ubi_close_volume(c->ubi); 2096 ubi_close_volume(c->ubi);
2103out_free: 2097out:
2104 kfree(c);
2105 return err; 2098 return err;
2106} 2099}
2107 2100
2108static int sb_test(struct super_block *sb, void *data) 2101static int sb_test(struct super_block *sb, void *data)
2109{ 2102{
2110 dev_t *dev = data; 2103 struct ubifs_info *c1 = data;
2111 struct ubifs_info *c = sb->s_fs_info; 2104 struct ubifs_info *c = sb->s_fs_info;
2112 2105
2113 return c->vi.cdev == *dev; 2106 return c->vi.cdev == c1->vi.cdev;
2107}
2108
2109static int sb_set(struct super_block *sb, void *data)
2110{
2111 sb->s_fs_info = data;
2112 return set_anon_super(sb, NULL);
2114} 2113}
2115 2114
2116static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, 2115static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
2117 const char *name, void *data) 2116 const char *name, void *data)
2118{ 2117{
2119 struct ubi_volume_desc *ubi; 2118 struct ubi_volume_desc *ubi;
2120 struct ubi_volume_info vi; 2119 struct ubifs_info *c;
2121 struct super_block *sb; 2120 struct super_block *sb;
2122 int err; 2121 int err;
2123 2122
@@ -2134,19 +2133,24 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
2134 name, (int)PTR_ERR(ubi)); 2133 name, (int)PTR_ERR(ubi));
2135 return ERR_CAST(ubi); 2134 return ERR_CAST(ubi);
2136 } 2135 }
2137 ubi_get_volume_info(ubi, &vi);
2138 2136
2139 dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); 2137 c = alloc_ubifs_info(ubi);
2138 if (!c) {
2139 err = -ENOMEM;
2140 goto out_close;
2141 }
2142
2143 dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
2140 2144
2141 sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); 2145 sb = sget(fs_type, sb_test, sb_set, c);
2142 if (IS_ERR(sb)) { 2146 if (IS_ERR(sb)) {
2143 err = PTR_ERR(sb); 2147 err = PTR_ERR(sb);
2144 goto out_close; 2148 kfree(c);
2145 } 2149 }
2146 2150
2147 if (sb->s_root) { 2151 if (sb->s_root) {
2148 struct ubifs_info *c1 = sb->s_fs_info; 2152 struct ubifs_info *c1 = sb->s_fs_info;
2149 2153 kfree(c);
2150 /* A new mount point for already mounted UBIFS */ 2154 /* A new mount point for already mounted UBIFS */
2151 dbg_gen("this ubi volume is already mounted"); 2155 dbg_gen("this ubi volume is already mounted");
2152 if (!!(flags & MS_RDONLY) != c1->ro_mount) { 2156 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 } 2159 }
2156 } else { 2160 } else {
2157 sb->s_flags = flags; 2161 sb->s_flags = flags;
2158 /*
2159 * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
2160 * replaced by 'c'.
2161 */
2162 sb->s_fs_info = ubi;
2163 err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); 2162 err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
2164 if (err) 2163 if (err)
2165 goto out_deact; 2164 goto out_deact;
@@ -2179,11 +2178,18 @@ out_close:
2179 return ERR_PTR(err); 2178 return ERR_PTR(err);
2180} 2179}
2181 2180
2181static void kill_ubifs_super(struct super_block *s)
2182{
2183 struct ubifs_info *c = s->s_fs_info;
2184 kill_anon_super(s);
2185 kfree(c);
2186}
2187
2182static struct file_system_type ubifs_fs_type = { 2188static struct file_system_type ubifs_fs_type = {
2183 .name = "ubifs", 2189 .name = "ubifs",
2184 .owner = THIS_MODULE, 2190 .owner = THIS_MODULE,
2185 .mount = ubifs_mount, 2191 .mount = ubifs_mount,
2186 .kill_sb = kill_anon_super, 2192 .kill_sb = kill_ubifs_super,
2187}; 2193};
2188 2194
2189/* 2195/*