]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ovl: add flag for upper in ovl_entry
authorMiklos Szeredi <mszeredi@redhat.com>
Tue, 4 Jul 2017 20:03:18 +0000 (22:03 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 4 Jul 2017 20:03:18 +0000 (22:03 +0200)
For rename, we need to ensure that an upper alias exists for hard links
before attempting the operation.  Introduce a flag in ovl_entry to track
the state of the upper alias.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/namei.c
fs/overlayfs/overlayfs.h
fs/overlayfs/ovl_entry.h
fs/overlayfs/super.c
fs/overlayfs/util.c

index 8f9e26e9138632999dcf99fec2465efec89ca663..58c06bd58a96d2fdcdb74a21ee54c501416550b7 100644 (file)
@@ -472,6 +472,7 @@ static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c)
        if (err)
                goto out_cleanup;
 
+       ovl_dentry_set_upper_alias(c->dentry);
        ovl_inode_update(d_inode(c->dentry), newdentry);
 out:
        dput(temp);
index a072c27e03bc275396feb90ba3ce80ca805530b8..8b2b23181b19cfe26b692159ffac6f6fa230335c 100644 (file)
@@ -156,6 +156,7 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
                            struct dentry *newdentry, bool hardlink)
 {
        ovl_dentry_version_inc(dentry->d_parent);
+       ovl_dentry_set_upper_alias(dentry);
        if (!hardlink) {
                ovl_inode_update(inode, newdentry);
                ovl_copyattr(newdentry->d_inode, inode);
index f7fb0c91941971135606fab77b2ea9446468c533..2d8b6292fe21e90cfc4d50f9cec50739bc73b382 100644 (file)
@@ -674,7 +674,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
        memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
        dentry->d_fsdata = oe;
 
-       if (index && !upperdentry)
+       if (upperdentry)
+               ovl_dentry_set_upper_alias(dentry);
+       else if (index)
                upperdentry = dget(index);
 
        if (upperdentry || ctr) {
index f3e49cf3451781cb564315740c0e36a6e0533b4a..751b36a5c22f253579fe643a5e33f335e6fd265f 100644 (file)
@@ -206,6 +206,8 @@ void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
 bool ovl_dentry_is_opaque(struct dentry *dentry);
 bool ovl_dentry_is_whiteout(struct dentry *dentry);
 void ovl_dentry_set_opaque(struct dentry *dentry);
+bool ovl_dentry_has_upper_alias(struct dentry *dentry);
+void ovl_dentry_set_upper_alias(struct dentry *dentry);
 bool ovl_redirect_dir(struct super_block *sb);
 const char *ovl_dentry_get_redirect(struct dentry *dentry);
 void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
index 9642ec64467b56501d107f953e8835d2ae91f533..878a750986dd799ad17d9acfc3818e93dcf288fa 100644 (file)
@@ -42,7 +42,10 @@ struct ovl_fs {
 /* private information held for every overlayfs dentry */
 struct ovl_entry {
        union {
-               bool opaque;
+               struct {
+                       unsigned long has_upper;
+                       bool opaque;
+               };
                struct rcu_head rcu;
        };
        unsigned numlower;
index 791581c370f514e5754298ea537bc7f31f9db406..f29ee08cf99f832a2103e46b7e215a7101d205b6 100644 (file)
@@ -1119,6 +1119,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        kfree(lowertmp);
 
        if (upperpath.dentry) {
+               oe->has_upper = true;
                if (ovl_is_impuredir(upperpath.dentry))
                        ovl_set_flag(OVL_IMPURE, d_inode(root_dentry));
        }
index c80b4bf1e64f1ce06244d98a0a8823cabdc7df8e..38fa75228c66e21d229695c5cd5df8730b6bc4d1 100644 (file)
@@ -201,6 +201,25 @@ void ovl_dentry_set_opaque(struct dentry *dentry)
        oe->opaque = true;
 }
 
+/*
+ * For hard links it's possible for ovl_dentry_upper() to return positive, while
+ * there's no actual upper alias for the inode.  Copy up code needs to know
+ * about the existence of the upper alias, so it can't use ovl_dentry_upper().
+ */
+bool ovl_dentry_has_upper_alias(struct dentry *dentry)
+{
+       struct ovl_entry *oe = dentry->d_fsdata;
+
+       return oe->has_upper;
+}
+
+void ovl_dentry_set_upper_alias(struct dentry *dentry)
+{
+       struct ovl_entry *oe = dentry->d_fsdata;
+
+       oe->has_upper = true;
+}
+
 bool ovl_redirect_dir(struct super_block *sb)
 {
        struct ovl_fs *ofs = sb->s_fs_info;