From nobody Tue Sep 29 14:57:04 2026 Received: from mta1.migadu.com (out-133.mta1.migadu.com [95.215.58.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2BDBF3B4E83 for ; Fri, 21 Aug 2026 05:05:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.133 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288723; cv=none; b=Yh2YQEquZznKeBkck9vJIhMipjX0ij+Qrm5CJKfrMKepTxlfSZKYAWdPuhrt648PTKEx/uWalq/r8DqfHJtAK3KcQhhkrZVQPtvHa7JfaecQNk5qP6UeEOZE4hbcUngbGqWcpbZZme4M4o9aIP19Lik4ZBMjvD0Pfl3FA+3SRB0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288723; c=relaxed/simple; bh=acqatnoAVaMG9JAF5AWwMi2WJf4TI5Sdk+koVDC0QIs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WofU7Zu6D2dBziKX4lVPcBg5gvK+uN3a6biKRP4cscuJVTkPDh0xC4oLQRrpNjlqmTl1zdNo2KM4Lk982HHLTcmf45vkezyseSqKePotv9Q1z+BgJvzUctfEXyQoRO1j2rkhePBGY0HzpyItEr9kDsfm3xc+/J4kLZHv66iyaDI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Bkl2Nx6h; arc=none smtp.client-ip=95.215.58.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Bkl2Nx6h" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=acqatnoAVaMG9JAF5AWwMi2WJf4TI5Sdk+koVDC0QIs=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787288720; v=1; x=1787893520; b=Bkl2Nx6hP+8QZ1nAHKKXUKTzA0FEyMUT3yLSByJVKDSMo81anYtEsMli6PDOhxoZ4TRN43z8 C5uLxhtE09/h3xGdtsMTXNsRJxHSRH7wT01kOOgSkkYmO78LY744oxqPGAODJX1hERwEJIM9T9A gh1ULiloP6r1qjS11eEPZ6vc= X-Envelope-To: linux-kernel@vger.kernel.org Received: from localhost (2a03:2880:10ff:4c::) by smtp.migadu.com with ESMTPS id bfa9432652a67ff2; Fri, 21 Aug 2026 05:05:19 +0000 X-Mizu-Trace-ID: bfa9432652a67ff2 X-Migadu-Flow: FLOW_OUT From: Shakeel Butt To: Greg Kroah-Hartman , Tejun Heo Cc: Christian Brauner , Meta kernel team , driver-core@lists.linux.dev, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] kernfs: Use VFS lookup context in d_revalidate() Date: Thu, 20 Aug 2026 22:05:04 -0700 Message-ID: <20260821050507.2161607-2-shakeel.butt@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260821050507.2161607-1-shakeel.butt@linux.dev> References: <20260821050507.2161607-1-shakeel.butt@linux.dev> 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" The VFS supplies a stable parent inode and expected name to the revalidation callback. Use them instead of recovering the same information from mutable dentry fields. Compare the name using its explicit length because it may point into the pathname and need not be terminated at name->len. This also prepares the callback for lockless operation. Signed-off-by: Shakeel Butt Reviewed-by: Ian Kent --- fs/kernfs/dir.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 82bbaeb326aa..541bb5525437 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1171,23 +1171,19 @@ struct kernfs_node *kernfs_create_empty_dir(struct = kernfs_node *parent, static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *nam= e, struct dentry *dentry, unsigned int flags) { - struct kernfs_node *kn, *parent; + struct kernfs_node *kn, *kn_parent; + struct kernfs_node *parent =3D dir->i_private; struct kernfs_root *root; + const char *kn_name; =20 if (flags & LOOKUP_RCU) return -ECHILD; =20 /* Negative hashed dentry? */ if (d_really_is_negative(dentry)) { - /* If the kernfs parent node has changed discard and - * proceed to ->lookup. - * - * There's nothing special needed here when getting the - * dentry parent, even if a concurrent rename is in - * progress. That's because the dentry is negative so - * it can only be the target of the rename and it will - * be doing a d_move() not a replace. Consequently the - * dentry d_parent won't change over the d_move(). + /* + * If the kernfs parent node has changed discard and proceed to + * ->lookup. * * Also kernfs negative dentries transitioning from * negative to positive during revalidate won't happen @@ -1195,14 +1191,11 @@ static int kernfs_dop_revalidate(struct inode *dir,= const struct qstr *name, * changes and the lookup re-done so that a new positive * dentry can be properly created. */ - root =3D kernfs_root_from_sb(dentry->d_sb); + root =3D kernfs_root(parent); down_read(&root->kernfs_rwsem); - parent =3D kernfs_dentry_node(dentry->d_parent); - if (parent) { - if (kernfs_dir_changed(parent, dentry)) { - up_read(&root->kernfs_rwsem); - return 0; - } + if (kernfs_dir_changed(parent, dentry)) { + up_read(&root->kernfs_rwsem); + return 0; } up_read(&root->kernfs_rwsem); =20 @@ -1220,18 +1213,20 @@ static int kernfs_dop_revalidate(struct inode *dir,= const struct qstr *name, if (!kernfs_active(kn)) goto out_bad; =20 - parent =3D kernfs_parent(kn); + kn_parent =3D kernfs_parent(kn); /* The kernfs node has been moved? */ - if (kernfs_dentry_node(dentry->d_parent) !=3D parent) + if (parent !=3D kn_parent) goto out_bad; =20 /* The kernfs node has been renamed */ - if (strcmp(dentry->d_name.name, kernfs_rcu_name(kn)) !=3D 0) + kn_name =3D kernfs_rcu_name(kn); + if (name->len !=3D strlen(kn_name) || + memcmp(name->name, kn_name, name->len)) goto out_bad; =20 /* The kernfs node has been moved to a different namespace */ - if (parent && kernfs_ns_enabled(parent) && - kernfs_ns_id(kernfs_info(dentry->d_sb)->ns) !=3D kernfs_ns_id(kn->ns)) + if (kn_parent && kernfs_ns_enabled(kn_parent) && + kernfs_ns_id(kernfs_info(dir->i_sb)->ns) !=3D kernfs_ns_id(kn->ns)) goto out_bad; =20 up_read(&root->kernfs_rwsem); --=20 2.53.0-Meta From nobody Tue Sep 29 14:57:04 2026 Received: from mta1.migadu.com (out-135.mta1.migadu.com [95.215.58.135]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 149653F39C8 for ; Fri, 21 Aug 2026 05:05:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.135 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288729; cv=none; b=lKd2fpe+7doSjcWNBqs8og7PleWjMMAo0nFMHOUqWsodPvMeiaOOmB954XK4wJjLnUvZsF69/MmHDLzLOwtmfRRAWD5lPmEoJ1BY+w+EJ51k/anlwLv2G4VTOZy7MNZrngJ4QZCmzw0ZaD+WcK0n4PBpGe7nPaiILEDh5xIqsYs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288729; c=relaxed/simple; bh=U1l/0x7ZD0ZfGu+oDn4yhMeqTklxKFrZPzWL2YzeyXk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Yq07hthXrmbiXlXjrN7cQRGY0rEhpxwQ9CILMNRwToMG6D3iGNAxHoTPc94PP3YQKDw6r/v16JV0yRJU8ADM+qBf5zv6hs9iHqK4tPXVQPa35Ip0TYA5qZsIPaA7QP/Zo7GvNTXOk0ygJgkb8Zw3Zfltm0GlPs1LBTmmLxnDOWQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=wF0yiLrV; arc=none smtp.client-ip=95.215.58.135 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="wF0yiLrV" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=U1l/0x7ZD0ZfGu+oDn4yhMeqTklxKFrZPzWL2YzeyXk=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787288725; v=1; x=1787893525; b=wF0yiLrVOpnBsKe4eMBPDn3RBgWM3jufS+sCCLKrIJ4wsdWdZPM7HrReZCKmip1zCxDINRlU anE5Fa7dYk3NNwV0Q6focM73CgJqcVWBwKbaZyv4+mVBN1VP1nax9/fmPk38zSr4JejpCgoPzXQ o/4CUG3axHcv5Dif21GlM2xY= X-Envelope-To: linux-kernel@vger.kernel.org Received: from localhost (2a03:2880:10ff:2::) by smtp.migadu.com with ESMTPS id af484d0623c2cb60; Fri, 21 Aug 2026 05:05:25 +0000 X-Mizu-Trace-ID: af484d0623c2cb60 X-Migadu-Flow: FLOW_OUT From: Shakeel Butt To: Greg Kroah-Hartman , Tejun Heo Cc: Christian Brauner , Meta kernel team , driver-core@lists.linux.dev, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] kernfs: Prepare directory revisions for lockless reads Date: Thu, 20 Aug 2026 22:05:05 -0700 Message-ID: <20260821050507.2161607-3-shakeel.butt@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260821050507.2161607-1-shakeel.butt@linux.dev> References: <20260821050507.2161607-1-shakeel.butt@linux.dev> 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" Negative dentry revalidation only needs to sample the parent directory generation and compare it with the value recorded at lookup time. Annotate those accesses with READ_ONCE() and WRITE_ONCE() so the comparison can safely move outside kernfs_rwsem. Revision updates remain serialized by kernfs_rwsem. Assert that writer contract in kernfs_inc_rev(); the read half of the increment stays plain because the semaphore excludes other writers. Signed-off-by: Shakeel Butt Reviewed-by: Ian Kent --- fs/kernfs/kernfs-internal.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index aa784b540b36..20a0cf42ba8d 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -147,20 +147,19 @@ static inline struct kernfs_node *kernfs_dentry_node(= struct dentry *dentry) static inline void kernfs_set_rev(struct kernfs_node *parent, struct dentry *dentry) { - dentry->d_time =3D parent->dir.rev; + WRITE_ONCE(dentry->d_time, READ_ONCE(parent->dir.rev)); } =20 static inline void kernfs_inc_rev(struct kernfs_node *parent) { - parent->dir.rev++; + lockdep_assert_held_write(&parent->dir.root->kernfs_rwsem); + WRITE_ONCE(parent->dir.rev, parent->dir.rev + 1); } =20 static inline bool kernfs_dir_changed(struct kernfs_node *parent, struct dentry *dentry) { - if (parent->dir.rev !=3D dentry->d_time) - return true; - return false; + return READ_ONCE(parent->dir.rev) !=3D READ_ONCE(dentry->d_time); } =20 extern const struct super_operations kernfs_sops; --=20 2.53.0-Meta From nobody Tue Sep 29 14:57:04 2026 Received: from mta1.migadu.com (out-138.mta1.migadu.com [95.215.58.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8B043F4DF3 for ; Fri, 21 Aug 2026 05:05:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288731; cv=none; b=q5Y58z33b4+NnX5EPcpYNbAAzOndebWPiyGZ10Xf4D1a4hPPYSwoPWNezVt11JKgbyuTviX7qsJJUIvlqbY15Is4nnAjQFedJLe1nSFleVtbRtSDFC/tRrAjbtljyfunGmO1j4qeZ0OQrn5CEigQd9rYtLxSxo94ez1zOgS1aNg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288731; c=relaxed/simple; bh=LIUw7uKUV9KhIrN1qzokJl5Rc/EjHIF80hcbDXs5RD0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M+Z0d3J9+X4UfH71XI2bouboafOIjK8/YupxiR0l+zvyPPyElEjCEtIrSwFoOUgMC7LyfBjVALKVSVEan+Wku0t78TnboRM6ohQcmkkAZ/dW2BsbAHURTwa585BFpD/FQefzAOr1QBwQb7bP5lxskOA2ZOU3JfJAzc2Rd4SB5tA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=ZpnJkXFw; arc=none smtp.client-ip=95.215.58.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="ZpnJkXFw" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=LIUw7uKUV9KhIrN1qzokJl5Rc/EjHIF80hcbDXs5RD0=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787288727; v=1; x=1787893527; b=ZpnJkXFwxTnzV/HT1kRS2Qv1Mj3gEVRGJhOLrytTSI1otvj07C1OXyc7C7Gq4fBM0CH/2jO5 M82s0klc/R4g1a38+Bsi8c26qvT25zY5ANPSqllU3K6w13rnJGyI78zndOcO1CDY5qTQhRiWlJo KMcyYuOAADd63r9fE8bgOBq8= X-Envelope-To: linux-kernel@vger.kernel.org Received: from localhost (2a03:2880:10ff:4::) by smtp.migadu.com with ESMTPS id fc17124732d1a8a7; Fri, 21 Aug 2026 05:05:27 +0000 X-Mizu-Trace-ID: fc17124732d1a8a7 X-Migadu-Flow: FLOW_OUT From: Shakeel Butt To: Greg Kroah-Hartman , Tejun Heo Cc: Christian Brauner , Meta kernel team , driver-core@lists.linux.dev, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] kernfs: Avoid namespace dereference in d_revalidate() Date: Thu, 20 Aug 2026 22:05:06 -0700 Message-ID: <20260821050507.2161607-4-shakeel.butt@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260821050507.2161607-1-shakeel.butt@linux.dev> References: <20260821050507.2161607-1-shakeel.butt@linux.dev> 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" Commit 1fe989e1c42a ("kernfs: use namespace id instead of pointer for hashing and comparison") changed dentry revalidation to compare namespace IDs along with the comparisons that determine visible directory ordering. Dereferencing a namespace tag that kernfs_rename_ns() can replace is not suitable once dentry revalidation stops taking kernfs_rwsem. Use pointer equality for this non-user-visible equality check instead. Namespace IDs uniquely identify namespace objects, so pointer and ID equality cannot disagree for valid tags. Hashing and directory ordering continue to use IDs. kn->ns becomes a lockless read in the next commit, so mark both sides of it now. The read is in kernfs_dop_revalidate(); the stores that can run while the node is visible are the two in kernfs_rename_ns(). The remaining stores, in kernfs_create_dir_ns(), kernfs_create_empty_dir() and kernfs_create_link(), all precede kernfs_add_one() and need no marking. Signed-off-by: Shakeel Butt Reviewed-by: Ian Kent --- fs/kernfs/dir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 541bb5525437..27949b0e027c 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1226,7 +1226,7 @@ static int kernfs_dop_revalidate(struct inode *dir, c= onst struct qstr *name, =20 /* The kernfs node has been moved to a different namespace */ if (kn_parent && kernfs_ns_enabled(kn_parent) && - kernfs_ns_id(kernfs_info(dir->i_sb)->ns) !=3D kernfs_ns_id(kn->ns)) + kernfs_info(dir->i_sb)->ns !=3D READ_ONCE(kn->ns)) goto out_bad; =20 up_read(&root->kernfs_rwsem); @@ -1873,7 +1873,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct k= ernfs_node *new_parent, =20 rcu_assign_pointer(kn->__parent, new_parent); =20 - kn->ns =3D new_ns; + WRITE_ONCE(kn->ns, new_ns); if (new_name) rcu_assign_pointer(kn->name, new_name); =20 @@ -1881,7 +1881,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct k= ernfs_node *new_parent, kernfs_put(old_parent); } else { /* name assignment is RCU protected, parent is the same */ - kn->ns =3D new_ns; + WRITE_ONCE(kn->ns, new_ns); if (new_name) rcu_assign_pointer(kn->name, new_name); } --=20 2.53.0-Meta From nobody Tue Sep 29 14:57:04 2026 Received: from mta0.migadu.com (out-151.mta0.migadu.com [91.218.175.151]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 825A13F58FF for ; Fri, 21 Aug 2026 05:05:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.151 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288733; cv=none; b=b5kzJnBf6Y9qSPULeXr7uxolJrSn31tztb5NHR/XMcOntYBvhEKMQxWQAyvxr5RhWQRd+2hEtqU3CMoOuASedh5s470dmResXC9KTJKbUqVMa6Yo5LotbzoWJ9QyyWVa+OcrP6svMRl5Jro2JH2BfOfCXJopBankOO4LGQkaXxc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787288733; c=relaxed/simple; bh=53i/STOUHRyVxCyimladd4nzeFEb3TLbeSjH6w1ciak=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e0K/Uf91/5IJC8Ng7uj/0gw5LxqkboXm9OBB+HciclOiUGlmf4IjhoufAMQj2cALUBtsX4GDA3l9L+x5nbnPzVk9SSxfioYTD660zkh/BsLBFXDyIid1v1CVTE853zXKJdFSGAqnbqYCPSE3zPrlO+YusKncl1XTDqar2//qw1o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=SEU4aZ9d; arc=none smtp.client-ip=91.218.175.151 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="SEU4aZ9d" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=53i/STOUHRyVxCyimladd4nzeFEb3TLbeSjH6w1ciak=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787288729; v=1; x=1787893529; b=SEU4aZ9dMavPOOaxOZ0q/SrbIpW9XpJdDODXzx7XD5gmd4/N13PrudZriqwMuibno0xO3ERJ 7Hi3AcXpZFfcjlICn/42NnDK7pDi3yrT+pSbNdrDocoCxf7qKwmRwcLXIlULBO9/uMNwGPHC775 EpFesQPcFv+sFE0f0AryIkEU= X-Envelope-To: linux-kernel@vger.kernel.org Received: from localhost (2a03:2880:10ff:8::) by smtp.migadu.com with ESMTPS id cc4b1c61de8fdc04; Fri, 21 Aug 2026 05:05:29 +0000 X-Mizu-Trace-ID: cc4b1c61de8fdc04 X-Migadu-Flow: FLOW_OUT From: Shakeel Butt To: Greg Kroah-Hartman , Tejun Heo Cc: Christian Brauner , Meta kernel team , driver-core@lists.linux.dev, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/4] kernfs: Remove kernfs_rwsem from dentry revalidation Date: Thu, 20 Aug 2026 22:05:07 -0700 Message-ID: <20260821050507.2161607-5-shakeel.butt@linux.dev> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260821050507.2161607-1-shakeel.butt@linux.dev> References: <20260821050507.2161607-1-shakeel.butt@linux.dev> 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" kernfs_dop_revalidate() takes kernfs_rwsem for read once per path component of every walk into a kernfs mount. Linux rwsems do not permit reader lock stealing once a writer is queued, so a single writer parks the whole incoming reader stream in uninterruptible sleep, stalling cgroup-polling daemons for minutes. Nothing the callback reads requires the semaphore. kn->active is an atomic_t that kernfs_find_and_get_node_by_id() already tests through __kernfs_active(); kn->__parent and kn->name are RCU pointers whose old values are freed only after a grace period; kn->ns is now compared rather than dereferenced; parent->dir.rev was annotated earlier in this series. What the semaphore does provide is a coherent snapshot, and that is not needed. ->d_revalidate() answers a question about a single instant, and the answer is already stale when it returns: a rename landing just after up_read() gives the same outcome as one observed mid-read. A lockless reader can only return "valid" for the (parent, name, namespace) triple identifying the dentry it was handed, and that triple was true when the dentry was instantiated, so it reports a genuine past state exactly as the locked version did. Removal is backstopped by kernfs_get_active() failing in the subsequent open(). Take an RCU read lock instead. kernfs_parent() and kernfs_rcu_name() work unchanged: the condition in their rcu_dereference_check() is an alternative to holding the RCU read lock, not an extra requirement. The negative dentry path needs nothing, as @dir pins the parent. The namespace check can use @parent directly once the preceding check establishes it equals kernfs_parent(kn), so the kn_parent local and its NULL test go away. kernfs_ns_enabled() reads @parent->flags, which KERNFS_ACTIVATED and KERNFS_REMOVING update as a plain read-modify-write under kernfs_rwsem. Those bits are not read here and KERNFS_NS cannot change once the directory has children, so mark the read data_race() rather than READ_ONCE(), which would not silence KCSAN against the unmarked writers anyway. kernfs_iop_permission() still forces every walk out of RCU-walk before children are revalidated, so lifting the LOOKUP_RCU bail here would have no observable effect; it is left to the series fixing that path. Readers walking cgroupfs and sysfs against concurrent cgroup and netdev churn: kernfs_rwsem read acquisitions drop from 48,593,360 to 1,280,280, and kernfs_dop_revalidate() no longer appears among its contention sites. Signed-off-by: Shakeel Butt Reviewed-by: Ian Kent --- fs/kernfs/dir.c | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 27949b0e027c..cd7a8ff8b6b2 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1171,9 +1171,8 @@ struct kernfs_node *kernfs_create_empty_dir(struct ke= rnfs_node *parent, static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *nam= e, struct dentry *dentry, unsigned int flags) { - struct kernfs_node *kn, *kn_parent; struct kernfs_node *parent =3D dir->i_private; - struct kernfs_root *root; + struct kernfs_node *kn; const char *kn_name; =20 if (flags & LOOKUP_RCU) @@ -1191,49 +1190,41 @@ static int kernfs_dop_revalidate(struct inode *dir,= const struct qstr *name, * changes and the lookup re-done so that a new positive * dentry can be properly created. */ - root =3D kernfs_root(parent); - down_read(&root->kernfs_rwsem); - if (kernfs_dir_changed(parent, dentry)) { - up_read(&root->kernfs_rwsem); - return 0; - } - up_read(&root->kernfs_rwsem); - - /* The kernfs parent node hasn't changed, leave the - * dentry negative and return success. - */ - return 1; + return !kernfs_dir_changed(parent, dentry); } =20 kn =3D kernfs_dentry_node(dentry); - root =3D kernfs_root(kn); - down_read(&root->kernfs_rwsem); + + guard(rcu)(); =20 /* The kernfs node has been deactivated */ - if (!kernfs_active(kn)) - goto out_bad; + if (!__kernfs_active(kn)) + return 0; =20 - kn_parent =3D kernfs_parent(kn); /* The kernfs node has been moved? */ - if (parent !=3D kn_parent) - goto out_bad; + if (kernfs_parent(kn) !=3D parent) + return 0; =20 /* The kernfs node has been renamed */ kn_name =3D kernfs_rcu_name(kn); if (name->len !=3D strlen(kn_name) || memcmp(name->name, kn_name, name->len)) - goto out_bad; + return 0; =20 - /* The kernfs node has been moved to a different namespace */ - if (kn_parent && kernfs_ns_enabled(kn_parent) && + /* + * The kernfs node has been moved to a different namespace. + * + * KERNFS_NS is set by kernfs_enable_ns() while @parent still has no + * children, so it cannot change while a child of @parent is being + * revalidated. The other bits in that word, KERNFS_ACTIVATED and + * KERNFS_REMOVING, are updated under kernfs_rwsem and are not read + * here, so racing with them is intentional and harmless. + */ + if (data_race(kernfs_ns_enabled(parent)) && kernfs_info(dir->i_sb)->ns !=3D READ_ONCE(kn->ns)) - goto out_bad; + return 0; =20 - up_read(&root->kernfs_rwsem); return 1; -out_bad: - up_read(&root->kernfs_rwsem); - return 0; } =20 const struct dentry_operations kernfs_dops =3D { --=20 2.53.0-Meta