dcache.c: create helper function for duplicated functionality
This creates a helper function for he "try to ascend into the parent directory" case, which was written out in triplicate before. With all the locking and subtle sequence number stuff, we really don't want to duplicate that kind of code. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
76ca078328
commit
c826cb7dfc
1 changed files with 37 additions and 51 deletions
88
fs/dcache.c
88
fs/dcache.c
|
@ -1011,6 +1011,34 @@ void shrink_dcache_for_umount(struct super_block *sb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This tries to ascend one level of parenthood, but
|
||||||
|
* we can race with renaming, so we need to re-check
|
||||||
|
* the parenthood after dropping the lock and check
|
||||||
|
* that the sequence number still matches.
|
||||||
|
*/
|
||||||
|
static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
|
||||||
|
{
|
||||||
|
struct dentry *new = old->d_parent;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
spin_unlock(&old->d_lock);
|
||||||
|
spin_lock(&new->d_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* might go back up the wrong parent if we have had a rename
|
||||||
|
* or deletion
|
||||||
|
*/
|
||||||
|
if (new != old->d_parent ||
|
||||||
|
(!locked && read_seqretry(&rename_lock, seq))) {
|
||||||
|
spin_unlock(&new->d_lock);
|
||||||
|
new = NULL;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search for at least 1 mount point in the dentry's subdirs.
|
* Search for at least 1 mount point in the dentry's subdirs.
|
||||||
* We descend to the next level whenever the d_subdirs
|
* We descend to the next level whenever the d_subdirs
|
||||||
|
@ -1066,24 +1094,10 @@ resume:
|
||||||
* All done at this level ... ascend and resume the search.
|
* All done at this level ... ascend and resume the search.
|
||||||
*/
|
*/
|
||||||
if (this_parent != parent) {
|
if (this_parent != parent) {
|
||||||
struct dentry *tmp;
|
struct dentry *child = this_parent;
|
||||||
struct dentry *child;
|
this_parent = try_to_ascend(this_parent, locked, seq);
|
||||||
|
if (!this_parent)
|
||||||
tmp = this_parent->d_parent;
|
|
||||||
rcu_read_lock();
|
|
||||||
spin_unlock(&this_parent->d_lock);
|
|
||||||
child = this_parent;
|
|
||||||
this_parent = tmp;
|
|
||||||
spin_lock(&this_parent->d_lock);
|
|
||||||
/* might go back up the wrong parent if we have had a rename
|
|
||||||
* or deletion */
|
|
||||||
if (this_parent != child->d_parent ||
|
|
||||||
(!locked && read_seqretry(&rename_lock, seq))) {
|
|
||||||
spin_unlock(&this_parent->d_lock);
|
|
||||||
rcu_read_unlock();
|
|
||||||
goto rename_retry;
|
goto rename_retry;
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
next = child->d_u.d_child.next;
|
next = child->d_u.d_child.next;
|
||||||
goto resume;
|
goto resume;
|
||||||
}
|
}
|
||||||
|
@ -1181,24 +1195,10 @@ resume:
|
||||||
* All done at this level ... ascend and resume the search.
|
* All done at this level ... ascend and resume the search.
|
||||||
*/
|
*/
|
||||||
if (this_parent != parent) {
|
if (this_parent != parent) {
|
||||||
struct dentry *tmp;
|
struct dentry *child = this_parent;
|
||||||
struct dentry *child;
|
this_parent = try_to_ascend(this_parent, locked, seq);
|
||||||
|
if (!this_parent)
|
||||||
tmp = this_parent->d_parent;
|
|
||||||
rcu_read_lock();
|
|
||||||
spin_unlock(&this_parent->d_lock);
|
|
||||||
child = this_parent;
|
|
||||||
this_parent = tmp;
|
|
||||||
spin_lock(&this_parent->d_lock);
|
|
||||||
/* might go back up the wrong parent if we have had a rename
|
|
||||||
* or deletion */
|
|
||||||
if (this_parent != child->d_parent ||
|
|
||||||
(!locked && read_seqretry(&rename_lock, seq))) {
|
|
||||||
spin_unlock(&this_parent->d_lock);
|
|
||||||
rcu_read_unlock();
|
|
||||||
goto rename_retry;
|
goto rename_retry;
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
next = child->d_u.d_child.next;
|
next = child->d_u.d_child.next;
|
||||||
goto resume;
|
goto resume;
|
||||||
}
|
}
|
||||||
|
@ -2942,28 +2942,14 @@ resume:
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
if (this_parent != root) {
|
if (this_parent != root) {
|
||||||
struct dentry *tmp;
|
struct dentry *child = this_parent;
|
||||||
struct dentry *child;
|
|
||||||
|
|
||||||
tmp = this_parent->d_parent;
|
|
||||||
if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
|
if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
|
||||||
this_parent->d_flags |= DCACHE_GENOCIDE;
|
this_parent->d_flags |= DCACHE_GENOCIDE;
|
||||||
this_parent->d_count--;
|
this_parent->d_count--;
|
||||||
}
|
}
|
||||||
rcu_read_lock();
|
this_parent = try_to_ascend(this_parent, locked, seq);
|
||||||
spin_unlock(&this_parent->d_lock);
|
if (!this_parent)
|
||||||
child = this_parent;
|
|
||||||
this_parent = tmp;
|
|
||||||
spin_lock(&this_parent->d_lock);
|
|
||||||
/* might go back up the wrong parent if we have had a rename
|
|
||||||
* or deletion */
|
|
||||||
if (this_parent != child->d_parent ||
|
|
||||||
(!locked && read_seqretry(&rename_lock, seq))) {
|
|
||||||
spin_unlock(&this_parent->d_lock);
|
|
||||||
rcu_read_unlock();
|
|
||||||
goto rename_retry;
|
goto rename_retry;
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
next = child->d_u.d_child.next;
|
next = child->d_u.d_child.next;
|
||||||
goto resume;
|
goto resume;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue