diff options
author | Erez Zadok <ezk@fsl.cs.sunysb.edu> | 2014-10-24 00:14:38 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-10-24 00:14:38 +0200 |
commit | f45827e84186af152492c6d0dcf4105b4a605f9b (patch) | |
tree | c202fa1dc66dec8c0cacd98d38492026a0359965 /fs | |
parent | cc2596392af3b1404421aaef828a255303c46f93 (diff) | |
download | linux-exynos-f45827e84186af152492c6d0dcf4105b4a605f9b.tar.gz linux-exynos-f45827e84186af152492c6d0dcf4105b4a605f9b.tar.bz2 linux-exynos-f45827e84186af152492c6d0dcf4105b4a605f9b.zip |
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.c | 76 |
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 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/statfs.h> +#include <linux/seq_file.h> #include "overlayfs.h" MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); @@ -25,12 +26,20 @@ MODULE_LICENSE("GPL"); #define OVERLAYFS_SUPER_MAGIC 0x794c764f +struct ovl_config { + char *lowerdir; + char *upperdir; + char *workdir; +}; + /* private information held for overlayfs's superblock */ struct ovl_fs { struct vfsmount *upper_mnt; struct vfsmount *lower_mnt; struct dentry *workdir; long lower_namelen; + /* pathnames of lower and upper dirs, for show_options */ + struct ovl_config config; }; struct ovl_dir_cache; @@ -384,6 +393,9 @@ static void ovl_put_super(struct super_block *sb) mntput(ufs->upper_mnt); mntput(ufs->lower_mnt); + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); + kfree(ufs->config.workdir); kfree(ufs); } @@ -413,15 +425,27 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) return err; } +/** + * ovl_show_options + * + * Prints the mount options for a given superblock. + * Returns zero; does not fail. + */ +static int ovl_show_options(struct seq_file *m, struct dentry *dentry) +{ + struct super_block *sb = dentry->d_sb; + struct ovl_fs *ufs = sb->s_fs_info; + + seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); + seq_printf(m, ",upperdir=%s", ufs->config.upperdir); + seq_printf(m, ",workdir=%s", ufs->config.workdir); + return 0; +} + static const struct super_operations ovl_super_operations = { .put_super = ovl_put_super, .statfs = ovl_statfs, -}; - -struct ovl_config { - char *lowerdir; - char *upperdir; - char *workdir; + .show_options = ovl_show_options, }; enum { @@ -442,10 +466,6 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) { char *p; - config->upperdir = NULL; - config->lowerdir = NULL; - config->workdir = NULL; - while ((p = strsep(&opt, ",")) != NULL) { int token; substring_t args[MAX_OPT_ARGS]; @@ -586,39 +606,40 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) struct dentry *root_dentry; struct ovl_entry *oe; struct ovl_fs *ufs; - struct ovl_config config; struct kstatfs statfs; int err; - err = ovl_parse_opt((char *) data, &config); - if (err) + err = -ENOMEM; + ufs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL); + if (!ufs) goto out; + err = ovl_parse_opt((char *) data, &ufs->config); + if (err) + goto out_free_config; + /* FIXME: workdir is not needed for a R/O mount */ err = -EINVAL; - if (!config.upperdir || !config.lowerdir || !config.workdir) { + if (!ufs->config.upperdir || !ufs->config.lowerdir || + !ufs->config.workdir) { pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); goto out_free_config; } err = -ENOMEM; - ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); - if (!ufs) - goto out_free_config; - oe = ovl_alloc_entry(); if (oe == NULL) - goto out_free_ufs; + goto out_free_config; - err = ovl_mount_dir(config.upperdir, &upperpath); + err = ovl_mount_dir(ufs->config.upperdir, &upperpath); if (err) goto out_free_oe; - err = ovl_mount_dir(config.lowerdir, &lowerpath); + err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath); if (err) goto out_put_upperpath; - err = ovl_mount_dir(config.workdir, &workpath); + err = ovl_mount_dir(ufs->config.workdir, &workpath); if (err) goto out_put_lowerpath; @@ -674,7 +695,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) err = PTR_ERR(ufs->workdir); if (IS_ERR(ufs->workdir)) { pr_err("overlayfs: failed to create directory %s/%s\n", - config.workdir, OVL_WORKDIR_NAME); + ufs->config.workdir, OVL_WORKDIR_NAME); goto out_put_lower_mnt; } @@ -729,12 +750,11 @@ out_put_upperpath: path_put(&upperpath); out_free_oe: kfree(oe); -out_free_ufs: - kfree(ufs); out_free_config: - kfree(config.lowerdir); - kfree(config.upperdir); - kfree(config.workdir); + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); + kfree(ufs->config.workdir); + kfree(ufs); out: return err; } |