diff options
Diffstat (limited to 'fs/jffs2/super.c')
-rw-r--r-- | fs/jffs2/super.c | 172 |
1 files changed, 83 insertions, 89 deletions
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index af4aa6599473..cbe70637c117 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -19,7 +19,8 @@ | |||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/parser.h> | 22 | #include <linux/fs_context.h> |
23 | #include <linux/fs_parser.h> | ||
23 | #include <linux/jffs2.h> | 24 | #include <linux/jffs2.h> |
24 | #include <linux/pagemap.h> | 25 | #include <linux/pagemap.h> |
25 | #include <linux/mtd/super.h> | 26 | #include <linux/mtd/super.h> |
@@ -157,96 +158,77 @@ static const struct export_operations jffs2_export_ops = { | |||
157 | /* | 158 | /* |
158 | * JFFS2 mount options. | 159 | * JFFS2 mount options. |
159 | * | 160 | * |
161 | * Opt_source: The source device | ||
160 | * Opt_override_compr: override default compressor | 162 | * Opt_override_compr: override default compressor |
161 | * Opt_rp_size: size of reserved pool in KiB | 163 | * Opt_rp_size: size of reserved pool in KiB |
162 | * Opt_err: just end of array marker | ||
163 | */ | 164 | */ |
164 | enum { | 165 | enum { |
166 | Opt_source, | ||
165 | Opt_override_compr, | 167 | Opt_override_compr, |
166 | Opt_rp_size, | 168 | Opt_rp_size, |
167 | Opt_err, | ||
168 | }; | 169 | }; |
169 | 170 | ||
170 | static const match_table_t tokens = { | 171 | static const struct fs_parameter_spec jffs2_param_specs[] = { |
171 | {Opt_override_compr, "compr=%s"}, | 172 | fsparam_string ("source", Opt_source), |
172 | {Opt_rp_size, "rp_size=%u"}, | 173 | fsparam_enum ("compr", Opt_override_compr), |
173 | {Opt_err, NULL}, | 174 | fsparam_u32 ("rp_size", Opt_rp_size), |
175 | {} | ||
174 | }; | 176 | }; |
175 | 177 | ||
176 | static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) | 178 | static const struct fs_parameter_enum jffs2_param_enums[] = { |
177 | { | 179 | { Opt_override_compr, "none", JFFS2_COMPR_MODE_NONE }, |
178 | substring_t args[MAX_OPT_ARGS]; | ||
179 | char *p, *name; | ||
180 | unsigned int opt; | ||
181 | |||
182 | if (!data) | ||
183 | return 0; | ||
184 | |||
185 | while ((p = strsep(&data, ","))) { | ||
186 | int token; | ||
187 | |||
188 | if (!*p) | ||
189 | continue; | ||
190 | |||
191 | token = match_token(p, tokens, args); | ||
192 | switch (token) { | ||
193 | case Opt_override_compr: | ||
194 | name = match_strdup(&args[0]); | ||
195 | |||
196 | if (!name) | ||
197 | return -ENOMEM; | ||
198 | if (!strcmp(name, "none")) | ||
199 | c->mount_opts.compr = JFFS2_COMPR_MODE_NONE; | ||
200 | #ifdef CONFIG_JFFS2_LZO | 180 | #ifdef CONFIG_JFFS2_LZO |
201 | else if (!strcmp(name, "lzo")) | 181 | { Opt_override_compr, "lzo", JFFS2_COMPR_MODE_FORCELZO }, |
202 | c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO; | ||
203 | #endif | 182 | #endif |
204 | #ifdef CONFIG_JFFS2_ZLIB | 183 | #ifdef CONFIG_JFFS2_ZLIB |
205 | else if (!strcmp(name, "zlib")) | 184 | { Opt_override_compr, "zlib", JFFS2_COMPR_MODE_FORCEZLIB }, |
206 | c->mount_opts.compr = | ||
207 | JFFS2_COMPR_MODE_FORCEZLIB; | ||
208 | #endif | 185 | #endif |
209 | else { | 186 | {} |
210 | pr_err("Error: unknown compressor \"%s\"\n", | 187 | }; |
211 | name); | 188 | |
212 | kfree(name); | 189 | const struct fs_parameter_description jffs2_fs_parameters = { |
213 | return -EINVAL; | 190 | .name = "jffs2", |
214 | } | 191 | .specs = jffs2_param_specs, |
215 | kfree(name); | 192 | .enums = jffs2_param_enums, |
216 | c->mount_opts.override_compr = true; | 193 | }; |
217 | break; | 194 | |
218 | case Opt_rp_size: | 195 | static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param) |
219 | if (match_int(&args[0], &opt)) | 196 | { |
220 | return -EINVAL; | 197 | struct fs_parse_result result; |
221 | opt *= 1024; | 198 | struct jffs2_sb_info *c = fc->s_fs_info; |
222 | if (opt > c->mtd->size) { | 199 | int opt; |
223 | pr_warn("Too large reserve pool specified, max " | 200 | |
224 | "is %llu KB\n", c->mtd->size / 1024); | 201 | opt = fs_parse(fc, &jffs2_fs_parameters, param, &result); |
225 | return -EINVAL; | 202 | if (opt < 0) |
226 | } | 203 | return opt; |
227 | c->mount_opts.rp_size = opt; | 204 | |
228 | break; | 205 | switch (opt) { |
229 | default: | 206 | case Opt_override_compr: |
230 | pr_err("Error: unrecognized mount option '%s' or missing value\n", | 207 | c->mount_opts.compr = result.uint_32; |
231 | p); | 208 | c->mount_opts.override_compr = true; |
232 | return -EINVAL; | 209 | break; |
233 | } | 210 | case Opt_rp_size: |
211 | if (result.uint_32 > UINT_MAX / 1024) | ||
212 | return invalf(fc, "jffs2: rp_size unrepresentable"); | ||
213 | opt = result.uint_32 * 1024; | ||
214 | if (opt > c->mtd->size) | ||
215 | return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB", | ||
216 | c->mtd->size / 1024); | ||
217 | c->mount_opts.rp_size = opt; | ||
218 | break; | ||
219 | default: | ||
220 | return -EINVAL; | ||
234 | } | 221 | } |
235 | 222 | ||
236 | return 0; | 223 | return 0; |
237 | } | 224 | } |
238 | 225 | ||
239 | static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data) | 226 | static int jffs2_reconfigure(struct fs_context *fc) |
240 | { | 227 | { |
241 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 228 | struct super_block *sb = fc->root->d_sb; |
242 | int err; | ||
243 | 229 | ||
244 | sync_filesystem(sb); | 230 | sync_filesystem(sb); |
245 | err = jffs2_parse_options(c, data); | 231 | return jffs2_do_remount_fs(sb, fc); |
246 | if (err) | ||
247 | return -EINVAL; | ||
248 | |||
249 | return jffs2_do_remount_fs(sb, flags, data); | ||
250 | } | 232 | } |
251 | 233 | ||
252 | static const struct super_operations jffs2_super_operations = | 234 | static const struct super_operations jffs2_super_operations = |
@@ -255,7 +237,6 @@ static const struct super_operations jffs2_super_operations = | |||
255 | .free_inode = jffs2_free_inode, | 237 | .free_inode = jffs2_free_inode, |
256 | .put_super = jffs2_put_super, | 238 | .put_super = jffs2_put_super, |
257 | .statfs = jffs2_statfs, | 239 | .statfs = jffs2_statfs, |
258 | .remount_fs = jffs2_remount_fs, | ||
259 | .evict_inode = jffs2_evict_inode, | 240 | .evict_inode = jffs2_evict_inode, |
260 | .dirty_inode = jffs2_dirty_inode, | 241 | .dirty_inode = jffs2_dirty_inode, |
261 | .show_options = jffs2_show_options, | 242 | .show_options = jffs2_show_options, |
@@ -265,26 +246,16 @@ static const struct super_operations jffs2_super_operations = | |||
265 | /* | 246 | /* |
266 | * fill in the superblock | 247 | * fill in the superblock |
267 | */ | 248 | */ |
268 | static int jffs2_fill_super(struct super_block *sb, void *data, int silent) | 249 | static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc) |
269 | { | 250 | { |
270 | struct jffs2_sb_info *c; | 251 | struct jffs2_sb_info *c = sb->s_fs_info; |
271 | int ret; | ||
272 | 252 | ||
273 | jffs2_dbg(1, "jffs2_get_sb_mtd():" | 253 | jffs2_dbg(1, "jffs2_get_sb_mtd():" |
274 | " New superblock for device %d (\"%s\")\n", | 254 | " New superblock for device %d (\"%s\")\n", |
275 | sb->s_mtd->index, sb->s_mtd->name); | 255 | sb->s_mtd->index, sb->s_mtd->name); |
276 | 256 | ||
277 | c = kzalloc(sizeof(*c), GFP_KERNEL); | ||
278 | if (!c) | ||
279 | return -ENOMEM; | ||
280 | |||
281 | c->mtd = sb->s_mtd; | 257 | c->mtd = sb->s_mtd; |
282 | c->os_priv = sb; | 258 | c->os_priv = sb; |
283 | sb->s_fs_info = c; | ||
284 | |||
285 | ret = jffs2_parse_options(c, data); | ||
286 | if (ret) | ||
287 | return -EINVAL; | ||
288 | 259 | ||
289 | /* Initialize JFFS2 superblock locks, the further initialization will | 260 | /* Initialize JFFS2 superblock locks, the further initialization will |
290 | * be done later */ | 261 | * be done later */ |
@@ -302,15 +273,37 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) | |||
302 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 273 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
303 | sb->s_flags |= SB_POSIXACL; | 274 | sb->s_flags |= SB_POSIXACL; |
304 | #endif | 275 | #endif |
305 | ret = jffs2_do_fill_super(sb, data, silent); | 276 | return jffs2_do_fill_super(sb, fc); |
306 | return ret; | ||
307 | } | 277 | } |
308 | 278 | ||
309 | static struct dentry *jffs2_mount(struct file_system_type *fs_type, | 279 | static int jffs2_get_tree(struct fs_context *fc) |
310 | int flags, const char *dev_name, | ||
311 | void *data) | ||
312 | { | 280 | { |
313 | return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super); | 281 | return get_tree_mtd(fc, jffs2_fill_super); |
282 | } | ||
283 | |||
284 | static void jffs2_free_fc(struct fs_context *fc) | ||
285 | { | ||
286 | kfree(fc->s_fs_info); | ||
287 | } | ||
288 | |||
289 | static const struct fs_context_operations jffs2_context_ops = { | ||
290 | .free = jffs2_free_fc, | ||
291 | .parse_param = jffs2_parse_param, | ||
292 | .get_tree = jffs2_get_tree, | ||
293 | .reconfigure = jffs2_reconfigure, | ||
294 | }; | ||
295 | |||
296 | static int jffs2_init_fs_context(struct fs_context *fc) | ||
297 | { | ||
298 | struct jffs2_sb_info *ctx; | ||
299 | |||
300 | ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL); | ||
301 | if (!ctx) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | fc->s_fs_info = ctx; | ||
305 | fc->ops = &jffs2_context_ops; | ||
306 | return 0; | ||
314 | } | 307 | } |
315 | 308 | ||
316 | static void jffs2_put_super (struct super_block *sb) | 309 | static void jffs2_put_super (struct super_block *sb) |
@@ -347,7 +340,8 @@ static void jffs2_kill_sb(struct super_block *sb) | |||
347 | static struct file_system_type jffs2_fs_type = { | 340 | static struct file_system_type jffs2_fs_type = { |
348 | .owner = THIS_MODULE, | 341 | .owner = THIS_MODULE, |
349 | .name = "jffs2", | 342 | .name = "jffs2", |
350 | .mount = jffs2_mount, | 343 | .init_fs_context = jffs2_init_fs_context, |
344 | .parameters = &jffs2_fs_parameters, | ||
351 | .kill_sb = jffs2_kill_sb, | 345 | .kill_sb = jffs2_kill_sb, |
352 | }; | 346 | }; |
353 | MODULE_ALIAS_FS("jffs2"); | 347 | MODULE_ALIAS_FS("jffs2"); |