.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2011 Novell Inc. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
7 | | - * the Free Software Foundation. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/fs.h> |
---|
.. | .. |
---|
21 | 18 | |
---|
22 | 19 | static unsigned short ovl_redirect_max = 256; |
---|
23 | 20 | module_param_named(redirect_max, ovl_redirect_max, ushort, 0644); |
---|
24 | | -MODULE_PARM_DESC(ovl_redirect_max, |
---|
| 21 | +MODULE_PARM_DESC(redirect_max, |
---|
25 | 22 | "Maximum length of absolute redirect xattr value"); |
---|
26 | 23 | |
---|
27 | 24 | static int ovl_set_redirect(struct dentry *dentry, bool samedir); |
---|
.. | .. |
---|
38 | 35 | dput(wdentry); |
---|
39 | 36 | |
---|
40 | 37 | if (err) { |
---|
41 | | - pr_err("overlayfs: cleanup of '%pd2' failed (%i)\n", |
---|
| 38 | + pr_err("cleanup of '%pd2' failed (%i)\n", |
---|
42 | 39 | wdentry, err); |
---|
43 | 40 | } |
---|
44 | 41 | |
---|
45 | 42 | return err; |
---|
46 | 43 | } |
---|
47 | 44 | |
---|
48 | | -static struct dentry *ovl_lookup_temp(struct dentry *workdir) |
---|
| 45 | +struct dentry *ovl_lookup_temp(struct dentry *workdir) |
---|
49 | 46 | { |
---|
50 | 47 | struct dentry *temp; |
---|
51 | 48 | char name[20]; |
---|
.. | .. |
---|
56 | 53 | |
---|
57 | 54 | temp = lookup_one_len(name, workdir, strlen(name)); |
---|
58 | 55 | if (!IS_ERR(temp) && temp->d_inode) { |
---|
59 | | - pr_err("overlayfs: workdir/%s already exists\n", name); |
---|
| 56 | + pr_err("workdir/%s already exists\n", name); |
---|
60 | 57 | dput(temp); |
---|
61 | 58 | temp = ERR_PTR(-EIO); |
---|
62 | 59 | } |
---|
.. | .. |
---|
65 | 62 | } |
---|
66 | 63 | |
---|
67 | 64 | /* caller holds i_mutex on workdir */ |
---|
68 | | -static struct dentry *ovl_whiteout(struct dentry *workdir) |
---|
| 65 | +static struct dentry *ovl_whiteout(struct ovl_fs *ofs) |
---|
69 | 66 | { |
---|
70 | 67 | int err; |
---|
71 | 68 | struct dentry *whiteout; |
---|
| 69 | + struct dentry *workdir = ofs->workdir; |
---|
72 | 70 | struct inode *wdir = workdir->d_inode; |
---|
73 | 71 | |
---|
74 | | - whiteout = ovl_lookup_temp(workdir); |
---|
75 | | - if (IS_ERR(whiteout)) |
---|
76 | | - return whiteout; |
---|
| 72 | + if (!ofs->whiteout) { |
---|
| 73 | + whiteout = ovl_lookup_temp(workdir); |
---|
| 74 | + if (IS_ERR(whiteout)) |
---|
| 75 | + goto out; |
---|
77 | 76 | |
---|
78 | | - err = ovl_do_whiteout(wdir, whiteout); |
---|
79 | | - if (err) { |
---|
80 | | - dput(whiteout); |
---|
81 | | - whiteout = ERR_PTR(err); |
---|
| 77 | + err = ovl_do_whiteout(wdir, whiteout); |
---|
| 78 | + if (err) { |
---|
| 79 | + dput(whiteout); |
---|
| 80 | + whiteout = ERR_PTR(err); |
---|
| 81 | + goto out; |
---|
| 82 | + } |
---|
| 83 | + ofs->whiteout = whiteout; |
---|
82 | 84 | } |
---|
83 | 85 | |
---|
| 86 | + if (ofs->share_whiteout) { |
---|
| 87 | + whiteout = ovl_lookup_temp(workdir); |
---|
| 88 | + if (IS_ERR(whiteout)) |
---|
| 89 | + goto out; |
---|
| 90 | + |
---|
| 91 | + err = ovl_do_link(ofs->whiteout, wdir, whiteout); |
---|
| 92 | + if (!err) |
---|
| 93 | + goto out; |
---|
| 94 | + |
---|
| 95 | + if (err != -EMLINK) { |
---|
| 96 | + pr_warn("Failed to link whiteout - disabling whiteout inode sharing(nlink=%u, err=%i)\n", |
---|
| 97 | + ofs->whiteout->d_inode->i_nlink, err); |
---|
| 98 | + ofs->share_whiteout = false; |
---|
| 99 | + } |
---|
| 100 | + dput(whiteout); |
---|
| 101 | + } |
---|
| 102 | + whiteout = ofs->whiteout; |
---|
| 103 | + ofs->whiteout = NULL; |
---|
| 104 | +out: |
---|
84 | 105 | return whiteout; |
---|
85 | 106 | } |
---|
86 | 107 | |
---|
87 | 108 | /* Caller must hold i_mutex on both workdir and dir */ |
---|
88 | | -int ovl_cleanup_and_whiteout(struct dentry *workdir, struct inode *dir, |
---|
| 109 | +int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir, |
---|
89 | 110 | struct dentry *dentry) |
---|
90 | 111 | { |
---|
91 | | - struct inode *wdir = workdir->d_inode; |
---|
| 112 | + struct inode *wdir = ofs->workdir->d_inode; |
---|
92 | 113 | struct dentry *whiteout; |
---|
93 | 114 | int err; |
---|
94 | 115 | int flags = 0; |
---|
95 | 116 | |
---|
96 | | - whiteout = ovl_whiteout(workdir); |
---|
| 117 | + whiteout = ovl_whiteout(ofs); |
---|
97 | 118 | err = PTR_ERR(whiteout); |
---|
98 | 119 | if (IS_ERR(whiteout)) |
---|
99 | 120 | return err; |
---|
.. | .. |
---|
136 | 157 | d = lookup_one_len(dentry->d_name.name, dentry->d_parent, |
---|
137 | 158 | dentry->d_name.len); |
---|
138 | 159 | if (IS_ERR(d)) { |
---|
139 | | - pr_warn("overlayfs: failed lookup after mkdir (%pd2, err=%i).\n", |
---|
| 160 | + pr_warn("failed lookup after mkdir (%pd2, err=%i).\n", |
---|
140 | 161 | dentry, err); |
---|
141 | 162 | return PTR_ERR(d); |
---|
142 | 163 | } |
---|
.. | .. |
---|
245 | 266 | |
---|
246 | 267 | ovl_dir_modified(dentry->d_parent, false); |
---|
247 | 268 | ovl_dentry_set_upper_alias(dentry); |
---|
| 269 | + ovl_dentry_init_reval(dentry, newdentry); |
---|
| 270 | + |
---|
248 | 271 | if (!hardlink) { |
---|
249 | 272 | /* |
---|
250 | 273 | * ovl_obtain_alias() can be called after ovl_create_real() |
---|
.. | .. |
---|
261 | 284 | inode = ovl_get_inode(dentry->d_sb, &oip); |
---|
262 | 285 | if (IS_ERR(inode)) |
---|
263 | 286 | return PTR_ERR(inode); |
---|
| 287 | + if (inode == oip.newinode) |
---|
| 288 | + ovl_set_flag(OVL_UPPERDATA, inode); |
---|
264 | 289 | } else { |
---|
265 | 290 | WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); |
---|
266 | 291 | dput(newdentry); |
---|
.. | .. |
---|
269 | 294 | |
---|
270 | 295 | d_instantiate(dentry, inode); |
---|
271 | 296 | if (inode != oip.newinode) { |
---|
272 | | - pr_warn_ratelimited("overlayfs: newly created inode found in cache (%pd2)\n", |
---|
| 297 | + pr_warn_ratelimited("newly created inode found in cache (%pd2)\n", |
---|
273 | 298 | dentry); |
---|
274 | 299 | } |
---|
275 | 300 | |
---|
.. | .. |
---|
367 | 392 | if (IS_ERR(opaquedir)) |
---|
368 | 393 | goto out_unlock; |
---|
369 | 394 | |
---|
370 | | - err = ovl_copy_xattr(upper, opaquedir); |
---|
| 395 | + err = ovl_copy_xattr(dentry->d_sb, upper, opaquedir); |
---|
371 | 396 | if (err) |
---|
372 | 397 | goto out_cleanup; |
---|
373 | 398 | |
---|
.. | .. |
---|
413 | 438 | if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl) |
---|
414 | 439 | return 0; |
---|
415 | 440 | |
---|
416 | | - size = posix_acl_to_xattr(NULL, acl, NULL, 0); |
---|
| 441 | + size = posix_acl_xattr_size(acl->a_count); |
---|
417 | 442 | buffer = kmalloc(size, GFP_KERNEL); |
---|
418 | 443 | if (!buffer) |
---|
419 | 444 | return -ENOMEM; |
---|
420 | 445 | |
---|
421 | | - size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); |
---|
422 | | - err = size; |
---|
| 446 | + err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); |
---|
423 | 447 | if (err < 0) |
---|
424 | 448 | goto out_free; |
---|
425 | 449 | |
---|
.. | .. |
---|
561 | 585 | goto out_revert_creds; |
---|
562 | 586 | } |
---|
563 | 587 | |
---|
564 | | - err = -ENOMEM; |
---|
565 | | - override_cred = prepare_creds(); |
---|
566 | | - if (override_cred) { |
---|
| 588 | + if (!attr->hardlink) { |
---|
| 589 | + err = -ENOMEM; |
---|
| 590 | + override_cred = prepare_creds(); |
---|
| 591 | + if (!override_cred) |
---|
| 592 | + goto out_revert_creds; |
---|
| 593 | + /* |
---|
| 594 | + * In the creation cases(create, mkdir, mknod, symlink), |
---|
| 595 | + * ovl should transfer current's fs{u,g}id to underlying |
---|
| 596 | + * fs. Because underlying fs want to initialize its new |
---|
| 597 | + * inode owner using current's fs{u,g}id. And in this |
---|
| 598 | + * case, the @inode is a new inode that is initialized |
---|
| 599 | + * in inode_init_owner() to current's fs{u,g}id. So use |
---|
| 600 | + * the inode's i_{u,g}id to override the cred's fs{u,g}id. |
---|
| 601 | + * |
---|
| 602 | + * But in the other hardlink case, ovl_link() does not |
---|
| 603 | + * create a new inode, so just use the ovl mounter's |
---|
| 604 | + * fs{u,g}id. |
---|
| 605 | + */ |
---|
567 | 606 | override_cred->fsuid = inode->i_uid; |
---|
568 | 607 | override_cred->fsgid = inode->i_gid; |
---|
569 | | - if (!attr->hardlink) { |
---|
570 | | - err = security_dentry_create_files_as(dentry, |
---|
571 | | - attr->mode, &dentry->d_name, |
---|
572 | | - old_cred ? old_cred : current_cred(), |
---|
573 | | - override_cred); |
---|
574 | | - if (err) { |
---|
575 | | - put_cred(override_cred); |
---|
576 | | - goto out_revert_creds; |
---|
577 | | - } |
---|
| 608 | + err = security_dentry_create_files_as(dentry, |
---|
| 609 | + attr->mode, &dentry->d_name, |
---|
| 610 | + old_cred ? old_cred : current_cred(), |
---|
| 611 | + override_cred); |
---|
| 612 | + if (err) { |
---|
| 613 | + put_cred(override_cred); |
---|
| 614 | + goto out_revert_creds; |
---|
578 | 615 | } |
---|
579 | 616 | hold_cred = override_creds(override_cred); |
---|
580 | 617 | put_cred(override_cred); |
---|
581 | | - |
---|
582 | | - if (!ovl_dentry_is_whiteout(dentry)) |
---|
583 | | - err = ovl_create_upper(dentry, inode, attr); |
---|
584 | | - else |
---|
585 | | - err = ovl_create_over_whiteout(dentry, inode, attr); |
---|
586 | 618 | } |
---|
| 619 | + |
---|
| 620 | + if (!ovl_dentry_is_whiteout(dentry)) |
---|
| 621 | + err = ovl_create_upper(dentry, inode, attr); |
---|
| 622 | + else |
---|
| 623 | + err = ovl_create_over_whiteout(dentry, inode, attr); |
---|
| 624 | + |
---|
587 | 625 | out_revert_creds: |
---|
588 | | - ovl_revert_creds(old_cred ?: hold_cred); |
---|
| 626 | + ovl_revert_creds(dentry->d_sb, old_cred ?: hold_cred); |
---|
589 | 627 | if (old_cred && hold_cred) |
---|
590 | 628 | put_cred(hold_cred); |
---|
591 | 629 | return err; |
---|
.. | .. |
---|
663 | 701 | |
---|
664 | 702 | old_cred = ovl_override_creds(dentry->d_sb); |
---|
665 | 703 | err = ovl_set_redirect(dentry, false); |
---|
666 | | - ovl_revert_creds(old_cred); |
---|
| 704 | + ovl_revert_creds(dentry->d_sb, old_cred); |
---|
667 | 705 | |
---|
668 | 706 | return err; |
---|
669 | 707 | } |
---|
.. | .. |
---|
672 | 710 | struct dentry *new) |
---|
673 | 711 | { |
---|
674 | 712 | int err; |
---|
675 | | - bool locked = false; |
---|
676 | 713 | struct inode *inode; |
---|
677 | 714 | |
---|
678 | 715 | err = ovl_want_write(old); |
---|
.. | .. |
---|
693 | 730 | goto out_drop_write; |
---|
694 | 731 | } |
---|
695 | 732 | |
---|
696 | | - err = ovl_nlink_start(old, &locked); |
---|
| 733 | + err = ovl_nlink_start(old); |
---|
697 | 734 | if (err) |
---|
698 | 735 | goto out_drop_write; |
---|
699 | 736 | |
---|
.. | .. |
---|
706 | 743 | if (err) |
---|
707 | 744 | iput(inode); |
---|
708 | 745 | |
---|
709 | | - ovl_nlink_end(old, locked); |
---|
| 746 | + ovl_nlink_end(old); |
---|
710 | 747 | out_drop_write: |
---|
711 | 748 | ovl_drop_write(old); |
---|
712 | 749 | out: |
---|
.. | .. |
---|
721 | 758 | static int ovl_remove_and_whiteout(struct dentry *dentry, |
---|
722 | 759 | struct list_head *list) |
---|
723 | 760 | { |
---|
| 761 | + struct ovl_fs *ofs = OVL_FS(dentry->d_sb); |
---|
724 | 762 | struct dentry *workdir = ovl_workdir(dentry); |
---|
725 | 763 | struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); |
---|
726 | 764 | struct dentry *upper; |
---|
.. | .. |
---|
754 | 792 | goto out_dput_upper; |
---|
755 | 793 | } |
---|
756 | 794 | |
---|
757 | | - err = ovl_cleanup_and_whiteout(workdir, d_inode(upperdir), upper); |
---|
| 795 | + err = ovl_cleanup_and_whiteout(ofs, d_inode(upperdir), upper); |
---|
758 | 796 | if (err) |
---|
759 | 797 | goto out_d_drop; |
---|
760 | 798 | |
---|
.. | .. |
---|
828 | 866 | !ovl_test_flag(OVL_WHITEOUTS, d_inode(dentry)); |
---|
829 | 867 | } |
---|
830 | 868 | |
---|
| 869 | +static void ovl_drop_nlink(struct dentry *dentry) |
---|
| 870 | +{ |
---|
| 871 | + struct inode *inode = d_inode(dentry); |
---|
| 872 | + struct dentry *alias; |
---|
| 873 | + |
---|
| 874 | + /* Try to find another, hashed alias */ |
---|
| 875 | + spin_lock(&inode->i_lock); |
---|
| 876 | + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { |
---|
| 877 | + if (alias != dentry && !d_unhashed(alias)) |
---|
| 878 | + break; |
---|
| 879 | + } |
---|
| 880 | + spin_unlock(&inode->i_lock); |
---|
| 881 | + |
---|
| 882 | + /* |
---|
| 883 | + * Changes to underlying layers may cause i_nlink to lose sync with |
---|
| 884 | + * reality. In this case prevent the link count from going to zero |
---|
| 885 | + * prematurely. |
---|
| 886 | + */ |
---|
| 887 | + if (inode->i_nlink > !!alias) |
---|
| 888 | + drop_nlink(inode); |
---|
| 889 | +} |
---|
| 890 | + |
---|
831 | 891 | static int ovl_do_remove(struct dentry *dentry, bool is_dir) |
---|
832 | 892 | { |
---|
833 | 893 | int err; |
---|
834 | | - bool locked = false; |
---|
835 | 894 | const struct cred *old_cred; |
---|
836 | 895 | struct dentry *upperdentry; |
---|
837 | 896 | bool lower_positive = ovl_lower_positive(dentry); |
---|
.. | .. |
---|
852 | 911 | if (err) |
---|
853 | 912 | goto out_drop_write; |
---|
854 | 913 | |
---|
855 | | - err = ovl_nlink_start(dentry, &locked); |
---|
| 914 | + err = ovl_nlink_start(dentry); |
---|
856 | 915 | if (err) |
---|
857 | 916 | goto out_drop_write; |
---|
858 | 917 | |
---|
.. | .. |
---|
861 | 920 | err = ovl_remove_upper(dentry, is_dir, &list); |
---|
862 | 921 | else |
---|
863 | 922 | err = ovl_remove_and_whiteout(dentry, &list); |
---|
864 | | - ovl_revert_creds(old_cred); |
---|
| 923 | + ovl_revert_creds(dentry->d_sb, old_cred); |
---|
865 | 924 | if (!err) { |
---|
866 | 925 | if (is_dir) |
---|
867 | 926 | clear_nlink(dentry->d_inode); |
---|
868 | 927 | else |
---|
869 | | - drop_nlink(dentry->d_inode); |
---|
| 928 | + ovl_drop_nlink(dentry); |
---|
870 | 929 | } |
---|
871 | | - ovl_nlink_end(dentry, locked); |
---|
| 930 | + ovl_nlink_end(dentry); |
---|
872 | 931 | |
---|
873 | 932 | /* |
---|
874 | 933 | * Copy ctime |
---|
.. | .. |
---|
1019 | 1078 | spin_unlock(&dentry->d_lock); |
---|
1020 | 1079 | } else { |
---|
1021 | 1080 | kfree(redirect); |
---|
1022 | | - pr_warn_ratelimited("overlayfs: failed to set redirect (%i)\n", |
---|
| 1081 | + pr_warn_ratelimited("failed to set redirect (%i)\n", |
---|
1023 | 1082 | err); |
---|
1024 | 1083 | /* Fall back to userspace copy-up */ |
---|
1025 | 1084 | err = -EXDEV; |
---|
.. | .. |
---|
1032 | 1091 | unsigned int flags) |
---|
1033 | 1092 | { |
---|
1034 | 1093 | int err; |
---|
1035 | | - bool locked = false; |
---|
1036 | 1094 | struct dentry *old_upperdir; |
---|
1037 | 1095 | struct dentry *new_upperdir; |
---|
1038 | 1096 | struct dentry *olddentry; |
---|
.. | .. |
---|
1041 | 1099 | bool old_opaque; |
---|
1042 | 1100 | bool new_opaque; |
---|
1043 | 1101 | bool cleanup_whiteout = false; |
---|
| 1102 | + bool update_nlink = false; |
---|
1044 | 1103 | bool overwrite = !(flags & RENAME_EXCHANGE); |
---|
1045 | 1104 | bool is_dir = d_is_dir(old); |
---|
1046 | 1105 | bool new_is_dir = d_is_dir(new); |
---|
.. | .. |
---|
1098 | 1157 | err = ovl_copy_up(new); |
---|
1099 | 1158 | if (err) |
---|
1100 | 1159 | goto out_drop_write; |
---|
1101 | | - } else { |
---|
1102 | | - err = ovl_nlink_start(new, &locked); |
---|
| 1160 | + } else if (d_inode(new)) { |
---|
| 1161 | + err = ovl_nlink_start(new); |
---|
1103 | 1162 | if (err) |
---|
1104 | 1163 | goto out_drop_write; |
---|
| 1164 | + |
---|
| 1165 | + update_nlink = true; |
---|
1105 | 1166 | } |
---|
1106 | 1167 | |
---|
1107 | 1168 | old_cred = ovl_override_creds(old->d_sb); |
---|
.. | .. |
---|
1213 | 1274 | if (new_is_dir) |
---|
1214 | 1275 | clear_nlink(d_inode(new)); |
---|
1215 | 1276 | else |
---|
1216 | | - drop_nlink(d_inode(new)); |
---|
| 1277 | + ovl_drop_nlink(new); |
---|
1217 | 1278 | } |
---|
1218 | 1279 | |
---|
1219 | 1280 | ovl_dir_modified(old->d_parent, ovl_type_origin(old) || |
---|
.. | .. |
---|
1233 | 1294 | out_unlock: |
---|
1234 | 1295 | unlock_rename(new_upperdir, old_upperdir); |
---|
1235 | 1296 | out_revert_creds: |
---|
1236 | | - ovl_revert_creds(old_cred); |
---|
1237 | | - ovl_nlink_end(new, locked); |
---|
| 1297 | + ovl_revert_creds(old->d_sb, old_cred); |
---|
| 1298 | + if (update_nlink) |
---|
| 1299 | + ovl_nlink_end(new); |
---|
1238 | 1300 | out_drop_write: |
---|
1239 | 1301 | ovl_drop_write(old); |
---|
1240 | 1302 | out: |
---|