From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from fhigh-a5-smtp.messagingengine.com (fhigh-a5-smtp.messagingengine.com [103.168.172.156]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 59721258EC1; Mon, 27 Apr 2026 04:06:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.156 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777262786; cv=none; b=HgDIOKdgVQ+2ZB+RhHe2h8zhGx4G3hyIq+jijbDRkWCTKGGSC/g8eP5Tv2aaLazms5/4uKMOHrXN6/MfYHslKsr+ejdprJ7qKgWohlyPQMdkG/mJlwtunmCarqf8rX8RCxl0ouFqaLVXkH2XIy6/+Cm61WTjn24S5fjtEMcjqZg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777262786; c=relaxed/simple; bh=7PSFy+u24kcVfO16woP75mAbbdGt9GZMtu9sxyLPjrI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LC1iAymbYLzLce52a7IfzYLnOVEtlYjSw/QZa655/y2w7n3qHEYuxw2ePqnhROEwmSm167USCxerQ/FJmgx37erZ9veFlPR7qiRvlQ4E7AgMZge4n7D9iIccqtpBF98RBLcdr7XzCRkffI1OojNbwbXDp2tCY6NgxcXdOwL10Qo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ownmail.net; spf=pass smtp.mailfrom=ownmail.net; dkim=pass (2048-bit key) header.d=ownmail.net header.i=@ownmail.net header.b=holsSESn; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=i897OZXF; arc=none smtp.client-ip=103.168.172.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ownmail.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ownmail.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ownmail.net header.i=@ownmail.net header.b="holsSESn"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="i897OZXF" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id 9ECC51400046; Mon, 27 Apr 2026 00:06:24 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Mon, 27 Apr 2026 00:06:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ownmail.net; h= cc:cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:reply-to:subject:subject:to:to; s=fm2; t=1777262784; x=1777349184; bh=8lHsylfevHWLXpDXjo+WYhNqHlp+1vh5/Px2rcHI56c=; b= holsSESn4c1BE330f4Gqjb9IFnJNYkTUtusbN5lqK0XjlsA8rpQB6JrRxuE1+U6Z 6pj8CbsWgK9pZJw6Roqd82KMqcccUk13AVwB6JC5DX7MrNAFj6M1+bYHZf7eS5QN XmUy3AT3lSnOZpzaba20jHHRFwl9cI/ytqxqyIG0ctNiKBtKw0FFVxQGqQMGo6b3 DXspIOqgG7fJca5JdgF9C+gmuoYo7GdOJdBFSOvYQ8QnyWhKUMMj95Srywwd2hUU u1xh30tCNoZq7/CRLmL6xgyGL8QIWxamo+HZuHSCRnYa7HajbWoFUhFhcSZ/Lddo h966wKmbX5VgNhNiOuXFeg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm2; t=1777262784; x=1777349184; bh=8 lHsylfevHWLXpDXjo+WYhNqHlp+1vh5/Px2rcHI56c=; b=i897OZXFm+CR1E6WF 0wQ7Uz54x1zIVJYG/EN9eD/HvKh9RUJS3JxUw2f1UT1pQqMv9+/f7BpEniTWwKkS 8J7zBnFG7l6Y9kKQ7fv0OkYYmqHamy/T8BeYTBkA7bqns4XyZs4uXbrX9Ufv1Hur fjXHkfKguUTbHLm74BUunf1qqNwzNMsuDVizdhYec+LbSRN//alecTBUy0hlMUjQ tsHAVzhE64J6bLV0VW+m1os2HQi8abjh9KN4/OieCkEaAi3LPd4YdBBmZrWhPSw6 ixYigmuQZzQK0lLXEXnTuW1WQg+LzRMamys6iroQNJ3kfNilZBNh5xR/LGT+Yk78 WgT8w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdejjeeikecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeduiedpmhhouggvpehsmhhtphho uhhtpdhrtghpthhtohepvhhirhhoseiivghnihhvrdhlihhnuhigrdhorhhgrdhukhdprh gtphhtthhopehlihhnuhigqdhunhhiohhnfhhssehvghgvrhdrkhgvrhhnvghlrdhorhhg pdhrtghpthhtoheplhhinhhugidqnhhfshesvhhgvghrrdhkvghrnhgvlhdrohhrghdprh gtphhtthhopehlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdp rhgtphhtthhopehlihhnuhigqdhfshguvghvvghlsehvghgvrhdrkhgvrhhnvghlrdhorh hgpdhrtghpthhtoheplhhinhhugidqvghfihesvhhgvghrrdhkvghrnhgvlhdrohhrghdp rhgtphhtthhopehmihhklhhoshesshiivghrvgguihdrhhhupdhrtghpthhtohepjhgrtg hksehsuhhsvgdrtgiipdhrtghpthhtohepjhhksehoiihlrggsshdrohhrgh X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 27 Apr 2026 00:06:20 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Alexander Viro , Christian Brauner , Jan Kara , Jeff Layton , Trond Myklebust , Anna Schumaker , Miklos Szeredi , Amir Goldstein , Jeremy Kerr , Ard Biesheuvel Cc: linux-efi@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-unionfs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 05/19] VFS: introduce d_alloc_noblock() Date: Mon, 27 Apr 2026 14:01:23 +1000 Message-ID: <20260427040517.828226-6-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260427040517.828226-1-neilb@ownmail.net> References: <20260427040517.828226-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: NeilBrown Several filesystems use the results of readdir to prime the dcache. These filesystems use d_alloc_parallel() which can block if there is a concurrent lookup. Blocking in that case is pointless as the lookup will add info to the dcache and there is no value in the readdir waiting to see if it should add the info too. Also these calls to d_alloc_parallel() are made while the parent directory is locked. A proposed change to locking will lock the parent later, after d_alloc_parallel(). This means it won't be safe to wait in d_alloc_parallel() while holding the directory lock. So this patch introduces d_alloc_noblock() which doesn't block but instead returns ERR_PTR(-EWOULDBLOCK). Filesystems that prime the dcache (smb/client, nfs, fuse, cephfs) can now use that and ignore -EWOULDBLOCK errors as harmless. Unlike d_alloc_parallel(), d_alloc_noblock() calculates the hash and performs a lookup before an allocation, as that is what all callers want. Signed-off-by: NeilBrown --- fs/dcache.c | 91 +++++++++++++++++++++++++++++++++++++++--- include/linux/dcache.h | 1 + 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 2dcefa60db32..dc06e70695d2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" #include "mount.h" @@ -2672,8 +2673,16 @@ static inline bool d_must_wait(struct dentry *dentry) return true; } -struct dentry *d_alloc_parallel(struct dentry *parent, - const struct qstr *name) +/* What to do when __d_alloc_parallel finds a d_in_lookup dentry */ +enum alloc_para { + ALLOC_PARA_WAIT, + ALLOC_PARA_FAIL, +}; + +static inline +struct dentry *__d_alloc_parallel(struct dentry *parent, + const struct qstr *name, + enum alloc_para how) { unsigned int hash = name->hash; struct hlist_bl_head *b = in_lookup_hash(parent, hash); @@ -2755,9 +2764,20 @@ struct dentry *d_alloc_parallel(struct dentry *parent, * wait for them to finish */ spin_lock(&dentry->d_lock); - wait_var_event_spinlock(&dentry->d_flags, - !d_must_wait(dentry), - &dentry->d_lock); + if (d_in_lookup(dentry)) + switch (how) { + case ALLOC_PARA_FAIL: + spin_unlock(&dentry->d_lock); + dput(new); + dput(dentry); + return ERR_PTR(-EWOULDBLOCK); + case ALLOC_PARA_WAIT: + wait_var_event_spinlock(&dentry->d_flags, + !d_must_wait(dentry), + &dentry->d_lock); + /* ... and continue */ + } + /* * it's not in-lookup anymore; in principle we should repeat * everything from dcache lookup, but it's likely to be what @@ -2786,8 +2806,69 @@ struct dentry *d_alloc_parallel(struct dentry *parent, dput(dentry); goto retry; } + +/** + * d_alloc_parallel() - allocate a new dentry and ensure uniqueness + * @parent - dentry of the parent + * @name - name of the dentry within that parent. + * + * A new dentry is allocated and, providing it is unique, added to the + * relevant index. + * If an existing dentry is found with the same parent/name that is + * not d_in_lookup(), then that is returned instead. + * If the existing dentry is d_in_lookup(), d_alloc_parallel() waits for + * that lookup to complete before returning the dentry and then ensures the + * match is still valid. + * Thus if the returned dentry is d_in_lookup() then the caller has + * exclusive access until it completes the lookup. + * If the returned dentry is not d_in_lookup() then a lookup has + * already completed. + * + * The @name must already have ->hash set, as can be achieved + * by e.g. try_lookup_noperm(). + * + * Returns: the dentry, whether found or allocated, or an error %-ENOMEM. + */ +struct dentry *d_alloc_parallel(struct dentry *parent, + const struct qstr *name) +{ + return __d_alloc_parallel(parent, name, ALLOC_PARA_WAIT); +} EXPORT_SYMBOL(d_alloc_parallel); +/** + * d_alloc_noblock() - find or allocate a new dentry + * @parent - dentry of the parent + * @name - name of the dentry within that parent. + * + * A new dentry is allocated and, providing it is unique, added to the + * relevant index. + * If an existing dentry is found with the same parent/name that is + * not d_in_lookup() then that is returned instead. + * If the existing dentry is d_in_lookup(), d_alloc_noblock() + * returns with error %-EWOULDBLOCK. + * Thus if the returned dentry is d_in_lookup() then the caller has + * exclusive access until it completes the lookup. + * If the returned dentry is not d_in_lookup() then a lookup has + * already completed. + * + * The @name need not already have ->hash set. + * + * Returns: the dentry, whether found or allocated, or an error + * %-ENOMEM, %-EWOULDBLOCK, and anything returned by ->d_hash(). + */ +struct dentry *d_alloc_noblock(struct dentry *parent, + struct qstr *name) +{ + struct dentry *de; + + de = try_lookup_noperm(name, parent); + if (!de) + de = __d_alloc_parallel(parent, name, ALLOC_PARA_FAIL); + return de; +} +EXPORT_SYMBOL(d_alloc_noblock); + /* * - Unhash the dentry * - Retrieve and clear the waitqueue head in dentry diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 14b91a7d0bb6..85e8570cbd48 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -257,6 +257,7 @@ extern void d_delete(struct dentry *); extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc_anon(struct super_block *); extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *); +extern struct dentry * d_alloc_noblock(struct dentry *, struct qstr *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); /* weird procfs mess; *NOT* exported */ extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *, -- 2.50.0.107.gf914562f5916.dirty