NetBSD Problem Report #59885
From www@netbsd.org Sat Jan 3 21:45:26 2026
Return-Path: <www@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)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
client-signature RSA-PSS (2048 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id E70BA1A923F
for <gnats-bugs@gnats.NetBSD.org>; Sat, 3 Jan 2026 21:45:25 +0000 (UTC)
Message-Id: <20260103214524.50D311A9241@mollari.NetBSD.org>
Date: Sat, 3 Jan 2026 21:45:24 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: zfs: unlink/rm is slow to delete last link because it always zil_commits
X-Send-Pr-Version: www-1.0
>Number: 59885
>Category: kern
>Synopsis: zfs: unlink/rm is slow to delete last link because it always zil_commits
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: needs-pullups
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Jan 03 21:50:00 +0000 2026
>Closed-Date:
>Last-Modified: Sun Mar 22 13:20:01 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11, 10, 9, ...
>Organization:
The NetZFS Slowdowndation, Inc.
>Environment:
>Description:
We have a local change to zfs to commit the zil whenever a zfs
vnode is reclaimed, which usually happens when deleting the
last link to a file:
/*
* Operation zfs_znode.c::zfs_zget_cleaner() depends on this
* zil_commit() as a barrier to guarantee the znode cannot
* get freed before its log entries are resolved.
*/
if (zfsvfs->z_log)
zil_commit(zfsvfs->z_log, zp->z_id);
This is required because the logic to write data for file the
to the log (zfs_get_data), queued up by past writes to the
file, relies on acquiring a reference to the vnode as indexed
by the zfs object id (equivalent of inode number) and using the
struct znode before it is freed.
That logic might run after the vnode has gone through
VOP_RECLAIM, but NetBSD's vnode life cycle treats reclamation
as final and forbids acquiring new references or even looking
up the vnode by its object id via vcache(9), and
zfs_netbsd_reclaim unconditionally frees the struct znode with
zfs_znode_free immediately afterward (all paths out of
zfs_zinactive go, either directly or via zfs_rmnode and
sometimes then via zfs_znode_delete, through zfs_znode_free):
if (zp->z_sa_hdl == NULL)
zfs_znode_free(zp);
else
zfs_zinactive(zp);
Committing the zil first avoids this trouble. But committing
the zil is costly (requires writing all pending transactions to
disk and flushing the disk cache and updating root pointers and
so on), much costlier than just logging a file operation like
unlink.
And removing the last link to a file causes its vnode to be
reclaimed synchronously, essentially every rm(1) or equivalent
(in the absence of multiple hard links to a file) triggers this
logic, making it very slow.
>How-To-Repeat:
rm -rf /large/directory/tree
>Fix:
It was a huge improvement to the reliability and
maintainability of NetBSD's vnode life cycle that we began to
forbid reviving vnodes from the dead about a decade ago, so
reversing that decision is a non-starter.
But perhaps we can add a reference count to the znode itself,
when it is pending in a log transaction for zfs_get_data later,
so that it is only freed after both zfs_netbsd_reclaim _and_
zfs_get_data are done with it. Note that the only use that
zfs_get_data makes of the _vnode_ is to release a reference
(which we have made into a no-op because it is taking that
`reference' only during reclamation when acquiring new vnode
references is forbidden).
This will also require making sure the object id is not
recycled too early -- possibly by some combination of
ZFS_OBJ_HOLD_ENTER and ZFS_TEARDOWN_INACTIVE_ENTER/EXIT_READ,
not sure.
>Release-Note:
>Audit-Trail:
From: "YAMAMOTO Takashi" <yamt@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/59885 CVS commit: src/sys/kern
Date: Sun, 22 Mar 2026 13:03:26 +0000
Module Name: src
Committed By: yamt
Date: Sun Mar 22 13:03:26 UTC 2026
Modified Files:
src/sys/kern: vfs_mount.c
Log Message:
dounmount/vfs_insmntque: allow vcache_get during VFS_UNMOUNT
we currently have assertions to prevent file systems from
populating its vnode cache during VFS_UNMOUNT. this commit
relaxes the assertions a bit to allow vcache_get during
VFS_UNMOUNT. although VFS_UNMOUNT should still eventually
drain the vnode cache for the mount, this commit allows it
to populate its vnode cache temporarily.
this is for zfs, which sometimes need to access znode when
committing the log. (zfs_get_data) a forthcoming zfs change
will depend on this change.
PR/59885
https://gnats.netbsd.org/59885
discussed on tech-kern.
https://mail-index.netbsd.org/tech-kern/2026/02/20/msg030817.html
To generate a diff of this commit:
cvs rdiff -u -r1.110 -r1.111 src/sys/kern/vfs_mount.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: open->needs-pullups
State-Changed-By: yamt@NetBSD.org
State-Changed-When: Sun, 22 Mar 2026 13:15:19 +0000
State-Changed-Why:
pullup-11. i haven't checked earlier branches.
From: "YAMAMOTO Takashi" <yamt@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/59885 CVS commit: src/external/cddl/osnet/dist/uts/common/fs/zfs
Date: Sun, 22 Mar 2026 13:10:57 +0000
Module Name: src
Committed By: yamt
Date: Sun Mar 22 13:10:57 UTC 2026
Modified Files:
src/external/cddl/osnet/dist/uts/common/fs/zfs: zfs_vfsops.c
zfs_vnops.c zfs_znode.c
src/external/cddl/osnet/dist/uts/common/fs/zfs/sys: zfs_znode.h
Log Message:
zfs: fix "slow rm" issue
* stop commiting zil in zfs_netbsd_reclaim and other operations
in vnode reclaim path.
* retire zfs_zget_cleaner/VN_RELE_CLEANER.
instead, just use normal zfs_zget and vrele_async.
note that these two changes depend on each other:
* zfs_zget_cleaner relies on zil_commit in zfs_netbsd_reclaim to
ensure that the znode referenced by TX_WRITE itx is always in-core.
* otoh, zfs_zget_clear makes zil_commit in the vnode reclaim path
possible. that is, zfs_netbsd_reclaim (VOP_RECLAIM) is called with
the vnode in VS_RECLAIMING state, which would make vcache_vget
block.
if the vnode being reclaimed happened to have TX_WRITE itx on the
zil, it deadlocks.
an alternative would be to make the upper layer (vfs_vnode.c) retain
unlinked vnodes for a while. (a bit longer than the 5 sec txg commit
interval should be enough.) eg. by making zfs_netbsd_inactive report
a_recycle = 0. but i guess it's better to remove
zfs_zget_cleaner/VN_RELE_CLEANER to to keep the code less diverged
from the upstream zfs.
also, this commit makes zfs_umount retry vflush a bit.
it's necessary because, for some reasons, during unmount, zil_close
commits the log, which can load some referenced vnodes back to the
cache. i don't understand why zil_close needs to commit the log
when we are syncing txg for unmount anyway. although it might be
possible to avoid the zil commit at all, probably this change
is less invasive than that. this logic is partly from J. Hannken-Illjes.
PR/59885
https://gnats.netbsd.org/59885
discussed on tech-kern.
https://mail-index.netbsd.org/tech-kern/2026/02/20/msg030817.html
To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 \
src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c
cvs rdiff -u -r1.91 -r1.92 \
src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c
cvs rdiff -u -r1.35 -r1.36 \
src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c
cvs rdiff -u -r1.9 -r1.10 \
src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 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.