diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:51 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:51 -0500 |
commit | 53a08cb9b8bccfe58f1228c7c27baf34a83da78b (patch) | |
tree | b3019e8ea9ea3c98a198184ac4f207a11339cc4e | |
parent | ab508822cab4c84f07373cd6ad107a1fd1362831 (diff) |
ovl: make upperdir optional
Make "upperdir=" mount option optional. If "upperdir=" is not given, then
the "workdir=" option is also optional (and ignored if given).
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r-- | fs/overlayfs/super.c | 83 |
1 files changed, 47 insertions, 36 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 592370ff453a..35bb0adf10cf 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -516,8 +516,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) | |||
516 | struct ovl_fs *ufs = sb->s_fs_info; | 516 | struct ovl_fs *ufs = sb->s_fs_info; |
517 | 517 | ||
518 | seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); | 518 | seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); |
519 | seq_printf(m, ",upperdir=%s", ufs->config.upperdir); | 519 | if (ufs->config.upperdir) { |
520 | seq_printf(m, ",workdir=%s", ufs->config.workdir); | 520 | seq_printf(m, ",upperdir=%s", ufs->config.upperdir); |
521 | seq_printf(m, ",workdir=%s", ufs->config.workdir); | ||
522 | } | ||
521 | return 0; | 523 | return 0; |
522 | } | 524 | } |
523 | 525 | ||
@@ -768,8 +770,8 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) | |||
768 | static int ovl_fill_super(struct super_block *sb, void *data, int silent) | 770 | static int ovl_fill_super(struct super_block *sb, void *data, int silent) |
769 | { | 771 | { |
770 | struct path lowerpath; | 772 | struct path lowerpath; |
771 | struct path upperpath; | 773 | struct path upperpath = { NULL, NULL }; |
772 | struct path workpath; | 774 | struct path workpath = { NULL, NULL }; |
773 | struct dentry *root_dentry; | 775 | struct dentry *root_dentry; |
774 | struct ovl_entry *oe; | 776 | struct ovl_entry *oe; |
775 | struct ovl_fs *ufs; | 777 | struct ovl_fs *ufs; |
@@ -786,31 +788,38 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
786 | if (err) | 788 | if (err) |
787 | goto out_free_config; | 789 | goto out_free_config; |
788 | 790 | ||
789 | /* FIXME: workdir is not needed for a R/O mount */ | ||
790 | err = -EINVAL; | 791 | err = -EINVAL; |
791 | if (!ufs->config.upperdir || !ufs->config.lowerdir || | 792 | if (!ufs->config.lowerdir) { |
792 | !ufs->config.workdir) { | 793 | pr_err("overlayfs: missing 'lowerdir'\n"); |
793 | pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); | ||
794 | goto out_free_config; | 794 | goto out_free_config; |
795 | } | 795 | } |
796 | 796 | ||
797 | err = ovl_mount_dir(ufs->config.upperdir, &upperpath); | 797 | sb->s_stack_depth = 0; |
798 | if (err) | 798 | if (ufs->config.upperdir) { |
799 | goto out_free_config; | 799 | /* FIXME: workdir is not needed for a R/O mount */ |
800 | if (!ufs->config.workdir) { | ||
801 | pr_err("overlayfs: missing 'workdir'\n"); | ||
802 | goto out_free_config; | ||
803 | } | ||
800 | 804 | ||
801 | err = ovl_mount_dir(ufs->config.workdir, &workpath); | 805 | err = ovl_mount_dir(ufs->config.upperdir, &upperpath); |
802 | if (err) | 806 | if (err) |
803 | goto out_put_upperpath; | 807 | goto out_free_config; |
804 | 808 | ||
805 | if (upperpath.mnt != workpath.mnt) { | 809 | err = ovl_mount_dir(ufs->config.workdir, &workpath); |
806 | pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); | 810 | if (err) |
807 | goto out_put_workpath; | 811 | goto out_put_upperpath; |
808 | } | 812 | |
809 | if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { | 813 | if (upperpath.mnt != workpath.mnt) { |
810 | pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); | 814 | pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); |
811 | goto out_put_workpath; | 815 | goto out_put_workpath; |
816 | } | ||
817 | if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { | ||
818 | pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); | ||
819 | goto out_put_workpath; | ||
820 | } | ||
821 | sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; | ||
812 | } | 822 | } |
813 | sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; | ||
814 | 823 | ||
815 | err = ovl_lower_dir(ufs->config.lowerdir, &lowerpath, | 824 | err = ovl_lower_dir(ufs->config.lowerdir, &lowerpath, |
816 | &ufs->lower_namelen, &sb->s_stack_depth); | 825 | &ufs->lower_namelen, &sb->s_stack_depth); |
@@ -824,19 +833,21 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
824 | goto out_put_lowerpath; | 833 | goto out_put_lowerpath; |
825 | } | 834 | } |
826 | 835 | ||
827 | ufs->upper_mnt = clone_private_mount(&upperpath); | 836 | if (ufs->config.upperdir) { |
828 | err = PTR_ERR(ufs->upper_mnt); | 837 | ufs->upper_mnt = clone_private_mount(&upperpath); |
829 | if (IS_ERR(ufs->upper_mnt)) { | 838 | err = PTR_ERR(ufs->upper_mnt); |
830 | pr_err("overlayfs: failed to clone upperpath\n"); | 839 | if (IS_ERR(ufs->upper_mnt)) { |
831 | goto out_put_lowerpath; | 840 | pr_err("overlayfs: failed to clone upperpath\n"); |
832 | } | 841 | goto out_put_lowerpath; |
842 | } | ||
833 | 843 | ||
834 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); | 844 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); |
835 | err = PTR_ERR(ufs->workdir); | 845 | err = PTR_ERR(ufs->workdir); |
836 | if (IS_ERR(ufs->workdir)) { | 846 | if (IS_ERR(ufs->workdir)) { |
837 | pr_err("overlayfs: failed to create directory %s/%s\n", | 847 | pr_err("overlayfs: failed to create directory %s/%s\n", |
838 | ufs->config.workdir, OVL_WORKDIR_NAME); | 848 | ufs->config.workdir, OVL_WORKDIR_NAME); |
839 | goto out_put_upper_mnt; | 849 | goto out_put_upper_mnt; |
850 | } | ||
840 | } | 851 | } |
841 | 852 | ||
842 | ufs->lower_mnt = kcalloc(1, sizeof(struct vfsmount *), GFP_KERNEL); | 853 | ufs->lower_mnt = kcalloc(1, sizeof(struct vfsmount *), GFP_KERNEL); |
@@ -858,8 +869,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
858 | ufs->lower_mnt[0] = mnt; | 869 | ufs->lower_mnt[0] = mnt; |
859 | ufs->numlower = 1; | 870 | ufs->numlower = 1; |
860 | 871 | ||
861 | /* If the upper fs is r/o, we mark overlayfs r/o too */ | 872 | /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */ |
862 | if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) | 873 | if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)) |
863 | sb->s_flags |= MS_RDONLY; | 874 | sb->s_flags |= MS_RDONLY; |
864 | 875 | ||
865 | sb->s_d_op = &ovl_dentry_operations; | 876 | sb->s_d_op = &ovl_dentry_operations; |