mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 11:10:44 +00:00
scoutfs: remove dentry invalidation relaxing
We walk the list of dentries in subdirs on lock invalidation. This can be a large number so we were trying to back off and give other tasks a chance to schedule and other processes a chance to grab the parent lock while we were iterating. The method for backing off saved our position in the list by getting a reference on a child dentry. It dropped that reference after resuming iteration. But it dropped the reference while holding the parent's lock. This is a deadlock if the put tries to finally remove the dentry because it's been unhashed. We saw this deadlock in practice, the crash dump showed us in the final dentry_kill with the parent locked. Let's just get rid of this premature optimization entirely. Both memory pressure and site logistics will tend to keep child lists in parents reasonably small. A CPU can burn through the locks and list entries for quite a few entries before anything will notice. We can revisit the hot spot later it if bubbles to the surface. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -173,16 +173,12 @@ static int put_task_ref(struct scoutfs_lock *lock, struct task_ref *ref)
|
||||
* active users that could modify the entries in the dcache (lookup,
|
||||
* create, rename, unlink). We have to make it through all the child
|
||||
* entries and remove them from the hash so that lookup can't find them.
|
||||
* They can still be disconnected in the cache or used as working
|
||||
* directories. A directory can have an enormous number of children so
|
||||
* we try to be break the lock if needed.
|
||||
*/
|
||||
static void invalidate_inode(struct super_block *sb, u64 ino)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *parent;
|
||||
struct dentry *child;
|
||||
struct dentry *saved;
|
||||
|
||||
inode = scoutfs_ilookup(sb, ino);
|
||||
if (!inode)
|
||||
@@ -192,32 +188,9 @@ static void invalidate_inode(struct super_block *sb, u64 ino)
|
||||
truncate_inode_pages(inode->i_mapping, 0);
|
||||
|
||||
if (S_ISDIR(inode->i_mode) && (parent = d_find_alias(inode))) {
|
||||
saved = NULL;
|
||||
restart:
|
||||
|
||||
spin_lock(&parent->d_lock);
|
||||
if (saved) {
|
||||
if (saved->d_parent != parent)
|
||||
child = NULL;
|
||||
else
|
||||
child = saved;
|
||||
dput(saved);
|
||||
} else {
|
||||
child = NULL;
|
||||
}
|
||||
|
||||
if (child == NULL)
|
||||
child = list_entry(parent->d_subdirs.next,
|
||||
struct dentry, d_u.d_child);
|
||||
|
||||
list_for_each_entry_from(child, &parent->d_subdirs,d_u.d_child){
|
||||
if (spin_needbreak(&parent->d_lock) || need_resched()) {
|
||||
saved = child;
|
||||
dget(saved);
|
||||
spin_unlock(&parent->d_lock);
|
||||
cond_resched();
|
||||
goto restart;
|
||||
}
|
||||
|
||||
list_for_each_entry(child, &parent->d_subdirs, d_u.d_child){
|
||||
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
__d_drop(child);
|
||||
spin_unlock(&child->d_lock);
|
||||
|
||||
Reference in New Issue
Block a user