diff --git a/external/cddl/osnet/dist/uts/common/fs/zfs/arc.c b/external/cddl/osnet/dist/uts/common/fs/zfs/arc.c index 44fee141aecf..c89a800b8d60 100644 --- a/external/cddl/osnet/dist/uts/common/fs/zfs/arc.c +++ b/external/cddl/osnet/dist/uts/common/fs/zfs/arc.c @@ -287,10 +287,6 @@ int arc_procfd; #define buf_init arc_buf_init #define freemem uvm_availmem(false) #define minfree uvmexp.freemin -#define desfree uvmexp.freetarg -#define zfs_arc_free_target desfree -#define lotsfree (desfree * 2) -#define availrmem desfree #define swapfs_minfree 0 #define swapfs_reserve 0 #undef curproc @@ -387,6 +383,7 @@ int zfs_arc_grow_retry = 0; int zfs_arc_shrink_shift = 0; int zfs_arc_p_min_shift = 0; uint64_t zfs_arc_average_blocksize = 8 * 1024; /* 8KB */ +u_int zfs_arc_free_target = 0; /* Absolute min for arc min / max is 16MB. */ static uint64_t arc_abs_min = 16 << 20; @@ -394,8 +391,6 @@ static uint64_t arc_abs_min = 16 << 20; boolean_t zfs_compressed_arc_enabled = B_TRUE; #if defined(__FreeBSD__) && defined(_KERNEL) -u_int zfs_arc_free_target = 0; - static int sysctl_vfs_zfs_arc_free_target(SYSCTL_HANDLER_ARGS); static int sysctl_vfs_zfs_arc_meta_limit(SYSCTL_HANDLER_ARGS); static int sysctl_vfs_zfs_arc_max(SYSCTL_HANDLER_ARGS); @@ -465,7 +460,103 @@ SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_meta_limit, CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_RW, 0, sizeof(uint64_t), sysctl_vfs_zfs_arc_meta_limit, "QU", "ARC metadata limit"); -#endif +#endif /* __FreeBSD__ && _KERNEL */ + +#if defined(__NetBSD__) && defined(_KERNEL) +static int sysctl_vfs_zfs_arc_free_target(SYSCTLFN_PROTO); +static int sysctl_vfs_zfs_arc_meta_limit(SYSCTLFN_PROTO); +static int sysctl_vfs_zfs_arc_max(SYSCTLFN_PROTO); +static int sysctl_vfs_zfs_arc_min(SYSCTLFN_PROTO); + +static void +arc_free_target_init(void *unused __unused) +{ + + zfs_arc_free_target = uvmexp.freetarg; +} + +SYSCTL_SETUP(sysctl_vfs_zfs_arc_setup, "sysctl vfs.zfs_arc subtree setup") +{ + const struct sysctlnode *rnode = NULL; + + /* vfs.zfs subtree */ + sysctl_createv(clog, 0, NULL, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "zfs", + SYSCTL_DESCR("zfs"), + NULL, 0, NULL, 0, + CTL_VFS, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, + "arc_free_target", + SYSCTL_DESCR("Desired number of free pages below which " + "ARC triggers reclaim"), + sysctl_vfs_zfs_arc_free_target, 0, + &zfs_arc_free_target, sizeof(zfs_arc_free_target), + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, + "compressed_arc_enabled", + SYSCTL_DESCR("Enable compressed ARC buffers"), + NULL, 0, &zfs_compressed_arc_enabled, sizeof(zfs_compressed_arc_enabled), + CTL_CREATE, CTL_EOL); + + /* vfs.zfs.arc subtree */ + sysctl_createv(clog, 0, &rnode, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "arc", + SYSCTL_DESCR("zfs ARC subtree"), + NULL, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READONLY, + CTLTYPE_QUAD, "average_blocksize", + SYSCTL_DESCR("Target average block size"), + NULL, 0, &zfs_arc_average_blocksize, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_QUAD, + "meta_limit", + SYSCTL_DESCR("ARC metadata limit"), + sysctl_vfs_zfs_arc_meta_limit, 0, + &zfs_arc_meta_limit, sizeof(zfs_arc_meta_limit), + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_QUAD, + "meta_min", + SYSCTL_DESCR("ARC metadata minimum"), + NULL, 0, &zfs_arc_meta_min, sizeof(zfs_arc_meta_min), + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_QUAD, + "min", + SYSCTL_DESCR("Minimum ARC size in bytes"), + sysctl_vfs_zfs_arc_min, 0, + &zfs_arc_min, sizeof(zfs_arc_min), + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_QUAD, + "max", + SYSCTL_DESCR("Maximum ARC size in bytes"), + sysctl_vfs_zfs_arc_max, 0, + &zfs_arc_max, sizeof(zfs_arc_max), + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, + "shrink_shift", + SYSCTL_DESCR("log2(fraction of ARC to reclaim)"), + NULL, 0, &zfs_arc_shrink_shift, sizeof(zfs_arc_shrink_shift), + CTL_CREATE, CTL_EOL); +} +#endif /* __NetBSD__ && _KERNEL */ /* * Note that buffers can be in one of 6 states: @@ -1166,7 +1257,128 @@ sysctl_vfs_zfs_arc_min(SYSCTL_HANDLER_ARGS) return (0); } -#endif +#endif /* __FreeBSD__ && _KERNEL */ + +#if defined(__NetBSD__) && defined(_KERNEL) +static int +sysctl_vfs_zfs_arc_meta_limit(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + uint64_t val; + int error; + + val = *(uint64_t *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return (error); + + if (val <= 0 || val > arc_c_max) + return (EINVAL); + + arc_meta_limit = val; + + *(uint64_t *)rnode->sysctl_data = val; + return (0); +} + +static int +sysctl_vfs_zfs_arc_max(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + uint64_t val; + int error; + + val = *(uint64_t *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return (error); + + if (val < arc_abs_min || val > kmem_size()) + return (EINVAL); + if (val < arc_c_min) + return (EINVAL); + if (zfs_arc_meta_limit > 0 && val < zfs_arc_meta_limit) + return (EINVAL); + + arc_c_max = val; + + arc_c = arc_c_max; + arc_p = (arc_c >> 1); + + if (zfs_arc_meta_limit == 0) { + /* limit meta-data to 1/4 of the arc capacity */ + arc_meta_limit = arc_c_max / 4; + } + + *(uint64_t *)rnode->sysctl_data = arc_c; + return (0); +} + +static int +sysctl_vfs_zfs_arc_min(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + uint64_t val; + int error; + + val = *(uint64_t *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return (error); + + if (val < arc_abs_min || val > arc_c_max) + return (EINVAL); + + arc_c_min = val; + + if (zfs_arc_meta_min == 0) + arc_meta_min = arc_c_min / 2; + + if (arc_c < arc_c_min) + arc_c = arc_c_min; + + *(uint64_t *)rnode->sysctl_data = arc_c_min; + return (0); + +} + +static int +sysctl_vfs_zfs_arc_free_target(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + u_int val; + int error; + + val = *(u_int *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return (error); + + if (val < minfree) + return (EINVAL); + if (val > uvmexp.npages) + return (EINVAL); + + *(u_int *)rnode->sysctl_data = val; + return (0); +} +#endif /* __NetBSD__ && _KERNEL */ #define GHOST_STATE(state) \ ((state) == arc_mru_ghost || (state) == arc_mfu_ghost || \ @@ -3902,6 +4114,14 @@ arc_available_memory(void) free_memory_reason_t r = FMR_UNKNOWN; #ifdef _KERNEL + if (__predict_false(zfs_arc_free_target == 0)) { + /* + * Re-initialise if arc_free_target_init() was called + * before virtual-memory was fully initialised. + */ + arc_free_target_init(NULL); + } + if (needfree > 0) { n = PAGESIZE * (-needfree); if (n < lowest) { @@ -6074,6 +6294,9 @@ arc_init(void) mutex_init(&arc_dnlc_evicts_lock, NULL, MUTEX_DEFAULT, NULL); cv_init(&arc_dnlc_evicts_cv, NULL, CV_DEFAULT, NULL); #endif +#if defined(__NetBSD__) && defined(_KERNEL) + arc_free_target_init(NULL); +#endif /* Convert seconds to clock ticks */ arc_min_prefetch_lifespan = 1 * hz;