summaryrefslogtreecommitdiff
path: root/fs/overlayfs/copy_up.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/copy_up.c')
-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);