summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-07-04 22:04:06 +0300
committerMiklos Szeredi <mszeredi@redhat.com>2017-07-04 22:08:15 +0200
commitf4439de118283159ff165e52036134a278ebf990 (patch)
treeb634785151c01ed649edd6376f22585b2f3dadd8
parent9412812ef54861081904f24ddaf176b957b98d40 (diff)
downloadlinux-f4439de118283159ff165e52036134a278ebf990.tar.gz
ovl: mark parent impure and restore timestamp on ovl_link_up()
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
-rw-r--r--fs/overlayfs/copy_up.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index f193976560de..acb6f97deb97 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -316,48 +316,57 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
 	return err;
 }
 
-static int ovl_link_up(struct dentry *parent, struct dentry *dentry)
+struct ovl_copy_up_ctx {
+	struct dentry *parent;
+	struct dentry *dentry;
+	struct path lowerpath;
+	struct kstat stat;
+	struct kstat pstat;
+	const char *link;
+	struct dentry *destdir;
+	struct qstr destname;
+	struct dentry *workdir;
+	bool tmpfile;
+	bool origin;
+};
+
+static int ovl_link_up(struct ovl_copy_up_ctx *c)
 {
 	int err;
 	struct dentry *upper;
-	struct dentry *upperdir = ovl_dentry_upper(parent);
+	struct dentry *upperdir = ovl_dentry_upper(c->parent);
 	struct inode *udir = d_inode(upperdir);
 
-	err = ovl_set_nlink_lower(dentry);
+	/* Mark parent "impure" because it may now contain non-pure upper */
+	err = ovl_set_impure(c->parent, upperdir);
+	if (err)
+		return err;
+
+	err = ovl_set_nlink_lower(c->dentry);
 	if (err)
 		return err;
 
 	inode_lock_nested(udir, I_MUTEX_PARENT);
-	upper = lookup_one_len(dentry->d_name.name, upperdir,
-			       dentry->d_name.len);
+	upper = lookup_one_len(c->dentry->d_name.name, upperdir,
+			       c->dentry->d_name.len);
 	err = PTR_ERR(upper);
 	if (!IS_ERR(upper)) {
-		err = ovl_do_link(ovl_dentry_upper(dentry), udir, upper, true);
+		err = ovl_do_link(ovl_dentry_upper(c->dentry), udir, upper,
+				  true);
 		dput(upper);
 
-		if (!err)
-			ovl_dentry_set_upper_alias(dentry);
+		if (!err) {
+			/* Restore timestamps on parent (best effort) */
+			ovl_set_timestamps(upperdir, &c->pstat);
+			ovl_dentry_set_upper_alias(c->dentry);
+		}
 	}
 	inode_unlock(udir);
-	ovl_set_nlink_upper(dentry);
+	ovl_set_nlink_upper(c->dentry);
 
 	return err;
 }
 
-struct ovl_copy_up_ctx {
-	struct dentry *parent;
-	struct dentry *dentry;
-	struct path lowerpath;
-	struct kstat stat;
-	struct kstat pstat;
-	const char *link;
-	struct dentry *destdir;
-	struct qstr destname;
-	struct dentry *workdir;
-	bool tmpfile;
-	bool origin;
-};
-
 static int ovl_install_temp(struct ovl_copy_up_ctx *c, struct dentry *temp,
 			    struct dentry **newdentry)
 {
@@ -629,7 +638,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 		if (!ovl_dentry_upper(dentry))
 			err = ovl_do_copy_up(&ctx);
 		if (!err && !ovl_dentry_has_upper_alias(dentry))
-			err = ovl_link_up(parent, dentry);
+			err = ovl_link_up(&ctx);
 		ovl_copy_up_end(dentry);
 	}
 	do_delayed_call(&done);