Commit 2a737871108de9ba8930f7650d549f1383767f8b
1 parent
9b4a9b14a7
Exists in
master
and in
4 other branches
Cache root in nameidata
New field: nd->root. When pathname resolution wants to know the root, check if nd->root.mnt is non-NULL; use nd->root if it is, otherwise copy current->fs->root there. After path_walk() is finished, we check if we'd got a cached value in nd->root and drop it. Before calling path_walk() we should either set nd->root.mnt to NULL *or* copy (and pin down) some path to nd->root. In the latter case we won't be looking at current->fs->root at all. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 2 changed files with 35 additions and 19 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -552,6 +552,17 @@ |
552 | 552 | return result; |
553 | 553 | } |
554 | 554 | |
555 | +static __always_inline void set_root(struct nameidata *nd) | |
556 | +{ | |
557 | + if (!nd->root.mnt) { | |
558 | + struct fs_struct *fs = current->fs; | |
559 | + read_lock(&fs->lock); | |
560 | + nd->root = fs->root; | |
561 | + path_get(&nd->root); | |
562 | + read_unlock(&fs->lock); | |
563 | + } | |
564 | +} | |
565 | + | |
555 | 566 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
556 | 567 | { |
557 | 568 | int res = 0; |
558 | 569 | |
... | ... | @@ -560,14 +571,10 @@ |
560 | 571 | goto fail; |
561 | 572 | |
562 | 573 | if (*link == '/') { |
563 | - struct fs_struct *fs = current->fs; | |
564 | - | |
574 | + set_root(nd); | |
565 | 575 | path_put(&nd->path); |
566 | - | |
567 | - read_lock(&fs->lock); | |
568 | - nd->path = fs->root; | |
569 | - path_get(&fs->root); | |
570 | - read_unlock(&fs->lock); | |
576 | + nd->path = nd->root; | |
577 | + path_get(&nd->root); | |
571 | 578 | } |
572 | 579 | |
573 | 580 | res = link_path_walk(link, nd); |
574 | 581 | |
575 | 582 | |
... | ... | @@ -741,19 +748,16 @@ |
741 | 748 | |
742 | 749 | static __always_inline void follow_dotdot(struct nameidata *nd) |
743 | 750 | { |
744 | - struct fs_struct *fs = current->fs; | |
751 | + set_root(nd); | |
745 | 752 | |
746 | 753 | while(1) { |
747 | 754 | struct vfsmount *parent; |
748 | 755 | struct dentry *old = nd->path.dentry; |
749 | 756 | |
750 | - read_lock(&fs->lock); | |
751 | - if (nd->path.dentry == fs->root.dentry && | |
752 | - nd->path.mnt == fs->root.mnt) { | |
753 | - read_unlock(&fs->lock); | |
757 | + if (nd->path.dentry == nd->root.dentry && | |
758 | + nd->path.mnt == nd->root.mnt) { | |
754 | 759 | break; |
755 | 760 | } |
756 | - read_unlock(&fs->lock); | |
757 | 761 | spin_lock(&dcache_lock); |
758 | 762 | if (nd->path.dentry != nd->path.mnt->mnt_root) { |
759 | 763 | nd->path.dentry = dget(nd->path.dentry->d_parent); |
760 | 764 | |
761 | 765 | |
762 | 766 | |
... | ... | @@ -1022,18 +1026,18 @@ |
1022 | 1026 | int retval = 0; |
1023 | 1027 | int fput_needed; |
1024 | 1028 | struct file *file; |
1025 | - struct fs_struct *fs = current->fs; | |
1026 | 1029 | |
1027 | 1030 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1028 | 1031 | nd->flags = flags; |
1029 | 1032 | nd->depth = 0; |
1033 | + nd->root.mnt = NULL; | |
1030 | 1034 | |
1031 | 1035 | if (*name=='/') { |
1032 | - read_lock(&fs->lock); | |
1033 | - nd->path = fs->root; | |
1034 | - path_get(&fs->root); | |
1035 | - read_unlock(&fs->lock); | |
1036 | + set_root(nd); | |
1037 | + nd->path = nd->root; | |
1038 | + path_get(&nd->root); | |
1036 | 1039 | } else if (dfd == AT_FDCWD) { |
1040 | + struct fs_struct *fs = current->fs; | |
1037 | 1041 | read_lock(&fs->lock); |
1038 | 1042 | nd->path = fs->pwd; |
1039 | 1043 | path_get(&fs->pwd); |
... | ... | @@ -1079,6 +1083,10 @@ |
1079 | 1083 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
1080 | 1084 | nd->path.dentry->d_inode)) |
1081 | 1085 | audit_inode(name, nd->path.dentry); |
1086 | + if (nd->root.mnt) { | |
1087 | + path_put(&nd->root); | |
1088 | + nd->root.mnt = NULL; | |
1089 | + } | |
1082 | 1090 | return retval; |
1083 | 1091 | } |
1084 | 1092 | |
... | ... | @@ -1115,6 +1123,7 @@ |
1115 | 1123 | nd->last_type = LAST_ROOT; |
1116 | 1124 | nd->flags = flags; |
1117 | 1125 | nd->depth = 0; |
1126 | + nd->root.mnt = NULL; | |
1118 | 1127 | |
1119 | 1128 | nd->path.dentry = dentry; |
1120 | 1129 | nd->path.mnt = mnt; |
1121 | 1130 | |
... | ... | @@ -1125,8 +1134,12 @@ |
1125 | 1134 | nd->path.dentry->d_inode)) |
1126 | 1135 | audit_inode(name, nd->path.dentry); |
1127 | 1136 | |
1128 | - return retval; | |
1137 | + if (nd->root.mnt) { | |
1138 | + path_put(&nd->root); | |
1139 | + nd->root.mnt = NULL; | |
1140 | + } | |
1129 | 1141 | |
1142 | + return retval; | |
1130 | 1143 | } |
1131 | 1144 | |
1132 | 1145 | /** |
... | ... | @@ -1817,6 +1830,8 @@ |
1817 | 1830 | if (!IS_ERR(nd.intent.open.file)) |
1818 | 1831 | release_open_intent(&nd); |
1819 | 1832 | exit_parent: |
1833 | + if (nd.root.mnt) | |
1834 | + path_put(&nd.root); | |
1820 | 1835 | path_put(&nd.path); |
1821 | 1836 | return ERR_PTR(error); |
1822 | 1837 |