NetBSD Problem Report #57005

From dholland@netbsd.org  Mon Sep 12 01:10:03 2022
Return-Path: <dholland@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 8811C1A923A
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 12 Sep 2022 01:10:03 +0000 (UTC)
Message-Id: <20220912011002.8C46984DC1@mail.netbsd.org>
Date: Mon, 12 Sep 2022 01:10:02 +0000 (UTC)
From: dholland@NetBSD.org
Reply-To: dholland@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: excessive namecache purging in ufs_rmdir
X-Send-Pr-Version: 3.95

>Number:         57005
>Category:       kern
>Synopsis:       excessive namecache purging in ufs_rmdir
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Sep 12 01:15:00 +0000 2022
>Last-Modified:  Thu Mar 26 05:15:00 +0000 2026
>Originator:     David A. Holland
>Release:        NetBSD 9.99.96 (20220310)
>Organization:
>Environment:
System: NetBSD valkyrie 9.99.97 NetBSD 9.99.97 (VALKYRIE) #10: Thu Aug 18 04:09:11 EDT 2022  dholland@valkyrie:/usr/src/sys/arch/amd64/compile/VALKYRIE amd64
Architecture: x86_64
Machine: amd64
>Description:

ufs_rmdir calls cache_purge(dvp), where dvp is the directory the
removal is happening in.

cache_purge(dvp) expands to cache_purge1(dvp, NULL, 0,
PURGE_PARENTS|PURGE_CHILDREN) which...

(a) purges *all* namecache entries in the directory, not just the one
for the directory being removed; and, even worse,
(b) purges any entries for dvp in _its_ parent.

From mjg at freebsd.

>How-To-Repeat:

Code inspection.

>Fix:

Call cache_purge1(dvp, cnp->cn_name, cnp->cn_namelen, 0). Unless the
name has been trashed or something at this stage, in which case the
name needs to be copied.

Also merge the change into ulfs_vnops.c and look for additional
cutpaste in other filesystems.

XXX: this call should really be in the caller, not in every
XXX: filesystem, but that's a bigger deal to change.

>Audit-Trail:
From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/57005: excessive namecache purging in ufs_rmdir
Date: Tue, 13 Sep 2022 01:12:55 +0000

 On Mon, Sep 12, 2022 at 01:15:00AM +0000, dholland@NetBSD.org wrote:
  > Call cache_purge1(dvp, cnp->cn_name, cnp->cn_namelen, 0). Unless the
  > name has been trashed or something at this stage, in which case the
  > name needs to be copied.
  > 
  > Also merge the change into ulfs_vnops.c and look for additional
  > cutpaste in other filesystems.
  > 
  > XXX: this call should really be in the caller, not in every
  > XXX: filesystem, but that's a bigger deal to change.

 Note that rename also does similar rubbish. (These are already tagged
 'XXX WTF'.)

 -- 
 David A. Holland
 dholland@netbsd.org

