diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:49 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:49 -0500 |
commit | ab508822cab4c84f07373cd6ad107a1fd1362831 (patch) | |
tree | d612d840a78d2c1f1ead7d0cd699becb68caeb95 /fs | |
parent | 3b7a9a249a93e68b7bb318de40e64d3b68ba1a6d (diff) |
ovl: improve mount helpers
Move common checks into ovl_mount_dir() helper.
Create helper for looking up lower directories.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/super.c | 125 |
1 files changed, 73 insertions, 52 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index a17702833dd0..592370ff453a 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -669,24 +669,6 @@ static void ovl_unescape(char *s) | |||
669 | } | 669 | } |
670 | } | 670 | } |
671 | 671 | ||
672 | static int ovl_mount_dir(const char *name, struct path *path) | ||
673 | { | ||
674 | int err; | ||
675 | char *tmp = kstrdup(name, GFP_KERNEL); | ||
676 | |||
677 | if (!tmp) | ||
678 | return -ENOMEM; | ||
679 | |||
680 | ovl_unescape(tmp); | ||
681 | err = kern_path(tmp, LOOKUP_FOLLOW, path); | ||
682 | if (err) { | ||
683 | pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err); | ||
684 | err = -EINVAL; | ||
685 | } | ||
686 | kfree(tmp); | ||
687 | return err; | ||
688 | } | ||
689 | |||
690 | static bool ovl_is_allowed_fs_type(struct dentry *root) | 672 | static bool ovl_is_allowed_fs_type(struct dentry *root) |
691 | { | 673 | { |
692 | const struct dentry_operations *dop = root->d_op; | 674 | const struct dentry_operations *dop = root->d_op; |
@@ -706,6 +688,71 @@ static bool ovl_is_allowed_fs_type(struct dentry *root) | |||
706 | return true; | 688 | return true; |
707 | } | 689 | } |
708 | 690 | ||
691 | static int ovl_mount_dir_noesc(const char *name, struct path *path) | ||
692 | { | ||
693 | int err; | ||
694 | |||
695 | err = kern_path(name, LOOKUP_FOLLOW, path); | ||
696 | if (err) { | ||
697 | pr_err("overlayfs: failed to resolve '%s': %i\n", name, err); | ||
698 | goto out; | ||
699 | } | ||
700 | err = -EINVAL; | ||
701 | if (!ovl_is_allowed_fs_type(path->dentry)) { | ||
702 | pr_err("overlayfs: filesystem on '%s' not supported\n", name); | ||
703 | goto out_put; | ||
704 | } | ||
705 | if (!S_ISDIR(path->dentry->d_inode->i_mode)) { | ||
706 | pr_err("overlayfs: '%s' not a directory\n", name); | ||
707 | goto out_put; | ||
708 | } | ||
709 | return 0; | ||
710 | |||
711 | out_put: | ||
712 | path_put(path); | ||
713 | out: | ||
714 | return err; | ||
715 | } | ||
716 | |||
717 | static int ovl_mount_dir(const char *name, struct path *path) | ||
718 | { | ||
719 | int err = -ENOMEM; | ||
720 | char *tmp = kstrdup(name, GFP_KERNEL); | ||
721 | |||
722 | if (tmp) { | ||
723 | ovl_unescape(tmp); | ||
724 | err = ovl_mount_dir_noesc(tmp, path); | ||
725 | kfree(tmp); | ||
726 | } | ||
727 | return err; | ||
728 | } | ||
729 | |||
730 | static int ovl_lower_dir(const char *name, struct path *path, long *namelen, | ||
731 | int *stack_depth) | ||
732 | { | ||
733 | int err; | ||
734 | struct kstatfs statfs; | ||
735 | |||
736 | err = ovl_mount_dir(name, path); | ||
737 | if (err) | ||
738 | goto out; | ||
739 | |||
740 | err = vfs_statfs(path, &statfs); | ||
741 | if (err) { | ||
742 | pr_err("overlayfs: statfs failed on '%s'\n", name); | ||
743 | goto out_put; | ||
744 | } | ||
745 | *namelen = max(*namelen, statfs.f_namelen); | ||
746 | *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth); | ||
747 | |||
748 | return 0; | ||
749 | |||
750 | out_put: | ||
751 | path_put(path); | ||
752 | out: | ||
753 | return err; | ||
754 | } | ||
755 | |||
709 | /* Workdir should not be subdir of upperdir and vice versa */ | 756 | /* Workdir should not be subdir of upperdir and vice versa */ |
710 | static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) | 757 | static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) |
711 | { | 758 | { |
@@ -726,7 +773,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
726 | struct dentry *root_dentry; | 773 | struct dentry *root_dentry; |
727 | struct ovl_entry *oe; | 774 | struct ovl_entry *oe; |
728 | struct ovl_fs *ufs; | 775 | struct ovl_fs *ufs; |
729 | struct kstatfs statfs; | ||
730 | struct vfsmount *mnt; | 776 | struct vfsmount *mnt; |
731 | unsigned int i; | 777 | unsigned int i; |
732 | int err; | 778 | int err; |
@@ -756,48 +802,23 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
756 | if (err) | 802 | if (err) |
757 | goto out_put_upperpath; | 803 | goto out_put_upperpath; |
758 | 804 | ||
759 | err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath); | ||
760 | if (err) | ||
761 | goto out_put_workpath; | ||
762 | |||
763 | err = -EINVAL; | ||
764 | if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || | ||
765 | !S_ISDIR(lowerpath.dentry->d_inode->i_mode) || | ||
766 | !S_ISDIR(workpath.dentry->d_inode->i_mode)) { | ||
767 | pr_err("overlayfs: upperdir or lowerdir or workdir not a directory\n"); | ||
768 | goto out_put_lowerpath; | ||
769 | } | ||
770 | |||
771 | if (upperpath.mnt != workpath.mnt) { | 805 | if (upperpath.mnt != workpath.mnt) { |
772 | pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); | 806 | pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); |
773 | goto out_put_lowerpath; | 807 | goto out_put_workpath; |
774 | } | 808 | } |
775 | if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { | 809 | if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { |
776 | pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); | 810 | pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); |
777 | goto out_put_lowerpath; | 811 | goto out_put_workpath; |
778 | } | ||
779 | |||
780 | if (!ovl_is_allowed_fs_type(upperpath.dentry)) { | ||
781 | pr_err("overlayfs: filesystem of upperdir is not supported\n"); | ||
782 | goto out_put_lowerpath; | ||
783 | } | ||
784 | |||
785 | if (!ovl_is_allowed_fs_type(lowerpath.dentry)) { | ||
786 | pr_err("overlayfs: filesystem of lowerdir is not supported\n"); | ||
787 | goto out_put_lowerpath; | ||
788 | } | ||
789 | |||
790 | err = vfs_statfs(&lowerpath, &statfs); | ||
791 | if (err) { | ||
792 | pr_err("overlayfs: statfs failed on lowerpath\n"); | ||
793 | goto out_put_lowerpath; | ||
794 | } | 812 | } |
795 | ufs->lower_namelen = statfs.f_namelen; | 813 | sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; |
796 | 814 | ||
797 | sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, | 815 | err = ovl_lower_dir(ufs->config.lowerdir, &lowerpath, |
798 | lowerpath.mnt->mnt_sb->s_stack_depth) + 1; | 816 | &ufs->lower_namelen, &sb->s_stack_depth); |
817 | if (err) | ||
818 | goto out_put_workpath; | ||
799 | 819 | ||
800 | err = -EINVAL; | 820 | err = -EINVAL; |
821 | sb->s_stack_depth++; | ||
801 | if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { | 822 | if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { |
802 | pr_err("overlayfs: maximum fs stacking depth exceeded\n"); | 823 | pr_err("overlayfs: maximum fs stacking depth exceeded\n"); |
803 | goto out_put_lowerpath; | 824 | goto out_put_lowerpath; |