aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2009-04-07 11:49:53 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-11 21:35:59 -0400
commit2a737871108de9ba8930f7650d549f1383767f8b (patch)
treed4a8c5d7da4624c4a8973a4c9369af7a915dca05 /fs/namei.c
parent9b4a9b14a793bc69b505ed916051f6f32db13bb8 (diff)
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 895733efc6b9..88baaf2b9167 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -552,6 +552,17 @@ static __always_inline int link_path_walk(const char *name, struct nameidata *nd
552 return result; 552 return result;
553} 553}
554 554
555static __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
555static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) 566static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
556{ 567{
557 int res = 0; 568 int res = 0;
@@ -560,14 +571,10 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
560 goto fail; 571 goto fail;
561 572
562 if (*link == '/') { 573 if (*link == '/') {
563 struct fs_struct *fs = current->fs; 574 set_root(nd);
564
565 path_put(&nd->path); 575 path_put(&nd->path);
566 576 nd->path = nd->root;
567 read_lock(&fs->lock); 577 path_get(&nd->root);
568 nd->path = fs->root;
569 path_get(&fs->root);
570 read_unlock(&fs->lock);
571 } 578 }
572 579
573 res = link_path_walk(link, nd); 580 res = link_path_walk(link, nd);
@@ -741,19 +748,16 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
741 748
742static __always_inline void follow_dotdot(struct nameidata *nd) 749static __always_inline void follow_dotdot(struct nameidata *nd)
743{ 750{
744 struct fs_struct *fs = current->fs; 751 set_root(nd);
745 752
746 while(1) { 753 while(1) {
747 struct vfsmount *parent; 754 struct vfsmount *parent;
748 struct dentry *old = nd->path.dentry; 755 struct dentry *old = nd->path.dentry;
749 756
750 read_lock(&fs->lock); 757 if (nd->path.dentry == nd->root.dentry &&
751 if (nd->path.dentry == fs->root.dentry && 758 nd->path.mnt == nd->root.mnt) {
752 nd->path.mnt == fs->root.mnt) {
753 read_unlock(&fs->lock);
754 break; 759 break;
755 } 760 }
756 read_unlock(&fs->lock);
757 spin_lock(&dcache_lock); 761 spin_lock(&dcache_lock);
758 if (nd->path.dentry != nd->path.mnt->mnt_root) { 762 if (nd->path.dentry != nd->path.mnt->mnt_root) {
759 nd->path.dentry = dget(nd->path.dentry->d_parent); 763 nd->path.dentry = dget(nd->path.dentry->d_parent);
@@ -1022,18 +1026,18 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
1022 int retval = 0; 1026 int retval = 0;
1023 int fput_needed; 1027 int fput_needed;
1024 struct file *file; 1028 struct file *file;
1025 struct fs_struct *fs = current->fs;
1026 1029
1027 nd->last_type = LAST_ROOT; /* if there are only slashes... */ 1030 nd->last_type = LAST_ROOT; /* if there are only slashes... */
1028 nd->flags = flags; 1031 nd->flags = flags;
1029 nd->depth = 0; 1032 nd->depth = 0;
1033 nd->root.mnt = NULL;
1030 1034
1031 if (*name=='/') { 1035 if (*name=='/') {
1032 read_lock(&fs->lock); 1036 set_root(nd);
1033 nd->path = fs->root; 1037 nd->path = nd->root;
1034 path_get(&fs->root); 1038 path_get(&nd->root);
1035 read_unlock(&fs->lock);
1036 } else if (dfd == AT_FDCWD) { 1039 } else if (dfd == AT_FDCWD) {
1040 struct fs_struct *fs = current->fs;
1037 read_lock(&fs->lock); 1041 read_lock(&fs->lock);
1038 nd->path = fs->pwd; 1042 nd->path = fs->pwd;
1039 path_get(&fs->pwd); 1043 path_get(&fs->pwd);
@@ -1079,6 +1083,10 @@ static int do_path_lookup(int dfd, const char *name,
1079 if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && 1083 if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
1080 nd->path.dentry->d_inode)) 1084 nd->path.dentry->d_inode))
1081 audit_inode(name, nd->path.dentry); 1085 audit_inode(name, nd->path.dentry);
1086 if (nd->root.mnt) {
1087 path_put(&nd->root);
1088 nd->root.mnt = NULL;
1089 }
1082 return retval; 1090 return retval;
1083} 1091}
1084 1092
@@ -1115,6 +1123,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
1115 nd->last_type = LAST_ROOT; 1123 nd->last_type = LAST_ROOT;
1116 nd->flags = flags; 1124 nd->flags = flags;
1117 nd->depth = 0; 1125 nd->depth = 0;
1126 nd->root.mnt = NULL;
1118 1127
1119 nd->path.dentry = dentry; 1128 nd->path.dentry = dentry;
1120 nd->path.mnt = mnt; 1129 nd->path.mnt = mnt;
@@ -1125,8 +1134,12 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
1125 nd->path.dentry->d_inode)) 1134 nd->path.dentry->d_inode))
1126 audit_inode(name, nd->path.dentry); 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 @@ exit:
1817 if (!IS_ERR(nd.intent.open.file)) 1830 if (!IS_ERR(nd.intent.open.file))
1818 release_open_intent(&nd); 1831 release_open_intent(&nd);
1819exit_parent: 1832exit_parent:
1833 if (nd.root.mnt)
1834 path_put(&nd.root);
1820 path_put(&nd.path); 1835 path_put(&nd.path);
1821 return ERR_PTR(error); 1836 return ERR_PTR(error);
1822 1837