aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2016-05-25 20:01:47 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:22 -0400
commit58ed4e70f253d80ed72faba7873dc11603b398bc (patch)
tree83d8e490d7ce0b206427305213a187416daa3152
parenteead4f2dc4f851a3790c49850e96a1d155bf5451 (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.c48
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
110int ovl_permission(struct inode *inode, int mask) 110int 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);
193out_dput:
194 dput(alias);
195 return err;
196} 170}
197 171
198static const char *ovl_get_link(struct dentry *dentry, 172static 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;