Commit 2a737871108de9ba8930f7650d549f1383767f8b

Authored by Al Viro
1 parent 9b4a9b14a7

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

... ... @@ -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  
include/linux/namei.h
... ... @@ -18,6 +18,7 @@
18 18 struct nameidata {
19 19 struct path path;
20 20 struct qstr last;
  21 + struct path root;
21 22 unsigned int flags;
22 23 int last_type;
23 24 unsigned depth;