diff options
| -rw-r--r-- | fs/overlayfs/readdir.c | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index c11f5c0906c3..ef1fe42ff7bb 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
| @@ -120,6 +120,10 @@ static bool ovl_calc_d_ino(struct ovl_readdir_data *rdd, | |||
| 120 | if (!rdd->dentry) | 120 | if (!rdd->dentry) |
| 121 | return false; | 121 | return false; |
| 122 | 122 | ||
| 123 | /* Always recalc d_ino when remapping lower inode numbers */ | ||
| 124 | if (ovl_xino_bits(rdd->dentry->d_sb)) | ||
| 125 | return true; | ||
| 126 | |||
| 123 | /* Always recalc d_ino for parent */ | 127 | /* Always recalc d_ino for parent */ |
| 124 | if (strcmp(p->name, "..") == 0) | 128 | if (strcmp(p->name, "..") == 0) |
| 125 | return true; | 129 | return true; |
| @@ -435,6 +439,19 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) | |||
| 435 | return cache; | 439 | return cache; |
| 436 | } | 440 | } |
| 437 | 441 | ||
| 442 | /* Map inode number to lower fs unique range */ | ||
| 443 | static u64 ovl_remap_lower_ino(u64 ino, int xinobits, int fsid, | ||
| 444 | const char *name, int namelen) | ||
| 445 | { | ||
| 446 | if (ino >> (64 - xinobits)) { | ||
| 447 | pr_warn_ratelimited("overlayfs: d_ino too big (%.*s, ino=%llu, xinobits=%d)\n", | ||
| 448 | namelen, name, ino, xinobits); | ||
| 449 | return ino; | ||
| 450 | } | ||
| 451 | |||
| 452 | return ino | ((u64)fsid) << (64 - xinobits); | ||
| 453 | } | ||
| 454 | |||
| 438 | /* | 455 | /* |
| 439 | * Set d_ino for upper entries. Non-upper entries should always report | 456 | * Set d_ino for upper entries. Non-upper entries should always report |
| 440 | * the uppermost real inode ino and should not call this function. | 457 | * the uppermost real inode ino and should not call this function. |
| @@ -452,9 +469,10 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p) | |||
| 452 | struct dentry *this = NULL; | 469 | struct dentry *this = NULL; |
| 453 | enum ovl_path_type type; | 470 | enum ovl_path_type type; |
| 454 | u64 ino = p->real_ino; | 471 | u64 ino = p->real_ino; |
| 472 | int xinobits = ovl_xino_bits(dir->d_sb); | ||
| 455 | int err = 0; | 473 | int err = 0; |
| 456 | 474 | ||
| 457 | if (!ovl_same_sb(dir->d_sb)) | 475 | if (!ovl_same_sb(dir->d_sb) && !xinobits) |
| 458 | goto out; | 476 | goto out; |
| 459 | 477 | ||
| 460 | if (p->name[0] == '.') { | 478 | if (p->name[0] == '.') { |
| @@ -491,6 +509,10 @@ get: | |||
| 491 | 509 | ||
| 492 | WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev); | 510 | WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev); |
| 493 | ino = stat.ino; | 511 | ino = stat.ino; |
| 512 | } else if (xinobits && !OVL_TYPE_UPPER(type)) { | ||
| 513 | ino = ovl_remap_lower_ino(ino, xinobits, | ||
| 514 | ovl_layer_lower(this)->fsid, | ||
| 515 | p->name, p->len); | ||
| 494 | } | 516 | } |
| 495 | 517 | ||
| 496 | out: | 518 | out: |
| @@ -618,6 +640,8 @@ struct ovl_readdir_translate { | |||
| 618 | struct ovl_dir_cache *cache; | 640 | struct ovl_dir_cache *cache; |
| 619 | struct dir_context ctx; | 641 | struct dir_context ctx; |
| 620 | u64 parent_ino; | 642 | u64 parent_ino; |
| 643 | int fsid; | ||
| 644 | int xinobits; | ||
| 621 | }; | 645 | }; |
| 622 | 646 | ||
| 623 | static int ovl_fill_real(struct dir_context *ctx, const char *name, | 647 | static int ovl_fill_real(struct dir_context *ctx, const char *name, |
| @@ -628,14 +652,17 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name, | |||
| 628 | container_of(ctx, struct ovl_readdir_translate, ctx); | 652 | container_of(ctx, struct ovl_readdir_translate, ctx); |
| 629 | struct dir_context *orig_ctx = rdt->orig_ctx; | 653 | struct dir_context *orig_ctx = rdt->orig_ctx; |
| 630 | 654 | ||
| 631 | if (rdt->parent_ino && strcmp(name, "..") == 0) | 655 | if (rdt->parent_ino && strcmp(name, "..") == 0) { |
| 632 | ino = rdt->parent_ino; | 656 | ino = rdt->parent_ino; |
| 633 | else if (rdt->cache) { | 657 | } else if (rdt->cache) { |
| 634 | struct ovl_cache_entry *p; | 658 | struct ovl_cache_entry *p; |
| 635 | 659 | ||
| 636 | p = ovl_cache_entry_find(&rdt->cache->root, name, namelen); | 660 | p = ovl_cache_entry_find(&rdt->cache->root, name, namelen); |
| 637 | if (p) | 661 | if (p) |
| 638 | ino = p->ino; | 662 | ino = p->ino; |
| 663 | } else if (rdt->xinobits) { | ||
| 664 | ino = ovl_remap_lower_ino(ino, rdt->xinobits, rdt->fsid, | ||
| 665 | name, namelen); | ||
| 639 | } | 666 | } |
| 640 | 667 | ||
| 641 | return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type); | 668 | return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type); |
| @@ -646,11 +673,16 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) | |||
| 646 | int err; | 673 | int err; |
| 647 | struct ovl_dir_file *od = file->private_data; | 674 | struct ovl_dir_file *od = file->private_data; |
| 648 | struct dentry *dir = file->f_path.dentry; | 675 | struct dentry *dir = file->f_path.dentry; |
| 676 | struct ovl_layer *lower_layer = ovl_layer_lower(dir); | ||
| 649 | struct ovl_readdir_translate rdt = { | 677 | struct ovl_readdir_translate rdt = { |
| 650 | .ctx.actor = ovl_fill_real, | 678 | .ctx.actor = ovl_fill_real, |
| 651 | .orig_ctx = ctx, | 679 | .orig_ctx = ctx, |
| 680 | .xinobits = ovl_xino_bits(dir->d_sb), | ||
| 652 | }; | 681 | }; |
| 653 | 682 | ||
| 683 | if (rdt.xinobits && lower_layer) | ||
| 684 | rdt.fsid = lower_layer->fsid; | ||
| 685 | |||
| 654 | if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) { | 686 | if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) { |
| 655 | struct kstat stat; | 687 | struct kstat stat; |
| 656 | struct path statpath = file->f_path; | 688 | struct path statpath = file->f_path; |
| @@ -693,9 +725,10 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
| 693 | * dir is impure then need to adjust d_ino for copied up | 725 | * dir is impure then need to adjust d_ino for copied up |
| 694 | * entries. | 726 | * entries. |
| 695 | */ | 727 | */ |
| 696 | if (ovl_same_sb(dentry->d_sb) && | 728 | if (ovl_xino_bits(dentry->d_sb) || |
| 697 | (ovl_test_flag(OVL_IMPURE, d_inode(dentry)) || | 729 | (ovl_same_sb(dentry->d_sb) && |
| 698 | OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)))) { | 730 | (ovl_test_flag(OVL_IMPURE, d_inode(dentry)) || |
| 731 | OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) { | ||
| 699 | return ovl_iterate_real(file, ctx); | 732 | return ovl_iterate_real(file, ctx); |
| 700 | } | 733 | } |
| 701 | return iterate_dir(od->realfile, ctx); | 734 | return iterate_dir(od->realfile, ctx); |
