diff options
Diffstat (limited to 'fs/overlayfs/readdir.c')
-rw-r--r-- | fs/overlayfs/readdir.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 910553f37aca..2a7ef4f8e2a6 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
@@ -21,9 +21,10 @@ struct ovl_cache_entry { | |||
21 | unsigned int len; | 21 | unsigned int len; |
22 | unsigned int type; | 22 | unsigned int type; |
23 | u64 ino; | 23 | u64 ino; |
24 | bool is_whiteout; | ||
25 | struct list_head l_node; | 24 | struct list_head l_node; |
26 | struct rb_node node; | 25 | struct rb_node node; |
26 | bool is_whiteout; | ||
27 | bool is_cursor; | ||
27 | char name[]; | 28 | char name[]; |
28 | }; | 29 | }; |
29 | 30 | ||
@@ -92,6 +93,7 @@ static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, | |||
92 | p->type = d_type; | 93 | p->type = d_type; |
93 | p->ino = ino; | 94 | p->ino = ino; |
94 | p->is_whiteout = false; | 95 | p->is_whiteout = false; |
96 | p->is_cursor = false; | ||
95 | } | 97 | } |
96 | 98 | ||
97 | return p; | 99 | return p; |
@@ -166,7 +168,7 @@ static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry) | |||
166 | { | 168 | { |
167 | struct ovl_dir_cache *cache = od->cache; | 169 | struct ovl_dir_cache *cache = od->cache; |
168 | 170 | ||
169 | list_del(&od->cursor.l_node); | 171 | list_del_init(&od->cursor.l_node); |
170 | WARN_ON(cache->refcount <= 0); | 172 | WARN_ON(cache->refcount <= 0); |
171 | cache->refcount--; | 173 | cache->refcount--; |
172 | if (!cache->refcount) { | 174 | if (!cache->refcount) { |
@@ -251,7 +253,7 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir, | |||
251 | 253 | ||
252 | mutex_lock(&dir->d_inode->i_mutex); | 254 | mutex_lock(&dir->d_inode->i_mutex); |
253 | list_for_each_entry(p, rdd->list, l_node) { | 255 | list_for_each_entry(p, rdd->list, l_node) { |
254 | if (!p->name) | 256 | if (p->is_cursor) |
255 | continue; | 257 | continue; |
256 | 258 | ||
257 | if (p->type != DT_CHR) | 259 | if (p->type != DT_CHR) |
@@ -307,7 +309,6 @@ static inline int ovl_dir_read_merged(struct path *upperpath, | |||
307 | } | 309 | } |
308 | out: | 310 | out: |
309 | return err; | 311 | return err; |
310 | |||
311 | } | 312 | } |
312 | 313 | ||
313 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | 314 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) |
@@ -316,7 +317,7 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | |||
316 | loff_t off = 0; | 317 | loff_t off = 0; |
317 | 318 | ||
318 | list_for_each_entry(p, &od->cache->entries, l_node) { | 319 | list_for_each_entry(p, &od->cache->entries, l_node) { |
319 | if (!p->name) | 320 | if (p->is_cursor) |
320 | continue; | 321 | continue; |
321 | if (off >= pos) | 322 | if (off >= pos) |
322 | break; | 323 | break; |
@@ -389,7 +390,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
389 | 390 | ||
390 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); | 391 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); |
391 | /* Skip cursors */ | 392 | /* Skip cursors */ |
392 | if (p->name) { | 393 | if (!p->is_cursor) { |
393 | if (!p->is_whiteout) { | 394 | if (!p->is_whiteout) { |
394 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) | 395 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) |
395 | break; | 396 | break; |
@@ -454,12 +455,13 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
454 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { | 455 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { |
455 | struct inode *inode = file_inode(file); | 456 | struct inode *inode = file_inode(file); |
456 | 457 | ||
457 | realfile = od->upperfile; | 458 | realfile =lockless_dereference(od->upperfile); |
458 | if (!realfile) { | 459 | if (!realfile) { |
459 | struct path upperpath; | 460 | struct path upperpath; |
460 | 461 | ||
461 | ovl_path_upper(dentry, &upperpath); | 462 | ovl_path_upper(dentry, &upperpath); |
462 | realfile = ovl_path_open(&upperpath, O_RDONLY); | 463 | realfile = ovl_path_open(&upperpath, O_RDONLY); |
464 | smp_mb__before_spinlock(); | ||
463 | mutex_lock(&inode->i_mutex); | 465 | mutex_lock(&inode->i_mutex); |
464 | if (!od->upperfile) { | 466 | if (!od->upperfile) { |
465 | if (IS_ERR(realfile)) { | 467 | if (IS_ERR(realfile)) { |
@@ -518,6 +520,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file) | |||
518 | od->realfile = realfile; | 520 | od->realfile = realfile; |
519 | od->is_real = (type != OVL_PATH_MERGE); | 521 | od->is_real = (type != OVL_PATH_MERGE); |
520 | od->is_upper = (type != OVL_PATH_LOWER); | 522 | od->is_upper = (type != OVL_PATH_LOWER); |
523 | od->cursor.is_cursor = true; | ||
521 | file->private_data = od; | 524 | file->private_data = od; |
522 | 525 | ||
523 | return 0; | 526 | return 0; |
@@ -569,7 +572,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) | |||
569 | { | 572 | { |
570 | struct ovl_cache_entry *p; | 573 | struct ovl_cache_entry *p; |
571 | 574 | ||
572 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_PARENT); | 575 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD); |
573 | list_for_each_entry(p, list, l_node) { | 576 | list_for_each_entry(p, list, l_node) { |
574 | struct dentry *dentry; | 577 | struct dentry *dentry; |
575 | 578 | ||