Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7d6ef97 authored by Al Viro's avatar Al Viro
Browse files

fix idiotic braino in d_alloc_parallel()



Check for d_unhashed() while searching in in-lookup hash was absolutely
wrong.  Worse, it masked a deadlock on dget() done under bitlock that
nests inside ->d_lock.  Thanks to J. R. Okajima for spotting it.

Spotted-by: default avatar"J. R. Okajima" <hooanon05g@gmail.com>
Wearing-brown-paperbag: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ea01a184
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -2503,7 +2503,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
		rcu_read_unlock();
		goto retry;
	}
	rcu_read_unlock();
	/*
	 * No changes for the parent since the beginning of d_lookup().
	 * Since all removals from the chain happen with hlist_bl_lock(),
@@ -2516,8 +2515,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
			continue;
		if (dentry->d_parent != parent)
			continue;
		if (d_unhashed(dentry))
			continue;
		if (parent->d_flags & DCACHE_OP_COMPARE) {
			int tlen = dentry->d_name.len;
			const char *tname = dentry->d_name.name;
@@ -2529,9 +2526,18 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
			if (dentry_cmp(dentry, str, len))
				continue;
		}
		dget(dentry);
		hlist_bl_unlock(b);
		/* somebody is doing lookup for it right now; wait for it */
		/* now we can try to grab a reference */
		if (!lockref_get_not_dead(&dentry->d_lockref)) {
			rcu_read_unlock();
			goto retry;
		}

		rcu_read_unlock();
		/*
		 * somebody is likely to be still doing lookup for it;
		 * wait for them to finish
		 */
		spin_lock(&dentry->d_lock);
		d_wait_lookup(dentry);
		/*
@@ -2562,6 +2568,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
		dput(new);
		return dentry;
	}
	rcu_read_unlock();
	/* we can't take ->d_lock here; it's OK, though. */
	new->d_flags |= DCACHE_PAR_LOOKUP;
	new->d_wait = wq;