aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-06-06 20:55:34 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-06-20 17:11:29 -0400
commitebaaa80e8f20ff2cbbccd6823f73a99565487502 (patch)
tree6e0ba18f132e5b9699754e3db13571c3c6b7464d
parent4f42c1b5b9c27b6228e6b9c57eee4beb3118b6b0 (diff)
lockless next_positive()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/libfs.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index b05b74ae3f16..74dc8b9e7f53 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -89,31 +89,53 @@ static struct dentry *next_positive(struct dentry *parent,
89 struct list_head *from, 89 struct list_head *from,
90 int count) 90 int count)
91{ 91{
92 struct dentry *res = NULL; 92 unsigned *seq = &parent->d_inode->i_dir_seq, n;
93 struct dentry *res;
93 struct list_head *p; 94 struct list_head *p;
95 bool skipped;
96 int i;
94 97
95 spin_lock(&parent->d_lock); 98retry:
99 i = count;
100 skipped = false;
101 n = smp_load_acquire(seq) & ~1;
102 res = NULL;
103 rcu_read_lock();
96 for (p = from->next; p != &parent->d_subdirs; p = p->next) { 104 for (p = from->next; p != &parent->d_subdirs; p = p->next) {
97 struct dentry *d = list_entry(p, struct dentry, d_child); 105 struct dentry *d = list_entry(p, struct dentry, d_child);
98 if (simple_positive(d) && !--count) { 106 if (!simple_positive(d)) {
107 skipped = true;
108 } else if (!--i) {
99 res = d; 109 res = d;
100 break; 110 break;
101 } 111 }
102 } 112 }
103 spin_unlock(&parent->d_lock); 113 rcu_read_unlock();
114 if (skipped) {
115 smp_rmb();
116 if (unlikely(*seq != n))
117 goto retry;
118 }
104 return res; 119 return res;
105} 120}
106 121
107static void move_cursor(struct dentry *cursor, struct list_head *after) 122static void move_cursor(struct dentry *cursor, struct list_head *after)
108{ 123{
109 struct dentry *parent = cursor->d_parent; 124 struct dentry *parent = cursor->d_parent;
110 125 unsigned n, *seq = &parent->d_inode->i_dir_seq;
111 spin_lock(&parent->d_lock); 126 spin_lock(&parent->d_lock);
127 for (;;) {
128 n = *seq;
129 if (!(n & 1) && cmpxchg(seq, n, n + 1) == n)
130 break;
131 cpu_relax();
132 }
112 __list_del(cursor->d_child.prev, cursor->d_child.next); 133 __list_del(cursor->d_child.prev, cursor->d_child.next);
113 if (after) 134 if (after)
114 list_add(&cursor->d_child, after); 135 list_add(&cursor->d_child, after);
115 else 136 else
116 list_add_tail(&cursor->d_child, &parent->d_subdirs); 137 list_add_tail(&cursor->d_child, &parent->d_subdirs);
138 smp_store_release(seq, n + 2);
117 spin_unlock(&parent->d_lock); 139 spin_unlock(&parent->d_lock);
118} 140}
119 141