aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-09-09 15:22:25 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-09-09 15:22:25 -0400
commit48f5ec21d9c67e881ff35343988e290ef5cf933f (patch)
tree515af9f0288fbdee85f2ba1fdc2d20e088a1fb17 /fs/dcache.c
parent232d2d60aa5469bb097f55728f65146bd49c1d25 (diff)
split read_seqretry_or_unlock(), convert d_walk() to resulting primitives
Separate "check if we need to retry" from "unlock if we are done and had seq_writelock"; that allows to use these guys in d_walk(), where we need to recheck every time we ascend back to parent, but do *not* want to unlock until the very end. Lift rcu_read_lock/rcu_read_unlock out into callers. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c64
1 files changed, 31 insertions, 33 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 38b1b0989a16..b9caf47d5389 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -100,30 +100,21 @@ static struct kmem_cache *dentry_cache __read_mostly;
100 */ 100 */
101static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) 101static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq)
102{ 102{
103 if (!(*seq & 1)) { /* Even */ 103 if (!(*seq & 1)) /* Even */
104 *seq = read_seqbegin(lock); 104 *seq = read_seqbegin(lock);
105 rcu_read_lock(); 105 else /* Odd */
106 } else /* Odd */
107 write_seqlock(lock); 106 write_seqlock(lock);
108} 107}
109 108
110/** 109static inline int need_seqretry(seqlock_t *lock, int seq)
111 * read_seqretry_or_unlock - end a seqretry or lock block & return retry status
112 * lock : sequence lock
113 * seq : sequence number
114 * Return: 1 to retry operation again, 0 to continue
115 */
116static inline int read_seqretry_or_unlock(seqlock_t *lock, int *seq)
117{ 110{
118 if (!(*seq & 1)) { /* Even */ 111 return !(seq & 1) && read_seqretry(lock, seq);
119 rcu_read_unlock(); 112}
120 if (read_seqretry(lock, *seq)) { 113
121 (*seq)++; /* Take writer lock */ 114static inline void done_seqretry(seqlock_t *lock, int seq)
122 return 1; 115{
123 } 116 if (seq & 1)
124 } else /* Odd */
125 write_sequnlock(lock); 117 write_sequnlock(lock);
126 return 0;
127} 118}
128 119
129/* 120/*
@@ -1047,7 +1038,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
1047 * the parenthood after dropping the lock and check 1038 * the parenthood after dropping the lock and check
1048 * that the sequence number still matches. 1039 * that the sequence number still matches.
1049 */ 1040 */
1050static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) 1041static struct dentry *try_to_ascend(struct dentry *old, unsigned seq)
1051{ 1042{
1052 struct dentry *new = old->d_parent; 1043 struct dentry *new = old->d_parent;
1053 1044
@@ -1061,7 +1052,7 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq
1061 */ 1052 */
1062 if (new != old->d_parent || 1053 if (new != old->d_parent ||
1063 (old->d_flags & DCACHE_DENTRY_KILLED) || 1054 (old->d_flags & DCACHE_DENTRY_KILLED) ||
1064 (!locked && read_seqretry(&rename_lock, seq))) { 1055 need_seqretry(&rename_lock, seq)) {
1065 spin_unlock(&new->d_lock); 1056 spin_unlock(&new->d_lock);
1066 new = NULL; 1057 new = NULL;
1067 } 1058 }
@@ -1098,13 +1089,12 @@ static void d_walk(struct dentry *parent, void *data,
1098{ 1089{
1099 struct dentry *this_parent; 1090 struct dentry *this_parent;
1100 struct list_head *next; 1091 struct list_head *next;
1101 unsigned seq; 1092 unsigned seq = 0;
1102 int locked = 0;
1103 enum d_walk_ret ret; 1093 enum d_walk_ret ret;
1104 bool retry = true; 1094 bool retry = true;
1105 1095
1106 seq = read_seqbegin(&rename_lock);
1107again: 1096again:
1097 read_seqbegin_or_lock(&rename_lock, &seq);
1108 this_parent = parent; 1098 this_parent = parent;
1109 spin_lock(&this_parent->d_lock); 1099 spin_lock(&this_parent->d_lock);
1110 1100
@@ -1158,13 +1148,13 @@ resume:
1158 */ 1148 */
1159 if (this_parent != parent) { 1149 if (this_parent != parent) {
1160 struct dentry *child = this_parent; 1150 struct dentry *child = this_parent;
1161 this_parent = try_to_ascend(this_parent, locked, seq); 1151 this_parent = try_to_ascend(this_parent, seq);
1162 if (!this_parent) 1152 if (!this_parent)
1163 goto rename_retry; 1153 goto rename_retry;
1164 next = child->d_u.d_child.next; 1154 next = child->d_u.d_child.next;
1165 goto resume; 1155 goto resume;
1166 } 1156 }
1167 if (!locked && read_seqretry(&rename_lock, seq)) { 1157 if (need_seqretry(&rename_lock, seq)) {
1168 spin_unlock(&this_parent->d_lock); 1158 spin_unlock(&this_parent->d_lock);
1169 goto rename_retry; 1159 goto rename_retry;
1170 } 1160 }
@@ -1173,17 +1163,13 @@ resume:
1173 1163
1174out_unlock: 1164out_unlock:
1175 spin_unlock(&this_parent->d_lock); 1165 spin_unlock(&this_parent->d_lock);
1176 if (locked) 1166 done_seqretry(&rename_lock, seq);
1177 write_sequnlock(&rename_lock);
1178 return; 1167 return;
1179 1168
1180rename_retry: 1169rename_retry:
1181 if (!retry) 1170 if (!retry)
1182 return; 1171 return;
1183 if (locked) 1172 seq = 1;
1184 goto again;
1185 locked = 1;
1186 write_seqlock(&rename_lock);
1187 goto again; 1173 goto again;
1188} 1174}
1189 1175
@@ -2745,6 +2731,7 @@ static int prepend_path(const struct path *path,
2745 char *bptr; 2731 char *bptr;
2746 int blen; 2732 int blen;
2747 2733
2734 rcu_read_lock();
2748restart: 2735restart:
2749 bptr = *buffer; 2736 bptr = *buffer;
2750 blen = *buflen; 2737 blen = *buflen;
@@ -2783,8 +2770,13 @@ restart:
2783 2770
2784 dentry = parent; 2771 dentry = parent;
2785 } 2772 }
2786 if (read_seqretry_or_unlock(&rename_lock, &seq)) 2773 if (!(seq & 1))
2774 rcu_read_unlock();
2775 if (need_seqretry(&rename_lock, seq)) {
2776 seq = 1;
2787 goto restart; 2777 goto restart;
2778 }
2779 done_seqretry(&rename_lock, seq);
2788 2780
2789 if (error >= 0 && bptr == *buffer) { 2781 if (error >= 0 && bptr == *buffer) {
2790 if (--blen < 0) 2782 if (--blen < 0)
@@ -2957,6 +2949,7 @@ static char *__dentry_path(struct dentry *dentry, char *buf, int buflen)
2957 int len, seq = 0; 2949 int len, seq = 0;
2958 int error = 0; 2950 int error = 0;
2959 2951
2952 rcu_read_lock();
2960restart: 2953restart:
2961 end = buf + buflen; 2954 end = buf + buflen;
2962 len = buflen; 2955 len = buflen;
@@ -2979,8 +2972,13 @@ restart:
2979 retval = end; 2972 retval = end;
2980 dentry = parent; 2973 dentry = parent;
2981 } 2974 }
2982 if (read_seqretry_or_unlock(&rename_lock, &seq)) 2975 if (!(seq & 1))
2976 rcu_read_unlock();
2977 if (need_seqretry(&rename_lock, seq)) {
2978 seq = 1;
2983 goto restart; 2979 goto restart;
2980 }
2981 done_seqretry(&rename_lock, seq);
2984 if (error) 2982 if (error)
2985 goto Elong; 2983 goto Elong;
2986 return retval; 2984 return retval;