lockless next_positive()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
4f42c1b5b9
commit
ebaaa80e8f
32
fs/libfs.c
32
fs/libfs.c
|
@ -89,31 +89,53 @@ static struct dentry *next_positive(struct dentry *parent,
|
|||
struct list_head *from,
|
||||
int count)
|
||||
{
|
||||
struct dentry *res = NULL;
|
||||
unsigned *seq = &parent->d_inode->i_dir_seq, n;
|
||||
struct dentry *res;
|
||||
struct list_head *p;
|
||||
bool skipped;
|
||||
int i;
|
||||
|
||||
spin_lock(&parent->d_lock);
|
||||
retry:
|
||||
i = count;
|
||||
skipped = false;
|
||||
n = smp_load_acquire(seq) & ~1;
|
||||
res = NULL;
|
||||
rcu_read_lock();
|
||||
for (p = from->next; p != &parent->d_subdirs; p = p->next) {
|
||||
struct dentry *d = list_entry(p, struct dentry, d_child);
|
||||
if (simple_positive(d) && !--count) {
|
||||
if (!simple_positive(d)) {
|
||||
skipped = true;
|
||||
} else if (!--i) {
|
||||
res = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&parent->d_lock);
|
||||
rcu_read_unlock();
|
||||
if (skipped) {
|
||||
smp_rmb();
|
||||
if (unlikely(*seq != n))
|
||||
goto retry;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void move_cursor(struct dentry *cursor, struct list_head *after)
|
||||
{
|
||||
struct dentry *parent = cursor->d_parent;
|
||||
|
||||
unsigned n, *seq = &parent->d_inode->i_dir_seq;
|
||||
spin_lock(&parent->d_lock);
|
||||
for (;;) {
|
||||
n = *seq;
|
||||
if (!(n & 1) && cmpxchg(seq, n, n + 1) == n)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
__list_del(cursor->d_child.prev, cursor->d_child.next);
|
||||
if (after)
|
||||
list_add(&cursor->d_child, after);
|
||||
else
|
||||
list_add_tail(&cursor->d_child, &parent->d_subdirs);
|
||||
smp_store_release(seq, n + 2);
|
||||
spin_unlock(&parent->d_lock);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue