.. | .. |
---|
19 | 19 | #include <linux/fs.h> |
---|
20 | 20 | #include <linux/err.h> |
---|
21 | 21 | #include <linux/mount.h> |
---|
22 | | -#include <linux/parser.h> |
---|
| 22 | +#include <linux/fs_context.h> |
---|
| 23 | +#include <linux/fs_parser.h> |
---|
23 | 24 | #include <linux/jffs2.h> |
---|
24 | 25 | #include <linux/pagemap.h> |
---|
25 | 26 | #include <linux/mtd/super.h> |
---|
.. | .. |
---|
44 | 45 | return &f->vfs_inode; |
---|
45 | 46 | } |
---|
46 | 47 | |
---|
47 | | -static void jffs2_i_callback(struct rcu_head *head) |
---|
| 48 | +static void jffs2_free_inode(struct inode *inode) |
---|
48 | 49 | { |
---|
49 | | - struct inode *inode = container_of(head, struct inode, i_rcu); |
---|
50 | 50 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
---|
51 | 51 | |
---|
52 | 52 | kfree(f->target); |
---|
53 | 53 | kmem_cache_free(jffs2_inode_cachep, f); |
---|
54 | | -} |
---|
55 | | - |
---|
56 | | -static void jffs2_destroy_inode(struct inode *inode) |
---|
57 | | -{ |
---|
58 | | - call_rcu(&inode->i_rcu, jffs2_i_callback); |
---|
59 | 54 | } |
---|
60 | 55 | |
---|
61 | 56 | static void jffs2_i_init_once(void *foo) |
---|
.. | .. |
---|
93 | 88 | |
---|
94 | 89 | if (opts->override_compr) |
---|
95 | 90 | seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); |
---|
96 | | - if (opts->rp_size) |
---|
| 91 | + if (opts->set_rp_size) |
---|
97 | 92 | seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); |
---|
98 | 93 | |
---|
99 | 94 | return 0; |
---|
.. | .. |
---|
163 | 158 | /* |
---|
164 | 159 | * JFFS2 mount options. |
---|
165 | 160 | * |
---|
| 161 | + * Opt_source: The source device |
---|
166 | 162 | * Opt_override_compr: override default compressor |
---|
167 | 163 | * Opt_rp_size: size of reserved pool in KiB |
---|
168 | | - * Opt_err: just end of array marker |
---|
169 | 164 | */ |
---|
170 | 165 | enum { |
---|
171 | 166 | Opt_override_compr, |
---|
172 | 167 | Opt_rp_size, |
---|
173 | | - Opt_err, |
---|
174 | 168 | }; |
---|
175 | 169 | |
---|
176 | | -static const match_table_t tokens = { |
---|
177 | | - {Opt_override_compr, "compr=%s"}, |
---|
178 | | - {Opt_rp_size, "rp_size=%u"}, |
---|
179 | | - {Opt_err, NULL}, |
---|
180 | | -}; |
---|
181 | | - |
---|
182 | | -static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) |
---|
183 | | -{ |
---|
184 | | - substring_t args[MAX_OPT_ARGS]; |
---|
185 | | - char *p, *name; |
---|
186 | | - unsigned int opt; |
---|
187 | | - |
---|
188 | | - if (!data) |
---|
189 | | - return 0; |
---|
190 | | - |
---|
191 | | - while ((p = strsep(&data, ","))) { |
---|
192 | | - int token; |
---|
193 | | - |
---|
194 | | - if (!*p) |
---|
195 | | - continue; |
---|
196 | | - |
---|
197 | | - token = match_token(p, tokens, args); |
---|
198 | | - switch (token) { |
---|
199 | | - case Opt_override_compr: |
---|
200 | | - name = match_strdup(&args[0]); |
---|
201 | | - |
---|
202 | | - if (!name) |
---|
203 | | - return -ENOMEM; |
---|
204 | | - if (!strcmp(name, "none")) |
---|
205 | | - c->mount_opts.compr = JFFS2_COMPR_MODE_NONE; |
---|
| 170 | +static const struct constant_table jffs2_param_compr[] = { |
---|
| 171 | + {"none", JFFS2_COMPR_MODE_NONE }, |
---|
206 | 172 | #ifdef CONFIG_JFFS2_LZO |
---|
207 | | - else if (!strcmp(name, "lzo")) |
---|
208 | | - c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO; |
---|
| 173 | + {"lzo", JFFS2_COMPR_MODE_FORCELZO }, |
---|
209 | 174 | #endif |
---|
210 | 175 | #ifdef CONFIG_JFFS2_ZLIB |
---|
211 | | - else if (!strcmp(name, "zlib")) |
---|
212 | | - c->mount_opts.compr = |
---|
213 | | - JFFS2_COMPR_MODE_FORCEZLIB; |
---|
| 176 | + {"zlib", JFFS2_COMPR_MODE_FORCEZLIB }, |
---|
214 | 177 | #endif |
---|
215 | | - else { |
---|
216 | | - pr_err("Error: unknown compressor \"%s\"\n", |
---|
217 | | - name); |
---|
218 | | - kfree(name); |
---|
219 | | - return -EINVAL; |
---|
220 | | - } |
---|
221 | | - kfree(name); |
---|
222 | | - c->mount_opts.override_compr = true; |
---|
223 | | - break; |
---|
224 | | - case Opt_rp_size: |
---|
225 | | - if (match_int(&args[0], &opt)) |
---|
226 | | - return -EINVAL; |
---|
227 | | - opt *= 1024; |
---|
228 | | - if (opt > c->mtd->size) { |
---|
229 | | - pr_warn("Too large reserve pool specified, max " |
---|
230 | | - "is %llu KB\n", c->mtd->size / 1024); |
---|
231 | | - return -EINVAL; |
---|
232 | | - } |
---|
233 | | - c->mount_opts.rp_size = opt; |
---|
234 | | - break; |
---|
235 | | - default: |
---|
236 | | - pr_err("Error: unrecognized mount option '%s' or missing value\n", |
---|
237 | | - p); |
---|
238 | | - return -EINVAL; |
---|
239 | | - } |
---|
| 178 | + {} |
---|
| 179 | +}; |
---|
| 180 | + |
---|
| 181 | +static const struct fs_parameter_spec jffs2_fs_parameters[] = { |
---|
| 182 | + fsparam_enum ("compr", Opt_override_compr, jffs2_param_compr), |
---|
| 183 | + fsparam_u32 ("rp_size", Opt_rp_size), |
---|
| 184 | + {} |
---|
| 185 | +}; |
---|
| 186 | + |
---|
| 187 | +static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param) |
---|
| 188 | +{ |
---|
| 189 | + struct fs_parse_result result; |
---|
| 190 | + struct jffs2_sb_info *c = fc->s_fs_info; |
---|
| 191 | + int opt; |
---|
| 192 | + |
---|
| 193 | + opt = fs_parse(fc, jffs2_fs_parameters, param, &result); |
---|
| 194 | + if (opt < 0) |
---|
| 195 | + return opt; |
---|
| 196 | + |
---|
| 197 | + switch (opt) { |
---|
| 198 | + case Opt_override_compr: |
---|
| 199 | + c->mount_opts.compr = result.uint_32; |
---|
| 200 | + c->mount_opts.override_compr = true; |
---|
| 201 | + break; |
---|
| 202 | + case Opt_rp_size: |
---|
| 203 | + if (result.uint_32 > UINT_MAX / 1024) |
---|
| 204 | + return invalf(fc, "jffs2: rp_size unrepresentable"); |
---|
| 205 | + c->mount_opts.rp_size = result.uint_32 * 1024; |
---|
| 206 | + c->mount_opts.set_rp_size = true; |
---|
| 207 | + break; |
---|
| 208 | + default: |
---|
| 209 | + return -EINVAL; |
---|
240 | 210 | } |
---|
241 | 211 | |
---|
242 | 212 | return 0; |
---|
243 | 213 | } |
---|
244 | 214 | |
---|
245 | | -static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data) |
---|
| 215 | +static inline void jffs2_update_mount_opts(struct fs_context *fc) |
---|
246 | 216 | { |
---|
247 | | - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
---|
248 | | - int err; |
---|
| 217 | + struct jffs2_sb_info *new_c = fc->s_fs_info; |
---|
| 218 | + struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb); |
---|
| 219 | + |
---|
| 220 | + mutex_lock(&c->alloc_sem); |
---|
| 221 | + if (new_c->mount_opts.override_compr) { |
---|
| 222 | + c->mount_opts.override_compr = new_c->mount_opts.override_compr; |
---|
| 223 | + c->mount_opts.compr = new_c->mount_opts.compr; |
---|
| 224 | + } |
---|
| 225 | + if (new_c->mount_opts.set_rp_size) { |
---|
| 226 | + c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size; |
---|
| 227 | + c->mount_opts.rp_size = new_c->mount_opts.rp_size; |
---|
| 228 | + } |
---|
| 229 | + mutex_unlock(&c->alloc_sem); |
---|
| 230 | +} |
---|
| 231 | + |
---|
| 232 | +static int jffs2_reconfigure(struct fs_context *fc) |
---|
| 233 | +{ |
---|
| 234 | + struct super_block *sb = fc->root->d_sb; |
---|
249 | 235 | |
---|
250 | 236 | sync_filesystem(sb); |
---|
251 | | - err = jffs2_parse_options(c, data); |
---|
252 | | - if (err) |
---|
253 | | - return -EINVAL; |
---|
| 237 | + jffs2_update_mount_opts(fc); |
---|
254 | 238 | |
---|
255 | | - return jffs2_do_remount_fs(sb, flags, data); |
---|
| 239 | + return jffs2_do_remount_fs(sb, fc); |
---|
256 | 240 | } |
---|
257 | 241 | |
---|
258 | 242 | static const struct super_operations jffs2_super_operations = |
---|
259 | 243 | { |
---|
260 | 244 | .alloc_inode = jffs2_alloc_inode, |
---|
261 | | - .destroy_inode =jffs2_destroy_inode, |
---|
| 245 | + .free_inode = jffs2_free_inode, |
---|
262 | 246 | .put_super = jffs2_put_super, |
---|
263 | 247 | .statfs = jffs2_statfs, |
---|
264 | | - .remount_fs = jffs2_remount_fs, |
---|
265 | 248 | .evict_inode = jffs2_evict_inode, |
---|
266 | 249 | .dirty_inode = jffs2_dirty_inode, |
---|
267 | 250 | .show_options = jffs2_show_options, |
---|
.. | .. |
---|
271 | 254 | /* |
---|
272 | 255 | * fill in the superblock |
---|
273 | 256 | */ |
---|
274 | | -static int jffs2_fill_super(struct super_block *sb, void *data, int silent) |
---|
| 257 | +static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc) |
---|
275 | 258 | { |
---|
276 | | - struct jffs2_sb_info *c; |
---|
277 | | - int ret; |
---|
| 259 | + struct jffs2_sb_info *c = sb->s_fs_info; |
---|
278 | 260 | |
---|
279 | 261 | jffs2_dbg(1, "jffs2_get_sb_mtd():" |
---|
280 | 262 | " New superblock for device %d (\"%s\")\n", |
---|
281 | 263 | sb->s_mtd->index, sb->s_mtd->name); |
---|
282 | 264 | |
---|
283 | | - c = kzalloc(sizeof(*c), GFP_KERNEL); |
---|
284 | | - if (!c) |
---|
285 | | - return -ENOMEM; |
---|
286 | | - |
---|
287 | 265 | c->mtd = sb->s_mtd; |
---|
288 | 266 | c->os_priv = sb; |
---|
289 | | - sb->s_fs_info = c; |
---|
290 | 267 | |
---|
291 | | - ret = jffs2_parse_options(c, data); |
---|
292 | | - if (ret) |
---|
293 | | - return -EINVAL; |
---|
| 268 | + if (c->mount_opts.rp_size > c->mtd->size) |
---|
| 269 | + return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB", |
---|
| 270 | + c->mtd->size / 1024); |
---|
294 | 271 | |
---|
295 | 272 | /* Initialize JFFS2 superblock locks, the further initialization will |
---|
296 | 273 | * be done later */ |
---|
.. | .. |
---|
308 | 285 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
---|
309 | 286 | sb->s_flags |= SB_POSIXACL; |
---|
310 | 287 | #endif |
---|
311 | | - ret = jffs2_do_fill_super(sb, data, silent); |
---|
312 | | - return ret; |
---|
| 288 | + return jffs2_do_fill_super(sb, fc); |
---|
313 | 289 | } |
---|
314 | 290 | |
---|
315 | | -static struct dentry *jffs2_mount(struct file_system_type *fs_type, |
---|
316 | | - int flags, const char *dev_name, |
---|
317 | | - void *data) |
---|
| 291 | +static int jffs2_get_tree(struct fs_context *fc) |
---|
318 | 292 | { |
---|
319 | | - return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super); |
---|
| 293 | + return get_tree_mtd(fc, jffs2_fill_super); |
---|
| 294 | +} |
---|
| 295 | + |
---|
| 296 | +static void jffs2_free_fc(struct fs_context *fc) |
---|
| 297 | +{ |
---|
| 298 | + kfree(fc->s_fs_info); |
---|
| 299 | +} |
---|
| 300 | + |
---|
| 301 | +static const struct fs_context_operations jffs2_context_ops = { |
---|
| 302 | + .free = jffs2_free_fc, |
---|
| 303 | + .parse_param = jffs2_parse_param, |
---|
| 304 | + .get_tree = jffs2_get_tree, |
---|
| 305 | + .reconfigure = jffs2_reconfigure, |
---|
| 306 | +}; |
---|
| 307 | + |
---|
| 308 | +static int jffs2_init_fs_context(struct fs_context *fc) |
---|
| 309 | +{ |
---|
| 310 | + struct jffs2_sb_info *ctx; |
---|
| 311 | + |
---|
| 312 | + ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL); |
---|
| 313 | + if (!ctx) |
---|
| 314 | + return -ENOMEM; |
---|
| 315 | + |
---|
| 316 | + fc->s_fs_info = ctx; |
---|
| 317 | + fc->ops = &jffs2_context_ops; |
---|
| 318 | + return 0; |
---|
320 | 319 | } |
---|
321 | 320 | |
---|
322 | 321 | static void jffs2_put_super (struct super_block *sb) |
---|
.. | .. |
---|
353 | 352 | static struct file_system_type jffs2_fs_type = { |
---|
354 | 353 | .owner = THIS_MODULE, |
---|
355 | 354 | .name = "jffs2", |
---|
356 | | - .mount = jffs2_mount, |
---|
| 355 | + .init_fs_context = jffs2_init_fs_context, |
---|
| 356 | + .parameters = jffs2_fs_parameters, |
---|
357 | 357 | .kill_sb = jffs2_kill_sb, |
---|
358 | 358 | }; |
---|
359 | 359 | MODULE_ALIAS_FS("jffs2"); |
---|
.. | .. |
---|
439 | 439 | MODULE_AUTHOR("Red Hat, Inc."); |
---|
440 | 440 | MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for |
---|
441 | 441 | // the sake of this tag. It's Free Software. |
---|
| 442 | +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); |
---|