From 34632de03f30209b8c722ffbc2eb51b5195228b2 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 18 Aug 2026 09:38:36 -0400 Subject: [PATCH 1/7] loader: init the ZFS control device when preloading libsolaris The --preload-zfs-library option loads libsolaris.so into memory but does not create the in-kernel ZFS control device /dev/zfs. For the ZFS builder that was sufficient, but it means an image whose root filesystem is not zfs (for example a ramfs root) cannot create or import a ZFS data pool at runtime: without /dev/zfs the zpool and zfs commands have no channel to the kernel and zpool create fails with /dev/zfs not found. load_zfs_library_and_mount_zfs_root() already calls zfsdev_init() on the fs=zfs path. Do the same on the preload path so a non-zfs-root image can bring up a ZFS data pool. Behavior for the ZFS builder is unchanged (it gets an additional, idempotent control-device init before it runs its own commands). --- loader.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/loader.cc b/loader.cc index 616d4c32b..37d6689bb 100644 --- a/loader.cc +++ b/loader.cc @@ -605,9 +605,28 @@ void* do_main_thread(void *_main_args) } } - //This option is only used by ZFS builder + // Preload the ZFS library WITHOUT mounting a ZFS root. Used by the ZFS + // builder, and by any image whose root filesystem is NOT zfs (e.g. + // fs=ramfs) but which still wants to create/import a ZFS *data* pool at + // runtime. In the latter case libsolaris.so alone is not enough: the + // in-kernel ZFS control device /dev/zfs must also exist, otherwise + // zpool/zfs commands cannot talk to the kernel and "zpool create" fails + // with "/dev/zfs not found". load_zfs_library_and_mount_zfs_root() calls + // zfsdev_init() for the fs=zfs path; do the same here for the no-root + // path so a ramfs-root image can bring up a ZFS data pool. + // + // The ZFS builder boots with --noinit and initializes the control device + // itself from its own bootfs tool (via libsolaris.so's exported + // zfsdev_init), so only bring the device up here when the image runs its + // normal init. That avoids creating the "zfs" device twice (the loader + // copy of the init guard is distinct from the libsolaris.so copy). if (opt_preload_zfs_library) { - if (load_fs_library(libsolaris_path)) { + bool init_zfsdev = opt_init; + if (load_fs_library(libsolaris_path, [init_zfsdev]() { + if (init_zfsdev) + zfsdev::zfsdev_init(); + return 0; + })) { fprintf(stderr, "Failed to preload ZFS library. Powering off.\n"); osv::poweroff(); } From 42afe7e50d39d3d2b3206cf5e6cecb31ae65f2ec Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 24 Aug 2026 16:45:10 +0000 Subject: [PATCH 2/7] loader: load ZFS libsolaris with RTLD_GLOBAL so userspace tools resolve The ZFS userspace tools (zpool.so, zfs.so) link only against libzfs.so and libc and resolve their nvpair/nvlist/fnvlist symbols against libsolaris.so at runtime. Loading libsolaris with RTLD_LOCAL left those exports out of the global symbol scope, so a later dlopen of zpool.so reported dozens of ignored missing nvpair symbols and then could not create the ZFS control device (/dev/zfs not found), blocking any runtime zpool/zfs command. Load the ZFS kernel library with RTLD_GLOBAL so the tools resolve correctly. --- loader.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/loader.cc b/loader.cc index 37d6689bb..baab7a25f 100644 --- a/loader.cc +++ b/loader.cc @@ -480,8 +480,15 @@ static void stop_all_remaining_app_threads() static int load_fs_library(const char* fs_library_path, std::function on_load_fun = nullptr) { - // Load and initialize filesystem driver - if (dlopen(fs_library_path, RTLD_LAZY)) { + // Load and initialize filesystem driver. RTLD_GLOBAL is load-bearing for + // the ZFS case: the userspace tools (/zpool.so, /zfs.so) are linked only + // against libzfs.so + libc and resolve their nvpair/nvlist/fnvlist symbols + // (~60 of them) against libsolaris.so at runtime. Loading libsolaris with + // RTLD_LOCAL leaves those symbols invisible to a later dlopen of the tools, + // so zpool.so loads with dozens of "ignoring missing symbol nvpair_*" and + // then cannot talk to the kernel ("/dev/zfs not found"). RTLD_GLOBAL puts + // libsolaris's exports in the global scope so the tools resolve correctly. + if (dlopen(fs_library_path, RTLD_LAZY | RTLD_GLOBAL)) { if (on_load_fun) { return on_load_fun(); } else { From 7cf27dcd09819526b58f4462d9249540c19b261d Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 24 Aug 2026 17:09:08 +0000 Subject: [PATCH 3/7] loader: create /etc/mnttab when preloading ZFS for a runtime data pool The ZFS userspace tools consult /etc/mnttab; on a non-ZFS root (e.g. ramfs) nothing creates it, so a runtime zpool create/import from a ramfs-root image found no mnttab. Mirror the in-tree zfs bench harness (zfsdev_init + creat /etc/mnttab) in the preload path so a ramfs-root image can bring up a ZFS data pool on a local disk. --- loader.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/loader.cc b/loader.cc index baab7a25f..ce0e910a2 100644 --- a/loader.cc +++ b/loader.cc @@ -63,6 +63,8 @@ #include "libc/network/__dns.hh" #include #include +#include +#include #include using namespace osv; @@ -630,8 +632,19 @@ void* do_main_thread(void *_main_args) if (opt_preload_zfs_library) { bool init_zfsdev = opt_init; if (load_fs_library(libsolaris_path, [init_zfsdev]() { - if (init_zfsdev) + if (init_zfsdev) { zfsdev::zfsdev_init(); + // The ZFS userspace tools (zpool/zfs) consult /etc/mnttab; + // on a non-ZFS root (e.g. ramfs) nothing else creates it, so + // an empty one must exist or the tools fail to enumerate + // mounts. Mirror what the in-tree zfs bench harness does + // (zfsdev_init + creat /etc/mnttab) so a runtime zpool + // create/import works from a ramfs-root image. + mkdir("/etc", 0755); + int fd = creat("/etc/mnttab", 0644); + if (fd >= 0) + close(fd); + } return 0; })) { fprintf(stderr, "Failed to preload ZFS library. Powering off.\n"); From 8805a945a22e44f75900e2f54503b507d7107d60 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 24 Aug 2026 17:29:12 +0000 Subject: [PATCH 4/7] loader: preload the ZFS library before the root-mount block dlopen of /usr/lib/fs/libsolaris.so from a bootfs ramfs root fails once the opt_mount block has run its unmount/pivot sequence, which is why the fs=zfs path (which loads libsolaris inside the mount block, before the pivot) worked while a post-mount preload did not. Run the preload before opt_mount so the bootfs path is still resolvable, bringing up the ZFS control device and an empty /etc/mnttab so a ramfs-root image can create a ZFS data pool at runtime. --- loader.cc | 72 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/loader.cc b/loader.cc index ce0e910a2..1aa7657f5 100644 --- a/loader.cc +++ b/loader.cc @@ -561,6 +561,40 @@ void* do_main_thread(void *_main_args) } boot_time.event("drivers loaded"); + // Preload the ZFS library WITHOUT mounting a ZFS root, BEFORE the root-mount + // block. Used by the ZFS builder, and by any image whose root filesystem + // is NOT zfs (e.g. fs=ramfs) but which still wants to create/import a ZFS + // *data* pool at runtime. This must run before opt_mount's unmount/pivot + // dance: after that, dlopen of /usr/lib/fs/libsolaris.so from the bootfs + // ramfs fails to open (the path is no longer resolvable), which is why the + // fs=zfs path (which dlopens libsolaris inside the mount block, before the + // pivot) works while a later preload did not. libsolaris.so alone is not + // enough: the in-kernel ZFS control device /dev/zfs must also exist, else + // zpool/zfs commands fail with "/dev/zfs not found". So also run + // zfsdev_init() (as load_zfs_library_and_mount_zfs_root does for fs=zfs) + // and create an empty /etc/mnttab (as the in-tree zfs bench harness does) + // so a ramfs-root image can bring up a ZFS data pool on a local disk. + // + // The ZFS builder boots with --noinit and initializes the control device + // itself from its own bootfs tool, so only bring the device up here when + // the image runs its normal init. + if (opt_preload_zfs_library) { + bool init_zfsdev = opt_init; + if (load_fs_library(libsolaris_path, [init_zfsdev]() { + if (init_zfsdev) { + zfsdev::zfsdev_init(); + mkdir("/etc", 0755); + int fd = creat("/etc/mnttab", 0644); + if (fd >= 0) + close(fd); + } + return 0; + })) { + fprintf(stderr, "Failed to preload ZFS library. Powering off.\n"); + osv::poweroff(); + } + } + if (opt_mount) { unmount_devfs(); @@ -614,43 +648,7 @@ void* do_main_thread(void *_main_args) } } - // Preload the ZFS library WITHOUT mounting a ZFS root. Used by the ZFS - // builder, and by any image whose root filesystem is NOT zfs (e.g. - // fs=ramfs) but which still wants to create/import a ZFS *data* pool at - // runtime. In the latter case libsolaris.so alone is not enough: the - // in-kernel ZFS control device /dev/zfs must also exist, otherwise - // zpool/zfs commands cannot talk to the kernel and "zpool create" fails - // with "/dev/zfs not found". load_zfs_library_and_mount_zfs_root() calls - // zfsdev_init() for the fs=zfs path; do the same here for the no-root - // path so a ramfs-root image can bring up a ZFS data pool. - // - // The ZFS builder boots with --noinit and initializes the control device - // itself from its own bootfs tool (via libsolaris.so's exported - // zfsdev_init), so only bring the device up here when the image runs its - // normal init. That avoids creating the "zfs" device twice (the loader - // copy of the init guard is distinct from the libsolaris.so copy). - if (opt_preload_zfs_library) { - bool init_zfsdev = opt_init; - if (load_fs_library(libsolaris_path, [init_zfsdev]() { - if (init_zfsdev) { - zfsdev::zfsdev_init(); - // The ZFS userspace tools (zpool/zfs) consult /etc/mnttab; - // on a non-ZFS root (e.g. ramfs) nothing else creates it, so - // an empty one must exist or the tools fail to enumerate - // mounts. Mirror what the in-tree zfs bench harness does - // (zfsdev_init + creat /etc/mnttab) so a runtime zpool - // create/import works from a ramfs-root image. - mkdir("/etc", 0755); - int fd = creat("/etc/mnttab", 0644); - if (fd >= 0) - close(fd); - } - return 0; - })) { - fprintf(stderr, "Failed to preload ZFS library. Powering off.\n"); - osv::poweroff(); - } - } + // (ZFS preload moved earlier, before the root-mount block.) #if CONF_networking_stack bool has_if = false; From 06d1738cebf36327b0d85aa4d432d3c4aa79388e Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 24 Aug 2026 17:49:40 +0000 Subject: [PATCH 5/7] modules/open_zfs: carry the libsolaris.so manifest entry on the provider libsolaris.so's manifest entry lived only on the zfs placeholder module, but the placeholder is replaced by its required provider (open_zfs) during module resolution, so the entry was dropped and libsolaris.so never landed in usr.manifest. For a bootfs-populated fs=ramfs image (whose bootfs is built from usr.manifest) this silently omitted libsolaris.so, so --preload-zfs-library could not dlopen /usr/lib/fs/libsolaris.so and no runtime ZFS data pool could be created. Generate the manifest entry on the open_zfs provider module itself (at import, matching zfs-tools) so it survives resolution and is packed. --- modules/open_zfs/module.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/open_zfs/module.py b/modules/open_zfs/module.py index 268bada2b..4cc9babcc 100644 --- a/modules/open_zfs/module.py +++ b/modules/open_zfs/module.py @@ -1,4 +1,5 @@ from osv.modules import api +import os # The `open_zfs` module PROVIDES the `zfs` capability for the vendored OpenZFS # 2.4.x implementation (conf_zfs=openzfs), analogous to how @@ -7,7 +8,18 @@ # normal parent-tracked source in modules/open_zfs/osv, and a single small patch # for the ~15 edited upstream files in modules/open_zfs/patches (applied at build # time). The kernel objects are linked into libsolaris.so by the top-level Makefile, which for -# conf_zfs=openzfs includes modules/open_zfs/open_zfs_sources.mk. This module -# carries no extra manifest of its own; the `zfs` placeholder module selects it -# via conf_zfs. +# conf_zfs=openzfs includes modules/open_zfs/open_zfs_sources.mk. +# +# libsolaris.so must be listed by the module that actually provides ZFS, not by +# the `zfs` placeholder: the placeholder is replaced by its required provider +# during module resolution, so a manifest carried only by the placeholder is +# dropped and libsolaris.so never lands in usr.manifest. That silently omits +# it from a bootfs-populated (fs=ramfs) image, where --preload-zfs-library then +# fails to dlopen /usr/lib/fs/libsolaris.so. Generate the manifest entry here +# (written at import time, matching zfs-tools) so the provider carries it. +_manifest = os.path.join(os.path.dirname(__file__), 'usr.manifest') +with open(_manifest, 'w') as f: + f.write('[manifest]\n') + f.write('/usr/lib/fs/libsolaris.so: libsolaris.so\n') + provides = ['zfs'] From 094a9e38d1ceb1771cbb9d87a19f5b9b79f524d2 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 25 Aug 2026 03:49:34 +0000 Subject: [PATCH 6/7] zfs(openzfs): nanosecond-precise cv_timedwait_hires so ZIL commits coalesce cv_timedwait_hires converted its nanosecond deadline to ddi_get_lbolt ticks and called the tick-granular cv_timedwait. At hz=1000 a tick is 1ms, so the ZIL commit-batch window (zil_commit_waiter_timeout sizes it as a small fraction of the last log-write latency, typically a few hundred microseconds) rounded down to zero. Concurrent fsyncs then never coalesced into one log-write-block plus one device cache flush, so every commit paid its own synchronous flush and sync-commit write throughput did not scale with concurrency. The old code also passed an absolute CALLOUT_FLAG_ABSOLUTE deadline to a relative-timeout tick API. Add openzfs_cv_timedwait_hires (bsd/porting/netport1.cc), which waits the true remaining nanoseconds via the OSv condvar chrono wait and honors the absolute vs relative flag, and route the OpenZFS SPL cv_timedwait_hires to it. The ZIL batch window is now respected and concurrent commits coalesce. --- bsd/porting/netport1.cc | 28 +++++++++++++++++++ .../cddl/compat/opensolaris/sys/kcondvar.h | 6 ++++ .../osv/include/os/osv/spl/sys/condvar.h | 23 ++++++++------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/bsd/porting/netport1.cc b/bsd/porting/netport1.cc index 74a9f7ce5..6abb70129 100644 --- a/bsd/porting/netport1.cc +++ b/bsd/porting/netport1.cc @@ -90,3 +90,31 @@ int openzfs_cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t abstime) auto ret = cv->wait(mutex, std::chrono::nanoseconds(ticks2ns(delta))); return ret == ETIMEDOUT ? -1 : 0; } + +// OpenZFS cv_timedwait_hires: a NANOSECOND-precision timed wait. The ZIL +// commit path (zil_commit_waiter_timeout) sizes its commit-batch window as a +// small fraction (~10%) of the last log-write latency -- typically hundreds of +// microseconds. Routing that through a tick-granular wait (hz=1000 -> 1ms +// ticks) rounds a sub-millisecond window down to zero, so concurrent fsyncs +// never coalesce into one log write + one device cache flush; every commit +// pays its own synchronous flush. Wait the exact nanosecond delay instead. +// `deadline_ns` is an absolute gethrtime() (uptime-ns) value when +// CALLOUT_FLAG_ABSOLUTE is set, otherwise a relative nanosecond delay; either +// way we wait the true remaining nanoseconds so the ZIL batch window is +// honored and commits coalesce. +OSV_LIBSOLARIS_API +int openzfs_cv_timedwait_hires(kcondvar_t *cv, mutex_t *mutex, + long long deadline_ns, int absolute) +{ + long long delta_ns = deadline_ns; + if (absolute) { + u64 now_ns = std::chrono::duration_cast + (osv::clock::uptime::now().time_since_epoch()).count(); + delta_ns = deadline_ns - (long long)now_ns; + } + if (delta_ns <= 0) { + return -1; + } + auto ret = cv->wait(mutex, std::chrono::nanoseconds(delta_ns)); + return ret == ETIMEDOUT ? -1 : 0; +} diff --git a/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h b/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h index dc08f6939..0531385b3 100644 --- a/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h +++ b/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h @@ -50,6 +50,12 @@ typedef enum { int cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t tmo); // OpenZFS variant: absolute deadline (see bsd/porting/netport1.cc). int openzfs_cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t abstime); +// OpenZFS hires variant: nanosecond-precision timed wait. deadline_ns is an +// absolute gethrtime() (uptime-ns) deadline when absolute!=0, else a relative +// nanosecond delay. Used by cv_timedwait_hires so the ZIL commit-batch window +// (sub-millisecond) is honored instead of being rounded to zero by ticks. +int openzfs_cv_timedwait_hires(kcondvar_t *cv, mutex_t *mutex, + long long deadline_ns, int absolute); #ifdef __cplusplus } diff --git a/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h b/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h index 1d15ea4a6..7e384df5b 100644 --- a/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h +++ b/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h @@ -50,16 +50,19 @@ static inline int cv_timedwait_hires(kcondvar_t *cvp, mutex_t *mp, long long tim, long long res __attribute__((unused)), int flag) { - clock_t ticks; - - if (flag == 0) { - /* Relative time: add current hrtime */ - tim += gethrtime(); - } - - /* Convert absolute hrtime (nanoseconds) to tick deadline */ - ticks = (clock_t)(tim / (1000000000LL / hz)); - return (cv_timedwait(cvp, mp, ticks)); + /* + * Nanosecond-precise wait. Tick granularity (1ms at hz=1000) would + * round the sub-millisecond ZIL commit-batch window + * (zil_commit_waiter_timeout sizes it as ~10% of the last log-write + * latency) down to zero, so concurrent fsyncs never coalesce into one + * log write plus one device cache flush and every commit pays its own + * synchronous flush. `tim` is an absolute gethrtime() (uptime-ns) + * deadline when the flag (ABSOLUTE) is nonzero, else a relative + * nanosecond delay. + */ + extern int openzfs_cv_timedwait_hires(kcondvar_t *, mutex_t *, + long long, int); + return (openzfs_cv_timedwait_hires(cvp, mp, tim, flag != 0)); } #define cv_timedwait_sig_hires cv_timedwait_hires From 25bde6b9622e98d12a9fad7d347ad8be98944ca6 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 25 Aug 2026 17:36:59 +0000 Subject: [PATCH 7/7] zfs(openzfs): use wall-clock base for cv_timedwait_hires absolute deadline The absolute deadline passed to cv_timedwait_hires is built from gethrtime(), which on OSv is clock_gettime(CLOCK_UPTIME) where CLOCK_UPTIME is #defined to CLOCK_REALTIME, i.e. a wall-clock nanosecond value (order 1.7e18 ns). The previous code subtracted uptime now (order 1e11 ns at boot) from that wall-clock deadline, producing a delay of order 1.7e18 ns (more than fifty years). The ZIL commit-batch timeout timer was therefore armed effectively forever and never fired; a backend that also missed its log-write-completion signal then waited on the condition variable permanently and stalled every later committer behind it. Subtract wall-clock now to match gethrtime()'s clock base, so the timed wait honors the true sub-millisecond commit-batch window. The relative branch already used the wall clock; only the absolute branch was wrong. Comments in netport1.cc, kcondvar.h and the SPL condvar.h that described the deadline as uptime are corrected to wall-clock. --- bsd/porting/netport1.cc | 9 +++++++-- bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h | 2 +- modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bsd/porting/netport1.cc b/bsd/porting/netport1.cc index 6abb70129..af30b7bb4 100644 --- a/bsd/porting/netport1.cc +++ b/bsd/porting/netport1.cc @@ -98,7 +98,7 @@ int openzfs_cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t abstime) // ticks) rounds a sub-millisecond window down to zero, so concurrent fsyncs // never coalesce into one log write + one device cache flush; every commit // pays its own synchronous flush. Wait the exact nanosecond delay instead. -// `deadline_ns` is an absolute gethrtime() (uptime-ns) value when +// `deadline_ns` is an absolute gethrtime() (wall-clock, CLOCK_REALTIME) value when // CALLOUT_FLAG_ABSOLUTE is set, otherwise a relative nanosecond delay; either // way we wait the true remaining nanoseconds so the ZIL batch window is // honored and commits coalesce. @@ -108,8 +108,13 @@ int openzfs_cv_timedwait_hires(kcondvar_t *cv, mutex_t *mutex, { long long delta_ns = deadline_ns; if (absolute) { + // gethrtime() is clock_gettime(CLOCK_UPTIME), and CLOCK_UPTIME is + // #defined to CLOCK_REALTIME, so an absolute deadline is a wall-clock + // nanosecond value. Subtract wall-clock now (not uptime, which is + // ~1e11 ns at boot and would leave a ~1.7e18 ns / >50 year delay, + // arming the ZIL commit-batch timeout effectively forever). u64 now_ns = std::chrono::duration_cast - (osv::clock::uptime::now().time_since_epoch()).count(); + (osv::clock::wall::now().time_since_epoch()).count(); delta_ns = deadline_ns - (long long)now_ns; } if (delta_ns <= 0) { diff --git a/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h b/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h index 0531385b3..f80f9339c 100644 --- a/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h +++ b/bsd/sys/cddl/compat/opensolaris/sys/kcondvar.h @@ -51,7 +51,7 @@ int cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t tmo); // OpenZFS variant: absolute deadline (see bsd/porting/netport1.cc). int openzfs_cv_timedwait(kcondvar_t *cv, mutex_t *mutex, clock_t abstime); // OpenZFS hires variant: nanosecond-precision timed wait. deadline_ns is an -// absolute gethrtime() (uptime-ns) deadline when absolute!=0, else a relative +// absolute gethrtime() (wall-clock, CLOCK_REALTIME) deadline when absolute!=0, else a relative // nanosecond delay. Used by cv_timedwait_hires so the ZIL commit-batch window // (sub-millisecond) is honored instead of being rounded to zero by ticks. int openzfs_cv_timedwait_hires(kcondvar_t *cv, mutex_t *mutex, diff --git a/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h b/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h index 7e384df5b..39e8b608c 100644 --- a/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h +++ b/modules/open_zfs/osv/include/os/osv/spl/sys/condvar.h @@ -56,7 +56,7 @@ cv_timedwait_hires(kcondvar_t *cvp, mutex_t *mp, long long tim, * (zil_commit_waiter_timeout sizes it as ~10% of the last log-write * latency) down to zero, so concurrent fsyncs never coalesce into one * log write plus one device cache flush and every commit pays its own - * synchronous flush. `tim` is an absolute gethrtime() (uptime-ns) + * synchronous flush. `tim` is an absolute gethrtime() (wall-clock, CLOCK_REALTIME) * deadline when the flag (ABSOLUTE) is nonzero, else a relative * nanosecond delay. */