Merge branch 'work.autofs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull autofs updates from Al Viro: "The most interesting part here is getting rid of the last trylock loop on dentry->d_lock. The ones in fs/dcache.c had been dealt with several years ago, but there'd been leftovers in fs/autofs/expire.c" * 'work.autofs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: autofs_lookup(): hold ->d_lock over playing with ->d_flags get rid of autofs_info->active_count autofs: simplify get_next_positive_...(), get rid of trylocks
This commit is contained in:
commit
8e6ee05d8a
|
@ -58,7 +58,6 @@ struct autofs_info {
|
|||
struct completion expire_complete;
|
||||
|
||||
struct list_head active;
|
||||
int active_count;
|
||||
|
||||
struct list_head expiring;
|
||||
|
||||
|
|
|
@ -70,6 +70,27 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
/* p->d_lock held */
|
||||
static struct dentry *positive_after(struct dentry *p, struct dentry *child)
|
||||
{
|
||||
if (child)
|
||||
child = list_next_entry(child, d_child);
|
||||
else
|
||||
child = list_first_entry(&p->d_subdirs, struct dentry, d_child);
|
||||
|
||||
list_for_each_entry_from(child, &p->d_subdirs, d_child) {
|
||||
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
if (simple_positive(child)) {
|
||||
dget_dlock(child);
|
||||
spin_unlock(&child->d_lock);
|
||||
return child;
|
||||
}
|
||||
spin_unlock(&child->d_lock);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate and dget next entry in the subdirs list under root.
|
||||
*/
|
||||
|
@ -77,43 +98,14 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
|
|||
struct dentry *root)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
|
||||
struct list_head *next;
|
||||
struct dentry *q;
|
||||
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
spin_lock(&root->d_lock);
|
||||
|
||||
if (prev)
|
||||
next = prev->d_child.next;
|
||||
else {
|
||||
prev = dget_dlock(root);
|
||||
next = prev->d_subdirs.next;
|
||||
}
|
||||
|
||||
cont:
|
||||
if (next == &root->d_subdirs) {
|
||||
spin_unlock(&root->d_lock);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
dput(prev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
q = list_entry(next, struct dentry, d_child);
|
||||
|
||||
spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
/* Already gone or negative dentry (under construction) - try next */
|
||||
if (!d_count(q) || !simple_positive(q)) {
|
||||
spin_unlock(&q->d_lock);
|
||||
next = q->d_child.next;
|
||||
goto cont;
|
||||
}
|
||||
dget_dlock(q);
|
||||
spin_unlock(&q->d_lock);
|
||||
q = positive_after(root, prev);
|
||||
spin_unlock(&root->d_lock);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
|
||||
dput(prev);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
@ -124,59 +116,28 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
|
|||
struct dentry *root)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
|
||||
struct list_head *next;
|
||||
struct dentry *p, *ret;
|
||||
struct dentry *p = prev, *ret = NULL, *d = NULL;
|
||||
|
||||
if (prev == NULL)
|
||||
return dget(root);
|
||||
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
relock:
|
||||
p = prev;
|
||||
spin_lock(&p->d_lock);
|
||||
again:
|
||||
next = p->d_subdirs.next;
|
||||
if (next == &p->d_subdirs) {
|
||||
while (1) {
|
||||
struct dentry *parent;
|
||||
while (1) {
|
||||
struct dentry *parent;
|
||||
|
||||
if (p == root) {
|
||||
spin_unlock(&p->d_lock);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
dput(prev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parent = p->d_parent;
|
||||
if (!spin_trylock(&parent->d_lock)) {
|
||||
spin_unlock(&p->d_lock);
|
||||
cpu_relax();
|
||||
goto relock;
|
||||
}
|
||||
spin_unlock(&p->d_lock);
|
||||
next = p->d_child.next;
|
||||
p = parent;
|
||||
if (next != &parent->d_subdirs)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = list_entry(next, struct dentry, d_child);
|
||||
|
||||
spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
/* Negative dentry - try next */
|
||||
if (!simple_positive(ret)) {
|
||||
ret = positive_after(p, d);
|
||||
if (ret || p == root)
|
||||
break;
|
||||
parent = p->d_parent;
|
||||
spin_unlock(&p->d_lock);
|
||||
lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_);
|
||||
p = ret;
|
||||
goto again;
|
||||
spin_lock(&parent->d_lock);
|
||||
d = p;
|
||||
p = parent;
|
||||
}
|
||||
dget_dlock(ret);
|
||||
spin_unlock(&ret->d_lock);
|
||||
spin_unlock(&p->d_lock);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
|
||||
dput(prev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,38 +60,15 @@ const struct dentry_operations autofs_dentry_operations = {
|
|||
.d_release = autofs_dentry_release,
|
||||
};
|
||||
|
||||
static void autofs_add_active(struct dentry *dentry)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
|
||||
struct autofs_info *ino;
|
||||
|
||||
ino = autofs_dentry_ino(dentry);
|
||||
if (ino) {
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
if (!ino->active_count) {
|
||||
if (list_empty(&ino->active))
|
||||
list_add(&ino->active, &sbi->active_list);
|
||||
}
|
||||
ino->active_count++;
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void autofs_del_active(struct dentry *dentry)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
|
||||
struct autofs_info *ino;
|
||||
|
||||
ino = autofs_dentry_ino(dentry);
|
||||
if (ino) {
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
ino->active_count--;
|
||||
if (!ino->active_count) {
|
||||
if (!list_empty(&ino->active))
|
||||
list_del_init(&ino->active);
|
||||
}
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
}
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
list_del_init(&ino->active);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
}
|
||||
|
||||
static int autofs_dir_open(struct inode *inode, struct file *file)
|
||||
|
@ -527,19 +504,22 @@ static struct dentry *autofs_lookup(struct inode *dir,
|
|||
if (!autofs_oz_mode(sbi) && !IS_ROOT(dentry->d_parent))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
/* Mark entries in the root as mount triggers */
|
||||
if (IS_ROOT(dentry->d_parent) &&
|
||||
autofs_type_indirect(sbi->type))
|
||||
__managed_dentry_set_managed(dentry);
|
||||
|
||||
ino = autofs_new_ino(sbi);
|
||||
if (!ino)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&sbi->lookup_lock);
|
||||
spin_lock(&dentry->d_lock);
|
||||
/* Mark entries in the root as mount triggers */
|
||||
if (IS_ROOT(dentry->d_parent) &&
|
||||
autofs_type_indirect(sbi->type))
|
||||
__managed_dentry_set_managed(dentry);
|
||||
dentry->d_fsdata = ino;
|
||||
ino->dentry = dentry;
|
||||
|
||||
autofs_add_active(dentry);
|
||||
list_add(&ino->active, &sbi->active_list);
|
||||
spin_unlock(&sbi->lookup_lock);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue