aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-09-13 21:55:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-09-14 14:19:44 -0400
commit7bd88377d482e1eae3c5329b12e33cfd664fa6a9 (patch)
tree814293d29b98c33b887c3140c11e24ccffbf9862
parentf5be3e29127aec8c87f883aadadff337f8c2cfd7 (diff)
don't bugger nd->seq on set_root_rcu() from follow_dotdot_rcu()
return the value instead, and have path_init() do the assignment. Broken by "vfs: Fix absolute RCU path walk failures due to uninitialized seq number", which was Cc-stable with 2.6.38+ as destination. This one should go where it went. To avoid dummy value returned in case when root is already set (it would do no harm, actually, since the only caller that doesn't ignore the return value is guaranteed to have nd->root *not* set, but it's more obvious that way), lift the check into callers. And do the same to set_root(), to keep them in sync. Cc: stable@vger.kernel.org # 2.6.38+ Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 3d1dc745f9d8..fe47e6d8e85f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -643,24 +643,22 @@ static int complete_walk(struct nameidata *nd)
643 643
644static __always_inline void set_root(struct nameidata *nd) 644static __always_inline void set_root(struct nameidata *nd)
645{ 645{
646 if (!nd->root.mnt) 646 get_fs_root(current->fs, &nd->root);
647 get_fs_root(current->fs, &nd->root);
648} 647}
649 648
650static int link_path_walk(const char *, struct nameidata *); 649static int link_path_walk(const char *, struct nameidata *);
651 650
652static __always_inline void set_root_rcu(struct nameidata *nd) 651static __always_inline unsigned set_root_rcu(struct nameidata *nd)
653{ 652{
654 if (!nd->root.mnt) { 653 struct fs_struct *fs = current->fs;
655 struct fs_struct *fs = current->fs; 654 unsigned seq, res;
656 unsigned seq;
657 655
658 do { 656 do {
659 seq = read_seqcount_begin(&fs->seq); 657 seq = read_seqcount_begin(&fs->seq);
660 nd->root = fs->root; 658 nd->root = fs->root;
661 nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq); 659 res = __read_seqcount_begin(&nd->root.dentry->d_seq);
662 } while (read_seqcount_retry(&fs->seq, seq)); 660 } while (read_seqcount_retry(&fs->seq, seq));
663 } 661 return res;
664} 662}
665 663
666static void path_put_conditional(struct path *path, struct nameidata *nd) 664static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -860,7 +858,8 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
860 return PTR_ERR(s); 858 return PTR_ERR(s);
861 } 859 }
862 if (*s == '/') { 860 if (*s == '/') {
863 set_root(nd); 861 if (!nd->root.mnt)
862 set_root(nd);
864 path_put(&nd->path); 863 path_put(&nd->path);
865 nd->path = nd->root; 864 nd->path = nd->root;
866 path_get(&nd->root); 865 path_get(&nd->root);
@@ -1143,7 +1142,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1143 1142
1144static int follow_dotdot_rcu(struct nameidata *nd) 1143static int follow_dotdot_rcu(struct nameidata *nd)
1145{ 1144{
1146 set_root_rcu(nd); 1145 if (!nd->root.mnt)
1146 set_root_rcu(nd);
1147 1147
1148 while (1) { 1148 while (1) {
1149 if (nd->path.dentry == nd->root.dentry && 1149 if (nd->path.dentry == nd->root.dentry &&
@@ -1256,7 +1256,8 @@ static void follow_mount(struct path *path)
1256 1256
1257static void follow_dotdot(struct nameidata *nd) 1257static void follow_dotdot(struct nameidata *nd)
1258{ 1258{
1259 set_root(nd); 1259 if (!nd->root.mnt)
1260 set_root(nd);
1260 1261
1261 while(1) { 1262 while(1) {
1262 struct dentry *old = nd->path.dentry; 1263 struct dentry *old = nd->path.dentry;
@@ -1852,7 +1853,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
1852 if (*name=='/') { 1853 if (*name=='/') {
1853 if (flags & LOOKUP_RCU) { 1854 if (flags & LOOKUP_RCU) {
1854 rcu_read_lock(); 1855 rcu_read_lock();
1855 set_root_rcu(nd); 1856 nd->seq = set_root_rcu(nd);
1856 } else { 1857 } else {
1857 set_root(nd); 1858 set_root(nd);
1858 path_get(&nd->root); 1859 path_get(&nd->root);