aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c53
-rw-r--r--include/linux/namei.h1
2 files changed, 35 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
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 518098fe63af..325dd3ad39a0 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -18,6 +18,7 @@ enum { MAX_NESTED_LINKS = 8 };
18struct nameidata { 18struct nameidata {
19 struct path path; 19 struct path path;
20 struct qstr last; 20 struct qstr last;
21 struct path root;
21 unsigned int flags; 22 unsigned int flags;
22 int last_type; 23 int last_type;
23 unsigned depth; 24 unsigned depth;