diff options
-rw-r--r-- | drivers/base/devtmpfs.c | 38 | ||||
-rw-r--r-- | drivers/mtd/mtdsuper.c | 189 | ||||
-rw-r--r-- | fs/cramfs/inode.c | 69 | ||||
-rw-r--r-- | fs/fs_parser.c | 18 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 21 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 4 | ||||
-rw-r--r-- | fs/jffs2/super.c | 172 | ||||
-rw-r--r-- | fs/ramfs/inode.c | 99 | ||||
-rw-r--r-- | fs/romfs/super.c | 46 | ||||
-rw-r--r-- | fs/squashfs/super.c | 100 | ||||
-rw-r--r-- | fs/super.c | 35 | ||||
-rw-r--r-- | include/linux/fs_context.h | 4 | ||||
-rw-r--r-- | include/linux/mtd/super.h | 3 | ||||
-rw-r--r-- | include/linux/ramfs.h | 6 | ||||
-rw-r--r-- | include/linux/shmem_fs.h | 3 | ||||
-rw-r--r-- | init/do_mounts.c | 11 | ||||
-rw-r--r-- | mm/shmem.c | 385 |
17 files changed, 609 insertions, 594 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index ba5c80903efe..30d0523014e0 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
@@ -56,20 +56,32 @@ static int __init mount_param(char *str) | |||
56 | } | 56 | } |
57 | __setup("devtmpfs.mount=", mount_param); | 57 | __setup("devtmpfs.mount=", mount_param); |
58 | 58 | ||
59 | static struct dentry *dev_mount(struct file_system_type *fs_type, int flags, | 59 | static struct vfsmount *mnt; |
60 | |||
61 | static struct dentry *public_dev_mount(struct file_system_type *fs_type, int flags, | ||
60 | const char *dev_name, void *data) | 62 | const char *dev_name, void *data) |
61 | { | 63 | { |
64 | struct super_block *s = mnt->mnt_sb; | ||
65 | atomic_inc(&s->s_active); | ||
66 | down_write(&s->s_umount); | ||
67 | return dget(s->s_root); | ||
68 | } | ||
69 | |||
70 | static struct file_system_type internal_fs_type = { | ||
71 | .name = "devtmpfs", | ||
62 | #ifdef CONFIG_TMPFS | 72 | #ifdef CONFIG_TMPFS |
63 | return mount_single(fs_type, flags, data, shmem_fill_super); | 73 | .init_fs_context = shmem_init_fs_context, |
74 | .parameters = &shmem_fs_parameters, | ||
64 | #else | 75 | #else |
65 | return mount_single(fs_type, flags, data, ramfs_fill_super); | 76 | .init_fs_context = ramfs_init_fs_context, |
77 | .parameters = &ramfs_fs_parameters, | ||
66 | #endif | 78 | #endif |
67 | } | 79 | .kill_sb = kill_litter_super, |
80 | }; | ||
68 | 81 | ||
69 | static struct file_system_type dev_fs_type = { | 82 | static struct file_system_type dev_fs_type = { |
70 | .name = "devtmpfs", | 83 | .name = "devtmpfs", |
71 | .mount = dev_mount, | 84 | .mount = public_dev_mount, |
72 | .kill_sb = kill_litter_super, | ||
73 | }; | 85 | }; |
74 | 86 | ||
75 | #ifdef CONFIG_BLOCK | 87 | #ifdef CONFIG_BLOCK |
@@ -378,12 +390,11 @@ static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid, | |||
378 | 390 | ||
379 | static int devtmpfsd(void *p) | 391 | static int devtmpfsd(void *p) |
380 | { | 392 | { |
381 | char options[] = "mode=0755"; | ||
382 | int *err = p; | 393 | int *err = p; |
383 | *err = ksys_unshare(CLONE_NEWNS); | 394 | *err = ksys_unshare(CLONE_NEWNS); |
384 | if (*err) | 395 | if (*err) |
385 | goto out; | 396 | goto out; |
386 | *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options); | 397 | *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL); |
387 | if (*err) | 398 | if (*err) |
388 | goto out; | 399 | goto out; |
389 | ksys_chdir("/.."); /* will traverse into overmounted root */ | 400 | ksys_chdir("/.."); /* will traverse into overmounted root */ |
@@ -420,7 +431,16 @@ out: | |||
420 | */ | 431 | */ |
421 | int __init devtmpfs_init(void) | 432 | int __init devtmpfs_init(void) |
422 | { | 433 | { |
423 | int err = register_filesystem(&dev_fs_type); | 434 | char opts[] = "mode=0755"; |
435 | int err; | ||
436 | |||
437 | mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", opts); | ||
438 | if (IS_ERR(mnt)) { | ||
439 | printk(KERN_ERR "devtmpfs: unable to create devtmpfs %ld\n", | ||
440 | PTR_ERR(mnt)); | ||
441 | return PTR_ERR(mnt); | ||
442 | } | ||
443 | err = register_filesystem(&dev_fs_type); | ||
424 | if (err) { | 444 | if (err) { |
425 | printk(KERN_ERR "devtmpfs: unable to register devtmpfs " | 445 | printk(KERN_ERR "devtmpfs: unable to register devtmpfs " |
426 | "type %i\n", err); | 446 | "type %i\n", err); |
diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 3f9a3b7b12c5..c3e2098372f2 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c | |||
@@ -194,195 +194,6 @@ int get_tree_mtd(struct fs_context *fc, | |||
194 | EXPORT_SYMBOL_GPL(get_tree_mtd); | 194 | EXPORT_SYMBOL_GPL(get_tree_mtd); |
195 | 195 | ||
196 | /* | 196 | /* |
197 | * compare superblocks to see if they're equivalent | ||
198 | * - they are if the underlying MTD device is the same | ||
199 | */ | ||
200 | static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) | ||
201 | { | ||
202 | struct mtd_info *mtd = _mtd; | ||
203 | |||
204 | if (sb->s_mtd == mtd) { | ||
205 | pr_debug("MTDSB: Match on device %d (\"%s\")\n", | ||
206 | mtd->index, mtd->name); | ||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", | ||
211 | sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * mark the superblock by the MTD device it is using | ||
217 | * - set the device number to be the correct MTD block device for pesuperstence | ||
218 | * of NFS exports | ||
219 | */ | ||
220 | static int get_sb_mtd_set(struct super_block *sb, void *_mtd) | ||
221 | { | ||
222 | struct mtd_info *mtd = _mtd; | ||
223 | |||
224 | sb->s_mtd = mtd; | ||
225 | sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, mtd->index); | ||
226 | sb->s_bdi = bdi_get(mtd_bdi); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * get a superblock on an MTD-backed filesystem | ||
233 | */ | ||
234 | static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, | ||
235 | const char *dev_name, void *data, | ||
236 | struct mtd_info *mtd, | ||
237 | int (*fill_super)(struct super_block *, void *, int)) | ||
238 | { | ||
239 | struct super_block *sb; | ||
240 | int ret; | ||
241 | |||
242 | sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, flags, mtd); | ||
243 | if (IS_ERR(sb)) | ||
244 | goto out_error; | ||
245 | |||
246 | if (sb->s_root) | ||
247 | goto already_mounted; | ||
248 | |||
249 | /* fresh new superblock */ | ||
250 | pr_debug("MTDSB: New superblock for device %d (\"%s\")\n", | ||
251 | mtd->index, mtd->name); | ||
252 | |||
253 | ret = fill_super(sb, data, flags & SB_SILENT ? 1 : 0); | ||
254 | if (ret < 0) { | ||
255 | deactivate_locked_super(sb); | ||
256 | return ERR_PTR(ret); | ||
257 | } | ||
258 | |||
259 | /* go */ | ||
260 | sb->s_flags |= SB_ACTIVE; | ||
261 | return dget(sb->s_root); | ||
262 | |||
263 | /* new mountpoint for an already mounted superblock */ | ||
264 | already_mounted: | ||
265 | pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n", | ||
266 | mtd->index, mtd->name); | ||
267 | put_mtd_device(mtd); | ||
268 | return dget(sb->s_root); | ||
269 | |||
270 | out_error: | ||
271 | put_mtd_device(mtd); | ||
272 | return ERR_CAST(sb); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * get a superblock on an MTD-backed filesystem by MTD device number | ||
277 | */ | ||
278 | static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, | ||
279 | const char *dev_name, void *data, int mtdnr, | ||
280 | int (*fill_super)(struct super_block *, void *, int)) | ||
281 | { | ||
282 | struct mtd_info *mtd; | ||
283 | |||
284 | mtd = get_mtd_device(NULL, mtdnr); | ||
285 | if (IS_ERR(mtd)) { | ||
286 | pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr); | ||
287 | return ERR_CAST(mtd); | ||
288 | } | ||
289 | |||
290 | return mount_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super); | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * set up an MTD-based superblock | ||
295 | */ | ||
296 | struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, | ||
297 | const char *dev_name, void *data, | ||
298 | int (*fill_super)(struct super_block *, void *, int)) | ||
299 | { | ||
300 | #ifdef CONFIG_BLOCK | ||
301 | struct block_device *bdev; | ||
302 | int ret, major; | ||
303 | #endif | ||
304 | int mtdnr; | ||
305 | |||
306 | if (!dev_name) | ||
307 | return ERR_PTR(-EINVAL); | ||
308 | |||
309 | pr_debug("MTDSB: dev_name \"%s\"\n", dev_name); | ||
310 | |||
311 | /* the preferred way of mounting in future; especially when | ||
312 | * CONFIG_BLOCK=n - we specify the underlying MTD device by number or | ||
313 | * by name, so that we don't require block device support to be present | ||
314 | * in the kernel. */ | ||
315 | if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { | ||
316 | if (dev_name[3] == ':') { | ||
317 | struct mtd_info *mtd; | ||
318 | |||
319 | /* mount by MTD device name */ | ||
320 | pr_debug("MTDSB: mtd:%%s, name \"%s\"\n", | ||
321 | dev_name + 4); | ||
322 | |||
323 | mtd = get_mtd_device_nm(dev_name + 4); | ||
324 | if (!IS_ERR(mtd)) | ||
325 | return mount_mtd_aux( | ||
326 | fs_type, flags, | ||
327 | dev_name, data, mtd, | ||
328 | fill_super); | ||
329 | |||
330 | printk(KERN_NOTICE "MTD:" | ||
331 | " MTD device with name \"%s\" not found.\n", | ||
332 | dev_name + 4); | ||
333 | |||
334 | } else if (isdigit(dev_name[3])) { | ||
335 | /* mount by MTD device number name */ | ||
336 | char *endptr; | ||
337 | |||
338 | mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); | ||
339 | if (!*endptr) { | ||
340 | /* It was a valid number */ | ||
341 | pr_debug("MTDSB: mtd%%d, mtdnr %d\n", | ||
342 | mtdnr); | ||
343 | return mount_mtd_nr(fs_type, flags, | ||
344 | dev_name, data, | ||
345 | mtdnr, fill_super); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | #ifdef CONFIG_BLOCK | ||
351 | /* try the old way - the hack where we allowed users to mount | ||
352 | * /dev/mtdblock$(n) but didn't actually _use_ the blockdev | ||
353 | */ | ||
354 | bdev = lookup_bdev(dev_name); | ||
355 | if (IS_ERR(bdev)) { | ||
356 | ret = PTR_ERR(bdev); | ||
357 | pr_debug("MTDSB: lookup_bdev() returned %d\n", ret); | ||
358 | return ERR_PTR(ret); | ||
359 | } | ||
360 | pr_debug("MTDSB: lookup_bdev() returned 0\n"); | ||
361 | |||
362 | ret = -EINVAL; | ||
363 | |||
364 | major = MAJOR(bdev->bd_dev); | ||
365 | mtdnr = MINOR(bdev->bd_dev); | ||
366 | bdput(bdev); | ||
367 | |||
368 | if (major != MTD_BLOCK_MAJOR) | ||
369 | goto not_an_MTD_device; | ||
370 | |||
371 | return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super); | ||
372 | |||
373 | not_an_MTD_device: | ||
374 | #endif /* CONFIG_BLOCK */ | ||
375 | |||
376 | if (!(flags & SB_SILENT)) | ||
377 | printk(KERN_NOTICE | ||
378 | "MTD: Attempt to mount non-MTD device \"%s\"\n", | ||
379 | dev_name); | ||
380 | return ERR_PTR(-EINVAL); | ||
381 | } | ||
382 | |||
383 | EXPORT_SYMBOL_GPL(mount_mtd); | ||
384 | |||
385 | /* | ||
386 | * destroy an MTD-based superblock | 197 | * destroy an MTD-based superblock |
387 | */ | 198 | */ |
388 | void kill_mtd_super(struct super_block *sb) | 199 | void kill_mtd_super(struct super_block *sb) |
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 4d1d8b7761ed..d12ea28836a5 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/blkdev.h> | 24 | #include <linux/blkdev.h> |
25 | #include <linux/mtd/mtd.h> | 25 | #include <linux/mtd/mtd.h> |
26 | #include <linux/mtd/super.h> | 26 | #include <linux/mtd/super.h> |
27 | #include <linux/fs_context.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/vfs.h> | 29 | #include <linux/vfs.h> |
29 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
@@ -506,18 +507,19 @@ static void cramfs_kill_sb(struct super_block *sb) | |||
506 | kfree(sbi); | 507 | kfree(sbi); |
507 | } | 508 | } |
508 | 509 | ||
509 | static int cramfs_remount(struct super_block *sb, int *flags, char *data) | 510 | static int cramfs_reconfigure(struct fs_context *fc) |
510 | { | 511 | { |
511 | sync_filesystem(sb); | 512 | sync_filesystem(fc->root->d_sb); |
512 | *flags |= SB_RDONLY; | 513 | fc->sb_flags |= SB_RDONLY; |
513 | return 0; | 514 | return 0; |
514 | } | 515 | } |
515 | 516 | ||
516 | static int cramfs_read_super(struct super_block *sb, | 517 | static int cramfs_read_super(struct super_block *sb, struct fs_context *fc, |
517 | struct cramfs_super *super, int silent) | 518 | struct cramfs_super *super) |
518 | { | 519 | { |
519 | struct cramfs_sb_info *sbi = CRAMFS_SB(sb); | 520 | struct cramfs_sb_info *sbi = CRAMFS_SB(sb); |
520 | unsigned long root_offset; | 521 | unsigned long root_offset; |
522 | bool silent = fc->sb_flags & SB_SILENT; | ||
521 | 523 | ||
522 | /* We don't know the real size yet */ | 524 | /* We don't know the real size yet */ |
523 | sbi->size = PAGE_SIZE; | 525 | sbi->size = PAGE_SIZE; |
@@ -532,7 +534,7 @@ static int cramfs_read_super(struct super_block *sb, | |||
532 | /* check for wrong endianness */ | 534 | /* check for wrong endianness */ |
533 | if (super->magic == CRAMFS_MAGIC_WEND) { | 535 | if (super->magic == CRAMFS_MAGIC_WEND) { |
534 | if (!silent) | 536 | if (!silent) |
535 | pr_err("wrong endianness\n"); | 537 | errorf(fc, "cramfs: wrong endianness"); |
536 | return -EINVAL; | 538 | return -EINVAL; |
537 | } | 539 | } |
538 | 540 | ||
@@ -544,22 +546,22 @@ static int cramfs_read_super(struct super_block *sb, | |||
544 | mutex_unlock(&read_mutex); | 546 | mutex_unlock(&read_mutex); |
545 | if (super->magic != CRAMFS_MAGIC) { | 547 | if (super->magic != CRAMFS_MAGIC) { |
546 | if (super->magic == CRAMFS_MAGIC_WEND && !silent) | 548 | if (super->magic == CRAMFS_MAGIC_WEND && !silent) |
547 | pr_err("wrong endianness\n"); | 549 | errorf(fc, "cramfs: wrong endianness"); |
548 | else if (!silent) | 550 | else if (!silent) |
549 | pr_err("wrong magic\n"); | 551 | errorf(fc, "cramfs: wrong magic"); |
550 | return -EINVAL; | 552 | return -EINVAL; |
551 | } | 553 | } |
552 | } | 554 | } |
553 | 555 | ||
554 | /* get feature flags first */ | 556 | /* get feature flags first */ |
555 | if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) { | 557 | if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) { |
556 | pr_err("unsupported filesystem features\n"); | 558 | errorf(fc, "cramfs: unsupported filesystem features"); |
557 | return -EINVAL; | 559 | return -EINVAL; |
558 | } | 560 | } |
559 | 561 | ||
560 | /* Check that the root inode is in a sane state */ | 562 | /* Check that the root inode is in a sane state */ |
561 | if (!S_ISDIR(super->root.mode)) { | 563 | if (!S_ISDIR(super->root.mode)) { |
562 | pr_err("root is not a directory\n"); | 564 | errorf(fc, "cramfs: root is not a directory"); |
563 | return -EINVAL; | 565 | return -EINVAL; |
564 | } | 566 | } |
565 | /* correct strange, hard-coded permissions of mkcramfs */ | 567 | /* correct strange, hard-coded permissions of mkcramfs */ |
@@ -578,12 +580,12 @@ static int cramfs_read_super(struct super_block *sb, | |||
578 | sbi->magic = super->magic; | 580 | sbi->magic = super->magic; |
579 | sbi->flags = super->flags; | 581 | sbi->flags = super->flags; |
580 | if (root_offset == 0) | 582 | if (root_offset == 0) |
581 | pr_info("empty filesystem"); | 583 | infof(fc, "cramfs: empty filesystem"); |
582 | else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && | 584 | else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && |
583 | ((root_offset != sizeof(struct cramfs_super)) && | 585 | ((root_offset != sizeof(struct cramfs_super)) && |
584 | (root_offset != 512 + sizeof(struct cramfs_super)))) | 586 | (root_offset != 512 + sizeof(struct cramfs_super)))) |
585 | { | 587 | { |
586 | pr_err("bad root offset %lu\n", root_offset); | 588 | errorf(fc, "cramfs: bad root offset %lu", root_offset); |
587 | return -EINVAL; | 589 | return -EINVAL; |
588 | } | 590 | } |
589 | 591 | ||
@@ -609,8 +611,7 @@ static int cramfs_finalize_super(struct super_block *sb, | |||
609 | return 0; | 611 | return 0; |
610 | } | 612 | } |
611 | 613 | ||
612 | static int cramfs_blkdev_fill_super(struct super_block *sb, void *data, | 614 | static int cramfs_blkdev_fill_super(struct super_block *sb, struct fs_context *fc) |
613 | int silent) | ||
614 | { | 615 | { |
615 | struct cramfs_sb_info *sbi; | 616 | struct cramfs_sb_info *sbi; |
616 | struct cramfs_super super; | 617 | struct cramfs_super super; |
@@ -625,14 +626,13 @@ static int cramfs_blkdev_fill_super(struct super_block *sb, void *data, | |||
625 | for (i = 0; i < READ_BUFFERS; i++) | 626 | for (i = 0; i < READ_BUFFERS; i++) |
626 | buffer_blocknr[i] = -1; | 627 | buffer_blocknr[i] = -1; |
627 | 628 | ||
628 | err = cramfs_read_super(sb, &super, silent); | 629 | err = cramfs_read_super(sb, fc, &super); |
629 | if (err) | 630 | if (err) |
630 | return err; | 631 | return err; |
631 | return cramfs_finalize_super(sb, &super.root); | 632 | return cramfs_finalize_super(sb, &super.root); |
632 | } | 633 | } |
633 | 634 | ||
634 | static int cramfs_mtd_fill_super(struct super_block *sb, void *data, | 635 | static int cramfs_mtd_fill_super(struct super_block *sb, struct fs_context *fc) |
635 | int silent) | ||
636 | { | 636 | { |
637 | struct cramfs_sb_info *sbi; | 637 | struct cramfs_sb_info *sbi; |
638 | struct cramfs_super super; | 638 | struct cramfs_super super; |
@@ -654,7 +654,7 @@ static int cramfs_mtd_fill_super(struct super_block *sb, void *data, | |||
654 | 654 | ||
655 | pr_info("checking physical address %pap for linear cramfs image\n", | 655 | pr_info("checking physical address %pap for linear cramfs image\n", |
656 | &sbi->linear_phys_addr); | 656 | &sbi->linear_phys_addr); |
657 | err = cramfs_read_super(sb, &super, silent); | 657 | err = cramfs_read_super(sb, fc, &super); |
658 | if (err) | 658 | if (err) |
659 | return err; | 659 | return err; |
660 | 660 | ||
@@ -949,32 +949,41 @@ static const struct inode_operations cramfs_dir_inode_operations = { | |||
949 | }; | 949 | }; |
950 | 950 | ||
951 | static const struct super_operations cramfs_ops = { | 951 | static const struct super_operations cramfs_ops = { |
952 | .remount_fs = cramfs_remount, | ||
953 | .statfs = cramfs_statfs, | 952 | .statfs = cramfs_statfs, |
954 | }; | 953 | }; |
955 | 954 | ||
956 | static struct dentry *cramfs_mount(struct file_system_type *fs_type, int flags, | 955 | static int cramfs_get_tree(struct fs_context *fc) |
957 | const char *dev_name, void *data) | ||
958 | { | 956 | { |
959 | struct dentry *ret = ERR_PTR(-ENOPROTOOPT); | 957 | int ret = -ENOPROTOOPT; |
960 | 958 | ||
961 | if (IS_ENABLED(CONFIG_CRAMFS_MTD)) { | 959 | if (IS_ENABLED(CONFIG_CRAMFS_MTD)) { |
962 | ret = mount_mtd(fs_type, flags, dev_name, data, | 960 | ret = get_tree_mtd(fc, cramfs_mtd_fill_super); |
963 | cramfs_mtd_fill_super); | 961 | if (ret < 0) |
964 | if (!IS_ERR(ret)) | ||
965 | return ret; | 962 | return ret; |
966 | } | 963 | } |
967 | if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) { | 964 | if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) |
968 | ret = mount_bdev(fs_type, flags, dev_name, data, | 965 | ret = get_tree_bdev(fc, cramfs_blkdev_fill_super); |
969 | cramfs_blkdev_fill_super); | ||
970 | } | ||
971 | return ret; | 966 | return ret; |
972 | } | 967 | } |
973 | 968 | ||
969 | static const struct fs_context_operations cramfs_context_ops = { | ||
970 | .get_tree = cramfs_get_tree, | ||
971 | .reconfigure = cramfs_reconfigure, | ||
972 | }; | ||
973 | |||
974 | /* | ||
975 | * Set up the filesystem mount context. | ||
976 | */ | ||
977 | static int cramfs_init_fs_context(struct fs_context *fc) | ||
978 | { | ||
979 | fc->ops = &cramfs_context_ops; | ||
980 | return 0; | ||
981 | } | ||
982 | |||
974 | static struct file_system_type cramfs_fs_type = { | 983 | static struct file_system_type cramfs_fs_type = { |
975 | .owner = THIS_MODULE, | 984 | .owner = THIS_MODULE, |
976 | .name = "cramfs", | 985 | .name = "cramfs", |
977 | .mount = cramfs_mount, | 986 | .init_fs_context = cramfs_init_fs_context, |
978 | .kill_sb = cramfs_kill_sb, | 987 | .kill_sb = cramfs_kill_sb, |
979 | .fs_flags = FS_REQUIRES_DEV, | 988 | .fs_flags = FS_REQUIRES_DEV, |
980 | }; | 989 | }; |
diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 460ea4206fa2..d1930adce68d 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c | |||
@@ -204,9 +204,23 @@ int fs_parse(struct fs_context *fc, | |||
204 | goto okay; | 204 | goto okay; |
205 | 205 | ||
206 | case fs_param_is_fd: { | 206 | case fs_param_is_fd: { |
207 | if (param->type != fs_value_is_file) | 207 | switch (param->type) { |
208 | case fs_value_is_string: | ||
209 | if (!result->has_value) | ||
210 | goto bad_value; | ||
211 | |||
212 | ret = kstrtouint(param->string, 0, &result->uint_32); | ||
213 | break; | ||
214 | case fs_value_is_file: | ||
215 | result->uint_32 = param->dirfd; | ||
216 | ret = 0; | ||
217 | default: | ||
208 | goto bad_value; | 218 | goto bad_value; |
209 | goto okay; | 219 | } |
220 | |||
221 | if (result->uint_32 > INT_MAX) | ||
222 | goto bad_value; | ||
223 | goto maybe_okay; | ||
210 | } | 224 | } |
211 | 225 | ||
212 | case fs_param_is_blockdev: | 226 | case fs_param_is_blockdev: |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index d0b59d03a7a9..05fe6cf5f1ac 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/cred.h> | 18 | #include <linux/cred.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/fs_context.h> | ||
20 | #include <linux/list.h> | 21 | #include <linux/list.h> |
21 | #include <linux/mtd/mtd.h> | 22 | #include <linux/mtd/mtd.h> |
22 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
@@ -184,7 +185,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
184 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { | 185 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { |
185 | truncate_setsize(inode, iattr->ia_size); | 186 | truncate_setsize(inode, iattr->ia_size); |
186 | inode->i_blocks = (inode->i_size + 511) >> 9; | 187 | inode->i_blocks = (inode->i_size + 511) >> 9; |
187 | } | 188 | } |
188 | 189 | ||
189 | return 0; | 190 | return 0; |
190 | } | 191 | } |
@@ -391,7 +392,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags) | |||
391 | jffs2_do_setattr(inode, &iattr); | 392 | jffs2_do_setattr(inode, &iattr); |
392 | } | 393 | } |
393 | 394 | ||
394 | int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data) | 395 | int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc) |
395 | { | 396 | { |
396 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 397 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
397 | 398 | ||
@@ -409,10 +410,10 @@ int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data) | |||
409 | mutex_unlock(&c->alloc_sem); | 410 | mutex_unlock(&c->alloc_sem); |
410 | } | 411 | } |
411 | 412 | ||
412 | if (!(*flags & SB_RDONLY)) | 413 | if (!(fc->sb_flags & SB_RDONLY)) |
413 | jffs2_start_garbage_collect_thread(c); | 414 | jffs2_start_garbage_collect_thread(c); |
414 | 415 | ||
415 | *flags |= SB_NOATIME; | 416 | fc->sb_flags |= SB_NOATIME; |
416 | return 0; | 417 | return 0; |
417 | } | 418 | } |
418 | 419 | ||
@@ -509,7 +510,7 @@ static int calculate_inocache_hashsize(uint32_t flash_size) | |||
509 | return hashsize; | 510 | return hashsize; |
510 | } | 511 | } |
511 | 512 | ||
512 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | 513 | int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) |
513 | { | 514 | { |
514 | struct jffs2_sb_info *c; | 515 | struct jffs2_sb_info *c; |
515 | struct inode *root_i; | 516 | struct inode *root_i; |
@@ -524,11 +525,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
524 | 525 | ||
525 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER | 526 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
526 | if (c->mtd->type == MTD_NANDFLASH) { | 527 | if (c->mtd->type == MTD_NANDFLASH) { |
527 | pr_err("Cannot operate on NAND flash unless jffs2 NAND support is compiled in\n"); | 528 | errorf(fc, "Cannot operate on NAND flash unless jffs2 NAND support is compiled in"); |
528 | return -EINVAL; | 529 | return -EINVAL; |
529 | } | 530 | } |
530 | if (c->mtd->type == MTD_DATAFLASH) { | 531 | if (c->mtd->type == MTD_DATAFLASH) { |
531 | pr_err("Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in\n"); | 532 | errorf(fc, "Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in"); |
532 | return -EINVAL; | 533 | return -EINVAL; |
533 | } | 534 | } |
534 | #endif | 535 | #endif |
@@ -542,12 +543,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
542 | */ | 543 | */ |
543 | if ((c->sector_size * blocks) != c->flash_size) { | 544 | if ((c->sector_size * blocks) != c->flash_size) { |
544 | c->flash_size = c->sector_size * blocks; | 545 | c->flash_size = c->sector_size * blocks; |
545 | pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n", | 546 | infof(fc, "Flash size not aligned to erasesize, reducing to %dKiB", |
546 | c->flash_size / 1024); | 547 | c->flash_size / 1024); |
547 | } | 548 | } |
548 | 549 | ||
549 | if (c->flash_size < 5*c->sector_size) { | 550 | if (c->flash_size < 5*c->sector_size) { |
550 | pr_err("Too few erase blocks (%d)\n", | 551 | errorf(fc, "Too few erase blocks (%d)", |
551 | c->flash_size / c->sector_size); | 552 | c->flash_size / c->sector_size); |
552 | return -EINVAL; | 553 | return -EINVAL; |
553 | } | 554 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index bd3d5f0ddc34..21071fc2975d 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -172,8 +172,8 @@ void jffs2_dirty_inode(struct inode *inode, int flags); | |||
172 | struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, | 172 | struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, |
173 | struct jffs2_raw_inode *ri); | 173 | struct jffs2_raw_inode *ri); |
174 | int jffs2_statfs (struct dentry *, struct kstatfs *); | 174 | int jffs2_statfs (struct dentry *, struct kstatfs *); |
175 | int jffs2_do_remount_fs(struct super_block *, int *, char *); | 175 | int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc); |
176 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); | 176 | int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc); |
177 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, | 177 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, |
178 | struct jffs2_inode_info *f); | 178 | struct jffs2_inode_info *f); |
179 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | 179 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, |
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"); |
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 733c6b4193dc..d82636e8eb65 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/magic.h> | 36 | #include <linux/magic.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/uaccess.h> | 38 | #include <linux/uaccess.h> |
39 | #include <linux/fs_context.h> | ||
40 | #include <linux/fs_parser.h> | ||
39 | #include "internal.h" | 41 | #include "internal.h" |
40 | 42 | ||
41 | struct ramfs_mount_opts { | 43 | struct ramfs_mount_opts { |
@@ -175,62 +177,52 @@ static const struct super_operations ramfs_ops = { | |||
175 | .show_options = ramfs_show_options, | 177 | .show_options = ramfs_show_options, |
176 | }; | 178 | }; |
177 | 179 | ||
178 | enum { | 180 | enum ramfs_param { |
179 | Opt_mode, | 181 | Opt_mode, |
180 | Opt_err | ||
181 | }; | 182 | }; |
182 | 183 | ||
183 | static const match_table_t tokens = { | 184 | static const struct fs_parameter_spec ramfs_param_specs[] = { |
184 | {Opt_mode, "mode=%o"}, | 185 | fsparam_u32oct("mode", Opt_mode), |
185 | {Opt_err, NULL} | 186 | {} |
186 | }; | 187 | }; |
187 | 188 | ||
188 | static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) | 189 | const struct fs_parameter_description ramfs_fs_parameters = { |
190 | .name = "ramfs", | ||
191 | .specs = ramfs_param_specs, | ||
192 | }; | ||
193 | |||
194 | static int ramfs_parse_param(struct fs_context *fc, struct fs_parameter *param) | ||
189 | { | 195 | { |
190 | substring_t args[MAX_OPT_ARGS]; | 196 | struct fs_parse_result result; |
191 | int option; | 197 | struct ramfs_fs_info *fsi = fc->s_fs_info; |
192 | int token; | 198 | int opt; |
193 | char *p; | 199 | |
194 | 200 | opt = fs_parse(fc, &ramfs_fs_parameters, param, &result); | |
195 | opts->mode = RAMFS_DEFAULT_MODE; | 201 | if (opt < 0) { |
196 | |||
197 | while ((p = strsep(&data, ",")) != NULL) { | ||
198 | if (!*p) | ||
199 | continue; | ||
200 | |||
201 | token = match_token(p, tokens, args); | ||
202 | switch (token) { | ||
203 | case Opt_mode: | ||
204 | if (match_octal(&args[0], &option)) | ||
205 | return -EINVAL; | ||
206 | opts->mode = option & S_IALLUGO; | ||
207 | break; | ||
208 | /* | 202 | /* |
209 | * We might like to report bad mount options here; | 203 | * We might like to report bad mount options here; |
210 | * but traditionally ramfs has ignored all mount options, | 204 | * but traditionally ramfs has ignored all mount options, |
211 | * and as it is used as a !CONFIG_SHMEM simple substitute | 205 | * and as it is used as a !CONFIG_SHMEM simple substitute |
212 | * for tmpfs, better continue to ignore other mount options. | 206 | * for tmpfs, better continue to ignore other mount options. |
213 | */ | 207 | */ |
214 | } | 208 | if (opt == -ENOPARAM) |
209 | opt = 0; | ||
210 | return opt; | ||
211 | } | ||
212 | |||
213 | switch (opt) { | ||
214 | case Opt_mode: | ||
215 | fsi->mount_opts.mode = result.uint_32 & S_IALLUGO; | ||
216 | break; | ||
215 | } | 217 | } |
216 | 218 | ||
217 | return 0; | 219 | return 0; |
218 | } | 220 | } |
219 | 221 | ||
220 | int ramfs_fill_super(struct super_block *sb, void *data, int silent) | 222 | static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc) |
221 | { | 223 | { |
222 | struct ramfs_fs_info *fsi; | 224 | struct ramfs_fs_info *fsi = sb->s_fs_info; |
223 | struct inode *inode; | 225 | struct inode *inode; |
224 | int err; | ||
225 | |||
226 | fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); | ||
227 | sb->s_fs_info = fsi; | ||
228 | if (!fsi) | ||
229 | return -ENOMEM; | ||
230 | |||
231 | err = ramfs_parse_options(data, &fsi->mount_opts); | ||
232 | if (err) | ||
233 | return err; | ||
234 | 226 | ||
235 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 227 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
236 | sb->s_blocksize = PAGE_SIZE; | 228 | sb->s_blocksize = PAGE_SIZE; |
@@ -247,10 +239,34 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) | |||
247 | return 0; | 239 | return 0; |
248 | } | 240 | } |
249 | 241 | ||
250 | struct dentry *ramfs_mount(struct file_system_type *fs_type, | 242 | static int ramfs_get_tree(struct fs_context *fc) |
251 | int flags, const char *dev_name, void *data) | ||
252 | { | 243 | { |
253 | return mount_nodev(fs_type, flags, data, ramfs_fill_super); | 244 | return get_tree_nodev(fc, ramfs_fill_super); |
245 | } | ||
246 | |||
247 | static void ramfs_free_fc(struct fs_context *fc) | ||
248 | { | ||
249 | kfree(fc->s_fs_info); | ||
250 | } | ||
251 | |||
252 | static const struct fs_context_operations ramfs_context_ops = { | ||
253 | .free = ramfs_free_fc, | ||
254 | .parse_param = ramfs_parse_param, | ||
255 | .get_tree = ramfs_get_tree, | ||
256 | }; | ||
257 | |||
258 | int ramfs_init_fs_context(struct fs_context *fc) | ||
259 | { | ||
260 | struct ramfs_fs_info *fsi; | ||
261 | |||
262 | fsi = kzalloc(sizeof(*fsi), GFP_KERNEL); | ||
263 | if (!fsi) | ||
264 | return -ENOMEM; | ||
265 | |||
266 | fsi->mount_opts.mode = RAMFS_DEFAULT_MODE; | ||
267 | fc->s_fs_info = fsi; | ||
268 | fc->ops = &ramfs_context_ops; | ||
269 | return 0; | ||
254 | } | 270 | } |
255 | 271 | ||
256 | static void ramfs_kill_sb(struct super_block *sb) | 272 | static void ramfs_kill_sb(struct super_block *sb) |
@@ -261,7 +277,8 @@ static void ramfs_kill_sb(struct super_block *sb) | |||
261 | 277 | ||
262 | static struct file_system_type ramfs_fs_type = { | 278 | static struct file_system_type ramfs_fs_type = { |
263 | .name = "ramfs", | 279 | .name = "ramfs", |
264 | .mount = ramfs_mount, | 280 | .init_fs_context = ramfs_init_fs_context, |
281 | .parameters = &ramfs_fs_parameters, | ||
265 | .kill_sb = ramfs_kill_sb, | 282 | .kill_sb = ramfs_kill_sb, |
266 | .fs_flags = FS_USERNS_MOUNT, | 283 | .fs_flags = FS_USERNS_MOUNT, |
267 | }; | 284 | }; |
diff --git a/fs/romfs/super.c b/fs/romfs/super.c index a42c0e3079dc..e582d001f792 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c | |||
@@ -65,7 +65,7 @@ | |||
65 | #include <linux/slab.h> | 65 | #include <linux/slab.h> |
66 | #include <linux/init.h> | 66 | #include <linux/init.h> |
67 | #include <linux/blkdev.h> | 67 | #include <linux/blkdev.h> |
68 | #include <linux/parser.h> | 68 | #include <linux/fs_context.h> |
69 | #include <linux/mount.h> | 69 | #include <linux/mount.h> |
70 | #include <linux/namei.h> | 70 | #include <linux/namei.h> |
71 | #include <linux/statfs.h> | 71 | #include <linux/statfs.h> |
@@ -423,10 +423,10 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
423 | /* | 423 | /* |
424 | * remounting must involve read-only | 424 | * remounting must involve read-only |
425 | */ | 425 | */ |
426 | static int romfs_remount(struct super_block *sb, int *flags, char *data) | 426 | static int romfs_reconfigure(struct fs_context *fc) |
427 | { | 427 | { |
428 | sync_filesystem(sb); | 428 | sync_filesystem(fc->root->d_sb); |
429 | *flags |= SB_RDONLY; | 429 | fc->sb_flags |= SB_RDONLY; |
430 | return 0; | 430 | return 0; |
431 | } | 431 | } |
432 | 432 | ||
@@ -434,7 +434,6 @@ static const struct super_operations romfs_super_ops = { | |||
434 | .alloc_inode = romfs_alloc_inode, | 434 | .alloc_inode = romfs_alloc_inode, |
435 | .free_inode = romfs_free_inode, | 435 | .free_inode = romfs_free_inode, |
436 | .statfs = romfs_statfs, | 436 | .statfs = romfs_statfs, |
437 | .remount_fs = romfs_remount, | ||
438 | }; | 437 | }; |
439 | 438 | ||
440 | /* | 439 | /* |
@@ -457,7 +456,7 @@ static __u32 romfs_checksum(const void *data, int size) | |||
457 | /* | 456 | /* |
458 | * fill in the superblock | 457 | * fill in the superblock |
459 | */ | 458 | */ |
460 | static int romfs_fill_super(struct super_block *sb, void *data, int silent) | 459 | static int romfs_fill_super(struct super_block *sb, struct fs_context *fc) |
461 | { | 460 | { |
462 | struct romfs_super_block *rsb; | 461 | struct romfs_super_block *rsb; |
463 | struct inode *root; | 462 | struct inode *root; |
@@ -506,8 +505,8 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) | |||
506 | 505 | ||
507 | if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || | 506 | if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || |
508 | img_size < ROMFH_SIZE) { | 507 | img_size < ROMFH_SIZE) { |
509 | if (!silent) | 508 | if (!(fc->sb_flags & SB_SILENT)) |
510 | pr_warn("VFS: Can't find a romfs filesystem on dev %s.\n", | 509 | errorf(fc, "VFS: Can't find a romfs filesystem on dev %s.\n", |
511 | sb->s_id); | 510 | sb->s_id); |
512 | goto error_rsb_inval; | 511 | goto error_rsb_inval; |
513 | } | 512 | } |
@@ -520,7 +519,7 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) | |||
520 | storage = sb->s_mtd ? "MTD" : "the block layer"; | 519 | storage = sb->s_mtd ? "MTD" : "the block layer"; |
521 | 520 | ||
522 | len = strnlen(rsb->name, ROMFS_MAXFN); | 521 | len = strnlen(rsb->name, ROMFS_MAXFN); |
523 | if (!silent) | 522 | if (!(fc->sb_flags & SB_SILENT)) |
524 | pr_notice("Mounting image '%*.*s' through %s\n", | 523 | pr_notice("Mounting image '%*.*s' through %s\n", |
525 | (unsigned) len, (unsigned) len, rsb->name, storage); | 524 | (unsigned) len, (unsigned) len, rsb->name, storage); |
526 | 525 | ||
@@ -550,23 +549,34 @@ error_rsb: | |||
550 | /* | 549 | /* |
551 | * get a superblock for mounting | 550 | * get a superblock for mounting |
552 | */ | 551 | */ |
553 | static struct dentry *romfs_mount(struct file_system_type *fs_type, | 552 | static int romfs_get_tree(struct fs_context *fc) |
554 | int flags, const char *dev_name, | ||
555 | void *data) | ||
556 | { | 553 | { |
557 | struct dentry *ret = ERR_PTR(-EINVAL); | 554 | int ret = -EINVAL; |
558 | 555 | ||
559 | #ifdef CONFIG_ROMFS_ON_MTD | 556 | #ifdef CONFIG_ROMFS_ON_MTD |
560 | ret = mount_mtd(fs_type, flags, dev_name, data, romfs_fill_super); | 557 | ret = get_tree_mtd(fc, romfs_fill_super); |
561 | #endif | 558 | #endif |
562 | #ifdef CONFIG_ROMFS_ON_BLOCK | 559 | #ifdef CONFIG_ROMFS_ON_BLOCK |
563 | if (ret == ERR_PTR(-EINVAL)) | 560 | if (ret == -EINVAL) |
564 | ret = mount_bdev(fs_type, flags, dev_name, data, | 561 | ret = get_tree_bdev(fc, romfs_fill_super); |
565 | romfs_fill_super); | ||
566 | #endif | 562 | #endif |
567 | return ret; | 563 | return ret; |
568 | } | 564 | } |
569 | 565 | ||
566 | static const struct fs_context_operations romfs_context_ops = { | ||
567 | .get_tree = romfs_get_tree, | ||
568 | .reconfigure = romfs_reconfigure, | ||
569 | }; | ||
570 | |||
571 | /* | ||
572 | * Set up the filesystem mount context. | ||
573 | */ | ||
574 | static int romfs_init_fs_context(struct fs_context *fc) | ||
575 | { | ||
576 | fc->ops = &romfs_context_ops; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
570 | /* | 580 | /* |
571 | * destroy a romfs superblock in the appropriate manner | 581 | * destroy a romfs superblock in the appropriate manner |
572 | */ | 582 | */ |
@@ -589,7 +599,7 @@ static void romfs_kill_sb(struct super_block *sb) | |||
589 | static struct file_system_type romfs_fs_type = { | 599 | static struct file_system_type romfs_fs_type = { |
590 | .owner = THIS_MODULE, | 600 | .owner = THIS_MODULE, |
591 | .name = "romfs", | 601 | .name = "romfs", |
592 | .mount = romfs_mount, | 602 | .init_fs_context = romfs_init_fs_context, |
593 | .kill_sb = romfs_kill_sb, | 603 | .kill_sb = romfs_kill_sb, |
594 | .fs_flags = FS_REQUIRES_DEV, | 604 | .fs_flags = FS_REQUIRES_DEV, |
595 | }; | 605 | }; |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index a9e9837617a9..0cc4ceec0562 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
18 | 18 | ||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/fs_context.h> | ||
20 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
@@ -36,26 +37,27 @@ | |||
36 | static struct file_system_type squashfs_fs_type; | 37 | static struct file_system_type squashfs_fs_type; |
37 | static const struct super_operations squashfs_super_ops; | 38 | static const struct super_operations squashfs_super_ops; |
38 | 39 | ||
39 | static const struct squashfs_decompressor *supported_squashfs_filesystem(short | 40 | static const struct squashfs_decompressor *supported_squashfs_filesystem( |
40 | major, short minor, short id) | 41 | struct fs_context *fc, |
42 | short major, short minor, short id) | ||
41 | { | 43 | { |
42 | const struct squashfs_decompressor *decompressor; | 44 | const struct squashfs_decompressor *decompressor; |
43 | 45 | ||
44 | if (major < SQUASHFS_MAJOR) { | 46 | if (major < SQUASHFS_MAJOR) { |
45 | ERROR("Major/Minor mismatch, older Squashfs %d.%d " | 47 | errorf(fc, "Major/Minor mismatch, older Squashfs %d.%d " |
46 | "filesystems are unsupported\n", major, minor); | 48 | "filesystems are unsupported", major, minor); |
47 | return NULL; | 49 | return NULL; |
48 | } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { | 50 | } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { |
49 | ERROR("Major/Minor mismatch, trying to mount newer " | 51 | errorf(fc, "Major/Minor mismatch, trying to mount newer " |
50 | "%d.%d filesystem\n", major, minor); | 52 | "%d.%d filesystem", major, minor); |
51 | ERROR("Please update your kernel\n"); | 53 | errorf(fc, "Please update your kernel"); |
52 | return NULL; | 54 | return NULL; |
53 | } | 55 | } |
54 | 56 | ||
55 | decompressor = squashfs_lookup_decompressor(id); | 57 | decompressor = squashfs_lookup_decompressor(id); |
56 | if (!decompressor->supported) { | 58 | if (!decompressor->supported) { |
57 | ERROR("Filesystem uses \"%s\" compression. This is not " | 59 | errorf(fc, "Filesystem uses \"%s\" compression. This is not supported", |
58 | "supported\n", decompressor->name); | 60 | decompressor->name); |
59 | return NULL; | 61 | return NULL; |
60 | } | 62 | } |
61 | 63 | ||
@@ -63,7 +65,7 @@ static const struct squashfs_decompressor *supported_squashfs_filesystem(short | |||
63 | } | 65 | } |
64 | 66 | ||
65 | 67 | ||
66 | static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | 68 | static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc) |
67 | { | 69 | { |
68 | struct squashfs_sb_info *msblk; | 70 | struct squashfs_sb_info *msblk; |
69 | struct squashfs_super_block *sblk = NULL; | 71 | struct squashfs_super_block *sblk = NULL; |
@@ -98,7 +100,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
98 | sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk)); | 100 | sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk)); |
99 | 101 | ||
100 | if (IS_ERR(sblk)) { | 102 | if (IS_ERR(sblk)) { |
101 | ERROR("unable to read squashfs_super_block\n"); | 103 | errorf(fc, "unable to read squashfs_super_block"); |
102 | err = PTR_ERR(sblk); | 104 | err = PTR_ERR(sblk); |
103 | sblk = NULL; | 105 | sblk = NULL; |
104 | goto failed_mount; | 106 | goto failed_mount; |
@@ -109,14 +111,15 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
109 | /* Check it is a SQUASHFS superblock */ | 111 | /* Check it is a SQUASHFS superblock */ |
110 | sb->s_magic = le32_to_cpu(sblk->s_magic); | 112 | sb->s_magic = le32_to_cpu(sblk->s_magic); |
111 | if (sb->s_magic != SQUASHFS_MAGIC) { | 113 | if (sb->s_magic != SQUASHFS_MAGIC) { |
112 | if (!silent) | 114 | if (!(fc->sb_flags & SB_SILENT)) |
113 | ERROR("Can't find a SQUASHFS superblock on %pg\n", | 115 | errorf(fc, "Can't find a SQUASHFS superblock on %pg", |
114 | sb->s_bdev); | 116 | sb->s_bdev); |
115 | goto failed_mount; | 117 | goto failed_mount; |
116 | } | 118 | } |
117 | 119 | ||
118 | /* Check the MAJOR & MINOR versions and lookup compression type */ | 120 | /* Check the MAJOR & MINOR versions and lookup compression type */ |
119 | msblk->decompressor = supported_squashfs_filesystem( | 121 | msblk->decompressor = supported_squashfs_filesystem( |
122 | fc, | ||
120 | le16_to_cpu(sblk->s_major), | 123 | le16_to_cpu(sblk->s_major), |
121 | le16_to_cpu(sblk->s_minor), | 124 | le16_to_cpu(sblk->s_minor), |
122 | le16_to_cpu(sblk->compression)); | 125 | le16_to_cpu(sblk->compression)); |
@@ -133,15 +136,15 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
133 | /* Check block size for sanity */ | 136 | /* Check block size for sanity */ |
134 | msblk->block_size = le32_to_cpu(sblk->block_size); | 137 | msblk->block_size = le32_to_cpu(sblk->block_size); |
135 | if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) | 138 | if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) |
136 | goto failed_mount; | 139 | goto insanity; |
137 | 140 | ||
138 | /* | 141 | /* |
139 | * Check the system page size is not larger than the filesystem | 142 | * Check the system page size is not larger than the filesystem |
140 | * block size (by default 128K). This is currently not supported. | 143 | * block size (by default 128K). This is currently not supported. |
141 | */ | 144 | */ |
142 | if (PAGE_SIZE > msblk->block_size) { | 145 | if (PAGE_SIZE > msblk->block_size) { |
143 | ERROR("Page size > filesystem block size (%d). This is " | 146 | errorf(fc, "Page size > filesystem block size (%d). This is " |
144 | "currently not supported!\n", msblk->block_size); | 147 | "currently not supported!", msblk->block_size); |
145 | goto failed_mount; | 148 | goto failed_mount; |
146 | } | 149 | } |
147 | 150 | ||
@@ -152,12 +155,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
152 | 155 | ||
153 | /* Check that block_size and block_log match */ | 156 | /* Check that block_size and block_log match */ |
154 | if (msblk->block_size != (1 << msblk->block_log)) | 157 | if (msblk->block_size != (1 << msblk->block_log)) |
155 | goto failed_mount; | 158 | goto insanity; |
156 | 159 | ||
157 | /* Check the root inode for sanity */ | 160 | /* Check the root inode for sanity */ |
158 | root_inode = le64_to_cpu(sblk->root_inode); | 161 | root_inode = le64_to_cpu(sblk->root_inode); |
159 | if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) | 162 | if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) |
160 | goto failed_mount; | 163 | goto insanity; |
161 | 164 | ||
162 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); | 165 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); |
163 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); | 166 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); |
@@ -199,7 +202,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
199 | msblk->read_page = squashfs_cache_init("data", | 202 | msblk->read_page = squashfs_cache_init("data", |
200 | squashfs_max_decompressors(), msblk->block_size); | 203 | squashfs_max_decompressors(), msblk->block_size); |
201 | if (msblk->read_page == NULL) { | 204 | if (msblk->read_page == NULL) { |
202 | ERROR("Failed to allocate read_page block\n"); | 205 | errorf(fc, "Failed to allocate read_page block"); |
203 | goto failed_mount; | 206 | goto failed_mount; |
204 | } | 207 | } |
205 | 208 | ||
@@ -207,7 +210,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
207 | if (IS_ERR(msblk->stream)) { | 210 | if (IS_ERR(msblk->stream)) { |
208 | err = PTR_ERR(msblk->stream); | 211 | err = PTR_ERR(msblk->stream); |
209 | msblk->stream = NULL; | 212 | msblk->stream = NULL; |
210 | goto failed_mount; | 213 | goto insanity; |
211 | } | 214 | } |
212 | 215 | ||
213 | /* Handle xattrs */ | 216 | /* Handle xattrs */ |
@@ -222,7 +225,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
222 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | 225 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, |
223 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); | 226 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); |
224 | if (IS_ERR(msblk->xattr_id_table)) { | 227 | if (IS_ERR(msblk->xattr_id_table)) { |
225 | ERROR("unable to read xattr id index table\n"); | 228 | errorf(fc, "unable to read xattr id index table"); |
226 | err = PTR_ERR(msblk->xattr_id_table); | 229 | err = PTR_ERR(msblk->xattr_id_table); |
227 | msblk->xattr_id_table = NULL; | 230 | msblk->xattr_id_table = NULL; |
228 | if (err != -ENOTSUPP) | 231 | if (err != -ENOTSUPP) |
@@ -236,7 +239,7 @@ allocate_id_index_table: | |||
236 | le64_to_cpu(sblk->id_table_start), next_table, | 239 | le64_to_cpu(sblk->id_table_start), next_table, |
237 | le16_to_cpu(sblk->no_ids)); | 240 | le16_to_cpu(sblk->no_ids)); |
238 | if (IS_ERR(msblk->id_table)) { | 241 | if (IS_ERR(msblk->id_table)) { |
239 | ERROR("unable to read id index table\n"); | 242 | errorf(fc, "unable to read id index table"); |
240 | err = PTR_ERR(msblk->id_table); | 243 | err = PTR_ERR(msblk->id_table); |
241 | msblk->id_table = NULL; | 244 | msblk->id_table = NULL; |
242 | goto failed_mount; | 245 | goto failed_mount; |
@@ -252,7 +255,7 @@ allocate_id_index_table: | |||
252 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | 255 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, |
253 | lookup_table_start, next_table, msblk->inodes); | 256 | lookup_table_start, next_table, msblk->inodes); |
254 | if (IS_ERR(msblk->inode_lookup_table)) { | 257 | if (IS_ERR(msblk->inode_lookup_table)) { |
255 | ERROR("unable to read inode lookup table\n"); | 258 | errorf(fc, "unable to read inode lookup table"); |
256 | err = PTR_ERR(msblk->inode_lookup_table); | 259 | err = PTR_ERR(msblk->inode_lookup_table); |
257 | msblk->inode_lookup_table = NULL; | 260 | msblk->inode_lookup_table = NULL; |
258 | goto failed_mount; | 261 | goto failed_mount; |
@@ -277,7 +280,7 @@ handle_fragments: | |||
277 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, | 280 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, |
278 | le64_to_cpu(sblk->fragment_table_start), next_table, fragments); | 281 | le64_to_cpu(sblk->fragment_table_start), next_table, fragments); |
279 | if (IS_ERR(msblk->fragment_index)) { | 282 | if (IS_ERR(msblk->fragment_index)) { |
280 | ERROR("unable to read fragment index table\n"); | 283 | errorf(fc, "unable to read fragment index table"); |
281 | err = PTR_ERR(msblk->fragment_index); | 284 | err = PTR_ERR(msblk->fragment_index); |
282 | msblk->fragment_index = NULL; | 285 | msblk->fragment_index = NULL; |
283 | goto failed_mount; | 286 | goto failed_mount; |
@@ -288,13 +291,13 @@ check_directory_table: | |||
288 | /* Sanity check directory_table */ | 291 | /* Sanity check directory_table */ |
289 | if (msblk->directory_table > next_table) { | 292 | if (msblk->directory_table > next_table) { |
290 | err = -EINVAL; | 293 | err = -EINVAL; |
291 | goto failed_mount; | 294 | goto insanity; |
292 | } | 295 | } |
293 | 296 | ||
294 | /* Sanity check inode_table */ | 297 | /* Sanity check inode_table */ |
295 | if (msblk->inode_table >= msblk->directory_table) { | 298 | if (msblk->inode_table >= msblk->directory_table) { |
296 | err = -EINVAL; | 299 | err = -EINVAL; |
297 | goto failed_mount; | 300 | goto insanity; |
298 | } | 301 | } |
299 | 302 | ||
300 | /* allocate root */ | 303 | /* allocate root */ |
@@ -323,6 +326,8 @@ check_directory_table: | |||
323 | kfree(sblk); | 326 | kfree(sblk); |
324 | return 0; | 327 | return 0; |
325 | 328 | ||
329 | insanity: | ||
330 | errorf(fc, "squashfs image failed sanity check"); | ||
326 | failed_mount: | 331 | failed_mount: |
327 | squashfs_cache_delete(msblk->block_cache); | 332 | squashfs_cache_delete(msblk->block_cache); |
328 | squashfs_cache_delete(msblk->fragment_cache); | 333 | squashfs_cache_delete(msblk->fragment_cache); |
@@ -338,6 +343,28 @@ failed_mount: | |||
338 | return err; | 343 | return err; |
339 | } | 344 | } |
340 | 345 | ||
346 | static int squashfs_get_tree(struct fs_context *fc) | ||
347 | { | ||
348 | return get_tree_bdev(fc, squashfs_fill_super); | ||
349 | } | ||
350 | |||
351 | static int squashfs_reconfigure(struct fs_context *fc) | ||
352 | { | ||
353 | sync_filesystem(fc->root->d_sb); | ||
354 | fc->sb_flags |= SB_RDONLY; | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static const struct fs_context_operations squashfs_context_ops = { | ||
359 | .get_tree = squashfs_get_tree, | ||
360 | .reconfigure = squashfs_reconfigure, | ||
361 | }; | ||
362 | |||
363 | static int squashfs_init_fs_context(struct fs_context *fc) | ||
364 | { | ||
365 | fc->ops = &squashfs_context_ops; | ||
366 | return 0; | ||
367 | } | ||
341 | 368 | ||
342 | static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 369 | static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
343 | { | 370 | { |
@@ -360,14 +387,6 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
360 | } | 387 | } |
361 | 388 | ||
362 | 389 | ||
363 | static int squashfs_remount(struct super_block *sb, int *flags, char *data) | ||
364 | { | ||
365 | sync_filesystem(sb); | ||
366 | *flags |= SB_RDONLY; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | |||
371 | static void squashfs_put_super(struct super_block *sb) | 390 | static void squashfs_put_super(struct super_block *sb) |
372 | { | 391 | { |
373 | if (sb->s_fs_info) { | 392 | if (sb->s_fs_info) { |
@@ -386,14 +405,6 @@ static void squashfs_put_super(struct super_block *sb) | |||
386 | } | 405 | } |
387 | } | 406 | } |
388 | 407 | ||
389 | |||
390 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, | ||
391 | int flags, const char *dev_name, void *data) | ||
392 | { | ||
393 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); | ||
394 | } | ||
395 | |||
396 | |||
397 | static struct kmem_cache *squashfs_inode_cachep; | 408 | static struct kmem_cache *squashfs_inode_cachep; |
398 | 409 | ||
399 | 410 | ||
@@ -470,7 +481,7 @@ static void squashfs_free_inode(struct inode *inode) | |||
470 | static struct file_system_type squashfs_fs_type = { | 481 | static struct file_system_type squashfs_fs_type = { |
471 | .owner = THIS_MODULE, | 482 | .owner = THIS_MODULE, |
472 | .name = "squashfs", | 483 | .name = "squashfs", |
473 | .mount = squashfs_mount, | 484 | .init_fs_context = squashfs_init_fs_context, |
474 | .kill_sb = kill_block_super, | 485 | .kill_sb = kill_block_super, |
475 | .fs_flags = FS_REQUIRES_DEV | 486 | .fs_flags = FS_REQUIRES_DEV |
476 | }; | 487 | }; |
@@ -481,7 +492,6 @@ static const struct super_operations squashfs_super_ops = { | |||
481 | .free_inode = squashfs_free_inode, | 492 | .free_inode = squashfs_free_inode, |
482 | .statfs = squashfs_statfs, | 493 | .statfs = squashfs_statfs, |
483 | .put_super = squashfs_put_super, | 494 | .put_super = squashfs_put_super, |
484 | .remount_fs = squashfs_remount | ||
485 | }; | 495 | }; |
486 | 496 | ||
487 | module_init(init_squashfs_fs); | 497 | module_init(init_squashfs_fs); |
diff --git a/fs/super.c b/fs/super.c index 2d679db9e8c7..8020974b2a68 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -1164,9 +1164,11 @@ int vfs_get_super(struct fs_context *fc, | |||
1164 | { | 1164 | { |
1165 | int (*test)(struct super_block *, struct fs_context *); | 1165 | int (*test)(struct super_block *, struct fs_context *); |
1166 | struct super_block *sb; | 1166 | struct super_block *sb; |
1167 | int err; | ||
1167 | 1168 | ||
1168 | switch (keying) { | 1169 | switch (keying) { |
1169 | case vfs_get_single_super: | 1170 | case vfs_get_single_super: |
1171 | case vfs_get_single_reconf_super: | ||
1170 | test = test_single_super; | 1172 | test = test_single_super; |
1171 | break; | 1173 | break; |
1172 | case vfs_get_keyed_super: | 1174 | case vfs_get_keyed_super: |
@@ -1184,18 +1186,29 @@ int vfs_get_super(struct fs_context *fc, | |||
1184 | return PTR_ERR(sb); | 1186 | return PTR_ERR(sb); |
1185 | 1187 | ||
1186 | if (!sb->s_root) { | 1188 | if (!sb->s_root) { |
1187 | int err = fill_super(sb, fc); | 1189 | err = fill_super(sb, fc); |
1188 | if (err) { | 1190 | if (err) |
1189 | deactivate_locked_super(sb); | 1191 | goto error; |
1190 | return err; | ||
1191 | } | ||
1192 | 1192 | ||
1193 | sb->s_flags |= SB_ACTIVE; | 1193 | sb->s_flags |= SB_ACTIVE; |
1194 | fc->root = dget(sb->s_root); | ||
1195 | } else { | ||
1196 | fc->root = dget(sb->s_root); | ||
1197 | if (keying == vfs_get_single_reconf_super) { | ||
1198 | err = reconfigure_super(fc); | ||
1199 | if (err < 0) { | ||
1200 | dput(fc->root); | ||
1201 | fc->root = NULL; | ||
1202 | goto error; | ||
1203 | } | ||
1204 | } | ||
1194 | } | 1205 | } |
1195 | 1206 | ||
1196 | BUG_ON(fc->root); | ||
1197 | fc->root = dget(sb->s_root); | ||
1198 | return 0; | 1207 | return 0; |
1208 | |||
1209 | error: | ||
1210 | deactivate_locked_super(sb); | ||
1211 | return err; | ||
1199 | } | 1212 | } |
1200 | EXPORT_SYMBOL(vfs_get_super); | 1213 | EXPORT_SYMBOL(vfs_get_super); |
1201 | 1214 | ||
@@ -1215,6 +1228,14 @@ int get_tree_single(struct fs_context *fc, | |||
1215 | } | 1228 | } |
1216 | EXPORT_SYMBOL(get_tree_single); | 1229 | EXPORT_SYMBOL(get_tree_single); |
1217 | 1230 | ||
1231 | int get_tree_single_reconf(struct fs_context *fc, | ||
1232 | int (*fill_super)(struct super_block *sb, | ||
1233 | struct fs_context *fc)) | ||
1234 | { | ||
1235 | return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super); | ||
1236 | } | ||
1237 | EXPORT_SYMBOL(get_tree_single_reconf); | ||
1238 | |||
1218 | int get_tree_keyed(struct fs_context *fc, | 1239 | int get_tree_keyed(struct fs_context *fc, |
1219 | int (*fill_super)(struct super_block *sb, | 1240 | int (*fill_super)(struct super_block *sb, |
1220 | struct fs_context *fc), | 1241 | struct fs_context *fc), |
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index 84a5eaa09f19..0424df7f6e6b 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h | |||
@@ -141,6 +141,7 @@ extern void put_fs_context(struct fs_context *fc); | |||
141 | */ | 141 | */ |
142 | enum vfs_get_super_keying { | 142 | enum vfs_get_super_keying { |
143 | vfs_get_single_super, /* Only one such superblock may exist */ | 143 | vfs_get_single_super, /* Only one such superblock may exist */ |
144 | vfs_get_single_reconf_super, /* As above, but reconfigure if it exists */ | ||
144 | vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */ | 145 | vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */ |
145 | vfs_get_independent_super, /* Multiple independent superblocks may exist */ | 146 | vfs_get_independent_super, /* Multiple independent superblocks may exist */ |
146 | }; | 147 | }; |
@@ -155,6 +156,9 @@ extern int get_tree_nodev(struct fs_context *fc, | |||
155 | extern int get_tree_single(struct fs_context *fc, | 156 | extern int get_tree_single(struct fs_context *fc, |
156 | int (*fill_super)(struct super_block *sb, | 157 | int (*fill_super)(struct super_block *sb, |
157 | struct fs_context *fc)); | 158 | struct fs_context *fc)); |
159 | extern int get_tree_single_reconf(struct fs_context *fc, | ||
160 | int (*fill_super)(struct super_block *sb, | ||
161 | struct fs_context *fc)); | ||
158 | extern int get_tree_keyed(struct fs_context *fc, | 162 | extern int get_tree_keyed(struct fs_context *fc, |
159 | int (*fill_super)(struct super_block *sb, | 163 | int (*fill_super)(struct super_block *sb, |
160 | struct fs_context *fc), | 164 | struct fs_context *fc), |
diff --git a/include/linux/mtd/super.h b/include/linux/mtd/super.h index 42db3f8e8136..3608a6c36fac 100644 --- a/include/linux/mtd/super.h +++ b/include/linux/mtd/super.h | |||
@@ -17,9 +17,6 @@ | |||
17 | extern int get_tree_mtd(struct fs_context *fc, | 17 | extern int get_tree_mtd(struct fs_context *fc, |
18 | int (*fill_super)(struct super_block *sb, | 18 | int (*fill_super)(struct super_block *sb, |
19 | struct fs_context *fc)); | 19 | struct fs_context *fc)); |
20 | extern struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, | ||
21 | const char *dev_name, void *data, | ||
22 | int (*fill_super)(struct super_block *, void *, int)); | ||
23 | extern void kill_mtd_super(struct super_block *sb); | 20 | extern void kill_mtd_super(struct super_block *sb); |
24 | 21 | ||
25 | 22 | ||
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index ee582bdb7fda..b806a0ff6554 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h | |||
@@ -4,8 +4,7 @@ | |||
4 | 4 | ||
5 | struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir, | 5 | struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir, |
6 | umode_t mode, dev_t dev); | 6 | umode_t mode, dev_t dev); |
7 | extern struct dentry *ramfs_mount(struct file_system_type *fs_type, | 7 | extern int ramfs_init_fs_context(struct fs_context *fc); |
8 | int flags, const char *dev_name, void *data); | ||
9 | 8 | ||
10 | #ifdef CONFIG_MMU | 9 | #ifdef CONFIG_MMU |
11 | static inline int | 10 | static inline int |
@@ -17,9 +16,8 @@ ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) | |||
17 | extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize); | 16 | extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize); |
18 | #endif | 17 | #endif |
19 | 18 | ||
19 | extern const struct fs_parameter_description ramfs_fs_parameters; | ||
20 | extern const struct file_operations ramfs_file_operations; | 20 | extern const struct file_operations ramfs_file_operations; |
21 | extern const struct vm_operations_struct generic_file_vm_ops; | 21 | extern const struct vm_operations_struct generic_file_vm_ops; |
22 | 22 | ||
23 | int ramfs_fill_super(struct super_block *sb, void *data, int silent); | ||
24 | |||
25 | #endif | 23 | #endif |
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 20d815a33145..de8e4b71e3ba 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h | |||
@@ -49,8 +49,9 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) | |||
49 | /* | 49 | /* |
50 | * Functions in mm/shmem.c called directly from elsewhere: | 50 | * Functions in mm/shmem.c called directly from elsewhere: |
51 | */ | 51 | */ |
52 | extern const struct fs_parameter_description shmem_fs_parameters; | ||
52 | extern int shmem_init(void); | 53 | extern int shmem_init(void); |
53 | extern int shmem_fill_super(struct super_block *sb, void *data, int silent); | 54 | extern int shmem_init_fs_context(struct fs_context *fc); |
54 | extern struct file *shmem_file_setup(const char *name, | 55 | extern struct file *shmem_file_setup(const char *name, |
55 | loff_t size, unsigned long flags); | 56 | loff_t size, unsigned long flags); |
56 | extern struct file *shmem_kernel_file_setup(const char *name, loff_t size, | 57 | extern struct file *shmem_kernel_file_setup(const char *name, loff_t size, |
diff --git a/init/do_mounts.c b/init/do_mounts.c index 53cb37b66227..9634ecf3743d 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c | |||
@@ -627,20 +627,17 @@ out: | |||
627 | } | 627 | } |
628 | 628 | ||
629 | static bool is_tmpfs; | 629 | static bool is_tmpfs; |
630 | static struct dentry *rootfs_mount(struct file_system_type *fs_type, | 630 | static int rootfs_init_fs_context(struct fs_context *fc) |
631 | int flags, const char *dev_name, void *data) | ||
632 | { | 631 | { |
633 | void *fill = ramfs_fill_super; | ||
634 | |||
635 | if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) | 632 | if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) |
636 | fill = shmem_fill_super; | 633 | return shmem_init_fs_context(fc); |
637 | 634 | ||
638 | return mount_nodev(fs_type, flags, data, fill); | 635 | return ramfs_init_fs_context(fc); |
639 | } | 636 | } |
640 | 637 | ||
641 | struct file_system_type rootfs_fs_type = { | 638 | struct file_system_type rootfs_fs_type = { |
642 | .name = "rootfs", | 639 | .name = "rootfs", |
643 | .mount = rootfs_mount, | 640 | .init_fs_context = rootfs_init_fs_context, |
644 | .kill_sb = kill_litter_super, | 641 | .kill_sb = kill_litter_super, |
645 | }; | 642 | }; |
646 | 643 | ||
diff --git a/mm/shmem.c b/mm/shmem.c index 2bed4761f279..0f7fd4a85db6 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/khugepaged.h> | 37 | #include <linux/khugepaged.h> |
38 | #include <linux/hugetlb.h> | 38 | #include <linux/hugetlb.h> |
39 | #include <linux/frontswap.h> | 39 | #include <linux/frontswap.h> |
40 | #include <linux/fs_parser.h> | ||
40 | 41 | ||
41 | #include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */ | 42 | #include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */ |
42 | 43 | ||
@@ -107,6 +108,20 @@ struct shmem_falloc { | |||
107 | pgoff_t nr_unswapped; /* how often writepage refused to swap out */ | 108 | pgoff_t nr_unswapped; /* how often writepage refused to swap out */ |
108 | }; | 109 | }; |
109 | 110 | ||
111 | struct shmem_options { | ||
112 | unsigned long long blocks; | ||
113 | unsigned long long inodes; | ||
114 | struct mempolicy *mpol; | ||
115 | kuid_t uid; | ||
116 | kgid_t gid; | ||
117 | umode_t mode; | ||
118 | int huge; | ||
119 | int seen; | ||
120 | #define SHMEM_SEEN_BLOCKS 1 | ||
121 | #define SHMEM_SEEN_INODES 2 | ||
122 | #define SHMEM_SEEN_HUGE 4 | ||
123 | }; | ||
124 | |||
110 | #ifdef CONFIG_TMPFS | 125 | #ifdef CONFIG_TMPFS |
111 | static unsigned long shmem_default_max_blocks(void) | 126 | static unsigned long shmem_default_max_blocks(void) |
112 | { | 127 | { |
@@ -3349,16 +3364,126 @@ static const struct export_operations shmem_export_ops = { | |||
3349 | .fh_to_dentry = shmem_fh_to_dentry, | 3364 | .fh_to_dentry = shmem_fh_to_dentry, |
3350 | }; | 3365 | }; |
3351 | 3366 | ||
3352 | static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | 3367 | enum shmem_param { |
3353 | bool remount) | 3368 | Opt_gid, |
3369 | Opt_huge, | ||
3370 | Opt_mode, | ||
3371 | Opt_mpol, | ||
3372 | Opt_nr_blocks, | ||
3373 | Opt_nr_inodes, | ||
3374 | Opt_size, | ||
3375 | Opt_uid, | ||
3376 | }; | ||
3377 | |||
3378 | static const struct fs_parameter_spec shmem_param_specs[] = { | ||
3379 | fsparam_u32 ("gid", Opt_gid), | ||
3380 | fsparam_enum ("huge", Opt_huge), | ||
3381 | fsparam_u32oct("mode", Opt_mode), | ||
3382 | fsparam_string("mpol", Opt_mpol), | ||
3383 | fsparam_string("nr_blocks", Opt_nr_blocks), | ||
3384 | fsparam_string("nr_inodes", Opt_nr_inodes), | ||
3385 | fsparam_string("size", Opt_size), | ||
3386 | fsparam_u32 ("uid", Opt_uid), | ||
3387 | {} | ||
3388 | }; | ||
3389 | |||
3390 | static const struct fs_parameter_enum shmem_param_enums[] = { | ||
3391 | { Opt_huge, "never", SHMEM_HUGE_NEVER }, | ||
3392 | { Opt_huge, "always", SHMEM_HUGE_ALWAYS }, | ||
3393 | { Opt_huge, "within_size", SHMEM_HUGE_WITHIN_SIZE }, | ||
3394 | { Opt_huge, "advise", SHMEM_HUGE_ADVISE }, | ||
3395 | {} | ||
3396 | }; | ||
3397 | |||
3398 | const struct fs_parameter_description shmem_fs_parameters = { | ||
3399 | .name = "tmpfs", | ||
3400 | .specs = shmem_param_specs, | ||
3401 | .enums = shmem_param_enums, | ||
3402 | }; | ||
3403 | |||
3404 | static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) | ||
3354 | { | 3405 | { |
3355 | char *this_char, *value, *rest; | 3406 | struct shmem_options *ctx = fc->fs_private; |
3356 | struct mempolicy *mpol = NULL; | 3407 | struct fs_parse_result result; |
3357 | uid_t uid; | 3408 | unsigned long long size; |
3358 | gid_t gid; | 3409 | char *rest; |
3410 | int opt; | ||
3411 | |||
3412 | opt = fs_parse(fc, &shmem_fs_parameters, param, &result); | ||
3413 | if (opt < 0) | ||
3414 | return opt; | ||
3415 | |||
3416 | switch (opt) { | ||
3417 | case Opt_size: | ||
3418 | size = memparse(param->string, &rest); | ||
3419 | if (*rest == '%') { | ||
3420 | size <<= PAGE_SHIFT; | ||
3421 | size *= totalram_pages(); | ||
3422 | do_div(size, 100); | ||
3423 | rest++; | ||
3424 | } | ||
3425 | if (*rest) | ||
3426 | goto bad_value; | ||
3427 | ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE); | ||
3428 | ctx->seen |= SHMEM_SEEN_BLOCKS; | ||
3429 | break; | ||
3430 | case Opt_nr_blocks: | ||
3431 | ctx->blocks = memparse(param->string, &rest); | ||
3432 | if (*rest) | ||
3433 | goto bad_value; | ||
3434 | ctx->seen |= SHMEM_SEEN_BLOCKS; | ||
3435 | break; | ||
3436 | case Opt_nr_inodes: | ||
3437 | ctx->inodes = memparse(param->string, &rest); | ||
3438 | if (*rest) | ||
3439 | goto bad_value; | ||
3440 | ctx->seen |= SHMEM_SEEN_INODES; | ||
3441 | break; | ||
3442 | case Opt_mode: | ||
3443 | ctx->mode = result.uint_32 & 07777; | ||
3444 | break; | ||
3445 | case Opt_uid: | ||
3446 | ctx->uid = make_kuid(current_user_ns(), result.uint_32); | ||
3447 | if (!uid_valid(ctx->uid)) | ||
3448 | goto bad_value; | ||
3449 | break; | ||
3450 | case Opt_gid: | ||
3451 | ctx->gid = make_kgid(current_user_ns(), result.uint_32); | ||
3452 | if (!gid_valid(ctx->gid)) | ||
3453 | goto bad_value; | ||
3454 | break; | ||
3455 | case Opt_huge: | ||
3456 | ctx->huge = result.uint_32; | ||
3457 | if (ctx->huge != SHMEM_HUGE_NEVER && | ||
3458 | !(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && | ||
3459 | has_transparent_hugepage())) | ||
3460 | goto unsupported_parameter; | ||
3461 | ctx->seen |= SHMEM_SEEN_HUGE; | ||
3462 | break; | ||
3463 | case Opt_mpol: | ||
3464 | if (IS_ENABLED(CONFIG_NUMA)) { | ||
3465 | mpol_put(ctx->mpol); | ||
3466 | ctx->mpol = NULL; | ||
3467 | if (mpol_parse_str(param->string, &ctx->mpol)) | ||
3468 | goto bad_value; | ||
3469 | break; | ||
3470 | } | ||
3471 | goto unsupported_parameter; | ||
3472 | } | ||
3473 | return 0; | ||
3474 | |||
3475 | unsupported_parameter: | ||
3476 | return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key); | ||
3477 | bad_value: | ||
3478 | return invalf(fc, "tmpfs: Bad value for '%s'", param->key); | ||
3479 | } | ||
3480 | |||
3481 | static int shmem_parse_options(struct fs_context *fc, void *data) | ||
3482 | { | ||
3483 | char *options = data; | ||
3359 | 3484 | ||
3360 | while (options != NULL) { | 3485 | while (options != NULL) { |
3361 | this_char = options; | 3486 | char *this_char = options; |
3362 | for (;;) { | 3487 | for (;;) { |
3363 | /* | 3488 | /* |
3364 | * NUL-terminate this option: unfortunately, | 3489 | * NUL-terminate this option: unfortunately, |
@@ -3374,139 +3499,83 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
3374 | break; | 3499 | break; |
3375 | } | 3500 | } |
3376 | } | 3501 | } |
3377 | if (!*this_char) | 3502 | if (*this_char) { |
3378 | continue; | 3503 | char *value = strchr(this_char,'='); |
3379 | if ((value = strchr(this_char,'=')) != NULL) { | 3504 | size_t len = 0; |
3380 | *value++ = 0; | 3505 | int err; |
3381 | } else { | 3506 | |
3382 | pr_err("tmpfs: No value for mount option '%s'\n", | 3507 | if (value) { |
3383 | this_char); | 3508 | *value++ = '\0'; |
3384 | goto error; | 3509 | len = strlen(value); |
3385 | } | ||
3386 | |||
3387 | if (!strcmp(this_char,"size")) { | ||
3388 | unsigned long long size; | ||
3389 | size = memparse(value,&rest); | ||
3390 | if (*rest == '%') { | ||
3391 | size <<= PAGE_SHIFT; | ||
3392 | size *= totalram_pages(); | ||
3393 | do_div(size, 100); | ||
3394 | rest++; | ||
3395 | } | 3510 | } |
3396 | if (*rest) | 3511 | err = vfs_parse_fs_string(fc, this_char, value, len); |
3397 | goto bad_val; | 3512 | if (err < 0) |
3398 | sbinfo->max_blocks = | 3513 | return err; |
3399 | DIV_ROUND_UP(size, PAGE_SIZE); | ||
3400 | } else if (!strcmp(this_char,"nr_blocks")) { | ||
3401 | sbinfo->max_blocks = memparse(value, &rest); | ||
3402 | if (*rest) | ||
3403 | goto bad_val; | ||
3404 | } else if (!strcmp(this_char,"nr_inodes")) { | ||
3405 | sbinfo->max_inodes = memparse(value, &rest); | ||
3406 | if (*rest) | ||
3407 | goto bad_val; | ||
3408 | } else if (!strcmp(this_char,"mode")) { | ||
3409 | if (remount) | ||
3410 | continue; | ||
3411 | sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777; | ||
3412 | if (*rest) | ||
3413 | goto bad_val; | ||
3414 | } else if (!strcmp(this_char,"uid")) { | ||
3415 | if (remount) | ||
3416 | continue; | ||
3417 | uid = simple_strtoul(value, &rest, 0); | ||
3418 | if (*rest) | ||
3419 | goto bad_val; | ||
3420 | sbinfo->uid = make_kuid(current_user_ns(), uid); | ||
3421 | if (!uid_valid(sbinfo->uid)) | ||
3422 | goto bad_val; | ||
3423 | } else if (!strcmp(this_char,"gid")) { | ||
3424 | if (remount) | ||
3425 | continue; | ||
3426 | gid = simple_strtoul(value, &rest, 0); | ||
3427 | if (*rest) | ||
3428 | goto bad_val; | ||
3429 | sbinfo->gid = make_kgid(current_user_ns(), gid); | ||
3430 | if (!gid_valid(sbinfo->gid)) | ||
3431 | goto bad_val; | ||
3432 | #ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE | ||
3433 | } else if (!strcmp(this_char, "huge")) { | ||
3434 | int huge; | ||
3435 | huge = shmem_parse_huge(value); | ||
3436 | if (huge < 0) | ||
3437 | goto bad_val; | ||
3438 | if (!has_transparent_hugepage() && | ||
3439 | huge != SHMEM_HUGE_NEVER) | ||
3440 | goto bad_val; | ||
3441 | sbinfo->huge = huge; | ||
3442 | #endif | ||
3443 | #ifdef CONFIG_NUMA | ||
3444 | } else if (!strcmp(this_char,"mpol")) { | ||
3445 | mpol_put(mpol); | ||
3446 | mpol = NULL; | ||
3447 | if (mpol_parse_str(value, &mpol)) | ||
3448 | goto bad_val; | ||
3449 | #endif | ||
3450 | } else { | ||
3451 | pr_err("tmpfs: Bad mount option %s\n", this_char); | ||
3452 | goto error; | ||
3453 | } | 3514 | } |
3454 | } | 3515 | } |
3455 | sbinfo->mpol = mpol; | ||
3456 | return 0; | 3516 | return 0; |
3457 | |||
3458 | bad_val: | ||
3459 | pr_err("tmpfs: Bad value '%s' for mount option '%s'\n", | ||
3460 | value, this_char); | ||
3461 | error: | ||
3462 | mpol_put(mpol); | ||
3463 | return 1; | ||
3464 | |||
3465 | } | 3517 | } |
3466 | 3518 | ||
3467 | static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) | 3519 | /* |
3520 | * Reconfigure a shmem filesystem. | ||
3521 | * | ||
3522 | * Note that we disallow change from limited->unlimited blocks/inodes while any | ||
3523 | * are in use; but we must separately disallow unlimited->limited, because in | ||
3524 | * that case we have no record of how much is already in use. | ||
3525 | */ | ||
3526 | static int shmem_reconfigure(struct fs_context *fc) | ||
3468 | { | 3527 | { |
3469 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); | 3528 | struct shmem_options *ctx = fc->fs_private; |
3470 | struct shmem_sb_info config = *sbinfo; | 3529 | struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb); |
3471 | unsigned long inodes; | 3530 | unsigned long inodes; |
3472 | int error = -EINVAL; | 3531 | const char *err; |
3473 | |||
3474 | config.mpol = NULL; | ||
3475 | if (shmem_parse_options(data, &config, true)) | ||
3476 | return error; | ||
3477 | 3532 | ||
3478 | spin_lock(&sbinfo->stat_lock); | 3533 | spin_lock(&sbinfo->stat_lock); |
3479 | inodes = sbinfo->max_inodes - sbinfo->free_inodes; | 3534 | inodes = sbinfo->max_inodes - sbinfo->free_inodes; |
3480 | if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0) | 3535 | if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) { |
3481 | goto out; | 3536 | if (!sbinfo->max_blocks) { |
3482 | if (config.max_inodes < inodes) | 3537 | err = "Cannot retroactively limit size"; |
3483 | goto out; | 3538 | goto out; |
3484 | /* | 3539 | } |
3485 | * Those tests disallow limited->unlimited while any are in use; | 3540 | if (percpu_counter_compare(&sbinfo->used_blocks, |
3486 | * but we must separately disallow unlimited->limited, because | 3541 | ctx->blocks) > 0) { |
3487 | * in that case we have no record of how much is already in use. | 3542 | err = "Too small a size for current use"; |
3488 | */ | 3543 | goto out; |
3489 | if (config.max_blocks && !sbinfo->max_blocks) | 3544 | } |
3490 | goto out; | 3545 | } |
3491 | if (config.max_inodes && !sbinfo->max_inodes) | 3546 | if ((ctx->seen & SHMEM_SEEN_INODES) && ctx->inodes) { |
3492 | goto out; | 3547 | if (!sbinfo->max_inodes) { |
3548 | err = "Cannot retroactively limit inodes"; | ||
3549 | goto out; | ||
3550 | } | ||
3551 | if (ctx->inodes < inodes) { | ||
3552 | err = "Too few inodes for current use"; | ||
3553 | goto out; | ||
3554 | } | ||
3555 | } | ||
3493 | 3556 | ||
3494 | error = 0; | 3557 | if (ctx->seen & SHMEM_SEEN_HUGE) |
3495 | sbinfo->huge = config.huge; | 3558 | sbinfo->huge = ctx->huge; |
3496 | sbinfo->max_blocks = config.max_blocks; | 3559 | if (ctx->seen & SHMEM_SEEN_BLOCKS) |
3497 | sbinfo->max_inodes = config.max_inodes; | 3560 | sbinfo->max_blocks = ctx->blocks; |
3498 | sbinfo->free_inodes = config.max_inodes - inodes; | 3561 | if (ctx->seen & SHMEM_SEEN_INODES) { |
3562 | sbinfo->max_inodes = ctx->inodes; | ||
3563 | sbinfo->free_inodes = ctx->inodes - inodes; | ||
3564 | } | ||
3499 | 3565 | ||
3500 | /* | 3566 | /* |
3501 | * Preserve previous mempolicy unless mpol remount option was specified. | 3567 | * Preserve previous mempolicy unless mpol remount option was specified. |
3502 | */ | 3568 | */ |
3503 | if (config.mpol) { | 3569 | if (ctx->mpol) { |
3504 | mpol_put(sbinfo->mpol); | 3570 | mpol_put(sbinfo->mpol); |
3505 | sbinfo->mpol = config.mpol; /* transfers initial ref */ | 3571 | sbinfo->mpol = ctx->mpol; /* transfers initial ref */ |
3572 | ctx->mpol = NULL; | ||
3506 | } | 3573 | } |
3574 | spin_unlock(&sbinfo->stat_lock); | ||
3575 | return 0; | ||
3507 | out: | 3576 | out: |
3508 | spin_unlock(&sbinfo->stat_lock); | 3577 | spin_unlock(&sbinfo->stat_lock); |
3509 | return error; | 3578 | return invalf(fc, "tmpfs: %s", err); |
3510 | } | 3579 | } |
3511 | 3580 | ||
3512 | static int shmem_show_options(struct seq_file *seq, struct dentry *root) | 3581 | static int shmem_show_options(struct seq_file *seq, struct dentry *root) |
@@ -3547,8 +3616,9 @@ static void shmem_put_super(struct super_block *sb) | |||
3547 | sb->s_fs_info = NULL; | 3616 | sb->s_fs_info = NULL; |
3548 | } | 3617 | } |
3549 | 3618 | ||
3550 | int shmem_fill_super(struct super_block *sb, void *data, int silent) | 3619 | static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) |
3551 | { | 3620 | { |
3621 | struct shmem_options *ctx = fc->fs_private; | ||
3552 | struct inode *inode; | 3622 | struct inode *inode; |
3553 | struct shmem_sb_info *sbinfo; | 3623 | struct shmem_sb_info *sbinfo; |
3554 | int err = -ENOMEM; | 3624 | int err = -ENOMEM; |
@@ -3559,9 +3629,6 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3559 | if (!sbinfo) | 3629 | if (!sbinfo) |
3560 | return -ENOMEM; | 3630 | return -ENOMEM; |
3561 | 3631 | ||
3562 | sbinfo->mode = 0777 | S_ISVTX; | ||
3563 | sbinfo->uid = current_fsuid(); | ||
3564 | sbinfo->gid = current_fsgid(); | ||
3565 | sb->s_fs_info = sbinfo; | 3632 | sb->s_fs_info = sbinfo; |
3566 | 3633 | ||
3567 | #ifdef CONFIG_TMPFS | 3634 | #ifdef CONFIG_TMPFS |
@@ -3571,12 +3638,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3571 | * but the internal instance is left unlimited. | 3638 | * but the internal instance is left unlimited. |
3572 | */ | 3639 | */ |
3573 | if (!(sb->s_flags & SB_KERNMOUNT)) { | 3640 | if (!(sb->s_flags & SB_KERNMOUNT)) { |
3574 | sbinfo->max_blocks = shmem_default_max_blocks(); | 3641 | if (!(ctx->seen & SHMEM_SEEN_BLOCKS)) |
3575 | sbinfo->max_inodes = shmem_default_max_inodes(); | 3642 | ctx->blocks = shmem_default_max_blocks(); |
3576 | if (shmem_parse_options(data, sbinfo, false)) { | 3643 | if (!(ctx->seen & SHMEM_SEEN_INODES)) |
3577 | err = -EINVAL; | 3644 | ctx->inodes = shmem_default_max_inodes(); |
3578 | goto failed; | ||
3579 | } | ||
3580 | } else { | 3645 | } else { |
3581 | sb->s_flags |= SB_NOUSER; | 3646 | sb->s_flags |= SB_NOUSER; |
3582 | } | 3647 | } |
@@ -3585,11 +3650,18 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3585 | #else | 3650 | #else |
3586 | sb->s_flags |= SB_NOUSER; | 3651 | sb->s_flags |= SB_NOUSER; |
3587 | #endif | 3652 | #endif |
3653 | sbinfo->max_blocks = ctx->blocks; | ||
3654 | sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes; | ||
3655 | sbinfo->uid = ctx->uid; | ||
3656 | sbinfo->gid = ctx->gid; | ||
3657 | sbinfo->mode = ctx->mode; | ||
3658 | sbinfo->huge = ctx->huge; | ||
3659 | sbinfo->mpol = ctx->mpol; | ||
3660 | ctx->mpol = NULL; | ||
3588 | 3661 | ||
3589 | spin_lock_init(&sbinfo->stat_lock); | 3662 | spin_lock_init(&sbinfo->stat_lock); |
3590 | if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) | 3663 | if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) |
3591 | goto failed; | 3664 | goto failed; |
3592 | sbinfo->free_inodes = sbinfo->max_inodes; | ||
3593 | spin_lock_init(&sbinfo->shrinklist_lock); | 3665 | spin_lock_init(&sbinfo->shrinklist_lock); |
3594 | INIT_LIST_HEAD(&sbinfo->shrinklist); | 3666 | INIT_LIST_HEAD(&sbinfo->shrinklist); |
3595 | 3667 | ||
@@ -3622,6 +3694,31 @@ failed: | |||
3622 | return err; | 3694 | return err; |
3623 | } | 3695 | } |
3624 | 3696 | ||
3697 | static int shmem_get_tree(struct fs_context *fc) | ||
3698 | { | ||
3699 | return get_tree_nodev(fc, shmem_fill_super); | ||
3700 | } | ||
3701 | |||
3702 | static void shmem_free_fc(struct fs_context *fc) | ||
3703 | { | ||
3704 | struct shmem_options *ctx = fc->fs_private; | ||
3705 | |||
3706 | if (ctx) { | ||
3707 | mpol_put(ctx->mpol); | ||
3708 | kfree(ctx); | ||
3709 | } | ||
3710 | } | ||
3711 | |||
3712 | static const struct fs_context_operations shmem_fs_context_ops = { | ||
3713 | .free = shmem_free_fc, | ||
3714 | .get_tree = shmem_get_tree, | ||
3715 | #ifdef CONFIG_TMPFS | ||
3716 | .parse_monolithic = shmem_parse_options, | ||
3717 | .parse_param = shmem_parse_one, | ||
3718 | .reconfigure = shmem_reconfigure, | ||
3719 | #endif | ||
3720 | }; | ||
3721 | |||
3625 | static struct kmem_cache *shmem_inode_cachep; | 3722 | static struct kmem_cache *shmem_inode_cachep; |
3626 | 3723 | ||
3627 | static struct inode *shmem_alloc_inode(struct super_block *sb) | 3724 | static struct inode *shmem_alloc_inode(struct super_block *sb) |
@@ -3738,7 +3835,6 @@ static const struct super_operations shmem_ops = { | |||
3738 | .destroy_inode = shmem_destroy_inode, | 3835 | .destroy_inode = shmem_destroy_inode, |
3739 | #ifdef CONFIG_TMPFS | 3836 | #ifdef CONFIG_TMPFS |
3740 | .statfs = shmem_statfs, | 3837 | .statfs = shmem_statfs, |
3741 | .remount_fs = shmem_remount_fs, | ||
3742 | .show_options = shmem_show_options, | 3838 | .show_options = shmem_show_options, |
3743 | #endif | 3839 | #endif |
3744 | .evict_inode = shmem_evict_inode, | 3840 | .evict_inode = shmem_evict_inode, |
@@ -3759,16 +3855,30 @@ static const struct vm_operations_struct shmem_vm_ops = { | |||
3759 | #endif | 3855 | #endif |
3760 | }; | 3856 | }; |
3761 | 3857 | ||
3762 | static struct dentry *shmem_mount(struct file_system_type *fs_type, | 3858 | int shmem_init_fs_context(struct fs_context *fc) |
3763 | int flags, const char *dev_name, void *data) | ||
3764 | { | 3859 | { |
3765 | return mount_nodev(fs_type, flags, data, shmem_fill_super); | 3860 | struct shmem_options *ctx; |
3861 | |||
3862 | ctx = kzalloc(sizeof(struct shmem_options), GFP_KERNEL); | ||
3863 | if (!ctx) | ||
3864 | return -ENOMEM; | ||
3865 | |||
3866 | ctx->mode = 0777 | S_ISVTX; | ||
3867 | ctx->uid = current_fsuid(); | ||
3868 | ctx->gid = current_fsgid(); | ||
3869 | |||
3870 | fc->fs_private = ctx; | ||
3871 | fc->ops = &shmem_fs_context_ops; | ||
3872 | return 0; | ||
3766 | } | 3873 | } |
3767 | 3874 | ||
3768 | static struct file_system_type shmem_fs_type = { | 3875 | static struct file_system_type shmem_fs_type = { |
3769 | .owner = THIS_MODULE, | 3876 | .owner = THIS_MODULE, |
3770 | .name = "tmpfs", | 3877 | .name = "tmpfs", |
3771 | .mount = shmem_mount, | 3878 | .init_fs_context = shmem_init_fs_context, |
3879 | #ifdef CONFIG_TMPFS | ||
3880 | .parameters = &shmem_fs_parameters, | ||
3881 | #endif | ||
3772 | .kill_sb = kill_litter_super, | 3882 | .kill_sb = kill_litter_super, |
3773 | .fs_flags = FS_USERNS_MOUNT, | 3883 | .fs_flags = FS_USERNS_MOUNT, |
3774 | }; | 3884 | }; |
@@ -3912,7 +4022,8 @@ bool shmem_huge_enabled(struct vm_area_struct *vma) | |||
3912 | 4022 | ||
3913 | static struct file_system_type shmem_fs_type = { | 4023 | static struct file_system_type shmem_fs_type = { |
3914 | .name = "tmpfs", | 4024 | .name = "tmpfs", |
3915 | .mount = ramfs_mount, | 4025 | .init_fs_context = ramfs_init_fs_context, |
4026 | .parameters = &ramfs_fs_parameters, | ||
3916 | .kill_sb = kill_litter_super, | 4027 | .kill_sb = kill_litter_super, |
3917 | .fs_flags = FS_USERNS_MOUNT, | 4028 | .fs_flags = FS_USERNS_MOUNT, |
3918 | }; | 4029 | }; |