diff options
author | Amir Goldstein <amir73il@gmail.com> | 2017-05-16 17:12:41 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2017-05-19 03:33:49 -0400 |
commit | 21a228781104ae6fed7e720137ab024575071feb (patch) | |
tree | e75c1046173e195f9dfacfa28c88e12ae42b2bbc /fs | |
parent | 6266d465bde044a105f6c2d4e244680f951a2d70 (diff) |
ovl: handle rename when upper doesn't support xattr
On failure to set opaque/redirect xattr on rename, skip setting xattr and
return -EXDEV.
On failure to set opaque xattr when creating a new directory, -EIO is
returned instead of -EOPNOTSUPP.
Any failure to set those xattr will be recorded in super block and
then setting any xattr on upper won't be attempted again.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/dir.c | 29 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 1 | ||||
-rw-r--r-- | fs/overlayfs/util.c | 9 |
3 files changed, 20 insertions, 19 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 723b98b90698..80e0e202a346 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
@@ -127,17 +127,28 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry, | |||
127 | return err; | 127 | return err; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) | 130 | static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper, |
131 | int xerr) | ||
131 | { | 132 | { |
132 | int err; | 133 | int err; |
133 | 134 | ||
134 | err = ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0); | 135 | err = ovl_check_setxattr(dentry, upper, OVL_XATTR_OPAQUE, "y", 1, xerr); |
135 | if (!err) | 136 | if (!err) |
136 | ovl_dentry_set_opaque(dentry); | 137 | ovl_dentry_set_opaque(dentry); |
137 | 138 | ||
138 | return err; | 139 | return err; |
139 | } | 140 | } |
140 | 141 | ||
142 | static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) | ||
143 | { | ||
144 | /* | ||
145 | * Fail with -EIO when trying to create opaque dir and upper doesn't | ||
146 | * support xattrs. ovl_rename() calls ovl_set_opaque_xerr(-EXDEV) to | ||
147 | * return a specific error for noxattr case. | ||
148 | */ | ||
149 | return ovl_set_opaque_xerr(dentry, upperdentry, -EIO); | ||
150 | } | ||
151 | |||
141 | /* Common operations required to be done after creation of file on upper */ | 152 | /* Common operations required to be done after creation of file on upper */ |
142 | static void ovl_instantiate(struct dentry *dentry, struct inode *inode, | 153 | static void ovl_instantiate(struct dentry *dentry, struct inode *inode, |
143 | struct dentry *newdentry, bool hardlink) | 154 | struct dentry *newdentry, bool hardlink) |
@@ -846,18 +857,16 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir) | |||
846 | if (IS_ERR(redirect)) | 857 | if (IS_ERR(redirect)) |
847 | return PTR_ERR(redirect); | 858 | return PTR_ERR(redirect); |
848 | 859 | ||
849 | err = ovl_do_setxattr(ovl_dentry_upper(dentry), OVL_XATTR_REDIRECT, | 860 | err = ovl_check_setxattr(dentry, ovl_dentry_upper(dentry), |
850 | redirect, strlen(redirect), 0); | 861 | OVL_XATTR_REDIRECT, |
862 | redirect, strlen(redirect), -EXDEV); | ||
851 | if (!err) { | 863 | if (!err) { |
852 | spin_lock(&dentry->d_lock); | 864 | spin_lock(&dentry->d_lock); |
853 | ovl_dentry_set_redirect(dentry, redirect); | 865 | ovl_dentry_set_redirect(dentry, redirect); |
854 | spin_unlock(&dentry->d_lock); | 866 | spin_unlock(&dentry->d_lock); |
855 | } else { | 867 | } else { |
856 | kfree(redirect); | 868 | kfree(redirect); |
857 | if (err == -EOPNOTSUPP) | 869 | pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); |
858 | ovl_clear_redirect_dir(dentry->d_sb); | ||
859 | else | ||
860 | pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); | ||
861 | /* Fall back to userspace copy-up */ | 870 | /* Fall back to userspace copy-up */ |
862 | err = -EXDEV; | 871 | err = -EXDEV; |
863 | } | 872 | } |
@@ -992,7 +1001,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
992 | if (ovl_type_merge_or_lower(old)) | 1001 | if (ovl_type_merge_or_lower(old)) |
993 | err = ovl_set_redirect(old, samedir); | 1002 | err = ovl_set_redirect(old, samedir); |
994 | else if (!old_opaque && ovl_type_merge(new->d_parent)) | 1003 | else if (!old_opaque && ovl_type_merge(new->d_parent)) |
995 | err = ovl_set_opaque(old, olddentry); | 1004 | err = ovl_set_opaque_xerr(old, olddentry, -EXDEV); |
996 | if (err) | 1005 | if (err) |
997 | goto out_dput; | 1006 | goto out_dput; |
998 | } | 1007 | } |
@@ -1000,7 +1009,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
1000 | if (ovl_type_merge_or_lower(new)) | 1009 | if (ovl_type_merge_or_lower(new)) |
1001 | err = ovl_set_redirect(new, samedir); | 1010 | err = ovl_set_redirect(new, samedir); |
1002 | else if (!new_opaque && ovl_type_merge(old->d_parent)) | 1011 | else if (!new_opaque && ovl_type_merge(old->d_parent)) |
1003 | err = ovl_set_opaque(new, newdentry); | 1012 | err = ovl_set_opaque_xerr(new, newdentry, -EXDEV); |
1004 | if (err) | 1013 | if (err) |
1005 | goto out_dput; | 1014 | goto out_dput; |
1006 | } | 1015 | } |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index ce7c3aba61e4..505b18b56330 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -206,7 +206,6 @@ bool ovl_dentry_is_opaque(struct dentry *dentry); | |||
206 | bool ovl_dentry_is_whiteout(struct dentry *dentry); | 206 | bool ovl_dentry_is_whiteout(struct dentry *dentry); |
207 | void ovl_dentry_set_opaque(struct dentry *dentry); | 207 | void ovl_dentry_set_opaque(struct dentry *dentry); |
208 | bool ovl_redirect_dir(struct super_block *sb); | 208 | bool ovl_redirect_dir(struct super_block *sb); |
209 | void ovl_clear_redirect_dir(struct super_block *sb); | ||
210 | const char *ovl_dentry_get_redirect(struct dentry *dentry); | 209 | const char *ovl_dentry_get_redirect(struct dentry *dentry); |
211 | void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect); | 210 | void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect); |
212 | void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); | 211 | void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); |
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index b5a0dc36ee96..4d541a8d0834 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c | |||
@@ -191,14 +191,7 @@ bool ovl_redirect_dir(struct super_block *sb) | |||
191 | { | 191 | { |
192 | struct ovl_fs *ofs = sb->s_fs_info; | 192 | struct ovl_fs *ofs = sb->s_fs_info; |
193 | 193 | ||
194 | return ofs->config.redirect_dir; | 194 | return ofs->config.redirect_dir && !ofs->noxattr; |
195 | } | ||
196 | |||
197 | void ovl_clear_redirect_dir(struct super_block *sb) | ||
198 | { | ||
199 | struct ovl_fs *ofs = sb->s_fs_info; | ||
200 | |||
201 | ofs->config.redirect_dir = false; | ||
202 | } | 195 | } |
203 | 196 | ||
204 | const char *ovl_dentry_get_redirect(struct dentry *dentry) | 197 | const char *ovl_dentry_get_redirect(struct dentry *dentry) |