diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:42 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-12-12 18:59:42 -0500 |
commit | 49c21e1cacd74a8c83407c70ad860c994e606e25 (patch) | |
tree | 16c50417ab340185c3a9c69b79e890712e298c8e | |
parent | b2776bf7149bddd1f4161f14f79520f17fc1d71d (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.c | 77 |
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 | ||
234 | static 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 | |||
277 | static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) | 261 | static 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 | /* |