mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-02 12:34:06 +00:00
lockless next_positive()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
4f42c1b5b9
commit
ebaaa80e8f
1 changed files with 27 additions and 5 deletions
32
fs/libfs.c
32
fs/libfs.c
|
@ -89,31 +89,53 @@ static struct dentry *next_positive(struct dentry *parent,
|
||||||
struct list_head *from,
|
struct list_head *from,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
struct dentry *res = NULL;
|
unsigned *seq = &parent->d_inode->i_dir_seq, n;
|
||||||
|
struct dentry *res;
|
||||||
struct list_head *p;
|
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) {
|
for (p = from->next; p != &parent->d_subdirs; p = p->next) {
|
||||||
struct dentry *d = list_entry(p, struct dentry, d_child);
|
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;
|
res = d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&parent->d_lock);
|
rcu_read_unlock();
|
||||||
|
if (skipped) {
|
||||||
|
smp_rmb();
|
||||||
|
if (unlikely(*seq != n))
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void move_cursor(struct dentry *cursor, struct list_head *after)
|
static void move_cursor(struct dentry *cursor, struct list_head *after)
|
||||||
{
|
{
|
||||||
struct dentry *parent = cursor->d_parent;
|
struct dentry *parent = cursor->d_parent;
|
||||||
|
unsigned n, *seq = &parent->d_inode->i_dir_seq;
|
||||||
spin_lock(&parent->d_lock);
|
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);
|
__list_del(cursor->d_child.prev, cursor->d_child.next);
|
||||||
if (after)
|
if (after)
|
||||||
list_add(&cursor->d_child, after);
|
list_add(&cursor->d_child, after);
|
||||||
else
|
else
|
||||||
list_add_tail(&cursor->d_child, &parent->d_subdirs);
|
list_add_tail(&cursor->d_child, &parent->d_subdirs);
|
||||||
|
smp_store_release(seq, n + 2);
|
||||||
spin_unlock(&parent->d_lock);
|
spin_unlock(&parent->d_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue