From 0b4ff90f9b77df7d53117ef409d1a6264f4b4feb Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 14 Jun 2024 09:07:03 -0600 Subject: [PATCH] Make txg_wait_synced conditional in zfsvfs_teardown, for FreeBSD This applies the same change in #9115 to FreeBSD. This was actually the old behavior in FreeBSD 12; it only regressed when FreeBSD support was added to OpenZFS. As far as I can tell, the timeline went like this: * Illumos's zfsvfs_teardown used an unconditional txg_wait_synced * Illumos added the dirty data check [^4] * FreeBSD merged in Illumos's conditional check [^3] * OpenZFS forked from Illumos * OpenZFS removed the dirty data check in #7795 [^5] * @mattmacy forked the OpenZFS repo and began to add FreeBSD support * OpenZFS PR #9115[^1] recreated the same dirty data check that Illumos used, in slightly different form. At this point the OpenZFS repo did not yet have multi-OS support. * Matt Macy merged in FreeBSD support in #8987[^2] , but it was based on slightly outdated OpenZFS code. In my local testing, this vastly improves the reboot speed of a server with a large pool that has 1000 datasets and is resilvering an HDD. [^1]: https://github.com/openzfs/zfs/pull/9115 [^2]: https://github.com/openzfs/zfs/pull/8987 [^3]: https://github.com/freebsd/freebsd-src/commit/10b9d77bf1ccf2f3affafa6261692cb92cf7e992 [^4]: https://github.com/illumos/illumos-gate/commit/5aaeed5c617553c4cec6328c1f4c19079a5a495a [^5]: https://github.com/openzfs/zfs/pull/7795 Sponsored by: Axcient Signed-off-by: Alan Somers --- module/os/freebsd/zfs/zfs_vfsops.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index a972c720dfdb..8e8bd608c0f7 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -1649,9 +1649,18 @@ zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting) zfs_unregister_callbacks(zfsvfs); /* - * Evict cached data + * Evict cached data. We must write out any dirty data before + * disowning the dataset. */ - if (!zfs_is_readonly(zfsvfs)) + objset_t *os = zfsvfs->z_os; + boolean_t os_dirty = B_FALSE; + for (int t = 0; t < TXG_SIZE; t++) { + if (dmu_objset_is_dirty(os, t)) { + os_dirty = B_TRUE; + break; + } + } + if (!zfs_is_readonly(zfsvfs) && os_dirty) txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0); dmu_objset_evict_dbufs(zfsvfs->z_os); dd = zfsvfs->z_os->os_dsl_dataset->ds_dir;