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
596 path_put(&nd->path);596 path_put(&nd->path);
597 for (i = 0; i < nd->depth; i++)597 for (i = 0; i < nd->depth; i++)
598 path_put(&nd->stack[i].link);598 path_put(&nd->stack[i].link);
599 if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {599 if (nd->flags & LOOKUP_ROOT_GRABBED) {
600 path_put(&nd->root);600 path_put(&nd->root);
601 nd->root.mnt = NULL;601 nd->flags &= ~LOOKUP_ROOT_GRABBED;
602 }602 }
603 } else {603 } else {
604 nd->flags &= ~LOOKUP_RCU;604 nd->flags &= ~LOOKUP_RCU;
605 if (!(nd->flags & LOOKUP_ROOT))
606 nd->root.mnt = NULL;
607 rcu_read_unlock();605 rcu_read_unlock();
608 }606 }
609 nd->depth = 0;607 nd->depth = 0;
@@ -645,6 +643,7 @@ static bool legitimize_root(struct nameidata *nd) · 35 unmodified lines
645{643{
646 if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))644 if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
647 return true;645 return true;
646 nd->flags |= LOOKUP_ROOT_GRABBED;
648 return legitimize_path(nd, &nd->root, nd->root_seq);647 return legitimize_path(nd, &nd->root, nd->root_seq);
649}648}
650 649
@@ -678,21 +677,18 @@ static int unlazy_walk(struct nameidata *nd) · 27 unmodified lines
678 677
679 nd->flags &= ~LOOKUP_RCU;678 nd->flags &= ~LOOKUP_RCU;
680 if (unlikely(!legitimize_links(nd)))679 if (unlikely(!legitimize_links(nd)))
681 goto out2;
682 if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
683 goto out1;680 goto out1;
681 if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
682 goto out;
684 if (unlikely(!legitimize_root(nd)))683 if (unlikely(!legitimize_root(nd)))
685 goto out;684 goto out;
686 rcu_read_unlock();685 rcu_read_unlock();
687 BUG_ON(nd->inode != parent->d_inode);686 BUG_ON(nd->inode != parent->d_inode);
688 return 0;687 return 0;
689 688
690out2:689out1:
691 nd->path.mnt = NULL;690 nd->path.mnt = NULL;
692 nd->path.dentry = NULL;691 nd->path.dentry = NULL;
693out1:
694 if (!(nd->flags & LOOKUP_ROOT))
695 nd->root.mnt = NULL;
696out:692out:
697 rcu_read_unlock();693 rcu_read_unlock();
698 return -ECHILD;694 return -ECHILD;
@@ -732,21 +728,14 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se · 33 unmodified lines
732 */728 */
733 if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))729 if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))
734 goto out;730 goto out;
735 if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) {731 if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
736 rcu_read_unlock();732 goto out_dput;
737 dput(dentry);
738 goto drop_root_mnt;
739 }
740 /*733 /*
741 * Sequence counts matched. Now make sure that the root is734 * Sequence counts matched. Now make sure that the root is
742 * still valid and get it if required.735 * still valid and get it if required.
743 */736 */
744 if (unlikely(!legitimize_root(nd))) {737 if (unlikely(!legitimize_root(nd)))
745 rcu_read_unlock();738 goto out_dput;
746 dput(dentry);
747 return -ECHILD;
748 }
749
750 rcu_read_unlock();739 rcu_read_unlock();
751 return 0;740 return 0;
752 741
@@ -756,9 +745,10 @@ out1: · 3 unmodified lines
756 nd->path.dentry = NULL;745 nd->path.dentry = NULL;
757out:746out:
758 rcu_read_unlock();747 rcu_read_unlock();
759drop_root_mnt:748 return -ECHILD;
760 if (!(nd->flags & LOOKUP_ROOT))749out_dput:
761 nd->root.mnt = NULL;750 rcu_read_unlock();
751 dput(dentry);
762 return -ECHILD;752 return -ECHILD;
763}753}
764 754
@@ -822,6 +812,7 @@ static void set_root(struct nameidata *nd) · 57 unmodified lines
822 } while (read_seqcount_retry(&fs->seq, seq));812 } while (read_seqcount_retry(&fs->seq, seq));
823 } else {813 } else {
824 get_fs_root(fs, &nd->root);814 get_fs_root(fs, &nd->root);
815 nd->flags |= LOOKUP_ROOT_GRABBED;
825 }816 }
826}817}
827 818
@@ -1738,8 +1729,6 @@ static int pick_link(struct nameidata *nd, struct path *link, · 910 unmodified lines
1738 nd->flags &= ~LOOKUP_RCU;1729 nd->flags &= ~LOOKUP_RCU;
1739 nd->path.mnt = NULL;1730 nd->path.mnt = NULL;
1740 nd->path.dentry = NULL;1731 nd->path.dentry = NULL;
1741 if (!(nd->flags & LOOKUP_ROOT))
1742 nd->root.mnt = NULL;
1743 rcu_read_unlock();1732 rcu_read_unlock();
1744 } else if (likely(unlazy_walk(nd)) == 0)1733 } else if (likely(unlazy_walk(nd)) == 0)
1745 error = nd_alloc_stack(nd);1734 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
37#define LOOKUP_NO_REVAL 0x008037#define LOOKUP_NO_REVAL 0x0080
38#define LOOKUP_JUMPED 0x100038#define LOOKUP_JUMPED 0x1000
39#define LOOKUP_ROOT 0x200039#define LOOKUP_ROOT 0x2000
40#define LOOKUP_ROOT_GRABBED 0x0008
40 41
41extern int path_pts(struct path *path);42extern int path_pts(struct path *path);
42 43

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