diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2016-05-25 20:01:47 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-07-29 06:05:22 -0400 |
commit | 58ed4e70f253d80ed72faba7873dc11603b398bc (patch) | |
tree | 83d8e490d7ce0b206427305213a187416daa3152 | |
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>
-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, | |||
109 | 109 | ||
110 | int ovl_permission(struct inode *inode, int mask) | 110 | int ovl_permission(struct inode *inode, int mask) |
111 | { | 111 | { |
112 | struct ovl_entry *oe; | 112 | struct ovl_entry *oe = inode->i_private; |
113 | struct dentry *alias = NULL; | ||
114 | struct inode *realinode; | ||
115 | struct dentry *realdentry; | ||
116 | bool is_upper; | 113 | bool is_upper; |
114 | struct dentry *realdentry = ovl_entry_real(oe, &is_upper); | ||
115 | struct inode *realinode; | ||
117 | int err; | 116 | int err; |
118 | 117 | ||
119 | if (S_ISDIR(inode->i_mode)) { | ||
120 | oe = inode->i_private; | ||
121 | } else if (mask & MAY_NOT_BLOCK) { | ||
122 | return -ECHILD; | ||
123 | } else { | ||
124 | /* | ||
125 | * For non-directories find an alias and get the info | ||
126 | * from there. | ||
127 | */ | ||
128 | alias = d_find_any_alias(inode); | ||
129 | if (WARN_ON(!alias)) | ||
130 | return -ENOENT; | ||
131 | |||
132 | oe = alias->d_fsdata; | ||
133 | } | ||
134 | |||
135 | realdentry = ovl_entry_real(oe, &is_upper); | ||
136 | |||
137 | if (ovl_is_default_permissions(inode)) { | 118 | if (ovl_is_default_permissions(inode)) { |
138 | struct kstat stat; | 119 | struct kstat stat; |
139 | struct path realpath = { .dentry = realdentry }; | 120 | struct path realpath = { .dentry = realdentry }; |
@@ -145,26 +126,23 @@ int ovl_permission(struct inode *inode, int mask) | |||
145 | 126 | ||
146 | err = vfs_getattr(&realpath, &stat); | 127 | err = vfs_getattr(&realpath, &stat); |
147 | if (err) | 128 | if (err) |
148 | goto out_dput; | 129 | return err; |
149 | 130 | ||
150 | err = -ESTALE; | ||
151 | if ((stat.mode ^ inode->i_mode) & S_IFMT) | 131 | if ((stat.mode ^ inode->i_mode) & S_IFMT) |
152 | goto out_dput; | 132 | return -ESTALE; |
153 | 133 | ||
154 | inode->i_mode = stat.mode; | 134 | inode->i_mode = stat.mode; |
155 | inode->i_uid = stat.uid; | 135 | inode->i_uid = stat.uid; |
156 | inode->i_gid = stat.gid; | 136 | inode->i_gid = stat.gid; |
157 | 137 | ||
158 | err = generic_permission(inode, mask); | 138 | return generic_permission(inode, mask); |
159 | goto out_dput; | ||
160 | } | 139 | } |
161 | 140 | ||
162 | /* Careful in RCU walk mode */ | 141 | /* Careful in RCU walk mode */ |
163 | realinode = ACCESS_ONCE(realdentry->d_inode); | 142 | realinode = d_inode_rcu(realdentry); |
164 | if (!realinode) { | 143 | if (!realinode) { |
165 | WARN_ON(!(mask & MAY_NOT_BLOCK)); | 144 | WARN_ON(!(mask & MAY_NOT_BLOCK)); |
166 | err = -ENOENT; | 145 | return -ENOENT; |
167 | goto out_dput; | ||
168 | } | 146 | } |
169 | 147 | ||
170 | if (mask & MAY_WRITE) { | 148 | if (mask & MAY_WRITE) { |
@@ -183,16 +161,12 @@ int ovl_permission(struct inode *inode, int mask) | |||
183 | * constructed return EROFS to prevent modification of | 161 | * constructed return EROFS to prevent modification of |
184 | * upper layer. | 162 | * upper layer. |
185 | */ | 163 | */ |
186 | err = -EROFS; | ||
187 | if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && | 164 | if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && |
188 | (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) | 165 | (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) |
189 | goto out_dput; | 166 | return -EROFS; |
190 | } | 167 | } |
191 | 168 | ||
192 | err = __inode_permission(realinode, mask); | 169 | return __inode_permission(realinode, mask); |
193 | out_dput: | ||
194 | dput(alias); | ||
195 | return err; | ||
196 | } | 170 | } |
197 | 171 | ||
198 | static const char *ovl_get_link(struct dentry *dentry, | 172 | 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, | |||
405 | inode->i_ino = get_next_ino(); | 379 | inode->i_ino = get_next_ino(); |
406 | inode->i_mode = mode; | 380 | inode->i_mode = mode; |
407 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 381 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
382 | inode->i_private = oe; | ||
408 | 383 | ||
409 | mode &= S_IFMT; | 384 | mode &= S_IFMT; |
410 | switch (mode) { | 385 | switch (mode) { |
411 | case S_IFDIR: | 386 | case S_IFDIR: |
412 | inode->i_private = oe; | ||
413 | inode->i_op = &ovl_dir_inode_operations; | 387 | inode->i_op = &ovl_dir_inode_operations; |
414 | inode->i_fop = &ovl_dir_operations; | 388 | inode->i_fop = &ovl_dir_operations; |
415 | break; | 389 | break; |