History

fs/namei.c: keep track of nd->root refcount status

The rules for nd->root are messy: * if we have LOOKUP_ROOT, it doesn't contribute to refcounts * if we have LOOKUP_RCU, it doesn't contribute to refcounts * if nd->root.mnt is NULL, it doesn't contribute to refcounts * otherwise it does contribute terminate_walk() needs to drop the references if they are contributing. So everything else should be careful not to confuse it, leading to rather convoluted code. It's easier to keep track of whether we'd grabbed the reference(s) explicitly. Use a new flag for that. Don't bother with zeroing nd->root.mnt on unlazy failures and in terminate_walk - it's not needed anymore (terminate_walk() won't care and the next path_init() will zero nd->root in !LOOKUP_ROOT case anyway). Resulting rules for nd->root refcounts are much simpler: they are contributing iff LOOKUP_ROOT_GRABBED is set in nd->flags.

Al Viro committed 7 years ago

Commit 84a2bd31 parent ee594bf2 files · +16 −26Browse files

Unified · Split

2 files
  1. fs/namei.c +15 −26
  2. include/linux/namei.h +1 −0
fs/namei.c+15−26
@@ -596,14 +596,12 @@ static void terminate_walk(struct nameidata *nd) · 595 unmodified lines
596596 path_put(&nd->path);
597597 for (i = 0; i < nd->depth; i++)
598598 path_put(&nd->stack[i].link);
599− if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
599+ if (nd->flags & LOOKUP_ROOT_GRABBED) {
600600 path_put(&nd->root);
601− nd->root.mnt = NULL;
601+ nd->flags &= ~LOOKUP_ROOT_GRABBED;
602602 }
603603 } else {
604604 nd->flags &= ~LOOKUP_RCU;
605− if (!(nd->flags & LOOKUP_ROOT))
606− nd->root.mnt = NULL;
607605 rcu_read_unlock();
608606 }
609607 nd->depth = 0;
@@ -645,6 +643,7 @@ static bool legitimize_root(struct nameidata *nd) · 35 unmodified lines
645643 {
646644 if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
647645 return true;
646+ nd->flags |= LOOKUP_ROOT_GRABBED;
648647 return legitimize_path(nd, &nd->root, nd->root_seq);
649648 }
650649
@@ -678,21 +677,18 @@ static int unlazy_walk(struct nameidata *nd) · 27 unmodified lines
678677
679678 nd->flags &= ~LOOKUP_RCU;
680679 if (unlikely(!legitimize_links(nd)))
681− goto out2;
682− if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
683680 goto out1;
681+ if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
682+ goto out;
684683 if (unlikely(!legitimize_root(nd)))
685684 goto out;
686685 rcu_read_unlock();
687686 BUG_ON(nd->inode != parent->d_inode);
688687 return 0;
689688
690−out2:
689+out1:
691690 nd->path.mnt = NULL;
692691 nd->path.dentry = NULL;
693−out1:
694− if (!(nd->flags & LOOKUP_ROOT))
695− nd->root.mnt = NULL;
696692 out:
697693 rcu_read_unlock();
698694 return -ECHILD;
@@ -732,21 +728,14 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se · 33 unmodified lines
732728 */
733729 if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))
734730 goto out;
735− if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) {
736− rcu_read_unlock();
737− dput(dentry);
738− goto drop_root_mnt;
739− }
731+ if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
732+ goto out_dput;
740733 /*
741734 * Sequence counts matched. Now make sure that the root is
742735 * still valid and get it if required.
743736 */
744− if (unlikely(!legitimize_root(nd))) {
745− rcu_read_unlock();
746− dput(dentry);
747− return -ECHILD;
748− }
749−
737+ if (unlikely(!legitimize_root(nd)))
738+ goto out_dput;
750739 rcu_read_unlock();
751740 return 0;
752741
@@ -756,9 +745,10 @@ out1: · 3 unmodified lines
756745 nd->path.dentry = NULL;
757746 out:
758747 rcu_read_unlock();
759−drop_root_mnt:
760− if (!(nd->flags & LOOKUP_ROOT))
761− nd->root.mnt = NULL;
748+ return -ECHILD;
749+out_dput:
750+ rcu_read_unlock();
751+ dput(dentry);
762752 return -ECHILD;
763753 }
764754
@@ -822,6 +812,7 @@ static void set_root(struct nameidata *nd) · 57 unmodified lines
822812 } while (read_seqcount_retry(&fs->seq, seq));
823813 } else {
824814 get_fs_root(fs, &nd->root);
815+ nd->flags |= LOOKUP_ROOT_GRABBED;
825816 }
826817 }
827818
@@ -1738,8 +1729,6 @@ static int pick_link(struct nameidata *nd, struct path *link, · 910 unmodified lines
17381729 nd->flags &= ~LOOKUP_RCU;
17391730 nd->path.mnt = NULL;
17401731 nd->path.dentry = NULL;
1741− if (!(nd->flags & LOOKUP_ROOT))
1742− nd->root.mnt = NULL;
17431732 rcu_read_unlock();
17441733 } else if (likely(unlazy_walk(nd)) == 0)
17451734 error = nd_alloc_stack(nd);
include/linux/namei.h+1−0
@@ -37,6 +37,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; · 36 unmodified lines
3737 #define LOOKUP_NO_REVAL 0x0080
3838 #define LOOKUP_JUMPED 0x1000
3939 #define LOOKUP_ROOT 0x2000
40+#define LOOKUP_ROOT_GRABBED 0x0008
4041
4142 extern int path_pts(struct path *path);
4243

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t