aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-12-12 18:59:42 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2014-12-12 18:59:42 -0500
commit49c21e1cacd74a8c83407c70ad860c994e606e25 (patch)
tree16c50417ab340185c3a9c69b79e890712e298c8e
parentb2776bf7149bddd1f4161f14f79520f17fc1d71d (diff)
ovl: check whiteout while reading directory
Don't make a separate pass for checking whiteouts, since we can do it while reading the upper directory. This will make it easier to handle multiple layers. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/overlayfs/readdir.c77
1 files changed, 28 insertions, 49 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index ab1e3dcbed95..3efa44acf98b 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -40,6 +40,7 @@ struct ovl_readdir_data {
40 struct rb_root root; 40 struct rb_root root;
41 struct list_head *list; 41 struct list_head *list;
42 struct list_head middle; 42 struct list_head middle;
43 struct dentry *dir;
43 int count; 44 int count;
44 int err; 45 int err;
45}; 46};
@@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
126 if (p == NULL) 127 if (p == NULL)
127 return -ENOMEM; 128 return -ENOMEM;
128 129
130 if (d_type == DT_CHR) {
131 struct dentry *dentry;
132 const struct cred *old_cred;
133 struct cred *override_cred;
134
135 override_cred = prepare_creds();
136 if (!override_cred) {
137 kfree(p);
138 return -ENOMEM;
139 }
140
141 /*
142 * CAP_DAC_OVERRIDE for lookup
143 */
144 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
145 old_cred = override_creds(override_cred);
146
147 dentry = lookup_one_len(name, rdd->dir, len);
148 if (!IS_ERR(dentry)) {
149 p->is_whiteout = ovl_is_whiteout(dentry);
150 dput(dentry);
151 }
152 revert_creds(old_cred);
153 put_cred(override_cred);
154 }
155
129 list_add_tail(&p->l_node, rdd->list); 156 list_add_tail(&p->l_node, rdd->list);
130 rb_link_node(&p->node, parent, newp); 157 rb_link_node(&p->node, parent, newp);
131 rb_insert_color(&p->node, &rdd->root); 158 rb_insert_color(&p->node, &rdd->root);
@@ -231,49 +258,6 @@ static void ovl_dir_reset(struct file *file)
231 od->is_real = false; 258 od->is_real = false;
232} 259}
233 260
234static int ovl_dir_mark_whiteouts(struct dentry *dir,
235 struct ovl_readdir_data *rdd)
236{
237 struct ovl_cache_entry *p;
238 struct dentry *dentry;
239 const struct cred *old_cred;
240 struct cred *override_cred;
241
242 override_cred = prepare_creds();
243 if (!override_cred) {
244 ovl_cache_free(rdd->list);
245 return -ENOMEM;
246 }
247
248 /*
249 * CAP_DAC_OVERRIDE for lookup
250 */
251 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
252 old_cred = override_creds(override_cred);
253
254 mutex_lock(&dir->d_inode->i_mutex);
255 list_for_each_entry(p, rdd->list, l_node) {
256 if (p->is_cursor)
257 continue;
258
259 if (p->type != DT_CHR)
260 continue;
261
262 dentry = lookup_one_len(p->name, dir, p->len);
263 if (IS_ERR(dentry))
264 continue;
265
266 p->is_whiteout = ovl_is_whiteout(dentry);
267 dput(dentry);
268 }
269 mutex_unlock(&dir->d_inode->i_mutex);
270
271 revert_creds(old_cred);
272 put_cred(override_cred);
273
274 return 0;
275}
276
277static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) 261static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
278{ 262{
279 int err; 263 int err;
@@ -290,15 +274,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
290 ovl_path_upper(dentry, &upperpath); 274 ovl_path_upper(dentry, &upperpath);
291 275
292 if (upperpath.dentry) { 276 if (upperpath.dentry) {
277 rdd.dir = upperpath.dentry;
293 err = ovl_dir_read(&upperpath, &rdd); 278 err = ovl_dir_read(&upperpath, &rdd);
294 if (err) 279 if (err)
295 goto out; 280 goto out;
296
297 if (lowerpath.dentry) {
298 err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
299 if (err)
300 goto out;
301 }
302 } 281 }
303 if (lowerpath.dentry) { 282 if (lowerpath.dentry) {
304 /* 283 /*