diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2017-07-04 22:03:18 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2017-07-04 22:03:18 +0200 |
commit | 55acc6618259c8ff0a400a131f0f4b613e96010a (patch) | |
tree | 82f73eccca8d417ec8c77ad1b02dd28748c5c456 /fs/overlayfs | |
parent | 23f0ab13eaa69b4a351184cbec448be2aad3a3a9 (diff) |
ovl: add flag for upper in ovl_entry
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>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r-- | fs/overlayfs/copy_up.c | 1 | ||||
-rw-r--r-- | fs/overlayfs/dir.c | 1 | ||||
-rw-r--r-- | fs/overlayfs/namei.c | 4 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 | ||||
-rw-r--r-- | fs/overlayfs/ovl_entry.h | 5 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 1 | ||||
-rw-r--r-- | fs/overlayfs/util.c | 19 |
7 files changed, 31 insertions, 2 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 8f9e26e91386..58c06bd58a96 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -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); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index a072c27e03bc..8b2b23181b19 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -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); diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index f7fb0c919419..2d8b6292fe21 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -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) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index f3e49cf34517..751b36a5c22f 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -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); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 9642ec64467b..878a750986dd 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -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; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 791581c370f5..f29ee08cf99f 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -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)); } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index c80b4bf1e64f..38fa75228c66 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -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; |