commit 438ec29437465e0b7e2b831d4452159f83cad0cf
Author: YAMAMOTO Takashi <imuwoto@gmail.com>
Date:   Wed Feb 18 07:56:41 2026 +0000

    zfs: fix "slow rm" issue
    
    * stop commiting zil in zfs_netbsd_reclaim.
    
    * 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 alwasy in-core.
    
    * otoh, zfs_zget_clear makes zil_commit in zfs_netbsd_reclaim 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 divergied
    from the upstream zfs.
    
    PR/59885
    
    https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=59885

diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h b/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h
index 935b4f18d985..128309d233cc 100644
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h
@@ -336,7 +336,6 @@ extern int	zfs_loadvnode(struct mount *, struct vnode *,
     const void *, size_t, const void **);
 extern int	zfs_newvnode(struct mount *, struct vnode *, struct vnode *,
     struct vattr *, kauth_cred_t, void *, size_t *, const void **);
-extern int	zfs_zget_cleaner(zfsvfs_t *, uint64_t, znode_t **);
 #endif
 extern int	zfs_zget(zfsvfs_t *, uint64_t, znode_t **);
 extern int	zfs_rezget(znode_t *);
diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c
index 5bfff41eaba0..7c6032865a91 100644
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vnops.c
@@ -1449,7 +1449,7 @@ zfs_get_done(zgd_t *zgd, int error)
 	 * Release the vnode asynchronously as we currently have the
 	 * txg stopped from syncing.
 	 */
-	VN_RELE_CLEANER(ZTOV(zp), dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
+	VN_RELE_ASYNC(ZTOV(zp), dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
 
 	if (error == 0 && zgd->zgd_bp)
 		zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
@@ -1484,14 +1484,14 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
 	/*
 	 * Nothing to do if the file has been removed
 	 */
-	if (zfs_zget_cleaner(zfsvfs, object, &zp) != 0)
+	if (zfs_zget(zfsvfs, object, &zp) != 0)
 		return (SET_ERROR(ENOENT));
 	if (zp->z_unlinked) {
 		/*
 		 * Release the vnode asynchronously as we currently have the
 		 * txg stopped from syncing.
 		 */
-		VN_RELE_CLEANER(ZTOV(zp),
+		VN_RELE_ASYNC(ZTOV(zp),
 		    dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
 		return (SET_ERROR(ENOENT));
 	}
@@ -5881,14 +5881,6 @@ zfs_netbsd_reclaim(void *v)
 		}
 	}
 
-	/*
-	 * 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);
-
 	if (zp->z_sa_hdl == NULL)
 		zfs_znode_free(zp);
 	else
diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c
index 4d3ab49393d7..d5a132802f5b 100644
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c
@@ -1291,43 +1291,6 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
 	return error;
 }
 
-/*
- * Get a known cached znode, to be used from zil_commit()->zfs_get_data()
- * to resolve log entries.  Doesn't take a reference, will never fail and
- * depends on zfs_vnops.c::zfs_netbsd_reclaim() running a zil_commit()
- * before the znode gets freed.
- */
-int
-zfs_zget_cleaner(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
-{
-	dmu_buf_t *db;
-	sa_handle_t *hdl;
-	dmu_object_info_t doi;
-	znode_t *zp;
-
-	ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num);
-
-	VERIFY(0 == sa_buf_hold(zfsvfs->z_os, obj_num, NULL, &db));
-
-	dmu_object_info_from_db(db, &doi);
-	ASSERT(doi.doi_bonus_type == DMU_OT_SA ||
-	    (doi.doi_bonus_type == DMU_OT_ZNODE &&
-	    doi.doi_bonus_size >= sizeof (znode_phys_t)));
-
-	hdl = dmu_buf_get_user(db);
-	ASSERT3P(hdl, !=, NULL);
-
-	zp = sa_get_userdata(hdl);
-	ASSERT3U(zp->z_id, ==, obj_num);
-
-	sa_buf_rele(db, NULL);
-
-	ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
-
-	*zpp = zp;
-	return (0);
-}
-
 #else /* __NetBSD__ */
 
 int
diff --git a/external/cddl/osnet/sys/sys/vnode.h b/external/cddl/osnet/sys/sys/vnode.h
index fddea6d82088..76fca9cf77e5 100644
--- a/external/cddl/osnet/sys/sys/vnode.h
+++ b/external/cddl/osnet/sys/sys/vnode.h
@@ -172,7 +172,6 @@ do {								      \
 #define	VN_URELE(v)	vput(v)
 #undef VN_RELE_ASYNC
 #define VN_RELE_ASYNC(vp, taskq) 	vrele_async((vp))
-#define VN_RELE_CLEANER(vp, taskq)	/* nothing */
 
 #define	vnevent_create(vp, ct)			do { } while (0)
 #define	vnevent_link(vp, ct)			do { } while (0)
