From aa88a112a579b0122e62eff87d581fcca11ad805 Mon Sep 17 00:00:00 2001 From: Erez Zadok Date: Mon, 23 May 2011 20:59:20 -0400 Subject: [PATCH 06/13] overlayfs: implement show_options Patch-mainline: not yet 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. Signed-off-by: Erez Zadok Signed-off-by: Miklos Szeredi --- fs/overlayfs/super.c | 63 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 20 deletions(-) --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "overlayfs.h" MODULE_AUTHOR("Miklos Szeredi "); @@ -26,12 +27,21 @@ MODULE_LICENSE("GPL"); #define OVERLAYFS_SUPER_MAGIC 0x794c764f +struct ovl_config { + char *lowerdir; + char *upperdir; +}; + +/* private information held for overlayfs's superblock */ struct ovl_fs { struct vfsmount *upper_mnt; struct vfsmount *lower_mnt; long lower_namelen; + /* pathnames of lower and upper dirs, for show_options */ + struct ovl_config config; }; +/* private information held for every overlayfs dentry */ struct ovl_entry { /* * Keep "double reference" on upper dentries, so that @@ -389,6 +399,8 @@ static void ovl_put_super(struct super_b mntput(ufs->upper_mnt); mntput(ufs->lower_mnt); + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); kfree(ufs); } @@ -437,15 +449,27 @@ static int ovl_statfs(struct dentry *den 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); + return 0; +} + static const struct super_operations ovl_super_operations = { .put_super = ovl_put_super, .remount_fs = ovl_remount_fs, .statfs = ovl_statfs, -}; - -struct ovl_config { - char *lowerdir; - char *upperdir; + .show_options = ovl_show_options, }; enum { @@ -505,34 +529,33 @@ static int ovl_fill_super(struct super_b 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 = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); + if (!ufs) goto out; + err = ovl_parse_opt((char *) data, &ufs->config); + if (err) + goto out_free_ufs; + err = -EINVAL; - if (!config.upperdir || !config.lowerdir) { + if (!ufs->config.upperdir || !ufs->config.lowerdir) { pr_err("overlayfs: missing upperdir or lowerdir\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 = kern_path(config.upperdir, LOOKUP_FOLLOW, &upperpath); + err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); if (err) goto out_free_oe; - err = kern_path(config.lowerdir, LOOKUP_FOLLOW, &lowerpath); + err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); if (err) goto out_put_upperpath; @@ -616,11 +639,11 @@ static int ovl_fill_super(struct super_b path_put(&upperpath); out_free_oe: kfree(oe); +out_free_config: + kfree(ufs->config.lowerdir); + kfree(ufs->config.upperdir); out_free_ufs: kfree(ufs); -out_free_config: - kfree(config.lowerdir); - kfree(config.upperdir); out: return err; }