diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:52 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:52 -0500 |
commit | a78d9f0d5d5ca9054703376c7c23c901807ddd87 (patch) | |
tree | 956a4d1e7517b9ead6f6f101dbfc1f344bec87fd /fs | |
parent | 53a08cb9b8bccfe58f1228c7c27baf34a83da78b (diff) |
ovl: support multiple lower layers
Allow "lowerdir=" option to contain multiple lower directories separated by
a colon (e.g. "lowerdir=/bin:/usr/bin"). Colon characters in filenames can
be escaped with a backslash.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/super.c | 110 |
1 files changed, 83 insertions, 27 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 35bb0adf10cf..5c495a17a5a3 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -60,6 +60,8 @@ struct ovl_entry { | |||
60 | struct path lowerstack[]; | 60 | struct path lowerstack[]; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | #define OVL_MAX_STACK 500 | ||
64 | |||
63 | const char *ovl_opaque_xattr = "trusted.overlay.opaque"; | 65 | const char *ovl_opaque_xattr = "trusted.overlay.opaque"; |
64 | 66 | ||
65 | static struct dentry *__ovl_dentry_lower(struct ovl_entry *oe) | 67 | static struct dentry *__ovl_dentry_lower(struct ovl_entry *oe) |
@@ -692,8 +694,12 @@ static bool ovl_is_allowed_fs_type(struct dentry *root) | |||
692 | 694 | ||
693 | static int ovl_mount_dir_noesc(const char *name, struct path *path) | 695 | static int ovl_mount_dir_noesc(const char *name, struct path *path) |
694 | { | 696 | { |
695 | int err; | 697 | int err = -EINVAL; |
696 | 698 | ||
699 | if (!*name) { | ||
700 | pr_err("overlayfs: empty lowerdir\n"); | ||
701 | goto out; | ||
702 | } | ||
697 | err = kern_path(name, LOOKUP_FOLLOW, path); | 703 | err = kern_path(name, LOOKUP_FOLLOW, path); |
698 | if (err) { | 704 | if (err) { |
699 | pr_err("overlayfs: failed to resolve '%s': %i\n", name, err); | 705 | pr_err("overlayfs: failed to resolve '%s': %i\n", name, err); |
@@ -735,7 +741,7 @@ static int ovl_lower_dir(const char *name, struct path *path, long *namelen, | |||
735 | int err; | 741 | int err; |
736 | struct kstatfs statfs; | 742 | struct kstatfs statfs; |
737 | 743 | ||
738 | err = ovl_mount_dir(name, path); | 744 | err = ovl_mount_dir_noesc(name, path); |
739 | if (err) | 745 | if (err) |
740 | goto out; | 746 | goto out; |
741 | 747 | ||
@@ -767,15 +773,38 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) | |||
767 | return ok; | 773 | return ok; |
768 | } | 774 | } |
769 | 775 | ||
776 | static unsigned int ovl_split_lowerdirs(char *str) | ||
777 | { | ||
778 | unsigned int ctr = 1; | ||
779 | char *s, *d; | ||
780 | |||
781 | for (s = d = str;; s++, d++) { | ||
782 | if (*s == '\\') { | ||
783 | s++; | ||
784 | } else if (*s == ':') { | ||
785 | *d = '\0'; | ||
786 | ctr++; | ||
787 | continue; | ||
788 | } | ||
789 | *d = *s; | ||
790 | if (!*s) | ||
791 | break; | ||
792 | } | ||
793 | return ctr; | ||
794 | } | ||
795 | |||
770 | static int ovl_fill_super(struct super_block *sb, void *data, int silent) | 796 | static int ovl_fill_super(struct super_block *sb, void *data, int silent) |
771 | { | 797 | { |
772 | struct path lowerpath; | ||
773 | struct path upperpath = { NULL, NULL }; | 798 | struct path upperpath = { NULL, NULL }; |
774 | struct path workpath = { NULL, NULL }; | 799 | struct path workpath = { NULL, NULL }; |
775 | struct dentry *root_dentry; | 800 | struct dentry *root_dentry; |
776 | struct ovl_entry *oe; | 801 | struct ovl_entry *oe; |
777 | struct ovl_fs *ufs; | 802 | struct ovl_fs *ufs; |
778 | struct vfsmount *mnt; | 803 | struct path *stack = NULL; |
804 | char *lowertmp; | ||
805 | char *lower; | ||
806 | unsigned int numlower; | ||
807 | unsigned int stacklen = 0; | ||
779 | unsigned int i; | 808 | unsigned int i; |
780 | int err; | 809 | int err; |
781 | 810 | ||
@@ -820,13 +849,31 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
820 | } | 849 | } |
821 | sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; | 850 | sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; |
822 | } | 851 | } |
823 | 852 | err = -ENOMEM; | |
824 | err = ovl_lower_dir(ufs->config.lowerdir, &lowerpath, | 853 | lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL); |
825 | &ufs->lower_namelen, &sb->s_stack_depth); | 854 | if (!lowertmp) |
826 | if (err) | ||
827 | goto out_put_workpath; | 855 | goto out_put_workpath; |
828 | 856 | ||
829 | err = -EINVAL; | 857 | err = -EINVAL; |
858 | stacklen = ovl_split_lowerdirs(lowertmp); | ||
859 | if (stacklen > OVL_MAX_STACK) | ||
860 | goto out_free_lowertmp; | ||
861 | |||
862 | stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); | ||
863 | if (!stack) | ||
864 | goto out_free_lowertmp; | ||
865 | |||
866 | lower = lowertmp; | ||
867 | for (numlower = 0; numlower < stacklen; numlower++) { | ||
868 | err = ovl_lower_dir(lower, &stack[numlower], | ||
869 | &ufs->lower_namelen, &sb->s_stack_depth); | ||
870 | if (err) | ||
871 | goto out_put_lowerpath; | ||
872 | |||
873 | lower = strchr(lower, '\0') + 1; | ||
874 | } | ||
875 | |||
876 | err = -EINVAL; | ||
830 | sb->s_stack_depth++; | 877 | sb->s_stack_depth++; |
831 | if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { | 878 | if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { |
832 | pr_err("overlayfs: maximum fs stacking depth exceeded\n"); | 879 | pr_err("overlayfs: maximum fs stacking depth exceeded\n"); |
@@ -850,24 +897,25 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
850 | } | 897 | } |
851 | } | 898 | } |
852 | 899 | ||
853 | ufs->lower_mnt = kcalloc(1, sizeof(struct vfsmount *), GFP_KERNEL); | 900 | ufs->lower_mnt = kcalloc(numlower, sizeof(struct vfsmount *), GFP_KERNEL); |
854 | if (ufs->lower_mnt == NULL) | 901 | if (ufs->lower_mnt == NULL) |
855 | goto out_put_workdir; | 902 | goto out_put_workdir; |
903 | for (i = 0; i < numlower; i++) { | ||
904 | struct vfsmount *mnt = clone_private_mount(&stack[i]); | ||
856 | 905 | ||
857 | mnt = clone_private_mount(&lowerpath); | 906 | if (IS_ERR(mnt)) { |
858 | err = PTR_ERR(mnt); | 907 | pr_err("overlayfs: failed to clone lowerpath\n"); |
859 | if (IS_ERR(mnt)) { | 908 | goto out_put_lower_mnt; |
860 | pr_err("overlayfs: failed to clone lowerpath\n"); | 909 | } |
861 | goto out_put_lower_mnt; | 910 | /* |
862 | } | 911 | * Make lower_mnt R/O. That way fchmod/fchown on lower file |
863 | /* | 912 | * will fail instead of modifying lower fs. |
864 | * Make lower_mnt R/O. That way fchmod/fchown on lower file | 913 | */ |
865 | * will fail instead of modifying lower fs. | 914 | mnt->mnt_flags |= MNT_READONLY; |
866 | */ | ||
867 | mnt->mnt_flags |= MNT_READONLY; | ||
868 | 915 | ||
869 | ufs->lower_mnt[0] = mnt; | 916 | ufs->lower_mnt[ufs->numlower] = mnt; |
870 | ufs->numlower = 1; | 917 | ufs->numlower++; |
918 | } | ||
871 | 919 | ||
872 | /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */ | 920 | /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */ |
873 | if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)) | 921 | if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)) |
@@ -876,7 +924,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
876 | sb->s_d_op = &ovl_dentry_operations; | 924 | sb->s_d_op = &ovl_dentry_operations; |
877 | 925 | ||
878 | err = -ENOMEM; | 926 | err = -ENOMEM; |
879 | oe = ovl_alloc_entry(1); | 927 | oe = ovl_alloc_entry(numlower); |
880 | if (!oe) | 928 | if (!oe) |
881 | goto out_put_lower_mnt; | 929 | goto out_put_lower_mnt; |
882 | 930 | ||
@@ -885,12 +933,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
885 | goto out_free_oe; | 933 | goto out_free_oe; |
886 | 934 | ||
887 | mntput(upperpath.mnt); | 935 | mntput(upperpath.mnt); |
888 | mntput(lowerpath.mnt); | 936 | for (i = 0; i < numlower; i++) |
937 | mntput(stack[i].mnt); | ||
889 | path_put(&workpath); | 938 | path_put(&workpath); |
939 | kfree(lowertmp); | ||
890 | 940 | ||
891 | oe->__upperdentry = upperpath.dentry; | 941 | oe->__upperdentry = upperpath.dentry; |
892 | oe->lowerstack[0].dentry = lowerpath.dentry; | 942 | for (i = 0; i < numlower; i++) { |
893 | oe->lowerstack[0].mnt = ufs->lower_mnt[0]; | 943 | oe->lowerstack[i].dentry = stack[i].dentry; |
944 | oe->lowerstack[i].mnt = ufs->lower_mnt[i]; | ||
945 | } | ||
894 | 946 | ||
895 | root_dentry->d_fsdata = oe; | 947 | root_dentry->d_fsdata = oe; |
896 | 948 | ||
@@ -912,7 +964,11 @@ out_put_workdir: | |||
912 | out_put_upper_mnt: | 964 | out_put_upper_mnt: |
913 | mntput(ufs->upper_mnt); | 965 | mntput(ufs->upper_mnt); |
914 | out_put_lowerpath: | 966 | out_put_lowerpath: |
915 | path_put(&lowerpath); | 967 | for (i = 0; i < numlower; i++) |
968 | path_put(&stack[i]); | ||
969 | kfree(stack); | ||
970 | out_free_lowertmp: | ||
971 | kfree(lowertmp); | ||
916 | out_put_workpath: | 972 | out_put_workpath: |
917 | path_put(&workpath); | 973 | path_put(&workpath); |
918 | out_put_upperpath: | 974 | out_put_upperpath: |