summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-12-16 11:02:55 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-16 11:02:55 +0100
commit3ee23ff1025a18796607cf4110a8ffa8e2d163fd (patch)
tree1b5173c39a66443e5665efaf82e7fe1b4c40119e
parent370e55ace59c2d3ed8f0ca933155030b9652e04f (diff)
downloadlwn-3ee23ff1025a18796607cf4110a8ffa8e2d163fd.tar.gz
lwn-3ee23ff1025a18796607cf4110a8ffa8e2d163fd.zip
ovl: check lower existence of rename target
Check if something exists on the lower layer(s) under the target or rename to decide if directory needs to be marked "opaque". Marking opaque is done before the rename, and on failure the marking was undone. Also the opaque xattr was removed if the target didn't cover anything. This patch changes behavior so that removal of "opaque" is not done in either of the above cases. This means that directory may have the opaque flag even if it doesn't cover anything. However this shouldn't affect the performance or semantics of the overalay, while simplifying the code. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/dir.c63
1 files changed, 11 insertions, 52 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 69c3971a9992..f24b6b967901 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -126,17 +126,6 @@ static int ovl_set_opaque(struct dentry *upperdentry)
return ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0);
}
-static void ovl_remove_opaque(struct dentry *upperdentry)
-{
- int err;
-
- err = ovl_do_removexattr(upperdentry, OVL_XATTR_OPAQUE);
- if (err) {
- pr_warn("overlayfs: failed to remove opaque from '%s' (%i)\n",
- upperdentry->d_name.name, err);
- }
-}
-
static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
@@ -817,9 +806,6 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
goto out_drop_write;
}
- old_opaque = ovl_dentry_is_opaque(old);
- new_opaque = ovl_dentry_is_opaque(new);
-
old_cred = ovl_override_creds(old->d_sb);
if (overwrite && new_is_dir && ovl_type_merge_or_lower(new)) {
@@ -868,6 +854,9 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (IS_ERR(newdentry))
goto out_dput_old;
+ old_opaque = ovl_dentry_is_opaque(old);
+ new_opaque = ovl_dentry_is_opaque(new);
+
err = -ESTALE;
if (ovl_dentry_upper(new)) {
if (opaquedir) {
@@ -891,54 +880,24 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (WARN_ON(olddentry->d_inode == newdentry->d_inode))
goto out_dput;
- if (is_dir && !old_opaque && new_opaque) {
+ if (is_dir && !old_opaque && ovl_lower_positive(new)) {
err = ovl_set_opaque(olddentry);
if (err)
goto out_dput;
+ ovl_dentry_set_opaque(old, true);
}
- if (!overwrite && new_is_dir && old_opaque && !new_opaque) {
+ if (!overwrite &&
+ new_is_dir && !new_opaque && ovl_lower_positive(old)) {
err = ovl_set_opaque(newdentry);
if (err)
goto out_dput;
+ ovl_dentry_set_opaque(new, true);
}
- if (old_opaque || new_opaque) {
- err = ovl_do_rename(old_upperdir->d_inode, olddentry,
- new_upperdir->d_inode, newdentry,
- flags);
- } else {
- /* No debug for the plain case */
- BUG_ON(flags & ~RENAME_EXCHANGE);
- err = vfs_rename(old_upperdir->d_inode, olddentry,
- new_upperdir->d_inode, newdentry,
- NULL, flags);
- }
-
- if (err) {
- if (is_dir && !old_opaque && new_opaque)
- ovl_remove_opaque(olddentry);
- if (!overwrite && new_is_dir && old_opaque && !new_opaque)
- ovl_remove_opaque(newdentry);
+ err = ovl_do_rename(old_upperdir->d_inode, olddentry,
+ new_upperdir->d_inode, newdentry, flags);
+ if (err)
goto out_dput;
- }
-
- if (is_dir && old_opaque && !new_opaque)
- ovl_remove_opaque(olddentry);
- if (!overwrite && new_is_dir && !old_opaque && new_opaque)
- ovl_remove_opaque(newdentry);
-
- /*
- * Old dentry now lives in different location. Dentries in
- * lowerstack are stale. We cannot drop them here because
- * access to them is lockless. This could be only pure upper
- * or opaque directory - numlower is zero. Or upper non-dir
- * entry - its pureness is tracked by flag opaque.
- */
- if (old_opaque != new_opaque) {
- ovl_dentry_set_opaque(old, new_opaque);
- if (!overwrite)
- ovl_dentry_set_opaque(new, old_opaque);
- }
if (cleanup_whiteout)
ovl_cleanup(old_upperdir->d_inode, newdentry);