aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorErez Zadok <ezk@fsl.cs.sunysb.edu>2014-10-23 18:14:38 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2014-10-23 18:14:38 -0400
commitf45827e84186af152492c6d0dcf4105b4a605f9b (patch)
treec202fa1dc66dec8c0cacd98d38492026a0359965 /fs
parentcc2596392af3b1404421aaef828a255303c46f93 (diff)
overlayfs: implement show_options
This is useful because of the stacking nature of overlayfs. Users like to find out (via /proc/mounts) which lower/upper directory were used at mount time. AV: even failing ovl_parse_opt() could've done some kstrdup() AV: failure of ovl_alloc_entry() should end up with ENOMEM, not EINVAL Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r--fs/overlayfs/super.c76
1 files changed, 48 insertions, 28 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index aaf562b9f937..7dcc24e84417 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/statfs.h> 19#include <linux/statfs.h>
20#include <linux/seq_file.h>
20#include "overlayfs.h" 21#include "overlayfs.h"
21 22
22MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); 23MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
@@ -25,12 +26,20 @@ MODULE_LICENSE("GPL");
25 26
26#define OVERLAYFS_SUPER_MAGIC 0x794c764f 27#define OVERLAYFS_SUPER_MAGIC 0x794c764f
27 28
29struct ovl_config {
30 char *lowerdir;
31 char *upperdir;
32 char *workdir;
33};
34
28/* private information held for overlayfs's superblock */ 35/* private information held for overlayfs's superblock */
29struct ovl_fs { 36struct ovl_fs {
30 struct vfsmount *upper_mnt; 37 struct vfsmount *upper_mnt;
31 struct vfsmount *lower_mnt; 38 struct vfsmount *lower_mnt;
32 struct dentry *workdir; 39 struct dentry *workdir;
33 long lower_namelen; 40 long lower_namelen;
41 /* pathnames of lower and upper dirs, for show_options */
42 struct ovl_config config;
34}; 43};
35 44
36struct ovl_dir_cache; 45struct ovl_dir_cache;
@@ -384,6 +393,9 @@ static void ovl_put_super(struct super_block *sb)
384 mntput(ufs->upper_mnt); 393 mntput(ufs->upper_mnt);
385 mntput(ufs->lower_mnt); 394 mntput(ufs->lower_mnt);
386 395
396 kfree(ufs->config.lowerdir);
397 kfree(ufs->config.upperdir);
398 kfree(ufs->config.workdir);
387 kfree(ufs); 399 kfree(ufs);
388} 400}
389 401
@@ -413,15 +425,27 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
413 return err; 425 return err;
414} 426}
415 427
428/**
429 * ovl_show_options
430 *
431 * Prints the mount options for a given superblock.
432 * Returns zero; does not fail.
433 */
434static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
435{
436 struct super_block *sb = dentry->d_sb;
437 struct ovl_fs *ufs = sb->s_fs_info;
438
439 seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir);
440 seq_printf(m, ",upperdir=%s", ufs->config.upperdir);
441 seq_printf(m, ",workdir=%s", ufs->config.workdir);
442 return 0;
443}
444
416static const struct super_operations ovl_super_operations = { 445static const struct super_operations ovl_super_operations = {
417 .put_super = ovl_put_super, 446 .put_super = ovl_put_super,
418 .statfs = ovl_statfs, 447 .statfs = ovl_statfs,
419}; 448 .show_options = ovl_show_options,
420
421struct ovl_config {
422 char *lowerdir;
423 char *upperdir;
424 char *workdir;
425}; 449};
426 450
427enum { 451enum {
@@ -442,10 +466,6 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
442{ 466{
443 char *p; 467 char *p;
444 468
445 config->upperdir = NULL;
446 config->lowerdir = NULL;
447 config->workdir = NULL;
448
449 while ((p = strsep(&opt, ",")) != NULL) { 469 while ((p = strsep(&opt, ",")) != NULL) {
450 int token; 470 int token;
451 substring_t args[MAX_OPT_ARGS]; 471 substring_t args[MAX_OPT_ARGS];
@@ -586,39 +606,40 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
586 struct dentry *root_dentry; 606 struct dentry *root_dentry;
587 struct ovl_entry *oe; 607 struct ovl_entry *oe;
588 struct ovl_fs *ufs; 608 struct ovl_fs *ufs;
589 struct ovl_config config;
590 struct kstatfs statfs; 609 struct kstatfs statfs;
591 int err; 610 int err;
592 611
593 err = ovl_parse_opt((char *) data, &config); 612 err = -ENOMEM;
594 if (err) 613 ufs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
614 if (!ufs)
595 goto out; 615 goto out;
596 616
617 err = ovl_parse_opt((char *) data, &ufs->config);
618 if (err)
619 goto out_free_config;
620
597 /* FIXME: workdir is not needed for a R/O mount */ 621 /* FIXME: workdir is not needed for a R/O mount */
598 err = -EINVAL; 622 err = -EINVAL;
599 if (!config.upperdir || !config.lowerdir || !config.workdir) { 623 if (!ufs->config.upperdir || !ufs->config.lowerdir ||
624 !ufs->config.workdir) {
600 pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); 625 pr_err("overlayfs: missing upperdir or lowerdir or workdir\n");
601 goto out_free_config; 626 goto out_free_config;
602 } 627 }
603 628
604 err = -ENOMEM; 629 err = -ENOMEM;
605 ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL);
606 if (!ufs)
607 goto out_free_config;
608
609 oe = ovl_alloc_entry(); 630 oe = ovl_alloc_entry();
610 if (oe == NULL) 631 if (oe == NULL)
611 goto out_free_ufs; 632 goto out_free_config;
612 633
613 err = ovl_mount_dir(config.upperdir, &upperpath); 634 err = ovl_mount_dir(ufs->config.upperdir, &upperpath);
614 if (err) 635 if (err)
615 goto out_free_oe; 636 goto out_free_oe;
616 637
617 err = ovl_mount_dir(config.lowerdir, &lowerpath); 638 err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath);
618 if (err) 639 if (err)
619 goto out_put_upperpath; 640 goto out_put_upperpath;
620 641
621 err = ovl_mount_dir(config.workdir, &workpath); 642 err = ovl_mount_dir(ufs->config.workdir, &workpath);
622 if (err) 643 if (err)
623 goto out_put_lowerpath; 644 goto out_put_lowerpath;
624 645
@@ -674,7 +695,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
674 err = PTR_ERR(ufs->workdir); 695 err = PTR_ERR(ufs->workdir);
675 if (IS_ERR(ufs->workdir)) { 696 if (IS_ERR(ufs->workdir)) {
676 pr_err("overlayfs: failed to create directory %s/%s\n", 697 pr_err("overlayfs: failed to create directory %s/%s\n",
677 config.workdir, OVL_WORKDIR_NAME); 698 ufs->config.workdir, OVL_WORKDIR_NAME);
678 goto out_put_lower_mnt; 699 goto out_put_lower_mnt;
679 } 700 }
680 701
@@ -729,12 +750,11 @@ out_put_upperpath:
729 path_put(&upperpath); 750 path_put(&upperpath);
730out_free_oe: 751out_free_oe:
731 kfree(oe); 752 kfree(oe);
732out_free_ufs:
733 kfree(ufs);
734out_free_config: 753out_free_config:
735 kfree(config.lowerdir); 754 kfree(ufs->config.lowerdir);
736 kfree(config.upperdir); 755 kfree(ufs->config.upperdir);
737 kfree(config.workdir); 756 kfree(ufs->config.workdir);
757 kfree(ufs);
738out: 758out:
739 return err; 759 return err;
740} 760}