diff options
| -rw-r--r-- | fs/overlayfs/readdir.c | 38 |
1 files changed, 14 insertions, 24 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 9df848f2e622..dcf1d412888d 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
| @@ -24,7 +24,6 @@ struct ovl_cache_entry { | |||
| 24 | struct list_head l_node; | 24 | struct list_head l_node; |
| 25 | struct rb_node node; | 25 | struct rb_node node; |
| 26 | bool is_whiteout; | 26 | bool is_whiteout; |
| 27 | bool is_cursor; | ||
| 28 | char name[]; | 27 | char name[]; |
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| @@ -49,7 +48,7 @@ struct ovl_dir_file { | |||
| 49 | bool is_real; | 48 | bool is_real; |
| 50 | bool is_upper; | 49 | bool is_upper; |
| 51 | struct ovl_dir_cache *cache; | 50 | struct ovl_dir_cache *cache; |
| 52 | struct ovl_cache_entry cursor; | 51 | struct list_head *cursor; |
| 53 | struct file *realfile; | 52 | struct file *realfile; |
| 54 | struct file *upperfile; | 53 | struct file *upperfile; |
| 55 | }; | 54 | }; |
| @@ -97,7 +96,6 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir, | |||
| 97 | p->type = d_type; | 96 | p->type = d_type; |
| 98 | p->ino = ino; | 97 | p->ino = ino; |
| 99 | p->is_whiteout = false; | 98 | p->is_whiteout = false; |
| 100 | p->is_cursor = false; | ||
| 101 | 99 | ||
| 102 | if (d_type == DT_CHR) { | 100 | if (d_type == DT_CHR) { |
| 103 | struct dentry *dentry; | 101 | struct dentry *dentry; |
| @@ -196,7 +194,6 @@ static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry) | |||
| 196 | { | 194 | { |
| 197 | struct ovl_dir_cache *cache = od->cache; | 195 | struct ovl_dir_cache *cache = od->cache; |
| 198 | 196 | ||
| 199 | list_del_init(&od->cursor.l_node); | ||
| 200 | WARN_ON(cache->refcount <= 0); | 197 | WARN_ON(cache->refcount <= 0); |
| 201 | cache->refcount--; | 198 | cache->refcount--; |
| 202 | if (!cache->refcount) { | 199 | if (!cache->refcount) { |
| @@ -254,6 +251,7 @@ static void ovl_dir_reset(struct file *file) | |||
| 254 | if (cache && ovl_dentry_version_get(dentry) != cache->version) { | 251 | if (cache && ovl_dentry_version_get(dentry) != cache->version) { |
| 255 | ovl_cache_put(od, dentry); | 252 | ovl_cache_put(od, dentry); |
| 256 | od->cache = NULL; | 253 | od->cache = NULL; |
| 254 | od->cursor = NULL; | ||
| 257 | } | 255 | } |
| 258 | WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type)); | 256 | WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type)); |
| 259 | if (od->is_real && OVL_TYPE_MERGE(type)) | 257 | if (od->is_real && OVL_TYPE_MERGE(type)) |
| @@ -295,17 +293,16 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) | |||
| 295 | 293 | ||
| 296 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | 294 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) |
| 297 | { | 295 | { |
| 298 | struct ovl_cache_entry *p; | 296 | struct list_head *p; |
| 299 | loff_t off = 0; | 297 | loff_t off = 0; |
| 300 | 298 | ||
| 301 | list_for_each_entry(p, &od->cache->entries, l_node) { | 299 | list_for_each(p, &od->cache->entries) { |
| 302 | if (p->is_cursor) | ||
| 303 | continue; | ||
| 304 | if (off >= pos) | 300 | if (off >= pos) |
| 305 | break; | 301 | break; |
| 306 | off++; | 302 | off++; |
| 307 | } | 303 | } |
| 308 | list_move_tail(&od->cursor.l_node, &p->l_node); | 304 | /* Cursor is safe since the cache is stable */ |
| 305 | od->cursor = p; | ||
| 309 | } | 306 | } |
| 310 | 307 | ||
| 311 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) | 308 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) |
| @@ -344,6 +341,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
| 344 | { | 341 | { |
| 345 | struct ovl_dir_file *od = file->private_data; | 342 | struct ovl_dir_file *od = file->private_data; |
| 346 | struct dentry *dentry = file->f_path.dentry; | 343 | struct dentry *dentry = file->f_path.dentry; |
| 344 | struct ovl_cache_entry *p; | ||
| 347 | 345 | ||
| 348 | if (!ctx->pos) | 346 | if (!ctx->pos) |
| 349 | ovl_dir_reset(file); | 347 | ovl_dir_reset(file); |
| @@ -362,19 +360,13 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
| 362 | ovl_seek_cursor(od, ctx->pos); | 360 | ovl_seek_cursor(od, ctx->pos); |
| 363 | } | 361 | } |
| 364 | 362 | ||
| 365 | while (od->cursor.l_node.next != &od->cache->entries) { | 363 | while (od->cursor != &od->cache->entries) { |
| 366 | struct ovl_cache_entry *p; | 364 | p = list_entry(od->cursor, struct ovl_cache_entry, l_node); |
| 367 | 365 | if (!p->is_whiteout) | |
| 368 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); | 366 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) |
| 369 | /* Skip cursors */ | 367 | break; |
| 370 | if (!p->is_cursor) { | 368 | od->cursor = p->l_node.next; |
| 371 | if (!p->is_whiteout) { | 369 | ctx->pos++; |
| 372 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | ctx->pos++; | ||
| 376 | } | ||
| 377 | list_move(&od->cursor.l_node, &p->l_node); | ||
| 378 | } | 370 | } |
| 379 | return 0; | 371 | return 0; |
| 380 | } | 372 | } |
| @@ -493,11 +485,9 @@ static int ovl_dir_open(struct inode *inode, struct file *file) | |||
| 493 | kfree(od); | 485 | kfree(od); |
| 494 | return PTR_ERR(realfile); | 486 | return PTR_ERR(realfile); |
| 495 | } | 487 | } |
| 496 | INIT_LIST_HEAD(&od->cursor.l_node); | ||
| 497 | od->realfile = realfile; | 488 | od->realfile = realfile; |
| 498 | od->is_real = !OVL_TYPE_MERGE(type); | 489 | od->is_real = !OVL_TYPE_MERGE(type); |
| 499 | od->is_upper = OVL_TYPE_UPPER(type); | 490 | od->is_upper = OVL_TYPE_UPPER(type); |
| 500 | od->cursor.is_cursor = true; | ||
| 501 | file->private_data = od; | 491 | file->private_data = od; |
| 502 | 492 | ||
| 503 | return 0; | 493 | return 0; |