From: Rudra Pratap Singh <rudra.singh.offset@gmail.com>
To: gnats-bugs@netbsd.org
Cc: tech-kern@netbsd.org
Subject: Re: kern/57005
Date: Thu, 26 Mar 2026 10:41:18 +0530

 Hi,

 PR kern/57005 reports that ufs_rmdir calls cache_purge(dvp) which
 expands to cache_purge1(dvp, NULL, 0, PURGE_PARENTS|PURGE_CHILDREN),
 purging all namecache entries in the parent directory and its parent,
 when only the single removed entry needs to go.

 The fix is to replace cache_purge(dvp) with cache_purge1(dvp,
 cnp->cn_nameptr, cnp->cn_namelen, 0) which evicts only the specific
 entry being deleted. The same issue exists in ulfs_vnops.c,
 ext2fs_vnops.c, msdosfs_vnops.c and tmpfs_vnops.c and is fixed here
 too.

 dholland noted cn_nameptr might be trashed at that point. I traced the
 call chain: the path buffer is allocated in do_sys_unlinkat
 (vfs_syscalls.c) and freed at line 2977 only after VOP_RMDIR returns.
 None of the calls inside each rmdir function before cache_purge(dvp)
 receive cnp itself as a pointer. Per vnode_if.src, cnp is marked IN
 only for vop_rmdir with no ownership transfer.

 Note: dholland also mentioned rename has the same issue. This patch
 addresses rmdir only; rename can follow separately.






 Index: sys/ufs/ufs/ufs_vnops.c

 ===================================================================

 RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v

 retrieving revision 1.264

 diff -u -r1.264 ufs_vnops.c

 --- sys/ufs/ufs/ufs_vnops.c     22 Jan 2026 03:24:19 -0000      1.264

 +++ sys/ufs/ufs/ufs_vnops.c     25 Mar 2026 23:41:43 -0000

 @@ -1451,7 +1451,7 @@

                 UFS_WAPBL_END(dvp->v_mount);

                 goto out;

         }

 -       cache_purge(dvp);

 +       cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0);

         /*

          * Truncate inode.  The only stuff left in the directory is "." and

          * "..".  The "." reference is inconsequential since we're quashing

 Index: sys/ufs/lfs/ulfs_vnops.c

 ===================================================================

 RCS file: /cvsroot/src/sys/ufs/lfs/ulfs_vnops.c,v

 retrieving revision 1.56

 diff -u -r1.56 ulfs_vnops.c

 --- sys/ufs/lfs/ulfs_vnops.c    27 Mar 2022 16:24:59 -0000      1.56

 +++ sys/ufs/lfs/ulfs_vnops.c    25 Mar 2026 23:41:43 -0000

 @@ -735,7 +735,7 @@

         if (error) {

                 goto out;

         }

 -       cache_purge(dvp);

 +       cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0);

         /*

          * Truncate inode.  The only stuff left in the directory is "." and

          * "..".  The "." reference is inconsequential since we're quashing

 Index: sys/ufs/ext2fs/ext2fs_vnops.c

 ===================================================================

 RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vnops.c,v

 retrieving revision 1.139

 diff -u -r1.139 ext2fs_vnops.c

 --- sys/ufs/ext2fs/ext2fs_vnops.c       29 Jan 2024 18:27:09 -0000      1.139

 +++ sys/ufs/ext2fs/ext2fs_vnops.c       25 Mar 2026 23:41:44 -0000

 @@ -795,7 +795,7 @@

         if (dp->i_e2fs_nlink != EXT2FS_LINK_INF)

                 dp->i_e2fs_nlink--;

         dp->i_flag |= IN_CHANGE;

 -       cache_purge(dvp);

 +       cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0);

         /*

          * Truncate inode.  The only stuff left

          * in the directory is "." and "..".  The

 Index: sys/fs/msdosfs/msdosfs_vnops.c

 ===================================================================

 RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_vnops.c,v

 retrieving revision 1.113

 diff -u -r1.113 msdosfs_vnops.c

 --- sys/fs/msdosfs/msdosfs_vnops.c      11 Sep 2024 00:27:54 -0000      1.113

 +++ sys/fs/msdosfs/msdosfs_vnops.c      25 Mar 2026 23:41:44 -0000

 @@ -925,7 +925,7 @@

          * directory.  Since dos filesystems don't do this we just purge

          * the name cache and let go of the parent directory denode.

          */

 -       cache_purge(dvp);

 +       cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0);

         /*

          * Truncate the directory that is being deleted.

          */

 Index: sys/fs/tmpfs/tmpfs_vnops.c

 ===================================================================

 RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_vnops.c,v

 retrieving revision 1.150

 diff -u -r1.150 tmpfs_vnops.c

 --- sys/fs/tmpfs/tmpfs_vnops.c  1 Jun 2022 08:42:38 -0000       1.150

 +++ sys/fs/tmpfs/tmpfs_vnops.c  25 Mar 2026 23:41:44 -0000

 @@ -912,7 +912,7 @@

         tmpfs_dir_detach(dnode, de);


         /* Purge the cache for parent. */

 -       cache_purge(dvp);

 +       cache_purge1(dvp, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen, 0);


         /*

          * Destroy the directory entry or replace it with a whiteout.



 --
 Rudra Pratap Singh

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.49 2026/05/14 01:52:41 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.