From nobody Tue Jun 16 18:31:26 2026 Received: from fout-b7-smtp.messagingengine.com (fout-b7-smtp.messagingengine.com [202.12.124.150]) (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 17ED833F8BC; Thu, 30 Apr 2026 03:09:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.150 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518558; cv=none; b=rDMrp7KpLBN9jhE+55MLMpr2mxs3jZbYuF6SZJ5SLloIzqayvXBI8Lx0ooH5NiSpK5egiM7AKyR6FBRoU/+QvwNMjsun+immezi+dtp3MAsSbn51DOT9KWXKjpg6cSwQUHYNCbUFazwUp8kvJ97372nGU014Yar8OoXo+EPUvtQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518558; c=relaxed/simple; bh=DELTMxF9kP8S3D0HUlogd9b5wHyCedqPjH1ZMIOOcJw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qSfCKTVKiI/Y22O5PNfSFl9qh7wYAGtwQ9QWSgi8oF7xuG6XIwbmhbMZSEoCOP1zRBqTYH0iYb1HDYzMQ9WEAkrM6zjQCmwqSD36Y0FBs4rdS1MMCAK+OosPP2Wak5WKrHw84/vPaQwsFXu3bflaLMRjdO923+54XOFztyX9Cr8= 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=mA9cLTcZ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=CKt9daO/; arc=none smtp.client-ip=202.12.124.150 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="mA9cLTcZ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="CKt9daO/" Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfout.stl.internal (Postfix) with ESMTP id DF81A1D00113; Wed, 29 Apr 2026 23:09:15 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-04.internal (MEProxy); Wed, 29 Apr 2026 23:09:16 -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=1777518555; x=1777604955; bh=/9kQHGI58tF58bk2NGiFwIvwHRvIsc6zHHG5MNu+tic=; b= mA9cLTcZJqFExX9klI457lYJdeqyEBK/E3wY20Xvh+IIkNIh+XC01umfK5+tEbSv nyV7d9ObIhzaaSyEoGISPa/1Oyk/ASrYaeCD2k807/FUWfm3wqepDNHpT2LCIf2N NWARDOIdUV/nAe2Tk21plhFDiD67Z6XZHtr/+Gfe1N2fsxcVIOp9s+lR9ymxHKUJ voOhbAILlZJU5iqAviBt5WFoX9Zkfurh5Q8k1/ZBzkGn8xaStxpMB8d52yeW7nsK vymhh5iKBZ6EvoRIMXBhmbEZcS9UHSis+u4rl02WPtRJywsu9IYMOBuT/jTFhvoM LlxR3bPdTtRZnOVdxwDEtg== 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=1777518555; x=1777604955; bh=/ 9kQHGI58tF58bk2NGiFwIvwHRvIsc6zHHG5MNu+tic=; b=CKt9daO/oWsYi7H40 ldtSbGFHNsvW0tJOCVW6o+DFf8Oa8TzfmSnoQhyGpYe2daFc4vWPool6pRemtvFJ GHnOiPJv5OoRTEHaafTXlGZplu0di041Sg7Yo4C3/FfLOqpqQPJpWZl3VsKLANAr yadrmz8KLXK1nnGdjHneF5QF9HJibEj5J37ghByaOuUvhxoXYg61t61D1ufhChFV JRRqkksgOixsndjSxmUT3/KE4tVJYH6dWcNjGGpn5BpQvCVTH/gzkxKEYDP5TDqw hQPG3EsNxl5bhIZVr5p+VKR19Nm5V5nbOpYJkUPoT4EaCewzCDYSArhLs00hrMnr zGSYQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:13 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 1/7] VFS: fix various typos in documentation for start_creating start_removing etc Date: Thu, 30 Apr 2026 11:56:54 +1000 Message-ID: <20260430020137.3305302-2-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown Various typos fixes. start_creating_dentry() now documented as *creating*, not *removing* the entry. Unwanted spaces in Documentation/filesystems/porting.rst removed. Signed-off-by: NeilBrown --- Documentation/filesystems/porting.rst | 8 +++---- fs/namei.c | 30 +++++++++++++-------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesyst= ems/porting.rst index fdf074429cd3..bfdff4608028 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1203,7 +1203,7 @@ will fail-safe. =20 --- =20 -** mandatory** +**mandatory** =20 lookup_one(), lookup_one_unlocked(), lookup_one_positive_unlocked() now take a qstr instead of a name and len. These, not the "one_len" @@ -1212,7 +1212,7 @@ that filesysmtem, through a mount point - which will = have a mnt_idmap. =20 --- =20 -** mandatory** +**mandatory** =20 Functions try_lookup_one_len(), lookup_one_len(), lookup_one_len_unlocked() and lookup_positive_unlocked() have been @@ -1229,7 +1229,7 @@ already been performed such as after vfs_path_parent_= lookup() =20 --- =20 -** mandatory** +**mandatory** =20 d_hash_and_lookup() is no longer exported or available outside the VFS. Use try_lookup_noperm() instead. This adds name validation and takes @@ -1371,7 +1371,7 @@ similar. =20 --- =20 -** mandatory** +**mandatory** =20 lock_rename(), lock_rename_child(), unlock_rename() are no longer available. Use start_renaming() or similar. diff --git a/fs/namei.c b/fs/namei.c index c7fac83c9a85..65e60536a6d1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2942,8 +2942,8 @@ struct dentry *start_dirop(struct dentry *parent, str= uct qstr *name, * end_dirop - signal completion of a dirop * @de: the dentry which was returned by start_dirop or similar. * - * If the de is an error, nothing happens. Otherwise any lock taken to - * protect the dentry is dropped and the dentry itself is release (dput()). + * If the @de is an error, nothing happens. Otherwise any lock taken to + * protect the dentry is dropped and the dentry itself is released (dput()= ). */ void end_dirop(struct dentry *de) { @@ -3260,7 +3260,7 @@ EXPORT_SYMBOL(lookup_one_unlocked); * the i_rwsem itself if necessary. If a fatal signal is pending or * delivered, it will return %-EINTR if the lock is needed. * - * Returns: A dentry, possibly negative, or + * Returns: A positive dentry, or * - same errors as lookup_one_unlocked() or * - ERR_PTR(-EINTR) if a fatal signal is pending. */ @@ -3382,7 +3382,7 @@ struct dentry *lookup_noperm_positive_unlocked(struct= qstr *name, EXPORT_SYMBOL(lookup_noperm_positive_unlocked); =20 /** - * start_creating - prepare to create a given name with permission checking + * start_creating - prepare to access or create a given name with permissi= on checking * @idmap: idmap of the mount * @parent: directory in which to prepare to create the name * @name: the name to be created @@ -3414,8 +3414,8 @@ EXPORT_SYMBOL(start_creating); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing - * an object from a directory. Permission checking (MAY_EXEC) is performed + * Locks are taken and a lookup is performed prior to removing an object + * from a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * * If the name doesn't exist, an error is returned. @@ -3441,7 +3441,7 @@ EXPORT_SYMBOL(start_removing); * @parent: directory in which to prepare to create the name * @name: the name to be created * - * Locks are taken and a lookup in performed prior to creating + * Locks are taken and a lookup is performed prior to creating * an object in a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * @@ -3470,7 +3470,7 @@ EXPORT_SYMBOL(start_creating_killable); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing + * Locks are taken and a lookup is performed prior to removing * an object from a directory. Permission checking (MAY_EXEC) is performed * against @idmap. * @@ -3500,7 +3500,7 @@ EXPORT_SYMBOL(start_removing_killable); * @parent: directory in which to prepare to create the name * @name: the name to be created * - * Locks are taken and a lookup in performed prior to creating + * Locks are taken and a lookup is performed prior to creating * an object in a directory. * * If the name already exists, a positive dentry is returned. @@ -3523,7 +3523,7 @@ EXPORT_SYMBOL(start_creating_noperm); * @parent: directory in which to find the name * @name: the name to be removed * - * Locks are taken and a lookup in performed prior to removing + * Locks are taken and a lookup is performed prior to removing * an object from a directory. * * If the name doesn't exist, an error is returned. @@ -3544,11 +3544,11 @@ struct dentry *start_removing_noperm(struct dentry = *parent, EXPORT_SYMBOL(start_removing_noperm); =20 /** - * start_creating_dentry - prepare to create a given dentry - * @parent: directory from which dentry should be removed - * @child: the dentry to be removed + * start_creating_dentry - prepare to access or create a given dentry + * @parent: directory of dentry + * @child: the dentry to be prepared * - * A lock is taken to protect the dentry again other dirops and + * A lock is taken to protect the dentry against other dirops and * the validity of the dentry is checked: correct parent and still hashed. * * If the dentry is valid and negative a reference is taken and @@ -3581,7 +3581,7 @@ EXPORT_SYMBOL(start_creating_dentry); * @parent: directory from which dentry should be removed * @child: the dentry to be removed * - * A lock is taken to protect the dentry again other dirops and + * A lock is taken to protect the dentry against other dirops and * the validity of the dentry is checked: correct parent and still hashed. * * If the dentry is valid and positive, a reference is taken and --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.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 7A17A33F8B7; Thu, 30 Apr 2026 03:09:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518564; cv=none; b=ENbOsYcaUxULk5vIT8VQ1b3iJlt+Q8urfE7rdVsNkaWKOi0InBFRLLhhF/dn8s3xpWtT2muX3c1emeh0uqRCk++YHAfUnKuSyBgYzTvPkK2kYw+ltUOFPDag14OszmBvvotWM953I43quQpoY40kr69jJSeYU8Ym19i4Il7Aaik= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518564; c=relaxed/simple; bh=jf6KAreEhzC9iKfr8qZxGb49Bp93yd84aSdVysagRTM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nRJeDTNDlc0rm7zsxTgR/zgpfOeASTA0MYmA0YYybrKhALPtAEe7csD1kF7FAYVq/71SyU6JqQEW82QQ5zTJsIQJttlBfjXXfiE7J9Rw1Q3QU8c+phjv0XSFIWG5A4yTfTmC+FxU8A28uBhBg+idg/OoCPkQRO1U8m/kHZ00cAU= 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=FYmUgT+O; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=btGk7LSk; arc=none smtp.client-ip=202.12.124.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="FYmUgT+O"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="btGk7LSk" Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id BFAD77A00EA; Wed, 29 Apr 2026 23:09:21 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Wed, 29 Apr 2026 23:09:21 -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=1777518561; x=1777604961; bh=+/kF3lV3RjcCVMTQn+tev9+a0eFeqoHqrap29/WwdPI=; b= FYmUgT+OcRLzzuZz99hKpjZiXngjMEiVI5Cnb+nVrMN2NCq6suKK15cf76VQMxaU X4Fdjd3zge9A/CNnCoKfzNawuOLVCoC23K+LynUSFK+V8L9dh/SC5nB56z0yQ8kS lVLroBUkfdPAGlI4WXV26MOnpZECqrbxH32Z5zKOfgS8UsTBXK3nPPjHn2iYu7M7 6cx3HSv1VwCEcNVh4E4DMX5Ag6Xn2hM0GUQXPAmYKFBItkxEPQ1NYyoaCxjUvHZT MrCHmQGDin/ZOc6wcZqVn7Kkfj709yrZDwtiY/VGewrWiJ1Zj2I26Au9Jb2ImelT D02te4NCqH/uayPaYiwhig== 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=1777518561; x=1777604961; bh=+ /kF3lV3RjcCVMTQn+tev9+a0eFeqoHqrap29/WwdPI=; b=btGk7LSkFiHU7JUIr jTILTwJxQRYR04fa5mUaLBD5hsh4H9tuUWlOkfO5rlEUrPFj4VURjEABh8msYZMz wqHYdJaD1qCpLCu7/cn3MyV4oOBP1A55UByZFB/r0LHkRK0UBzqyIMHXT2zGcJ97 yW6C7y19nlVkHRr8K/ZSNBgjbbWuCe89Qg/tFctVvWPuOiqdD2f009gHf/CCwKF/ vikwxRNUbWpoam68bhPLrwdEzTqKoYI8CRS8oTeViHED1t/QjbabnI/nwHBv10zk kYYtedvvObLlVZum3St/jnU2nFx4GeecDMJzp8uLjwrRbM1B0Zz4w/VEIJBIqK9p J1viw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:18 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 2/7] VFS: use wait_var_event for waiting in d_alloc_parallel() Date: Thu, 30 Apr 2026 11:56:55 +1000 Message-ID: <20260430020137.3305302-3-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown d_alloc_parallel() currently requires a wait_queue_head to be passed in. This must have a life time which extends until the lookup is completed. This makes it awkward to use and particularly make it hard to use in lookup_one_qstr_excl() which I hope to do in the future. This patch changes d_alloc_parallel() to use wake_up_var_locked() to wake up waiters, and wait_var_event_spinlock() to wait. dentry->d_lock is used for synchronisation as it is already held and the relevant times. In most cases there will be no waiters so the wake_up_var_locked() call (which can walk an arbitrarily long list) would be a complete waste. To optimise this a new ->d_flags flag is added: DCACHE_LOOKUP_WAITER. This is set whenever any thread prepares to wait for the dentry, and if it isn't set when DCACHE_PAR_LOOKUP is cleared, no wakeup is sent. DCACHE_LOOKUP_WAITER is cleared after the wakeup is set. __d_lookup_unhash() no longer returns a wq. Callers check DCACHE_LOOKUP_WAITER to check if a wakeup is needed, and wake_up_var_locked() can find the wq. __d_lookup_unhash() no longer needs to re-init ->d_lru. That was previously shared (in a union) with ->d_wait but ->d_wait is now gone so it no longer corrupts ->d_lru. Wakeup is move out of end_dir_add() as it is conceptually a separate action. Co-developed-by: Al Viro Signed-off-by: Al Viro Signed-off-by: NeilBrown --- Documentation/filesystems/porting.rst | 6 ++ fs/afs/dir_silly.c | 4 +- fs/dcache.c | 83 +++++++++++++++------------ fs/fuse/readdir.c | 3 +- fs/namei.c | 6 +- fs/nfs/dir.c | 6 +- fs/nfs/unlink.c | 3 +- fs/proc/base.c | 3 +- fs/proc/proc_sysctl.c | 3 +- fs/smb/client/readdir.c | 3 +- include/linux/dcache.h | 11 ++-- include/linux/nfs_xdr.h | 1 - 12 files changed, 67 insertions(+), 65 deletions(-) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesyst= ems/porting.rst index bfdff4608028..5cc6ae19845c 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1385,3 +1385,9 @@ for_each_alias(dentry, inode) instead of hlist_for_ea= ch_entry; better yet, see if any of the exported primitives could be used instead of the entire loop. You still need to hold ->i_lock of the inode over either form of manual loop. + +--- + +**mandatory** + +d_alloc_parallel() no longer requires a waitqueue_head. diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c index a748fd133faf..982bb6ec15f0 100644 --- a/fs/afs/dir_silly.c +++ b/fs/afs/dir_silly.c @@ -248,13 +248,11 @@ int afs_silly_iput(struct dentry *dentry, struct inod= e *inode) struct dentry *alias; int ret; =20 - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode); =20 down_read(&dvnode->rmdir_lock); =20 - alias =3D d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq); + alias =3D d_alloc_parallel(dentry->d_parent, &dentry->d_name); if (IS_ERR(alias)) { up_read(&dvnode->rmdir_lock); return 0; diff --git a/fs/dcache.c b/fs/dcache.c index 2c61aeea41f4..1a065df22ecd 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2250,8 +2250,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct= inode *inode, return found; } if (d_in_lookup(dentry)) { - found =3D d_alloc_parallel(dentry->d_parent, name, - dentry->d_wait); + found =3D d_alloc_parallel(dentry->d_parent, name); if (IS_ERR(found) || !d_in_lookup(found)) { iput(inode); return found; @@ -2638,32 +2637,24 @@ static inline unsigned start_dir_add(struct inode *= dir) } } =20 -static inline void end_dir_add(struct inode *dir, unsigned int n, - wait_queue_head_t *d_wait) +static inline void end_dir_add(struct inode *dir, unsigned int n) { smp_store_release(&dir->i_dir_seq, n + 2); preempt_enable_nested(); - if (wq_has_sleeper(d_wait)) - wake_up_all(d_wait); } =20 static void d_wait_lookup(struct dentry *dentry) { - if (d_in_lookup(dentry)) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(dentry->d_wait, &wait); - do { - set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock(&dentry->d_lock); - schedule(); - spin_lock(&dentry->d_lock); - } while (d_in_lookup(dentry)); + if (likely(d_in_lookup(dentry))) { + dentry->d_flags |=3D DCACHE_LOOKUP_WAITERS; + wait_var_event_spinlock(&dentry->d_flags, + !d_in_lookup(dentry), + &dentry->d_lock); } } =20 struct dentry *d_alloc_parallel(struct dentry *parent, - const struct qstr *name, - wait_queue_head_t *wq) + const struct qstr *name) { unsigned int hash =3D name->hash; struct hlist_bl_head *b =3D in_lookup_hash(parent, hash); @@ -2766,7 +2757,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent, return dentry; } rcu_read_unlock(); - new->d_wait =3D wq; hlist_bl_add_head(&new->d_in_lookup_hash, b); hlist_bl_unlock(b); return new; @@ -2778,13 +2768,26 @@ struct dentry *d_alloc_parallel(struct dentry *pare= nt, EXPORT_SYMBOL(d_alloc_parallel); =20 /* - * - Unhash the dentry - * - Retrieve and clear the waitqueue head in dentry - * - Return the waitqueue head + * Move dentry from in-lookup state to busy-negative one. + * + * From now on d_in_lookup(dentry) will return false and dentry is gone fr= om + * in-lookup hash. + * + * Anyone who had been waiting on it in d_alloc_parallel() is free to + * proceed after that. Note that waking such waiters up is left to + * the callers; PREEMPT_RT kernels can't have that wakeup done while + * in write-side critical area for ->i_dir_seq, so it's done by calling + * __d_wake_in_lookup_waiters() once it's safe to do so. + * + * Both __d_lookup_unhash() and __d_wake_in_lookup_waiters() should + * be called within the same ->d_lock scope. PAR_LOOKUP is cleared + * here, while LOOKUP_WAITERS (set by somebody finding dentry in + * the in-lookup hash and setting down to wait) is checked and cleared + * in __d_wake_in_lookup_waiters(). Both are gone by the end of + * ->d_lock scope. */ -static wait_queue_head_t *__d_lookup_unhash(struct dentry *dentry) +static void __d_lookup_unhash(struct dentry *dentry) { - wait_queue_head_t *d_wait; struct hlist_bl_head *b; =20 lockdep_assert_held(&dentry->d_lock); @@ -2793,18 +2796,23 @@ static wait_queue_head_t *__d_lookup_unhash(struct = dentry *dentry) hlist_bl_lock(b); dentry->d_flags &=3D ~DCACHE_PAR_LOOKUP; __hlist_bl_del(&dentry->d_in_lookup_hash); - d_wait =3D dentry->d_wait; - dentry->d_wait =3D NULL; hlist_bl_unlock(b); dentry->waiters =3D NULL; - INIT_LIST_HEAD(&dentry->d_lru); - return d_wait; +} + +static inline void __d_wake_in_lookup_waiters(struct dentry *dentry) +{ + if (dentry->d_flags & DCACHE_LOOKUP_WAITERS) { + wake_up_var_locked(&dentry->d_flags, &dentry->d_lock); + dentry->d_flags &=3D ~DCACHE_LOOKUP_WAITERS; + } } =20 void __d_lookup_unhash_wake(struct dentry *dentry) { spin_lock(&dentry->d_lock); - wake_up_all(__d_lookup_unhash(dentry)); + __d_lookup_unhash(dentry); + __d_wake_in_lookup_waiters(dentry); spin_unlock(&dentry->d_lock); } EXPORT_SYMBOL(__d_lookup_unhash_wake); @@ -2814,14 +2822,13 @@ EXPORT_SYMBOL(__d_lookup_unhash_wake); static inline void __d_add(struct dentry *dentry, struct inode *inode, const struct dentry_operations *ops) { - wait_queue_head_t *d_wait; struct inode *dir =3D NULL; unsigned n; spin_lock(&dentry->d_lock); if (unlikely(d_in_lookup(dentry))) { dir =3D dentry->d_parent->d_inode; n =3D start_dir_add(dir); - d_wait =3D __d_lookup_unhash(dentry); + __d_lookup_unhash(dentry); } if (unlikely(ops)) d_set_d_op(dentry, ops); @@ -2834,8 +2841,10 @@ static inline void __d_add(struct dentry *dentry, st= ruct inode *inode, fsnotify_update_flags(dentry); } __d_rehash(dentry); - if (dir) - end_dir_add(dir, n, d_wait); + if (dir) { + end_dir_add(dir, n); + __d_wake_in_lookup_waiters(dentry); + } spin_unlock(&dentry->d_lock); if (inode) spin_unlock(&inode->i_lock); @@ -2948,7 +2957,6 @@ static void __d_move(struct dentry *dentry, struct de= ntry *target, bool exchange) { struct dentry *old_parent, *p; - wait_queue_head_t *d_wait; struct inode *dir =3D NULL; unsigned n; =20 @@ -2979,7 +2987,7 @@ static void __d_move(struct dentry *dentry, struct de= ntry *target, if (unlikely(d_in_lookup(target))) { dir =3D target->d_parent->d_inode; n =3D start_dir_add(dir); - d_wait =3D __d_lookup_unhash(target); + __d_lookup_unhash(target); } =20 write_seqcount_begin(&dentry->d_seq); @@ -3018,9 +3026,10 @@ static void __d_move(struct dentry *dentry, struct d= entry *target, write_seqcount_end(&target->d_seq); write_seqcount_end(&dentry->d_seq); =20 - if (dir) - end_dir_add(dir, n, d_wait); - + if (dir) { + end_dir_add(dir, n); + __d_wake_in_lookup_waiters(dentry); + } if (dentry->d_parent !=3D old_parent) spin_unlock(&dentry->d_parent->d_lock); if (dentry !=3D old_parent) diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index db5ae8ec1030..a2361f1d9905 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -164,7 +164,6 @@ static int fuse_direntplus_link(struct file *file, struct inode *dir =3D d_inode(parent); struct fuse_conn *fc; struct inode *inode; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); int epoch; =20 if (!o->nodeid) { @@ -201,7 +200,7 @@ static int fuse_direntplus_link(struct file *file, dentry =3D d_lookup(parent, &name); if (!dentry) { retry: - dentry =3D d_alloc_parallel(parent, &name, &wq); + dentry =3D d_alloc_parallel(parent, &name); if (IS_ERR(dentry)) return PTR_ERR(dentry); } diff --git a/fs/namei.c b/fs/namei.c index 65e60536a6d1..a6349b31fdb6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1891,13 +1891,12 @@ static struct dentry *__lookup_slow(const struct qs= tr *name, { struct dentry *dentry, *old; struct inode *inode =3D dir->d_inode; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); =20 /* Don't go there if it's already dead */ if (unlikely(IS_DEADDIR(inode))) return ERR_PTR(-ENOENT); again: - dentry =3D d_alloc_parallel(dir, name, &wq); + dentry =3D d_alloc_parallel(dir, name); if (IS_ERR(dentry)) return dentry; if (unlikely(!d_in_lookup(dentry))) { @@ -4414,7 +4413,6 @@ static struct dentry *lookup_open(struct nameidata *n= d, struct file *file, struct dentry *dentry; int error, create_error =3D 0; umode_t mode =3D op->mode; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); =20 if (unlikely(IS_DEADDIR(dir_inode))) return ERR_PTR(-ENOENT); @@ -4423,7 +4421,7 @@ static struct dentry *lookup_open(struct nameidata *n= d, struct file *file, dentry =3D d_lookup(dir, &nd->last); for (;;) { if (!dentry) { - dentry =3D d_alloc_parallel(dir, &nd->last, &wq); + dentry =3D d_alloc_parallel(dir, &nd->last); if (IS_ERR(dentry)) return dentry; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e9ce1883288c..9580af999d70 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -726,7 +726,6 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs= _entry *entry, unsigned long dir_verifier) { struct qstr filename =3D QSTR_INIT(entry->name, entry->len); - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct dentry *dentry; struct dentry *alias; struct inode *inode; @@ -755,7 +754,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs= _entry *entry, dentry =3D d_lookup(parent, &filename); again: if (!dentry) { - dentry =3D d_alloc_parallel(parent, &filename, &wq); + dentry =3D d_alloc_parallel(parent, &filename); if (IS_ERR(dentry)) return; } @@ -2106,7 +2105,6 @@ int nfs_atomic_open(struct inode *dir, struct dentry = *dentry, struct file *file, unsigned open_flags, umode_t mode) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct nfs_open_context *ctx; struct dentry *res; struct iattr attr =3D { .ia_valid =3D ATTR_OPEN }; @@ -2162,7 +2160,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry = *dentry, d_drop(dentry); switched =3D true; dentry =3D d_alloc_parallel(dentry->d_parent, - &dentry->d_name, &wq); + &dentry->d_name); if (IS_ERR(dentry)) return PTR_ERR(dentry); if (unlikely(!d_in_lookup(dentry))) diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index df3ca4669df6..43ea897943c0 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -124,7 +124,7 @@ static int nfs_call_unlink(struct dentry *dentry, struc= t inode *inode, struct nf struct dentry *alias; =20 down_read_non_owner(&NFS_I(dir)->rmdir_sem); - alias =3D d_alloc_parallel(dentry->d_parent, &data->args.name, &data->wq); + alias =3D d_alloc_parallel(dentry->d_parent, &data->args.name); if (IS_ERR(alias)) { up_read_non_owner(&NFS_I(dir)->rmdir_sem); return 0; @@ -185,7 +185,6 @@ nfs_async_unlink(struct dentry *dentry, const struct qs= tr *name) =20 data->cred =3D get_current_cred(); data->res.dir_attr =3D &data->dir_attr; - init_waitqueue_head(&data->wq); =20 status =3D -EBUSY; spin_lock(&dentry->d_lock); diff --git a/fs/proc/base.c b/fs/proc/base.c index d9acfa89c894..d55a4b603188 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2132,8 +2132,7 @@ bool proc_fill_cache(struct file *file, struct dir_co= ntext *ctx, goto end_instantiate; =20 if (!child) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - child =3D d_alloc_parallel(dir, &qname, &wq); + child =3D d_alloc_parallel(dir, &qname); if (IS_ERR(child)) goto end_instantiate; if (d_in_lookup(child)) { diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 49ab74e0bfde..04a382178c65 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -692,8 +692,7 @@ static bool proc_sys_fill_cache(struct file *file, =20 child =3D d_lookup(dir, &qname); if (!child) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - child =3D d_alloc_parallel(dir, &qname, &wq); + child =3D d_alloc_parallel(dir, &qname); if (IS_ERR(child)) return false; if (d_in_lookup(child)) { diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index be22bbc4a65a..a8995261831c 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -73,7 +73,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *nam= e, struct cifs_sb_info *cifs_sb =3D CIFS_SB(sb); bool posix =3D cifs_sb_master_tcon(cifs_sb)->posix_extensions; bool reparse_need_reval =3D false; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); int rc; =20 cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); @@ -105,7 +104,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *n= ame, (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)) return; =20 - dentry =3D d_alloc_parallel(parent, name, &wq); + dentry =3D d_alloc_parallel(parent, name); } if (IS_ERR(dentry)) return; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 2577c05f84ec..97a887be150a 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -116,10 +116,7 @@ struct dentry { * possible! */ =20 - union { - struct list_head d_lru; /* LRU list */ - wait_queue_head_t *d_wait; /* in-lookup ones only */ - }; + struct list_head d_lru; /* LRU list */ struct hlist_node d_sib; /* child of parent list */ struct hlist_head d_children; /* our children */ /* @@ -210,6 +207,9 @@ enum dentry_flags { DCACHE_REFERENCED =3D BIT(6), /* Recently used, don't discard. */ DCACHE_DONTCACHE =3D BIT(7), /* Purge from memory on final dput() */ DCACHE_CANT_MOUNT =3D BIT(8), + DCACHE_LOOKUP_WAITERS =3D BIT(9), /* A thread is waiting for + * PAR_LOOKUP to clear + */ DCACHE_SHRINK_LIST =3D BIT(10), DCACHE_OP_WEAK_REVALIDATE =3D BIT(11), /* @@ -256,8 +256,7 @@ extern void d_delete(struct dentry *); /* allocate/de-allocate */ 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= *, - wait_queue_head_t *); +extern struct dentry * d_alloc_parallel(struct dentry *, const 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 *, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index fcbd21b5685f..6aced49d5f00 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1743,7 +1743,6 @@ struct nfs_unlinkdata { struct nfs_removeargs args; struct nfs_removeres res; struct dentry *dentry; - wait_queue_head_t wq; const struct cred *cred; struct nfs_fattr dir_attr; long timeout; --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.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 B2ED93431F2; Thu, 30 Apr 2026 03:09:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518569; cv=none; b=Vj+rdZ7WPgPf+kTMNk67uUN887YqtCfYwDwao1jRFpJpmxPQtN65poQ8A7GoZUFWIe0fq51ZyjK4JhWu7WppuJ/hLuP1uD1Wdnhn/1342h/EZ+Fdnc6Dwpfy2wEATWalluw5NgmqYViPh+Q7PoJ1FrDnWiWpZYAbtt2OLgAK+Ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518569; c=relaxed/simple; bh=5mBhhdWXfdaAZ07YKnPOt9GDUV+dFOUGUrrpEQj+IH8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=l57NqjwnqH8pJM4+xNYWeyjG7xC8wsO4zZuopTZLgDDjmO1ETez6OI876eo/3BerPU2KuNnJkOBu9mx+hbmv5LVYaDbfkkoji8ibcfr8Su4u5T3CKWztnZ65yfapY/yNLsU2vJcAPHUwe8uq/8cICXfXz20nIrUx0341iKMeul0= 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=CsREaFYr; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=vgkM2n3+; arc=none smtp.client-ip=202.12.124.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="CsREaFYr"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="vgkM2n3+" Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfhigh.stl.internal (Postfix) with ESMTP id ECA3E7A00EA; Wed, 29 Apr 2026 23:09:26 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Wed, 29 Apr 2026 23:09:27 -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=1777518566; x=1777604966; bh=o0VDMq63HKComdkN2neiDrUWUFgUELHBmVs/SqfLOjc=; b= CsREaFYrHvwKXb/dFGYAiGE7kmce7C5j6kWxFlszcFdtontDRTCY8qe/PFlNryTF /n/CuELwbu0h0+oODm3MFOoi/OV9JXTnvvh4B1/LryqMgH9jSokErgjXr7P1fYzU PGk3NpKXpUzgc6QEZmyIJYSqDuaal8p2hfYEmcBmPBdq1IRzLnvyFGQbCKv2pygg CJA26DGnqrUTEVA7Z0PduyWdtMRBI3fyYZX2MXC2AB+cDPwfLlrVjrxdHiCYeV+y WYHIws8I8zCtGydS1nhGgEFYiok8VwduVwJ7gV6EzT2dwvFHjLcOtkdyAFkrOJeY lUuv0wmHUxxIDOjqfZeAaA== 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=1777518566; x=1777604966; bh=o 0VDMq63HKComdkN2neiDrUWUFgUELHBmVs/SqfLOjc=; b=vgkM2n3+3vpZFFJVk JTXjuC+PDfWMgD9LZxbDQF2GR2Dpt1+qK9CXLl9TXxpRFdKg74Z/J7IIfjaw9U0H QcZU4Pq0vKBXZCz8P2zWJKOBGOgk1Q+sJnEuDB4h8Um9nFmoWutAuWhmoO/5S2Oa lftmKDBtSXZjIwwnyCGvDEge6d6P7rvYXxhXZX1RIio61DPpxyd9T4DzV287qd51 rRAq3uKAIPYMJlWYgrKI7/iTkilr+tqm24PjcwpSy3HhBhfJmKSuyzxNNWZr0hsO ISS+Ox81aDS+n+JT6aXZmCm71IX8LCUmO2fmHjPbetOWrObiJScvo6r68+VkiltJ JHJ1A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:24 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 3/7] VFS: enhance d_splice_alias() to handle in-lookup dentries Date: Thu, 30 Apr 2026 11:56:56 +1000 Message-ID: <20260430020137.3305302-4-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown We currently have three interfaces for attaching existing inodes to normal filesystems(*). - d_add() requires an unhashed or in-lookup dentry and doesn't handle splicing in case a directory already has dentry - d_instantiate() requires a hashed dentry, and also doesn't handle splicing. - d_splice_alias() requires unhashed or in-lookup and does handle splicing, and can return an alternate dentry. So there is no interface that supports both hashed and in-lookup, which is what ->atomic_open needs to deal with. Some filesystems check for in-lookup in their atomic_open and if found, perform a ->lookup and can subsequently use d_instantiate() if the dentry is still negative. Others d_drop() the dentry so they can use d_splice_alias(). This last will cause a problem for proposed changes to locking which require the dentry to remain hashed while and operation proceeds on it. There is also no interface which splices a directory (which might already have a dentry) to a hashed dentry. Filesystems which need to do this d_drop() first. Some filesystemss (NFS) skip ->lookup processing for LOOKUP_CREATE|LOOKUP_EXCL which includes mknod, link, symlink etc. So these inode operations might get an unhashed or a hashed-negative dentry. There is no interface for instantiating these so again they need to unhash first (nfs_link) So with this patch d_splice_alias() can handle hashed, unhashed, or in-lookup dentries. This makes it suitable for ->lookup, ->atomic_open, and ->mkdir and others. As a side effect d_add() will also now handle hashed dentries, but I have plans to remove d_add() as there is no benefit having it as well as the others. __d_add() currently contains code that is identical to __d_instantiate(), so the former is changed to call the later, and both d_add() and d_instantiate() call __d_add(). * There is also d_make_persistent() for filesystems which are dcache-based and don't support mkdir, create etc, and d_instantiate_new() for newly created inodes that are still locked. Signed-off-by: NeilBrown --- Documentation/filesystems/vfs.rst | 4 ++-- fs/dcache.c | 31 ++++++++++++------------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/= vfs.rst index 7c753148af88..d8df0a84cdba 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -507,8 +507,8 @@ otherwise noted. dentry before the first mkdir returns. =20 If there is any chance this could happen, then the new inode - should be d_drop()ed and attached with d_splice_alias(). The - returned dentry (if any) should be returned by ->mkdir(). + should be attached with d_splice_alias(). The returned + dentry (if any) should be returned by ->mkdir(). =20 ``rmdir`` called by the rmdir(2) system call. Only required if you want diff --git a/fs/dcache.c b/fs/dcache.c index 1a065df22ecd..a4ee380f3dfc 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2068,7 +2068,6 @@ static void __d_instantiate(struct dentry *dentry, st= ruct inode *inode) * (or otherwise set) by the caller to indicate that it is now * in use by the dcache. */ -=20 void d_instantiate(struct dentry *entry, struct inode * inode) { BUG_ON(d_really_is_positive(entry)); @@ -2829,18 +2828,14 @@ static inline void __d_add(struct dentry *dentry, s= truct inode *inode, dir =3D dentry->d_parent->d_inode; n =3D start_dir_add(dir); __d_lookup_unhash(dentry); + __d_rehash(dentry); + } else if (d_unhashed(dentry)) { + __d_rehash(dentry); } if (unlikely(ops)) d_set_d_op(dentry, ops); - if (inode) { - unsigned add_flags =3D d_flags_for_inode(inode); - hlist_add_head(&dentry->d_alias, &inode->i_dentry); - raw_write_seqcount_begin(&dentry->d_seq); - __d_set_inode_and_type(dentry, inode, add_flags); - raw_write_seqcount_end(&dentry->d_seq); - fsnotify_update_flags(dentry); - } - __d_rehash(dentry); + if (inode) + __d_instantiate(dentry, inode); if (dir) { end_dir_add(dir, n); __d_wake_in_lookup_waiters(dentry); @@ -3142,8 +3137,6 @@ struct dentry *d_splice_alias_ops(struct inode *inode= , struct dentry *dentry, if (IS_ERR(inode)) return ERR_CAST(inode); =20 - BUG_ON(!d_unhashed(dentry)); - if (!inode) goto out; =20 @@ -3192,6 +3185,8 @@ struct dentry *d_splice_alias_ops(struct inode *inode= , struct dentry *dentry, * @inode: the inode which may have a disconnected dentry * @dentry: a negative dentry which we want to point to the inode. * + * @dentry must be negative and may be in-lookup or unhashed or hashed. + * * If inode is a directory and has an IS_ROOT alias, then d_move that in * place of the given dentry and return it, else simply d_add the inode * to the dentry and return NULL. @@ -3199,16 +3194,14 @@ struct dentry *d_splice_alias_ops(struct inode *ino= de, struct dentry *dentry, * If a non-IS_ROOT directory is found, the filesystem is corrupt, and * we should error out: directories can't have multiple aliases. * - * This is needed in the lookup routine of any filesystem that is exportab= le - * (via knfsd) so that we can build dcache paths to directories effectivel= y. + * This should be used to return the result of ->lookup() and to + * instantiate the result of ->mkdir(), is often useful for + * ->atomic_open, and may be used to instantiate other objects. * * If a dentry was found and moved, then it is returned. Otherwise NULL - * is returned. This matches the expected return value of ->lookup. + * is returned. This matches the expected return value of ->lookup and + * ->mkdir. * - * Cluster filesystems may call this function with a negative, hashed dent= ry. - * In that case, we know that the inode will be a regular file, and also t= his - * will only occur during atomic_open. So we need to check for the dentry - * being already hashed only in the final case. */ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) { --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fout-b7-smtp.messagingengine.com (fout-b7-smtp.messagingengine.com [202.12.124.150]) (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 DF5DA340DA6; Thu, 30 Apr 2026 03:09:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.150 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518574; cv=none; b=FgZVmovvdWYOHALAS4vRH1H2JuBd3qnHBj4TtAwQXXHqHhcMuAX5kt6juicreUgZt/G3mVJwYZkbSbMx1zeEDmebKAEE+6D0WAVziNHbd9jgFMZ04A/6pAHT94rAnBisKBZuKNpkH6Typ5649lVAn/xp8YEtA9rkgaJodBmbR1o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518574; c=relaxed/simple; bh=BG15dbbtGmbo7py2hh2tQuZ/Chxlj2dVvwfxDnyR62A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pKnB4cG3ifL75/7NMpQRa32kzeECuI90RYnD426GGj0R529eKK6I1L0AE4iFBCMGPs4G26PfV/PeXmlB3oEtrblWGLaOZceNyDakcV4VldlSxLbwDoU4biNSkmQ7APBq4TkuK4wzSFdY2MgcTFt8NMFk7qalRfbzC2Yo+mi9Ndc= 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=PU/r3YeH; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=W4L5oU/s; arc=none smtp.client-ip=202.12.124.150 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="PU/r3YeH"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="W4L5oU/s" Received: from phl-compute-07.internal (phl-compute-07.internal [10.202.2.47]) by mailfout.stl.internal (Postfix) with ESMTP id 1BAB81D00187; Wed, 29 Apr 2026 23:09:32 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-07.internal (MEProxy); Wed, 29 Apr 2026 23:09:32 -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=1777518571; x=1777604971; bh=MyRgJx5tx/nmumUkV3zg5NFxjmBpebhpDnTbkO1uNVQ=; b= PU/r3YeH4X5iZ8lWrktH6VejSn4xCjecC503Y60bMWmCHLFE2do0L0kf3Xih/duf 4hocap2xaMxjSEbZ27iaZGRmQB9Mxf2TqPHz3NOf3k87cWeXn3GDyZLsJYXnKxp+ 783pCKRB/GEI7Dyhpxjw9sF8yH9BqMBcp6aF0fKCTeVXYuWfRI5P3aK0gmOg53l3 RXwW4CNQIOn1FajVqcBohC1cAn9xutvzUni63sFvG+V1j4/omv0ToBwEKuqcxzRZ Wk7VSTnPHSr5pVyM9CFxhMYqdTDwLXcBLc1MIUZ4yNoDGX6Z1c8pUE11+w/UXubA 1ZkryDzFOSc8C75TpJzx2A== 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=1777518571; x=1777604971; bh=M yRgJx5tx/nmumUkV3zg5NFxjmBpebhpDnTbkO1uNVQ=; b=W4L5oU/sVoY1Bzp6U 35dXIH02Y5qVKyge7gfX9WpQMUFtUFJiHuC1hNKy/NdS+MIDHRhLVkytJZgQxnAz abTzq0NW98ZTpzwHJpGRo+0/zNKB5cKaliIxQ+HkvfAKTg5AaKuBpkoyCwSxRY+n NyFh4AF84P7JvAeqfi93/MADuIhA1GvQLJh09OSx0wV4OI56mhvb57c+cG2C7j7z jOszDGxoqUKUIOg5/50YXVZM3QY+z1bdSTdCuDdqk2RxzqsarOCt1T8ZbaGoVNL/ xW086EoMkValTb3ebfx00GDzXiyV0iSFuxSkCZ1uH9nOs0M/ToRH+OWZfR/xNdUF rDCmg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:29 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 4/7] VFS: introduce d_alloc_noblock() Date: Thu, 30 Apr 2026 11:56:57 +1000 Message-ID: <20260430020137.3305302-5-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. This done using try_lookup_noperm() necessitating the includion of namei.h in dcache.c. Signed-off-by: NeilBrown --- fs/dcache.c | 87 ++++++++++++++++++++++++++++++++++++++++-- include/linux/dcache.h | 1 + 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a4ee380f3dfc..a0096ac02790 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" #include "mount.h" =20 @@ -2652,8 +2653,16 @@ static void d_wait_lookup(struct dentry *dentry) } } =20 -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 =3D name->hash; struct hlist_bl_head *b =3D in_lookup_hash(parent, hash); @@ -2735,7 +2744,18 @@ struct dentry *d_alloc_parallel(struct dentry *paren= t, * wait for them to finish */ spin_lock(&dentry->d_lock); - d_wait_lookup(dentry); + 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: + d_wait_lookup(dentry); + /* ... and continue */ + } + /* * it's not in-lookup anymore; in principle we should repeat * everything from dcache lookup, but it's likely to be what @@ -2764,8 +2784,69 @@ struct dentry *d_alloc_parallel(struct dentry *paren= t, 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); =20 +/** + * 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 =3D try_lookup_noperm(name, parent); + if (!de) + de =3D __d_alloc_parallel(parent, name, ALLOC_PARA_FAIL); + return de; +} +EXPORT_SYMBOL(d_alloc_noblock); + /* * Move dentry from in-lookup state to busy-negative one. * diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 97a887be150a..d22c308043bb 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 *, --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fout-b7-smtp.messagingengine.com (fout-b7-smtp.messagingengine.com [202.12.124.150]) (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 556E03451C1; Thu, 30 Apr 2026 03:09:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.150 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518579; cv=none; b=gjg4jYb1rtIUJNQ5Rv9YfuuB4I5eU1QxIwoCieM87qOJMJFVYc1GIuArY4m2iv0eSDl4v8yp4KhvdZ3zslqMTQ2NBU+tyK2gp0Vn0JU9+GOI58x7d9GhvSaooaacD3HjzyiaeKboRGmgZMikeXDQvcwKaxXIUhcLhYYFO75fIhE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518579; c=relaxed/simple; bh=aI/7LxQasa/WMqtdcaEEHsmvZknfOqE36vo7BSVAHxc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t9usimgavFeJSts7ePwW6BGVFgjzA68dDSKG9+pMbHBUH2STbqL9BWuvY/UbqnrCWumwE8nK6zH64wW4t+XEwCDhNkDTAQE7T5naZ+2LImb8CUVdo6pPrV6h1BDA2n+6/gqnwSwbJL3b5BXWDvMbWFAweUP5xmGCT9KrTUhd0ZE= 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=jiFKN5H6; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=WIHFdhxp; arc=none smtp.client-ip=202.12.124.150 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="jiFKN5H6"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="WIHFdhxp" Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfout.stl.internal (Postfix) with ESMTP id 529C81D00113; Wed, 29 Apr 2026 23:09:37 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-03.internal (MEProxy); Wed, 29 Apr 2026 23:09:37 -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=1777518577; x=1777604977; bh=NvBayTPXi0DVU1I5ML5QY0CEm4bJY9EzhHJqYyVRowQ=; b= jiFKN5H6lMe21XIRD5gxVqYnUexildLkn+nn77y2172uxtAJkftIPBJkpSnU/Bnb qPbUxEtrnV3U1Afxc64o10VFDLAlxREpp3uvF0SaZiYWeJeUMutViCUzn9Y/ZA79 mZ2ubLD5DOwuI8xnfccYBw5/E1jEXsXepwc4ZGK54cmVj+3Hwrb3q1wIAcZ9ruNz IJN6va1f5NPPsfxVF3QRSF+d8VBy+eaN+mpq7y3RO0V96kxbDhk/P7tcaKxD8DPc o2EHZseWL5Z7nT9DD9X2a3KkdP8f/8953jMQULmeivRDWDMPc0LZZ4trbZkQEdKW YXi8exxHJ+kAzHf/NU5apg== 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=1777518577; x=1777604977; bh=N vBayTPXi0DVU1I5ML5QY0CEm4bJY9EzhHJqYyVRowQ=; b=WIHFdhxpuK8pVZ88X r+XSaTC8kpZv89AXB56QmwnRIWdKd63b2n8obrEMCXVuz0FxoXzSQiPV+Jr34X8u Olpx/nXRtHjGowxlP0ek1q3JIaOBQzApSLy0ayyG3g3m9fdRNcZsbHydr0JOuGR+ tPQAzMg0ndhHYKRJ+dewMrs9fDxwLquHjJ+fmxSzz+tO8iCP5rPi8waerXb6Q9Mh UdfwKAQxegZLxYK+VnOwqxWBE5eQGjFvJIMP1LC+UETIAzHpZ0aoaXe9gusNwfs3 HAqnoN0RiLm7MKXZyLcggUxMaFLMMRc3X7kUcGH0EUYba7E/IPVgrF/E4Uj8irrP FgWEw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:34 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 5/7] VFS: add d_duplicate() Date: Thu, 30 Apr 2026 11:56:58 +1000 Message-ID: <20260430020137.3305302-6-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown Occasionally a single operation can require two sub-operations on the same name, and it is important that a d_alloc_parallel() (once that can be run unlocked) does not create another dentry with the same name between the operations. Two examples: 1/ rename where the target name (a positive dentry) needs to be "silly-renamed" to a temporary name so it will remain available on the server (NFS and AFS). Here the same name needs to be the subject of one rename, and the target of another. 2/ rename where the subject needs to be replaced with a white-out (shmemfs). Here the same name need to be the subject of a rename and the target of a mknod() In both cases the original dentry is renamed to something else, and a replacement is instantiated, possibly as the target of d_move(), possibly by d_instantiate(). Currently d_alloc() is used to create the dentry and the exclusive lock on the parent ensures no other dentry is created. When d_alloc_parallel() is moved out of the parent lock, this will no longer be sufficient. In particular if the original is renamed away before the new is instantiated, there is a window where d_alloc_parallel() could create another name. "silly-rename" does work in this order. shmemfs whiteout doesn't open this hole but is essentially the same pattern and should use the same approach. The new d_duplicate() creates an in-lookup dentry with the same name as the original dentry, which must be hashed. There is no need to check if an in-lookup dentry exists with the same name as d_alloc_parallel() will never try add one while the hashed dentry exists. Once the new in-lookup is created, d_alloc_parallel() will find it and wait for it to complete, then use it. Signed-off-by: NeilBrown --- fs/dcache.c | 51 ++++++++++++++++++++++++++++++++++++++++++ include/linux/dcache.h | 1 + 2 files changed, 52 insertions(+) diff --git a/fs/dcache.c b/fs/dcache.c index a0096ac02790..1943607f7547 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1900,6 +1900,57 @@ struct dentry *d_alloc(struct dentry * parent, const= struct qstr *name) } EXPORT_SYMBOL(d_alloc); =20 +/** + * d_duplicate - duplicate a dentry for combined atomic operation + * @dentry: the dentry to duplicate + * + * Some rename operations need to be combined with another operation + * inside the filesystem. + * 1/ A cluster filesystem when renaming to an in-use file might need to + * first "silly-rename" that target out of the way before the main rename + * 2/ A filesystem that supports white-out might want to create a whiteout + * in place of the file being moved. + * + * For this they need two dentries which temporarily have the same name, + * before one is renamed. d_duplicate() provides for this. Given a + * positive hashed dentry, it creates a second in-lookup dentry. + * Because the original dentry exists, no other thread will try to + * create an in-lookup dentry, so there can be no race in this create. + * + * The caller should d_move() the original to a new name, often via a + * rename request, and should call d_lookup_done() on the newly created + * dentry. If the new is instantiated then old MUST either be moved + * or dropped. + * + * Parent must be locked. + * + * Returns: an in-lookup dentry, or an error. + */ +struct dentry *d_duplicate(struct dentry *dentry) +{ + unsigned int hash =3D dentry->d_name.hash; + struct dentry *parent =3D dentry->d_parent; + struct hlist_bl_head *b =3D in_lookup_hash(parent, hash); + struct dentry *new =3D __d_alloc(parent->d_sb, &dentry->d_name); + + if (unlikely(!new)) + return ERR_PTR(-ENOMEM); + + new->d_flags |=3D DCACHE_PAR_LOOKUP; + spin_lock(&parent->d_lock); + new->d_parent =3D dget_dlock(parent); + hlist_add_head(&new->d_sib, &parent->d_children); + if (parent->d_flags & DCACHE_DISCONNECTED) + new->d_flags |=3D DCACHE_DISCONNECTED; + spin_unlock(&dentry->d_parent->d_lock); + + hlist_bl_lock(b); + hlist_bl_add_head(&new->d_in_lookup_hash, b); + hlist_bl_unlock(b); + return new; +} +EXPORT_SYMBOL(d_duplicate); + struct dentry *d_alloc_anon(struct super_block *sb) { return __d_alloc(sb, NULL); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index d22c308043bb..b4663a1a0636 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -259,6 +259,7 @@ 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 *); +struct dentry *d_duplicate(struct dentry *dentry); /* weird procfs mess; *NOT* exported */ extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *, const struct dentry_operations *); --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fout-b7-smtp.messagingengine.com (fout-b7-smtp.messagingengine.com [202.12.124.150]) (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 30E94345CCA; Thu, 30 Apr 2026 03:09:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.150 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518584; cv=none; b=fnOnrtxanGT29oYjDR5Ms46bv0msEO8HEZTP47w056m3VQLUx6G4HhvOa54s0g7piuUqCx81n2xbL6Ediy8e7ZTx8QexxDFFZxNkg88eVdlxZt+y+8NyxIApkzayZLBZpmGA2DvOrjJp+S6KxUd7wWxcgYYUkvDZu+Qk+22nUaA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518584; c=relaxed/simple; bh=Af17cpjWLrgjln+x15PYEXYO/pHIZybmrmOg/uu6FGs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hbRFRyQzRBkGsH8tciGLtPylG/oHmzG9j92qU6OvtC8c+gxfQve3BzBnCbcXKZkd4YeBcAIt7Jg1AVot8yltH0DkSlXyFEf/jQmPNCOnEo83g+5umhLcMjEpG1UEuqGnXfgbOlcNWM2TAIRNHgbHOcEG22HgCXWFN1lwR0m1oKA= 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=a0Y62ua1; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=HCOULj61; arc=none smtp.client-ip=202.12.124.150 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="a0Y62ua1"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="HCOULj61" Received: from phl-compute-07.internal (phl-compute-07.internal [10.202.2.47]) by mailfout.stl.internal (Postfix) with ESMTP id 6989F1D00187; Wed, 29 Apr 2026 23:09:42 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-07.internal (MEProxy); Wed, 29 Apr 2026 23:09:42 -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=1777518582; x=1777604982; bh=2Sazp1M0TdInI6mi6hF1QSnGjDghjOgL8lkwZNivMpc=; b= a0Y62ua1vVCLsl69JwzQxchZl1shpnRTPoaHvWI3PkzJGk+Hurdz/mjf1utsz6+2 qI+VFakyW8s6gXyMAbQxYqKj3cAl2y2XbU6fJg7PoinOYPFS0QGz5f9I+Z1s3RjT B1/sm1PD5aNttS+kn1/hBGB4tLJctn++xxK+PsnxNPC4IW/qzMHKOLFiGZ3XIlZV R06RJafSBj/qPSqVrUs7t0GbHWBDbvb63g/fmcQmKPV1x/2ywj+sqc37IdsBRB9B Abq0Pbe7ndqd4yaEX3rmpzfaPDYAK6bz4Mjn+ooDI1qauFfpi3/QjHgFxeJgTgBQ 9uQ1dLSHDOM7H6oUdpdvUQ== 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=1777518582; x=1777604982; bh=2 Sazp1M0TdInI6mi6hF1QSnGjDghjOgL8lkwZNivMpc=; b=HCOULj61wXs5YEkWO SnnwnyIKL3CEVfQtpnrfq//f5jPaXJ2mdAK0gXQhd8cA+uXRYtglOjTztf5PhpCp owjxux6a43GmNCherHrt1iEE/FQQCuonEBeOfiRiPPOM4mrSVkvbfnSYSeiL9bS2 HRd7UzormfXmbxr+I4plXNrEDFCgc2l1paL/3sigNf4DWGwBSK+Ge4CFBTGvETla 5WutSQB3OOSZvIA9R6b/BGjSyrPzKwMeWpknrb+R8p3Ikro4lnheUQ9gGdBkh/yp yNmQs0V0UF2R7kS65+yDrXAno4MvA8hh1BM0a39VlmN75XftzkEyBj+OML7uXOrh A/jEQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:39 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 6/7] VFS: Add LOOKUP_SHARED flag. Date: Thu, 30 Apr 2026 11:56:59 +1000 Message-ID: <20260430020137.3305302-7-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown Some ->lookup handlers will need to drop and retake the parent lock, so they can safely use d_alloc_parallel(). ->lookup can be called with the parent lock either exclusive or shared. A new flag, LOOKUP_SHARED, tells ->lookup how the parent is locked. This is rather ugly, but will be gone soon after we move d_alloc_parallel() out of the directory lock as ->lookup() will *always* called with a shared lock on the parent. Signed-off-by: NeilBrown --- fs/namei.c | 7 ++++--- include/linux/namei.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index a6349b31fdb6..e77ba9d31857 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1928,7 +1928,7 @@ static noinline struct dentry *lookup_slow(const stru= ct qstr *name, struct inode *inode =3D dir->d_inode; struct dentry *res; inode_lock_shared(inode); - res =3D __lookup_slow(name, dir, flags); + res =3D __lookup_slow(name, dir, flags | LOOKUP_SHARED); inode_unlock_shared(inode); return res; } @@ -1942,7 +1942,7 @@ static struct dentry *lookup_slow_killable(const stru= ct qstr *name, =20 if (inode_lock_shared_killable(inode)) return ERR_PTR(-EINTR); - res =3D __lookup_slow(name, dir, flags); + res =3D __lookup_slow(name, dir, flags | LOOKUP_SHARED); inode_unlock_shared(inode); return res; } @@ -4413,6 +4413,7 @@ static struct dentry *lookup_open(struct nameidata *n= d, struct file *file, struct dentry *dentry; int error, create_error =3D 0; umode_t mode =3D op->mode; + unsigned int shared_flag =3D (op->open_flag & O_CREAT) ? 0 : LOOKUP_SHARE= D; =20 if (unlikely(IS_DEADDIR(dir_inode))) return ERR_PTR(-ENOENT); @@ -4480,7 +4481,7 @@ static struct dentry *lookup_open(struct nameidata *n= d, struct file *file, =20 if (d_in_lookup(dentry)) { struct dentry *res =3D dir_inode->i_op->lookup(dir_inode, dentry, - nd->flags); + nd->flags | shared_flag); d_lookup_done(dentry); if (unlikely(res)) { if (IS_ERR(res)) { diff --git a/include/linux/namei.h b/include/linux/namei.h index 2ad6dd9987b9..b3346a513d8f 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -37,8 +37,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; #define LOOKUP_CREATE BIT(17) /* ... in object creation */ #define LOOKUP_EXCL BIT(18) /* ... in target must not exist */ #define LOOKUP_RENAME_TARGET BIT(19) /* ... in destination of rename() */ +#define LOOKUP_SHARED BIT(20) /* Parent lock is held shared */ =20 -/* 4 spare bits for intent */ +/* 3 spare bits for intent */ =20 /* Scoping flags for lookup. */ #define LOOKUP_NO_SYMLINKS BIT(24) /* No symlink crossing. */ --=20 2.50.0.107.gf914562f5916.dirty From nobody Tue Jun 16 18:31:26 2026 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.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 56B5233F5BA; Thu, 30 Apr 2026 03:09:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518589; cv=none; b=oz9OG7OEW5WG6sI3BvdBDd85aeJNUKoNEN3rurG+7meggI9N72muRqlxIpgDF2469H6DRSjsZu4uOgyic3Haa0TGePSzO8mXeOGXCJTPplD9JZDADcy4erWC9mpQ5yBClDUDczGZkFBMmpy9PcNOEW3eZMgJn+4OeCqzoFeepVU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777518589; c=relaxed/simple; bh=t9kggWsulA9KxdwVFklPlh4m30Ed/VK+5i4xHr1w7C0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cSya4jlrRvw+vTrl92h95pkdbN/nbPr3+v0uzr8sWLVt6dMxMdwLvd3cSKybnyhnbNsLXEnsJcRGONDYaAzNtI4JvE4uu9lLfhBeBa84mEH9PhuyKAm9l5meeQiHExqhxOgWEsMkqiRkmaLlNKvvKU9w8H0FWMgJP/T6+jCYsag= 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=mjOcLmdJ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=E4Hakb2i; arc=none smtp.client-ip=202.12.124.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="mjOcLmdJ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="E4Hakb2i" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id 9BBA87A00F5; Wed, 29 Apr 2026 23:09:47 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Wed, 29 Apr 2026 23:09:47 -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=1777518587; x=1777604987; bh=IPvhYgSpY2OYytpoQzuPZwD9BYsKRv/q4WdeXo/yL6E=; b= mjOcLmdJ3h41bDxvkjxgid0w9Nu1cvc39wuBEygvf1JMVgYYdV9zLh/NiaEYgHW/ FbRikC+bTbOqamyvM54fGa6eFF407CRfp+eAu+/vgB9204MGGsA4OfXglnHkzstW GNJVgq7EsloGgw/NW8fbofSIpoOkgw5SUH5kcVIYuta5IVI9EhTVKC5m90egkwLh K+txFgMxGnZ/Wg1BS+Ris3itmFLdQ65Qu6+pobYEAvm1Rg2OxXkYFemZLastA8Gd k/f6zp+2soffEhQYQZkXEKOCUDNeY/X1Ekbx46X84p+XnSfS3OtvRS9fwnaoQc23 Pa2RIp8SdBaBRf9oqPotjw== 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=1777518587; x=1777604987; bh=I PvhYgSpY2OYytpoQzuPZwD9BYsKRv/q4WdeXo/yL6E=; b=E4Hakb2iISaU+sNW+ 7BB5nZgPMwDJEiz3KMmIr9tFTv0Otp+zE5RmRb9pIqJB2GgPPLhpNgesv2VHMBpS fWL+lbuTes5SV1Ooo7+B3fguxl50sMyK+OdJchcR4FUEZxn1sSE7phpLy5rDLYCf VE9xqDscO04eHjBG8SqBTFvWm82Bt6o2udIkpVkBgQ4Amo6fYRSZvWucY1YbLTZI 4hjOh5l7PdjyRqWlRIdSj5JiuT5rmI7meIIEjhEKN882gk45wLE7XZU7yiA5X7/R UgFQMG+dJmrwDIQ3IR4Wwxw3SPlayaHofW5p5D6xt2pngQHL+B0RKjjL+oxclirw cafeg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdekiedvtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfrhgggfestdekredtredttdenucfhrhhomheppfgvihhluehr ohifnhcuoehnvghilhgssehofihnmhgrihhlrdhnvghtqeenucggtffrrghtthgvrhhnpe evveekffduueevhfeigefhgfdukedtleekjeeitdejudfgueekvdekffdvfedvudenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehnvghilhgsse hofihnmhgrihhlrdhnvghtpdhnsggprhgtphhtthhopeekpdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehvihhrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhinhhugidqfhhsuggvvhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrgh dprhgtphhtthhopehjrggtkhesshhushgvrdgtiidprhgtphhtthhopehtohhrvhgrlhgu sheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepjhhlrgihth honheskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghrrghunhgvrheskhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghmihhrjeefihhlsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: i9d664b8f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 29 Apr 2026 23:09:44 -0400 (EDT) From: NeilBrown To: Linus Torvalds , Al Viro , Christian Brauner , Jan Kara , Jeff Layton , Amir Goldstein Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 7/7] VFS/xfs/ntfs: drop parent lock across d_alloc_parallel() in d_add_ci() Date: Thu, 30 Apr 2026 11:57:00 +1000 Message-ID: <20260430020137.3305302-8-neilb@ownmail.net> X-Mailer: git-send-email 2.50.0.107.gf914562f5916.dirty In-Reply-To: <20260430020137.3305302-1-neilb@ownmail.net> References: <20260430020137.3305302-1-neilb@ownmail.net> Reply-To: NeilBrown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: NeilBrown A proposed change will invert the lock ordering between d_alloc_parallel() and inode_lock() on the parent. When that happens it will not be safe to call d_alloc_parallel() while holding the parent lock - even shared. We don't need to keep the parent lock held when d_add_ci() is run - the VFS doesn't need it as dentry is exclusively held due to DCACHE_PAR_LOOKUP and the filesystem has finished its work. So drop and reclaim the lock (shared or exclusive as determined by LOOKUP_SHARED) to avoid future deadlock. Signed-off-by: NeilBrown --- fs/dcache.c | 18 +++++++++++++++++- fs/ntfs/namei.c | 2 +- fs/xfs/xfs_iops.c | 2 +- include/linux/dcache.h | 3 ++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 1943607f7547..43cd0765670f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2275,6 +2275,7 @@ EXPORT_SYMBOL(d_obtain_root); * @dentry: the negative dentry that was passed to the parent's lookup func * @inode: the inode case-insensitive lookup has found * @name: the case-exact name to be associated with the returned dentry + * @lookup_flags: flags passed to ->lookup * * This is to avoid filling the dcache with case-insensitive names to the * same inode, only the actual correct case is stored in the dcache for @@ -2287,7 +2288,7 @@ EXPORT_SYMBOL(d_obtain_root); * the exact case, and return the spliced entry. */ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, - struct qstr *name) + struct qstr *name, unsigned int lookup_flags) { struct dentry *found, *res; =20 @@ -2300,6 +2301,17 @@ struct dentry *d_add_ci(struct dentry *dentry, struc= t inode *inode, iput(inode); return found; } + /* + * We are holding parent lock and so don't want to wait for a + * d_in_lookup() dentry. We can safely drop the parent lock and + * reclaim it as we have exclusive access to dentry as it is + * d_in_lookup() (so ->d_parent is stable) and we are near the + * end ->lookup() and will shortly drop the lock anyway. + */ + if (lookup_flags & LOOKUP_SHARED) + inode_unlock_shared(d_inode(dentry->d_parent)); + else + inode_unlock(d_inode(dentry->d_parent)); if (d_in_lookup(dentry)) { found =3D d_alloc_parallel(dentry->d_parent, name); if (IS_ERR(found) || !d_in_lookup(found)) { @@ -2313,6 +2325,10 @@ struct dentry *d_add_ci(struct dentry *dentry, struc= t inode *inode, return ERR_PTR(-ENOMEM); }=20 } + if (lookup_flags & LOOKUP_SHARED) + inode_lock_shared(d_inode(dentry->d_parent)); + else + inode_lock_nested(d_inode(dentry->d_parent), I_MUTEX_PARENT); res =3D d_splice_alias(inode, found); if (res) { d_lookup_done(found); diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 10894de519c3..e2f3430c2e6d 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -310,7 +310,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino= , struct dentry *dent, } nls_name.hash =3D full_name_hash(dent, nls_name.name, nls_name.len); =20 - dent =3D d_add_ci(dent, dent_inode, &nls_name); + dent =3D d_add_ci(dent, dent_inode, &nls_name, flags); kfree(nls_name.name); return dent; =20 diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 325c2200c501..db0beb3831a9 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -369,7 +369,7 @@ xfs_vn_ci_lookup( /* else case-insensitive match... */ dname.name =3D ci_name.name; dname.len =3D ci_name.len; - dentry =3D d_add_ci(dentry, VFS_I(ip), &dname); + dentry =3D d_add_ci(dentry, VFS_I(ip), &dname, flags); kfree(ci_name.name); return dentry; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index b4663a1a0636..9553bffbb098 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -263,7 +263,8 @@ struct dentry *d_duplicate(struct dentry *dentry); /* weird procfs mess; *NOT* exported */ extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *, const struct dentry_operations *); -extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qs= tr *); +extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qs= tr *, + unsigned int); extern bool d_same_name(const struct dentry *dentry, const struct dentry *= parent, const struct qstr *name); extern struct dentry *d_find_any_alias(struct inode *inode); --=20 2.50.0.107.gf914562f5916.dirty