| .. | .. |
|---|
| 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_update_reval(dentry, newdentry, |
|---|
| 270 | + DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE); |
|---|
| 271 | + |
|---|
| 248 | 272 | if (!hardlink) { |
|---|
| 249 | 273 | /* |
|---|
| 250 | 274 | * ovl_obtain_alias() can be called after ovl_create_real() |
|---|
| .. | .. |
|---|
| 261 | 285 | inode = ovl_get_inode(dentry->d_sb, &oip); |
|---|
| 262 | 286 | if (IS_ERR(inode)) |
|---|
| 263 | 287 | return PTR_ERR(inode); |
|---|
| 288 | + if (inode == oip.newinode) |
|---|
| 289 | + ovl_set_flag(OVL_UPPERDATA, inode); |
|---|
| 264 | 290 | } else { |
|---|
| 265 | 291 | WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); |
|---|
| 266 | 292 | dput(newdentry); |
|---|
| .. | .. |
|---|
| 269 | 295 | |
|---|
| 270 | 296 | d_instantiate(dentry, inode); |
|---|
| 271 | 297 | if (inode != oip.newinode) { |
|---|
| 272 | | - pr_warn_ratelimited("overlayfs: newly created inode found in cache (%pd2)\n", |
|---|
| 298 | + pr_warn_ratelimited("newly created inode found in cache (%pd2)\n", |
|---|
| 273 | 299 | dentry); |
|---|
| 274 | 300 | } |
|---|
| 275 | 301 | |
|---|
| .. | .. |
|---|
| 367 | 393 | if (IS_ERR(opaquedir)) |
|---|
| 368 | 394 | goto out_unlock; |
|---|
| 369 | 395 | |
|---|
| 370 | | - err = ovl_copy_xattr(upper, opaquedir); |
|---|
| 396 | + err = ovl_copy_xattr(dentry->d_sb, upper, opaquedir); |
|---|
| 371 | 397 | if (err) |
|---|
| 372 | 398 | goto out_cleanup; |
|---|
| 373 | 399 | |
|---|
| .. | .. |
|---|
| 413 | 439 | if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl) |
|---|
| 414 | 440 | return 0; |
|---|
| 415 | 441 | |
|---|
| 416 | | - size = posix_acl_to_xattr(NULL, acl, NULL, 0); |
|---|
| 442 | + size = posix_acl_xattr_size(acl->a_count); |
|---|
| 417 | 443 | buffer = kmalloc(size, GFP_KERNEL); |
|---|
| 418 | 444 | if (!buffer) |
|---|
| 419 | 445 | return -ENOMEM; |
|---|
| 420 | 446 | |
|---|
| 421 | | - size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); |
|---|
| 422 | | - err = size; |
|---|
| 447 | + err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); |
|---|
| 423 | 448 | if (err < 0) |
|---|
| 424 | 449 | goto out_free; |
|---|
| 425 | 450 | |
|---|
| .. | .. |
|---|
| 585 | 610 | err = ovl_create_over_whiteout(dentry, inode, attr); |
|---|
| 586 | 611 | } |
|---|
| 587 | 612 | out_revert_creds: |
|---|
| 588 | | - ovl_revert_creds(old_cred ?: hold_cred); |
|---|
| 613 | + ovl_revert_creds(dentry->d_sb, old_cred ?: hold_cred); |
|---|
| 589 | 614 | if (old_cred && hold_cred) |
|---|
| 590 | 615 | put_cred(hold_cred); |
|---|
| 591 | 616 | return err; |
|---|
| .. | .. |
|---|
| 663 | 688 | |
|---|
| 664 | 689 | old_cred = ovl_override_creds(dentry->d_sb); |
|---|
| 665 | 690 | err = ovl_set_redirect(dentry, false); |
|---|
| 666 | | - ovl_revert_creds(old_cred); |
|---|
| 691 | + ovl_revert_creds(dentry->d_sb, old_cred); |
|---|
| 667 | 692 | |
|---|
| 668 | 693 | return err; |
|---|
| 669 | 694 | } |
|---|
| .. | .. |
|---|
| 672 | 697 | struct dentry *new) |
|---|
| 673 | 698 | { |
|---|
| 674 | 699 | int err; |
|---|
| 675 | | - bool locked = false; |
|---|
| 676 | 700 | struct inode *inode; |
|---|
| 677 | 701 | |
|---|
| 678 | 702 | err = ovl_want_write(old); |
|---|
| .. | .. |
|---|
| 693 | 717 | goto out_drop_write; |
|---|
| 694 | 718 | } |
|---|
| 695 | 719 | |
|---|
| 696 | | - err = ovl_nlink_start(old, &locked); |
|---|
| 720 | + err = ovl_nlink_start(old); |
|---|
| 697 | 721 | if (err) |
|---|
| 698 | 722 | goto out_drop_write; |
|---|
| 699 | 723 | |
|---|
| .. | .. |
|---|
| 706 | 730 | if (err) |
|---|
| 707 | 731 | iput(inode); |
|---|
| 708 | 732 | |
|---|
| 709 | | - ovl_nlink_end(old, locked); |
|---|
| 733 | + ovl_nlink_end(old); |
|---|
| 710 | 734 | out_drop_write: |
|---|
| 711 | 735 | ovl_drop_write(old); |
|---|
| 712 | 736 | out: |
|---|
| .. | .. |
|---|
| 721 | 745 | static int ovl_remove_and_whiteout(struct dentry *dentry, |
|---|
| 722 | 746 | struct list_head *list) |
|---|
| 723 | 747 | { |
|---|
| 748 | + struct ovl_fs *ofs = OVL_FS(dentry->d_sb); |
|---|
| 724 | 749 | struct dentry *workdir = ovl_workdir(dentry); |
|---|
| 725 | 750 | struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); |
|---|
| 726 | 751 | struct dentry *upper; |
|---|
| .. | .. |
|---|
| 754 | 779 | goto out_dput_upper; |
|---|
| 755 | 780 | } |
|---|
| 756 | 781 | |
|---|
| 757 | | - err = ovl_cleanup_and_whiteout(workdir, d_inode(upperdir), upper); |
|---|
| 782 | + err = ovl_cleanup_and_whiteout(ofs, d_inode(upperdir), upper); |
|---|
| 758 | 783 | if (err) |
|---|
| 759 | 784 | goto out_d_drop; |
|---|
| 760 | 785 | |
|---|
| .. | .. |
|---|
| 828 | 853 | !ovl_test_flag(OVL_WHITEOUTS, d_inode(dentry)); |
|---|
| 829 | 854 | } |
|---|
| 830 | 855 | |
|---|
| 856 | +static void ovl_drop_nlink(struct dentry *dentry) |
|---|
| 857 | +{ |
|---|
| 858 | + struct inode *inode = d_inode(dentry); |
|---|
| 859 | + struct dentry *alias; |
|---|
| 860 | + |
|---|
| 861 | + /* Try to find another, hashed alias */ |
|---|
| 862 | + spin_lock(&inode->i_lock); |
|---|
| 863 | + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { |
|---|
| 864 | + if (alias != dentry && !d_unhashed(alias)) |
|---|
| 865 | + break; |
|---|
| 866 | + } |
|---|
| 867 | + spin_unlock(&inode->i_lock); |
|---|
| 868 | + |
|---|
| 869 | + /* |
|---|
| 870 | + * Changes to underlying layers may cause i_nlink to lose sync with |
|---|
| 871 | + * reality. In this case prevent the link count from going to zero |
|---|
| 872 | + * prematurely. |
|---|
| 873 | + */ |
|---|
| 874 | + if (inode->i_nlink > !!alias) |
|---|
| 875 | + drop_nlink(inode); |
|---|
| 876 | +} |
|---|
| 877 | + |
|---|
| 831 | 878 | static int ovl_do_remove(struct dentry *dentry, bool is_dir) |
|---|
| 832 | 879 | { |
|---|
| 833 | 880 | int err; |
|---|
| 834 | | - bool locked = false; |
|---|
| 835 | 881 | const struct cred *old_cred; |
|---|
| 836 | 882 | struct dentry *upperdentry; |
|---|
| 837 | 883 | bool lower_positive = ovl_lower_positive(dentry); |
|---|
| .. | .. |
|---|
| 852 | 898 | if (err) |
|---|
| 853 | 899 | goto out_drop_write; |
|---|
| 854 | 900 | |
|---|
| 855 | | - err = ovl_nlink_start(dentry, &locked); |
|---|
| 901 | + err = ovl_nlink_start(dentry); |
|---|
| 856 | 902 | if (err) |
|---|
| 857 | 903 | goto out_drop_write; |
|---|
| 858 | 904 | |
|---|
| .. | .. |
|---|
| 861 | 907 | err = ovl_remove_upper(dentry, is_dir, &list); |
|---|
| 862 | 908 | else |
|---|
| 863 | 909 | err = ovl_remove_and_whiteout(dentry, &list); |
|---|
| 864 | | - ovl_revert_creds(old_cred); |
|---|
| 910 | + ovl_revert_creds(dentry->d_sb, old_cred); |
|---|
| 865 | 911 | if (!err) { |
|---|
| 866 | 912 | if (is_dir) |
|---|
| 867 | 913 | clear_nlink(dentry->d_inode); |
|---|
| 868 | 914 | else |
|---|
| 869 | | - drop_nlink(dentry->d_inode); |
|---|
| 915 | + ovl_drop_nlink(dentry); |
|---|
| 870 | 916 | } |
|---|
| 871 | | - ovl_nlink_end(dentry, locked); |
|---|
| 917 | + ovl_nlink_end(dentry); |
|---|
| 872 | 918 | |
|---|
| 873 | 919 | /* |
|---|
| 874 | 920 | * Copy ctime |
|---|
| .. | .. |
|---|
| 1019 | 1065 | spin_unlock(&dentry->d_lock); |
|---|
| 1020 | 1066 | } else { |
|---|
| 1021 | 1067 | kfree(redirect); |
|---|
| 1022 | | - pr_warn_ratelimited("overlayfs: failed to set redirect (%i)\n", |
|---|
| 1068 | + pr_warn_ratelimited("failed to set redirect (%i)\n", |
|---|
| 1023 | 1069 | err); |
|---|
| 1024 | 1070 | /* Fall back to userspace copy-up */ |
|---|
| 1025 | 1071 | err = -EXDEV; |
|---|
| .. | .. |
|---|
| 1032 | 1078 | unsigned int flags) |
|---|
| 1033 | 1079 | { |
|---|
| 1034 | 1080 | int err; |
|---|
| 1035 | | - bool locked = false; |
|---|
| 1036 | 1081 | struct dentry *old_upperdir; |
|---|
| 1037 | 1082 | struct dentry *new_upperdir; |
|---|
| 1038 | 1083 | struct dentry *olddentry; |
|---|
| .. | .. |
|---|
| 1041 | 1086 | bool old_opaque; |
|---|
| 1042 | 1087 | bool new_opaque; |
|---|
| 1043 | 1088 | bool cleanup_whiteout = false; |
|---|
| 1089 | + bool update_nlink = false; |
|---|
| 1044 | 1090 | bool overwrite = !(flags & RENAME_EXCHANGE); |
|---|
| 1045 | 1091 | bool is_dir = d_is_dir(old); |
|---|
| 1046 | 1092 | bool new_is_dir = d_is_dir(new); |
|---|
| .. | .. |
|---|
| 1098 | 1144 | err = ovl_copy_up(new); |
|---|
| 1099 | 1145 | if (err) |
|---|
| 1100 | 1146 | goto out_drop_write; |
|---|
| 1101 | | - } else { |
|---|
| 1102 | | - err = ovl_nlink_start(new, &locked); |
|---|
| 1147 | + } else if (d_inode(new)) { |
|---|
| 1148 | + err = ovl_nlink_start(new); |
|---|
| 1103 | 1149 | if (err) |
|---|
| 1104 | 1150 | goto out_drop_write; |
|---|
| 1151 | + |
|---|
| 1152 | + update_nlink = true; |
|---|
| 1105 | 1153 | } |
|---|
| 1106 | 1154 | |
|---|
| 1107 | 1155 | old_cred = ovl_override_creds(old->d_sb); |
|---|
| .. | .. |
|---|
| 1213 | 1261 | if (new_is_dir) |
|---|
| 1214 | 1262 | clear_nlink(d_inode(new)); |
|---|
| 1215 | 1263 | else |
|---|
| 1216 | | - drop_nlink(d_inode(new)); |
|---|
| 1264 | + ovl_drop_nlink(new); |
|---|
| 1217 | 1265 | } |
|---|
| 1218 | 1266 | |
|---|
| 1219 | 1267 | ovl_dir_modified(old->d_parent, ovl_type_origin(old) || |
|---|
| .. | .. |
|---|
| 1233 | 1281 | out_unlock: |
|---|
| 1234 | 1282 | unlock_rename(new_upperdir, old_upperdir); |
|---|
| 1235 | 1283 | out_revert_creds: |
|---|
| 1236 | | - ovl_revert_creds(old_cred); |
|---|
| 1237 | | - ovl_nlink_end(new, locked); |
|---|
| 1284 | + ovl_revert_creds(old->d_sb, old_cred); |
|---|
| 1285 | + if (update_nlink) |
|---|
| 1286 | + ovl_nlink_end(new); |
|---|
| 1238 | 1287 | out_drop_write: |
|---|
| 1239 | 1288 | ovl_drop_write(old); |
|---|
| 1240 | 1289 | out: |
|---|