diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2016-05-26 02:01:47 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-07-29 12:05:22 +0200 |
commit | 58ed4e70f253d80ed72faba7873dc11603b398bc (patch) | |
tree | 83d8e490d7ce0b206427305213a187416daa3152 /fs | |
parent | eead4f2dc4f851a3790c49850e96a1d155bf5451 (diff) |
ovl: store ovl_entry in inode->i_private for all inodes
Previously this was only done for directory inodes. Doing so for all
inodes makes for a nice cleanup in ovl_permission at zero cost.
Inodes are not shared for hard links on the overlay, so this works fine.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/inode.c | 48 |
1 files changed, 11 insertions, 37 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index d554e86abbe3..32ae8b49a72c 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -109,31 +109,12 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, int ovl_permission(struct inode *inode, int mask) { - struct ovl_entry *oe; - struct dentry *alias = NULL; - struct inode *realinode; - struct dentry *realdentry; + struct ovl_entry *oe = inode->i_private; bool is_upper; + struct dentry *realdentry = ovl_entry_real(oe, &is_upper); + struct inode *realinode; int err; - if (S_ISDIR(inode->i_mode)) { - oe = inode->i_private; - } else if (mask & MAY_NOT_BLOCK) { - return -ECHILD; - } else { - /* - * For non-directories find an alias and get the info - * from there. - */ - alias = d_find_any_alias(inode); - if (WARN_ON(!alias)) - return -ENOENT; - - oe = alias->d_fsdata; - } - - realdentry = ovl_entry_real(oe, &is_upper); - if (ovl_is_default_permissions(inode)) { struct kstat stat; struct path realpath = { .dentry = realdentry }; @@ -145,26 +126,23 @@ int ovl_permission(struct inode *inode, int mask) err = vfs_getattr(&realpath, &stat); if (err) - goto out_dput; + return err; - err = -ESTALE; if ((stat.mode ^ inode->i_mode) & S_IFMT) - goto out_dput; + return -ESTALE; inode->i_mode = stat.mode; inode->i_uid = stat.uid; inode->i_gid = stat.gid; - err = generic_permission(inode, mask); - goto out_dput; + return generic_permission(inode, mask); } /* Careful in RCU walk mode */ - realinode = ACCESS_ONCE(realdentry->d_inode); + realinode = d_inode_rcu(realdentry); if (!realinode) { WARN_ON(!(mask & MAY_NOT_BLOCK)); - err = -ENOENT; - goto out_dput; + return -ENOENT; } if (mask & MAY_WRITE) { @@ -183,16 +161,12 @@ int ovl_permission(struct inode *inode, int mask) * constructed return EROFS to prevent modification of * upper layer. */ - err = -EROFS; if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - goto out_dput; + return -EROFS; } - err = __inode_permission(realinode, mask); -out_dput: - dput(alias); - return err; + return __inode_permission(realinode, mask); } static const char *ovl_get_link(struct dentry *dentry, @@ -405,11 +379,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_flags |= S_NOATIME | S_NOCMTIME; + inode->i_private = oe; mode &= S_IFMT; switch (mode) { case S_IFDIR: - inode->i_private = oe; inode->i_op = &ovl_dir_inode_operations; inode->i_fop = &ovl_dir_operations; break; |