diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-01 17:48:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-01 17:48:48 -0400 |
| commit | 7260935d71b6d582376543844185add72848dde8 (patch) | |
| tree | 611e2e57a36e2d65d27fc734abb64ea04d6a3ceb | |
| parent | 34c7685a177a7bc98066f7e5daa42eef621d0bdb (diff) | |
| parent | d47748e5ae5af6572e520cc9767bbe70c22ea498 (diff) | |
Merge tag 'ovl-update-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi:
"A mix of fixes and cleanups"
* tag 'ovl-update-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: automatically enable redirect_dir on metacopy=on
ovl: check whiteout in ovl_create_over_whiteout()
ovl: using posix_acl_xattr_size() to get size instead of posix_acl_to_xattr()
ovl: abstract ovl_inode lock with a helper
ovl: remove the 'locked' argument of ovl_nlink_{start,end}
ovl: relax requirement for non null uuid of lower fs
ovl: fold copy-up helpers into callers
ovl: untangle copy up call chain
ovl: relax permission checking on underlying layers
ovl: fix recursive oi->lock in ovl_link()
vfs: fix FIGETBSZ ioctl on an overlayfs file
ovl: clean up error handling in ovl_get_tmpfile()
ovl: fix error handling in ovl_verify_set_fh()
| -rw-r--r-- | Documentation/filesystems/overlayfs.txt | 6 | ||||
| -rw-r--r-- | fs/ioctl.c | 3 | ||||
| -rw-r--r-- | fs/overlayfs/copy_up.c | 213 | ||||
| -rw-r--r-- | fs/overlayfs/dir.c | 34 | ||||
| -rw-r--r-- | fs/overlayfs/inode.c | 17 | ||||
| -rw-r--r-- | fs/overlayfs/namei.c | 4 | ||||
| -rw-r--r-- | fs/overlayfs/overlayfs.h | 14 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 68 | ||||
| -rw-r--r-- | fs/overlayfs/util.c | 46 |
9 files changed, 260 insertions, 145 deletions
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index 51c136c821bf..eef7d9d259e8 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt | |||
| @@ -286,6 +286,12 @@ pointed by REDIRECT. This should not be possible on local system as setting | |||
| 286 | "trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible | 286 | "trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible |
| 287 | for untrusted layers like from a pen drive. | 287 | for untrusted layers like from a pen drive. |
| 288 | 288 | ||
| 289 | Note: redirect_dir={off|nofollow|follow(*)} conflicts with metacopy=on, and | ||
| 290 | results in an error. | ||
| 291 | |||
| 292 | (*) redirect_dir=follow only conflicts with metacopy=on if upperdir=... is | ||
| 293 | given. | ||
| 294 | |||
| 289 | Sharing and copying layers | 295 | Sharing and copying layers |
| 290 | -------------------------- | 296 | -------------------------- |
| 291 | 297 | ||
diff --git a/fs/ioctl.c b/fs/ioctl.c index 2005529af560..0400297c8d72 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -669,6 +669,9 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | |||
| 669 | return ioctl_fiemap(filp, arg); | 669 | return ioctl_fiemap(filp, arg); |
| 670 | 670 | ||
| 671 | case FIGETBSZ: | 671 | case FIGETBSZ: |
| 672 | /* anon_bdev filesystems may not have a block size */ | ||
| 673 | if (!inode->i_sb->s_blocksize) | ||
| 674 | return -EINVAL; | ||
| 672 | return put_user(inode->i_sb->s_blocksize, argp); | 675 | return put_user(inode->i_sb->s_blocksize, argp); |
| 673 | 676 | ||
| 674 | case FICLONE: | 677 | case FICLONE: |
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 1cc797a08a5b..d6a3346e2672 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
| @@ -395,7 +395,6 @@ struct ovl_copy_up_ctx { | |||
| 395 | struct dentry *destdir; | 395 | struct dentry *destdir; |
| 396 | struct qstr destname; | 396 | struct qstr destname; |
| 397 | struct dentry *workdir; | 397 | struct dentry *workdir; |
| 398 | bool tmpfile; | ||
| 399 | bool origin; | 398 | bool origin; |
| 400 | bool indexed; | 399 | bool indexed; |
| 401 | bool metacopy; | 400 | bool metacopy; |
| @@ -440,63 +439,6 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c) | |||
| 440 | return err; | 439 | return err; |
| 441 | } | 440 | } |
| 442 | 441 | ||
| 443 | static int ovl_install_temp(struct ovl_copy_up_ctx *c, struct dentry *temp, | ||
| 444 | struct dentry **newdentry) | ||
| 445 | { | ||
| 446 | int err; | ||
| 447 | struct dentry *upper; | ||
| 448 | struct inode *udir = d_inode(c->destdir); | ||
| 449 | |||
| 450 | upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len); | ||
| 451 | if (IS_ERR(upper)) | ||
| 452 | return PTR_ERR(upper); | ||
| 453 | |||
| 454 | if (c->tmpfile) | ||
| 455 | err = ovl_do_link(temp, udir, upper); | ||
| 456 | else | ||
| 457 | err = ovl_do_rename(d_inode(c->workdir), temp, udir, upper, 0); | ||
| 458 | |||
| 459 | if (!err) | ||
| 460 | *newdentry = dget(c->tmpfile ? upper : temp); | ||
| 461 | dput(upper); | ||
| 462 | |||
| 463 | return err; | ||
| 464 | } | ||
| 465 | |||
| 466 | static struct dentry *ovl_get_tmpfile(struct ovl_copy_up_ctx *c) | ||
| 467 | { | ||
| 468 | int err; | ||
| 469 | struct dentry *temp; | ||
| 470 | const struct cred *old_creds = NULL; | ||
| 471 | struct cred *new_creds = NULL; | ||
| 472 | struct ovl_cattr cattr = { | ||
| 473 | /* Can't properly set mode on creation because of the umask */ | ||
| 474 | .mode = c->stat.mode & S_IFMT, | ||
| 475 | .rdev = c->stat.rdev, | ||
| 476 | .link = c->link | ||
| 477 | }; | ||
| 478 | |||
| 479 | err = security_inode_copy_up(c->dentry, &new_creds); | ||
| 480 | temp = ERR_PTR(err); | ||
| 481 | if (err < 0) | ||
| 482 | goto out; | ||
| 483 | |||
| 484 | if (new_creds) | ||
| 485 | old_creds = override_creds(new_creds); | ||
| 486 | |||
| 487 | if (c->tmpfile) | ||
| 488 | temp = ovl_do_tmpfile(c->workdir, c->stat.mode); | ||
| 489 | else | ||
| 490 | temp = ovl_create_temp(c->workdir, &cattr); | ||
| 491 | out: | ||
| 492 | if (new_creds) { | ||
| 493 | revert_creds(old_creds); | ||
| 494 | put_cred(new_creds); | ||
| 495 | } | ||
| 496 | |||
| 497 | return temp; | ||
| 498 | } | ||
| 499 | |||
| 500 | static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) | 442 | static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) |
| 501 | { | 443 | { |
| 502 | int err; | 444 | int err; |
| @@ -548,51 +490,148 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) | |||
| 548 | return err; | 490 | return err; |
| 549 | } | 491 | } |
| 550 | 492 | ||
| 551 | static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c) | 493 | struct ovl_cu_creds { |
| 494 | const struct cred *old; | ||
| 495 | struct cred *new; | ||
| 496 | }; | ||
| 497 | |||
| 498 | static int ovl_prep_cu_creds(struct dentry *dentry, struct ovl_cu_creds *cc) | ||
| 499 | { | ||
| 500 | int err; | ||
| 501 | |||
| 502 | cc->old = cc->new = NULL; | ||
| 503 | err = security_inode_copy_up(dentry, &cc->new); | ||
| 504 | if (err < 0) | ||
| 505 | return err; | ||
| 506 | |||
| 507 | if (cc->new) | ||
| 508 | cc->old = override_creds(cc->new); | ||
| 509 | |||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | |||
| 513 | static void ovl_revert_cu_creds(struct ovl_cu_creds *cc) | ||
| 514 | { | ||
| 515 | if (cc->new) { | ||
| 516 | revert_creds(cc->old); | ||
| 517 | put_cred(cc->new); | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | /* | ||
| 522 | * Copyup using workdir to prepare temp file. Used when copying up directories, | ||
| 523 | * special files or when upper fs doesn't support O_TMPFILE. | ||
| 524 | */ | ||
| 525 | static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) | ||
| 552 | { | 526 | { |
| 553 | struct inode *udir = c->destdir->d_inode; | ||
| 554 | struct inode *inode; | 527 | struct inode *inode; |
| 555 | struct dentry *newdentry = NULL; | 528 | struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir); |
| 556 | struct dentry *temp; | 529 | struct dentry *temp, *upper; |
| 530 | struct ovl_cu_creds cc; | ||
| 557 | int err; | 531 | int err; |
| 532 | struct ovl_cattr cattr = { | ||
| 533 | /* Can't properly set mode on creation because of the umask */ | ||
| 534 | .mode = c->stat.mode & S_IFMT, | ||
| 535 | .rdev = c->stat.rdev, | ||
| 536 | .link = c->link | ||
| 537 | }; | ||
| 558 | 538 | ||
| 559 | temp = ovl_get_tmpfile(c); | 539 | err = ovl_lock_rename_workdir(c->workdir, c->destdir); |
| 540 | if (err) | ||
| 541 | return err; | ||
| 542 | |||
| 543 | err = ovl_prep_cu_creds(c->dentry, &cc); | ||
| 544 | if (err) | ||
| 545 | goto unlock; | ||
| 546 | |||
| 547 | temp = ovl_create_temp(c->workdir, &cattr); | ||
| 548 | ovl_revert_cu_creds(&cc); | ||
| 549 | |||
| 550 | err = PTR_ERR(temp); | ||
| 560 | if (IS_ERR(temp)) | 551 | if (IS_ERR(temp)) |
| 561 | return PTR_ERR(temp); | 552 | goto unlock; |
| 562 | 553 | ||
| 563 | err = ovl_copy_up_inode(c, temp); | 554 | err = ovl_copy_up_inode(c, temp); |
| 564 | if (err) | 555 | if (err) |
| 565 | goto out; | 556 | goto cleanup; |
| 566 | 557 | ||
| 567 | if (S_ISDIR(c->stat.mode) && c->indexed) { | 558 | if (S_ISDIR(c->stat.mode) && c->indexed) { |
| 568 | err = ovl_create_index(c->dentry, c->lowerpath.dentry, temp); | 559 | err = ovl_create_index(c->dentry, c->lowerpath.dentry, temp); |
| 569 | if (err) | 560 | if (err) |
| 570 | goto out; | 561 | goto cleanup; |
| 571 | } | 562 | } |
| 572 | 563 | ||
| 573 | if (c->tmpfile) { | 564 | upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len); |
| 574 | inode_lock_nested(udir, I_MUTEX_PARENT); | 565 | err = PTR_ERR(upper); |
| 575 | err = ovl_install_temp(c, temp, &newdentry); | 566 | if (IS_ERR(upper)) |
| 576 | inode_unlock(udir); | 567 | goto cleanup; |
| 577 | } else { | 568 | |
| 578 | err = ovl_install_temp(c, temp, &newdentry); | 569 | err = ovl_do_rename(wdir, temp, udir, upper, 0); |
| 579 | } | 570 | dput(upper); |
| 580 | if (err) | 571 | if (err) |
| 581 | goto out; | 572 | goto cleanup; |
| 582 | 573 | ||
| 583 | if (!c->metacopy) | 574 | if (!c->metacopy) |
| 584 | ovl_set_upperdata(d_inode(c->dentry)); | 575 | ovl_set_upperdata(d_inode(c->dentry)); |
| 585 | inode = d_inode(c->dentry); | 576 | inode = d_inode(c->dentry); |
| 586 | ovl_inode_update(inode, newdentry); | 577 | ovl_inode_update(inode, temp); |
| 587 | if (S_ISDIR(inode->i_mode)) | 578 | if (S_ISDIR(inode->i_mode)) |
| 588 | ovl_set_flag(OVL_WHITEOUTS, inode); | 579 | ovl_set_flag(OVL_WHITEOUTS, inode); |
| 580 | unlock: | ||
| 581 | unlock_rename(c->workdir, c->destdir); | ||
| 589 | 582 | ||
| 590 | out: | ||
| 591 | if (err && !c->tmpfile) | ||
| 592 | ovl_cleanup(d_inode(c->workdir), temp); | ||
| 593 | dput(temp); | ||
| 594 | return err; | 583 | return err; |
| 595 | 584 | ||
| 585 | cleanup: | ||
| 586 | ovl_cleanup(wdir, temp); | ||
| 587 | dput(temp); | ||
| 588 | goto unlock; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* Copyup using O_TMPFILE which does not require cross dir locking */ | ||
| 592 | static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) | ||
| 593 | { | ||
| 594 | struct inode *udir = d_inode(c->destdir); | ||
| 595 | struct dentry *temp, *upper; | ||
| 596 | struct ovl_cu_creds cc; | ||
| 597 | int err; | ||
| 598 | |||
| 599 | err = ovl_prep_cu_creds(c->dentry, &cc); | ||
| 600 | if (err) | ||
| 601 | return err; | ||
| 602 | |||
| 603 | temp = ovl_do_tmpfile(c->workdir, c->stat.mode); | ||
| 604 | ovl_revert_cu_creds(&cc); | ||
| 605 | |||
| 606 | if (IS_ERR(temp)) | ||
| 607 | return PTR_ERR(temp); | ||
| 608 | |||
| 609 | err = ovl_copy_up_inode(c, temp); | ||
| 610 | if (err) | ||
| 611 | goto out_dput; | ||
| 612 | |||
| 613 | inode_lock_nested(udir, I_MUTEX_PARENT); | ||
| 614 | |||
| 615 | upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len); | ||
| 616 | err = PTR_ERR(upper); | ||
| 617 | if (!IS_ERR(upper)) { | ||
| 618 | err = ovl_do_link(temp, udir, upper); | ||
| 619 | dput(upper); | ||
| 620 | } | ||
| 621 | inode_unlock(udir); | ||
| 622 | |||
| 623 | if (err) | ||
| 624 | goto out_dput; | ||
| 625 | |||
| 626 | if (!c->metacopy) | ||
| 627 | ovl_set_upperdata(d_inode(c->dentry)); | ||
| 628 | ovl_inode_update(d_inode(c->dentry), temp); | ||
| 629 | |||
| 630 | return 0; | ||
| 631 | |||
| 632 | out_dput: | ||
| 633 | dput(temp); | ||
| 634 | return err; | ||
| 596 | } | 635 | } |
| 597 | 636 | ||
| 598 | /* | 637 | /* |
| @@ -646,18 +685,10 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) | |||
| 646 | } | 685 | } |
| 647 | 686 | ||
| 648 | /* Should we copyup with O_TMPFILE or with workdir? */ | 687 | /* Should we copyup with O_TMPFILE or with workdir? */ |
| 649 | if (S_ISREG(c->stat.mode) && ofs->tmpfile) { | 688 | if (S_ISREG(c->stat.mode) && ofs->tmpfile) |
| 650 | c->tmpfile = true; | 689 | err = ovl_copy_up_tmpfile(c); |
| 651 | err = ovl_copy_up_locked(c); | 690 | else |
| 652 | } else { | 691 | err = ovl_copy_up_workdir(c); |
| 653 | err = ovl_lock_rename_workdir(c->workdir, c->destdir); | ||
| 654 | if (!err) { | ||
| 655 | err = ovl_copy_up_locked(c); | ||
| 656 | unlock_rename(c->workdir, c->destdir); | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | |||
| 661 | if (err) | 692 | if (err) |
| 662 | goto out; | 693 | goto out; |
| 663 | 694 | ||
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 276914ae3c60..c6289147c787 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -414,13 +414,12 @@ static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name, | |||
| 414 | if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl) | 414 | if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl) |
| 415 | return 0; | 415 | return 0; |
| 416 | 416 | ||
| 417 | size = posix_acl_to_xattr(NULL, acl, NULL, 0); | 417 | size = posix_acl_xattr_size(acl->a_count); |
| 418 | buffer = kmalloc(size, GFP_KERNEL); | 418 | buffer = kmalloc(size, GFP_KERNEL); |
| 419 | if (!buffer) | 419 | if (!buffer) |
| 420 | return -ENOMEM; | 420 | return -ENOMEM; |
| 421 | 421 | ||
| 422 | size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); | 422 | err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); |
| 423 | err = size; | ||
| 424 | if (err < 0) | 423 | if (err < 0) |
| 425 | goto out_free; | 424 | goto out_free; |
| 426 | 425 | ||
| @@ -463,6 +462,10 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, | |||
| 463 | if (IS_ERR(upper)) | 462 | if (IS_ERR(upper)) |
| 464 | goto out_unlock; | 463 | goto out_unlock; |
| 465 | 464 | ||
| 465 | err = -ESTALE; | ||
| 466 | if (d_is_negative(upper) || !IS_WHITEOUT(d_inode(upper))) | ||
| 467 | goto out_dput; | ||
| 468 | |||
| 466 | newdentry = ovl_create_temp(workdir, cattr); | 469 | newdentry = ovl_create_temp(workdir, cattr); |
| 467 | err = PTR_ERR(newdentry); | 470 | err = PTR_ERR(newdentry); |
| 468 | if (IS_ERR(newdentry)) | 471 | if (IS_ERR(newdentry)) |
| @@ -652,7 +655,6 @@ static int ovl_link(struct dentry *old, struct inode *newdir, | |||
| 652 | struct dentry *new) | 655 | struct dentry *new) |
| 653 | { | 656 | { |
| 654 | int err; | 657 | int err; |
| 655 | bool locked = false; | ||
| 656 | struct inode *inode; | 658 | struct inode *inode; |
| 657 | 659 | ||
| 658 | err = ovl_want_write(old); | 660 | err = ovl_want_write(old); |
| @@ -663,13 +665,17 @@ static int ovl_link(struct dentry *old, struct inode *newdir, | |||
| 663 | if (err) | 665 | if (err) |
| 664 | goto out_drop_write; | 666 | goto out_drop_write; |
| 665 | 667 | ||
| 668 | err = ovl_copy_up(new->d_parent); | ||
| 669 | if (err) | ||
| 670 | goto out_drop_write; | ||
| 671 | |||
| 666 | if (ovl_is_metacopy_dentry(old)) { | 672 | if (ovl_is_metacopy_dentry(old)) { |
| 667 | err = ovl_set_redirect(old, false); | 673 | err = ovl_set_redirect(old, false); |
| 668 | if (err) | 674 | if (err) |
| 669 | goto out_drop_write; | 675 | goto out_drop_write; |
| 670 | } | 676 | } |
| 671 | 677 | ||
| 672 | err = ovl_nlink_start(old, &locked); | 678 | err = ovl_nlink_start(old); |
| 673 | if (err) | 679 | if (err) |
| 674 | goto out_drop_write; | 680 | goto out_drop_write; |
| 675 | 681 | ||
| @@ -682,7 +688,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir, | |||
| 682 | if (err) | 688 | if (err) |
| 683 | iput(inode); | 689 | iput(inode); |
| 684 | 690 | ||
| 685 | ovl_nlink_end(old, locked); | 691 | ovl_nlink_end(old); |
| 686 | out_drop_write: | 692 | out_drop_write: |
| 687 | ovl_drop_write(old); | 693 | ovl_drop_write(old); |
| 688 | out: | 694 | out: |
| @@ -807,7 +813,6 @@ static bool ovl_pure_upper(struct dentry *dentry) | |||
| 807 | static int ovl_do_remove(struct dentry *dentry, bool is_dir) | 813 | static int ovl_do_remove(struct dentry *dentry, bool is_dir) |
| 808 | { | 814 | { |
| 809 | int err; | 815 | int err; |
| 810 | bool locked = false; | ||
| 811 | const struct cred *old_cred; | 816 | const struct cred *old_cred; |
| 812 | struct dentry *upperdentry; | 817 | struct dentry *upperdentry; |
| 813 | bool lower_positive = ovl_lower_positive(dentry); | 818 | bool lower_positive = ovl_lower_positive(dentry); |
| @@ -828,7 +833,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir) | |||
| 828 | if (err) | 833 | if (err) |
| 829 | goto out_drop_write; | 834 | goto out_drop_write; |
| 830 | 835 | ||
| 831 | err = ovl_nlink_start(dentry, &locked); | 836 | err = ovl_nlink_start(dentry); |
| 832 | if (err) | 837 | if (err) |
| 833 | goto out_drop_write; | 838 | goto out_drop_write; |
| 834 | 839 | ||
| @@ -844,7 +849,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir) | |||
| 844 | else | 849 | else |
| 845 | drop_nlink(dentry->d_inode); | 850 | drop_nlink(dentry->d_inode); |
| 846 | } | 851 | } |
| 847 | ovl_nlink_end(dentry, locked); | 852 | ovl_nlink_end(dentry); |
| 848 | 853 | ||
| 849 | /* | 854 | /* |
| 850 | * Copy ctime | 855 | * Copy ctime |
| @@ -1008,7 +1013,6 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
| 1008 | unsigned int flags) | 1013 | unsigned int flags) |
| 1009 | { | 1014 | { |
| 1010 | int err; | 1015 | int err; |
| 1011 | bool locked = false; | ||
| 1012 | struct dentry *old_upperdir; | 1016 | struct dentry *old_upperdir; |
| 1013 | struct dentry *new_upperdir; | 1017 | struct dentry *new_upperdir; |
| 1014 | struct dentry *olddentry; | 1018 | struct dentry *olddentry; |
| @@ -1017,6 +1021,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
| 1017 | bool old_opaque; | 1021 | bool old_opaque; |
| 1018 | bool new_opaque; | 1022 | bool new_opaque; |
| 1019 | bool cleanup_whiteout = false; | 1023 | bool cleanup_whiteout = false; |
| 1024 | bool update_nlink = false; | ||
| 1020 | bool overwrite = !(flags & RENAME_EXCHANGE); | 1025 | bool overwrite = !(flags & RENAME_EXCHANGE); |
| 1021 | bool is_dir = d_is_dir(old); | 1026 | bool is_dir = d_is_dir(old); |
| 1022 | bool new_is_dir = d_is_dir(new); | 1027 | bool new_is_dir = d_is_dir(new); |
| @@ -1074,10 +1079,12 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
| 1074 | err = ovl_copy_up(new); | 1079 | err = ovl_copy_up(new); |
| 1075 | if (err) | 1080 | if (err) |
| 1076 | goto out_drop_write; | 1081 | goto out_drop_write; |
| 1077 | } else { | 1082 | } else if (d_inode(new)) { |
| 1078 | err = ovl_nlink_start(new, &locked); | 1083 | err = ovl_nlink_start(new); |
| 1079 | if (err) | 1084 | if (err) |
| 1080 | goto out_drop_write; | 1085 | goto out_drop_write; |
| 1086 | |||
| 1087 | update_nlink = true; | ||
| 1081 | } | 1088 | } |
| 1082 | 1089 | ||
| 1083 | old_cred = ovl_override_creds(old->d_sb); | 1090 | old_cred = ovl_override_creds(old->d_sb); |
| @@ -1206,7 +1213,8 @@ out_unlock: | |||
| 1206 | unlock_rename(new_upperdir, old_upperdir); | 1213 | unlock_rename(new_upperdir, old_upperdir); |
| 1207 | out_revert_creds: | 1214 | out_revert_creds: |
| 1208 | revert_creds(old_cred); | 1215 | revert_creds(old_cred); |
| 1209 | ovl_nlink_end(new, locked); | 1216 | if (update_nlink) |
| 1217 | ovl_nlink_end(new); | ||
| 1210 | out_drop_write: | 1218 | out_drop_write: |
| 1211 | ovl_drop_write(old); | 1219 | ovl_drop_write(old); |
| 1212 | out: | 1220 | out: |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 3b7ed5d2279c..6bcc9dedc342 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
| @@ -286,13 +286,22 @@ int ovl_permission(struct inode *inode, int mask) | |||
| 286 | if (err) | 286 | if (err) |
| 287 | return err; | 287 | return err; |
| 288 | 288 | ||
| 289 | old_cred = ovl_override_creds(inode->i_sb); | 289 | /* No need to do any access on underlying for special files */ |
| 290 | if (!upperinode && | 290 | if (special_file(realinode->i_mode)) |
| 291 | !special_file(realinode->i_mode) && mask & MAY_WRITE) { | 291 | return 0; |
| 292 | |||
| 293 | /* No need to access underlying for execute */ | ||
| 294 | mask &= ~MAY_EXEC; | ||
| 295 | if ((mask & (MAY_READ | MAY_WRITE)) == 0) | ||
| 296 | return 0; | ||
| 297 | |||
| 298 | /* Lower files get copied up, so turn write access into read */ | ||
| 299 | if (!upperinode && mask & MAY_WRITE) { | ||
| 292 | mask &= ~(MAY_WRITE | MAY_APPEND); | 300 | mask &= ~(MAY_WRITE | MAY_APPEND); |
| 293 | /* Make sure mounter can read file for copy up later */ | ||
| 294 | mask |= MAY_READ; | 301 | mask |= MAY_READ; |
| 295 | } | 302 | } |
| 303 | |||
| 304 | old_cred = ovl_override_creds(inode->i_sb); | ||
| 296 | err = inode_permission(realinode, mask); | 305 | err = inode_permission(realinode, mask); |
| 297 | revert_creds(old_cred); | 306 | revert_creds(old_cred); |
| 298 | 307 | ||
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 9c0ca6a7becf..efd372312ef1 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c | |||
| @@ -422,8 +422,10 @@ int ovl_verify_set_fh(struct dentry *dentry, const char *name, | |||
| 422 | 422 | ||
| 423 | fh = ovl_encode_real_fh(real, is_upper); | 423 | fh = ovl_encode_real_fh(real, is_upper); |
| 424 | err = PTR_ERR(fh); | 424 | err = PTR_ERR(fh); |
| 425 | if (IS_ERR(fh)) | 425 | if (IS_ERR(fh)) { |
| 426 | fh = NULL; | ||
| 426 | goto fail; | 427 | goto fail; |
| 428 | } | ||
| 427 | 429 | ||
| 428 | err = ovl_verify_fh(dentry, name, fh); | 430 | err = ovl_verify_fh(dentry, name, fh); |
| 429 | if (set && err == -ENODATA) | 431 | if (set && err == -ENODATA) |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index a3c0d9584312..5e45cb3630a0 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
| @@ -271,8 +271,8 @@ bool ovl_test_flag(unsigned long flag, struct inode *inode); | |||
| 271 | bool ovl_inuse_trylock(struct dentry *dentry); | 271 | bool ovl_inuse_trylock(struct dentry *dentry); |
| 272 | void ovl_inuse_unlock(struct dentry *dentry); | 272 | void ovl_inuse_unlock(struct dentry *dentry); |
| 273 | bool ovl_need_index(struct dentry *dentry); | 273 | bool ovl_need_index(struct dentry *dentry); |
| 274 | int ovl_nlink_start(struct dentry *dentry, bool *locked); | 274 | int ovl_nlink_start(struct dentry *dentry); |
| 275 | void ovl_nlink_end(struct dentry *dentry, bool locked); | 275 | void ovl_nlink_end(struct dentry *dentry); |
| 276 | int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); | 276 | int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); |
| 277 | int ovl_check_metacopy_xattr(struct dentry *dentry); | 277 | int ovl_check_metacopy_xattr(struct dentry *dentry); |
| 278 | bool ovl_is_metacopy_dentry(struct dentry *dentry); | 278 | bool ovl_is_metacopy_dentry(struct dentry *dentry); |
| @@ -290,6 +290,16 @@ static inline unsigned int ovl_xino_bits(struct super_block *sb) | |||
| 290 | return ofs->xino_bits; | 290 | return ofs->xino_bits; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | static inline int ovl_inode_lock(struct inode *inode) | ||
| 294 | { | ||
| 295 | return mutex_lock_interruptible(&OVL_I(inode)->lock); | ||
| 296 | } | ||
| 297 | |||
| 298 | static inline void ovl_inode_unlock(struct inode *inode) | ||
| 299 | { | ||
| 300 | mutex_unlock(&OVL_I(inode)->lock); | ||
| 301 | } | ||
| 302 | |||
| 293 | 303 | ||
| 294 | /* namei.c */ | 304 | /* namei.c */ |
| 295 | int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); | 305 | int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 30adc9d408a0..0116735cc321 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
| @@ -472,6 +472,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 472 | { | 472 | { |
| 473 | char *p; | 473 | char *p; |
| 474 | int err; | 474 | int err; |
| 475 | bool metacopy_opt = false, redirect_opt = false; | ||
| 475 | 476 | ||
| 476 | config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL); | 477 | config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL); |
| 477 | if (!config->redirect_mode) | 478 | if (!config->redirect_mode) |
| @@ -516,6 +517,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 516 | config->redirect_mode = match_strdup(&args[0]); | 517 | config->redirect_mode = match_strdup(&args[0]); |
| 517 | if (!config->redirect_mode) | 518 | if (!config->redirect_mode) |
| 518 | return -ENOMEM; | 519 | return -ENOMEM; |
| 520 | redirect_opt = true; | ||
| 519 | break; | 521 | break; |
| 520 | 522 | ||
| 521 | case OPT_INDEX_ON: | 523 | case OPT_INDEX_ON: |
| @@ -548,6 +550,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 548 | 550 | ||
| 549 | case OPT_METACOPY_ON: | 551 | case OPT_METACOPY_ON: |
| 550 | config->metacopy = true; | 552 | config->metacopy = true; |
| 553 | metacopy_opt = true; | ||
| 551 | break; | 554 | break; |
| 552 | 555 | ||
| 553 | case OPT_METACOPY_OFF: | 556 | case OPT_METACOPY_OFF: |
| @@ -572,13 +575,32 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 572 | if (err) | 575 | if (err) |
| 573 | return err; | 576 | return err; |
| 574 | 577 | ||
| 575 | /* metacopy feature with upper requires redirect_dir=on */ | 578 | /* |
| 576 | if (config->upperdir && config->metacopy && !config->redirect_dir) { | 579 | * This is to make the logic below simpler. It doesn't make any other |
| 577 | pr_warn("overlayfs: metadata only copy up requires \"redirect_dir=on\", falling back to metacopy=off.\n"); | 580 | * difference, since config->redirect_dir is only used for upper. |
| 578 | config->metacopy = false; | 581 | */ |
| 579 | } else if (config->metacopy && !config->redirect_follow) { | 582 | if (!config->upperdir && config->redirect_follow) |
| 580 | pr_warn("overlayfs: metadata only copy up requires \"redirect_dir=follow\" on non-upper mount, falling back to metacopy=off.\n"); | 583 | config->redirect_dir = true; |
| 581 | config->metacopy = false; | 584 | |
| 585 | /* Resolve metacopy -> redirect_dir dependency */ | ||
| 586 | if (config->metacopy && !config->redirect_dir) { | ||
| 587 | if (metacopy_opt && redirect_opt) { | ||
| 588 | pr_err("overlayfs: conflicting options: metacopy=on,redirect_dir=%s\n", | ||
| 589 | config->redirect_mode); | ||
| 590 | return -EINVAL; | ||
| 591 | } | ||
| 592 | if (redirect_opt) { | ||
| 593 | /* | ||
| 594 | * There was an explicit redirect_dir=... that resulted | ||
| 595 | * in this conflict. | ||
| 596 | */ | ||
| 597 | pr_info("overlayfs: disabling metacopy due to redirect_dir=%s\n", | ||
| 598 | config->redirect_mode); | ||
| 599 | config->metacopy = false; | ||
| 600 | } else { | ||
| 601 | /* Automatically enable redirect otherwise. */ | ||
| 602 | config->redirect_follow = config->redirect_dir = true; | ||
| 603 | } | ||
| 582 | } | 604 | } |
| 583 | 605 | ||
| 584 | return 0; | 606 | return 0; |
| @@ -1175,9 +1197,29 @@ out: | |||
| 1175 | return err; | 1197 | return err; |
| 1176 | } | 1198 | } |
| 1177 | 1199 | ||
| 1200 | static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid) | ||
| 1201 | { | ||
| 1202 | unsigned int i; | ||
| 1203 | |||
| 1204 | if (!ofs->config.nfs_export && !(ofs->config.index && ofs->upper_mnt)) | ||
| 1205 | return true; | ||
| 1206 | |||
| 1207 | for (i = 0; i < ofs->numlowerfs; i++) { | ||
| 1208 | /* | ||
| 1209 | * We use uuid to associate an overlay lower file handle with a | ||
| 1210 | * lower layer, so we can accept lower fs with null uuid as long | ||
| 1211 | * as all lower layers with null uuid are on the same fs. | ||
| 1212 | */ | ||
| 1213 | if (uuid_equal(&ofs->lower_fs[i].sb->s_uuid, uuid)) | ||
| 1214 | return false; | ||
| 1215 | } | ||
| 1216 | return true; | ||
| 1217 | } | ||
| 1218 | |||
| 1178 | /* Get a unique fsid for the layer */ | 1219 | /* Get a unique fsid for the layer */ |
| 1179 | static int ovl_get_fsid(struct ovl_fs *ofs, struct super_block *sb) | 1220 | static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path) |
| 1180 | { | 1221 | { |
| 1222 | struct super_block *sb = path->mnt->mnt_sb; | ||
| 1181 | unsigned int i; | 1223 | unsigned int i; |
| 1182 | dev_t dev; | 1224 | dev_t dev; |
| 1183 | int err; | 1225 | int err; |
| @@ -1191,6 +1233,14 @@ static int ovl_get_fsid(struct ovl_fs *ofs, struct super_block *sb) | |||
| 1191 | return i + 1; | 1233 | return i + 1; |
| 1192 | } | 1234 | } |
| 1193 | 1235 | ||
| 1236 | if (!ovl_lower_uuid_ok(ofs, &sb->s_uuid)) { | ||
| 1237 | ofs->config.index = false; | ||
| 1238 | ofs->config.nfs_export = false; | ||
| 1239 | pr_warn("overlayfs: %s uuid detected in lower fs '%pd2', falling back to index=off,nfs_export=off.\n", | ||
| 1240 | uuid_is_null(&sb->s_uuid) ? "null" : "conflicting", | ||
| 1241 | path->dentry); | ||
| 1242 | } | ||
| 1243 | |||
| 1194 | err = get_anon_bdev(&dev); | 1244 | err = get_anon_bdev(&dev); |
| 1195 | if (err) { | 1245 | if (err) { |
| 1196 | pr_err("overlayfs: failed to get anonymous bdev for lowerpath\n"); | 1246 | pr_err("overlayfs: failed to get anonymous bdev for lowerpath\n"); |
| @@ -1225,7 +1275,7 @@ static int ovl_get_lower_layers(struct ovl_fs *ofs, struct path *stack, | |||
| 1225 | struct vfsmount *mnt; | 1275 | struct vfsmount *mnt; |
| 1226 | int fsid; | 1276 | int fsid; |
| 1227 | 1277 | ||
| 1228 | err = fsid = ovl_get_fsid(ofs, stack[i].mnt->mnt_sb); | 1278 | err = fsid = ovl_get_fsid(ofs, &stack[i]); |
| 1229 | if (err < 0) | 1279 | if (err < 0) |
| 1230 | goto out; | 1280 | goto out; |
| 1231 | 1281 | ||
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index ace4fe4c39a9..7c01327b1852 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c | |||
| @@ -65,8 +65,7 @@ struct super_block *ovl_same_sb(struct super_block *sb) | |||
| 65 | */ | 65 | */ |
| 66 | int ovl_can_decode_fh(struct super_block *sb) | 66 | int ovl_can_decode_fh(struct super_block *sb) |
| 67 | { | 67 | { |
| 68 | if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry || | 68 | if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry) |
| 69 | uuid_is_null(&sb->s_uuid)) | ||
| 70 | return 0; | 69 | return 0; |
| 71 | 70 | ||
| 72 | return sb->s_export_op->encode_fh ? -1 : FILEID_INO32_GEN; | 71 | return sb->s_export_op->encode_fh ? -1 : FILEID_INO32_GEN; |
| @@ -522,13 +521,13 @@ bool ovl_already_copied_up(struct dentry *dentry, int flags) | |||
| 522 | 521 | ||
| 523 | int ovl_copy_up_start(struct dentry *dentry, int flags) | 522 | int ovl_copy_up_start(struct dentry *dentry, int flags) |
| 524 | { | 523 | { |
| 525 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); | 524 | struct inode *inode = d_inode(dentry); |
| 526 | int err; | 525 | int err; |
| 527 | 526 | ||
| 528 | err = mutex_lock_interruptible(&oi->lock); | 527 | err = ovl_inode_lock(inode); |
| 529 | if (!err && ovl_already_copied_up_locked(dentry, flags)) { | 528 | if (!err && ovl_already_copied_up_locked(dentry, flags)) { |
| 530 | err = 1; /* Already copied up */ | 529 | err = 1; /* Already copied up */ |
| 531 | mutex_unlock(&oi->lock); | 530 | ovl_inode_unlock(inode); |
| 532 | } | 531 | } |
| 533 | 532 | ||
| 534 | return err; | 533 | return err; |
| @@ -536,7 +535,7 @@ int ovl_copy_up_start(struct dentry *dentry, int flags) | |||
| 536 | 535 | ||
| 537 | void ovl_copy_up_end(struct dentry *dentry) | 536 | void ovl_copy_up_end(struct dentry *dentry) |
| 538 | { | 537 | { |
| 539 | mutex_unlock(&OVL_I(d_inode(dentry))->lock); | 538 | ovl_inode_unlock(d_inode(dentry)); |
| 540 | } | 539 | } |
| 541 | 540 | ||
| 542 | bool ovl_check_origin_xattr(struct dentry *dentry) | 541 | bool ovl_check_origin_xattr(struct dentry *dentry) |
| @@ -739,14 +738,14 @@ fail: | |||
| 739 | * Operations that change overlay inode and upper inode nlink need to be | 738 | * Operations that change overlay inode and upper inode nlink need to be |
| 740 | * synchronized with copy up for persistent nlink accounting. | 739 | * synchronized with copy up for persistent nlink accounting. |
| 741 | */ | 740 | */ |
| 742 | int ovl_nlink_start(struct dentry *dentry, bool *locked) | 741 | int ovl_nlink_start(struct dentry *dentry) |
| 743 | { | 742 | { |
| 744 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); | 743 | struct inode *inode = d_inode(dentry); |
| 745 | const struct cred *old_cred; | 744 | const struct cred *old_cred; |
| 746 | int err; | 745 | int err; |
| 747 | 746 | ||
| 748 | if (!d_inode(dentry)) | 747 | if (WARN_ON(!inode)) |
| 749 | return 0; | 748 | return -ENOENT; |
| 750 | 749 | ||
| 751 | /* | 750 | /* |
| 752 | * With inodes index is enabled, we store the union overlay nlink | 751 | * With inodes index is enabled, we store the union overlay nlink |
| @@ -768,11 +767,11 @@ int ovl_nlink_start(struct dentry *dentry, bool *locked) | |||
| 768 | return err; | 767 | return err; |
| 769 | } | 768 | } |
| 770 | 769 | ||
| 771 | err = mutex_lock_interruptible(&oi->lock); | 770 | err = ovl_inode_lock(inode); |
| 772 | if (err) | 771 | if (err) |
| 773 | return err; | 772 | return err; |
| 774 | 773 | ||
| 775 | if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, d_inode(dentry))) | 774 | if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, inode)) |
| 776 | goto out; | 775 | goto out; |
| 777 | 776 | ||
| 778 | old_cred = ovl_override_creds(dentry->d_sb); | 777 | old_cred = ovl_override_creds(dentry->d_sb); |
| @@ -787,27 +786,24 @@ int ovl_nlink_start(struct dentry *dentry, bool *locked) | |||
| 787 | 786 | ||
| 788 | out: | 787 | out: |
| 789 | if (err) | 788 | if (err) |
| 790 | mutex_unlock(&oi->lock); | 789 | ovl_inode_unlock(inode); |
| 791 | else | ||
| 792 | *locked = true; | ||
| 793 | 790 | ||
| 794 | return err; | 791 | return err; |
| 795 | } | 792 | } |
| 796 | 793 | ||
| 797 | void ovl_nlink_end(struct dentry *dentry, bool locked) | 794 | void ovl_nlink_end(struct dentry *dentry) |
| 798 | { | 795 | { |
| 799 | if (locked) { | 796 | struct inode *inode = d_inode(dentry); |
| 800 | if (ovl_test_flag(OVL_INDEX, d_inode(dentry)) && | ||
| 801 | d_inode(dentry)->i_nlink == 0) { | ||
| 802 | const struct cred *old_cred; | ||
| 803 | 797 | ||
| 804 | old_cred = ovl_override_creds(dentry->d_sb); | 798 | if (ovl_test_flag(OVL_INDEX, inode) && inode->i_nlink == 0) { |
| 805 | ovl_cleanup_index(dentry); | 799 | const struct cred *old_cred; |
| 806 | revert_creds(old_cred); | ||
| 807 | } | ||
| 808 | 800 | ||
| 809 | mutex_unlock(&OVL_I(d_inode(dentry))->lock); | 801 | old_cred = ovl_override_creds(dentry->d_sb); |
| 802 | ovl_cleanup_index(dentry); | ||
| 803 | revert_creds(old_cred); | ||
| 810 | } | 804 | } |
| 805 | |||
| 806 | ovl_inode_unlock(inode); | ||
| 811 | } | 807 | } |
| 812 | 808 | ||
| 813 | int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir) | 809 | int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir) |
