ovl: mark parent impure and restore timestamp on ovl_link_up()
authorAmir Goldstein <amir73il@gmail.com>
Tue, 4 Jul 2017 19:04:06 +0000 (22:04 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 4 Jul 2017 20:08:15 +0000 (22:08 +0200)
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
fs/overlayfs/copy_up.c

index f193976560dee7b4da90963067de7669c73adfd2..acb6f97deb97ccd25c7a3b785f1ae1280858d6c4 100644 (file)
@@ -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);