]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Restore FreeBSD sysctl processing for arc.min and arc.max
authorAllan Jude <allan@klarasystems.com>
Mon, 16 Aug 2021 15:35:19 +0000 (11:35 -0400)
committerGitHub <noreply@github.com>
Mon, 16 Aug 2021 15:35:19 +0000 (09:35 -0600)
Before OpenZFS 2.0, trying to set the FreeBSD sysctl vfs.zfs.arc_max
to a disallowed value would return an error.
Since the switch, it instead only generates WARN_IF_TUNING_IGNORED

Keep the ability to set the sysctl's specifically to 0, even though
that is less than the minimum, because some tests depend on this.

Also lost, was the ability to set vfs.zfs.arc_max to a value less
than the default vfs.zfs.arc_min at boot time. Restore this as well.

Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Signed-off-by: Allan Jude <allan@klarasystems.com>
Closes #12161

include/os/freebsd/spl/sys/mod_os.h
include/sys/arc.h
include/sys/arc_impl.h
module/os/freebsd/zfs/sysctl_os.c
module/os/linux/zfs/arc_os.c
module/zfs/arc.c

index 5b3b3271e39e9ccefadc72f257d325fc2d9a85c4..5695abee7b858e0718d1eb4a1e39c25670f7a22f 100644 (file)
 #define        param_set_arc_long_args(var) \
     CTLTYPE_ULONG, &var, 0, param_set_arc_long, "LU"
 
+#define        param_set_arc_min_args(var) \
+    CTLTYPE_ULONG, &var, 0, param_set_arc_min, "LU"
+
+#define        param_set_arc_max_args(var) \
+    CTLTYPE_ULONG, &var, 0, param_set_arc_max, "LU"
+
 #define        param_set_arc_int_args(var) \
     CTLTYPE_INT, &var, 0, param_set_arc_int, "I"
 
index 20fa47bd95641a1e5f154b563fef6df38d28c995..afbe65bb1c97f6ecba987c83e2ba1beb90ce1fdb 100644 (file)
@@ -46,6 +46,13 @@ extern "C" {
  */
 #define        ARC_EVICT_ALL   UINT64_MAX
 
+/*
+ * ZFS gets very unhappy when the maximum ARC size is smaller than the maximum
+ * block size and a larger block is written.  To leave some safety margin, we
+ * limit the minimum for zfs_arc_max to the maximium transaction size.
+ */
+#define        MIN_ARC_MAX     DMU_MAX_ACCESS
+
 #define        HDR_SET_LSIZE(hdr, x) do { \
        ASSERT(IS_P2ALIGNED(x, 1U << SPA_MINBLOCKSHIFT)); \
        (hdr)->b_lsize = ((x) >> SPA_MINBLOCKSHIFT); \
index f99d2911b5df90e1884bd38af9ada9d221a0577f..89be78ce21f13ad469ced62e05db9434a402fdb3 100644 (file)
@@ -1004,6 +1004,8 @@ extern void arc_unregister_hotplug(void);
 
 extern int param_set_arc_long(ZFS_MODULE_PARAM_ARGS);
 extern int param_set_arc_int(ZFS_MODULE_PARAM_ARGS);
+extern int param_set_arc_min(ZFS_MODULE_PARAM_ARGS);
+extern int param_set_arc_max(ZFS_MODULE_PARAM_ARGS);
 
 /* used in zdb.c */
 boolean_t l2arc_log_blkptr_valid(l2arc_dev_t *dev,
index 94124fdcf6c393617d282eee9ce6d3a1b4b34483..5315b60982df90802514972cd3eef1bf254fe03b 100644 (file)
@@ -144,6 +144,55 @@ extern arc_state_t ARC_l2c_only;
 
 /* arc.c */
 
+int
+param_set_arc_max(SYSCTL_HANDLER_ARGS)
+{
+       uint64_t val;
+       int err;
+
+       val = zfs_arc_max;
+       err = sysctl_handle_long(oidp, &val, 0, req);
+       if (err != 0 || req->newptr == NULL)
+               return (SET_ERROR(err));
+
+       if (val != 0 && (val < MIN_ARC_MAX || val <= arc_c_min ||
+           val >= arc_all_memory()))
+               return (SET_ERROR(EINVAL));
+
+       zfs_arc_max = val;
+       arc_tuning_update(B_TRUE);
+
+       /* Update the sysctl to the tuned value */
+       if (val != 0)
+               zfs_arc_max = arc_c_max;
+
+       return (0);
+}
+
+int
+param_set_arc_min(SYSCTL_HANDLER_ARGS)
+{
+       uint64_t val;
+       int err;
+
+       val = zfs_arc_min;
+       err = sysctl_handle_64(oidp, &val, 0, req);
+       if (err != 0 || req->newptr == NULL)
+               return (SET_ERROR(err));
+
+       if (val != 0 && (val < 2ULL << SPA_MAXBLOCKSHIFT || val > arc_c_max))
+               return (SET_ERROR(EINVAL));
+
+       zfs_arc_min = val;
+       arc_tuning_update(B_TRUE);
+
+       /* Update the sysctl to the tuned value */
+       if (val != 0)
+               zfs_arc_min = arc_c_min;
+
+       return (0);
+}
+
 /* legacy compat */
 extern uint64_t l2arc_write_max;       /* def max write size */
 extern uint64_t l2arc_write_boost;     /* extra warmup write */
@@ -278,11 +327,11 @@ param_set_arc_int(SYSCTL_HANDLER_ARGS)
 
 SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_min,
     CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
-    &zfs_arc_min, sizeof (zfs_arc_min), param_set_arc_long, "LU",
+    &zfs_arc_min, sizeof (zfs_arc_min), param_set_arc_min, "LU",
     "min arc size (LEGACY)");
 SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_max,
     CTLTYPE_ULONG | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
-    &zfs_arc_max, sizeof (zfs_arc_max), param_set_arc_long, "LU",
+    &zfs_arc_max, sizeof (zfs_arc_max), param_set_arc_max, "LU",
     "max arc size (LEGACY)");
 
 /* dbuf.c */
index 415cfc281ae8374dde2cb0b749ea4e5fb7d3d259..c3e889d54180e7a84c72edd4eb677747f8c40155 100644 (file)
@@ -371,6 +371,18 @@ param_set_arc_long(const char *buf, zfs_kernel_param_t *kp)
        return (0);
 }
 
+int
+param_set_arc_min(const char *buf, zfs_kernel_param_t *kp)
+{
+       return (param_set_arc_long(buf, kp));
+}
+
+int
+param_set_arc_max(const char *buf, zfs_kernel_param_t *kp)
+{
+       return (param_set_arc_long(buf, kp));
+}
+
 int
 param_set_arc_int(const char *buf, zfs_kernel_param_t *kp)
 {
index 003aacc6c611613b7dfc5d5b589399602bdf8586..a8404182c832c9e5f2c1c8aebbd15dcf3543f422 100644 (file)
@@ -7498,7 +7498,7 @@ arc_tuning_update(boolean_t verbose)
 
        /* Valid range: 64M - <all physical memory> */
        if ((zfs_arc_max) && (zfs_arc_max != arc_c_max) &&
-           (zfs_arc_max >= 64 << 20) && (zfs_arc_max < allmem) &&
+           (zfs_arc_max >= MIN_ARC_MAX) && (zfs_arc_max < allmem) &&
            (zfs_arc_max > arc_c_min)) {
                arc_c_max = zfs_arc_max;
                arc_c = MIN(arc_c, arc_c_max);
@@ -7893,7 +7893,23 @@ arc_init(void)
 
        arc_set_limits(allmem);
 
-#ifndef _KERNEL
+#ifdef _KERNEL
+       /*
+        * If zfs_arc_max is non-zero at init, meaning it was set in the kernel
+        * environment before the module was loaded, don't block setting the
+        * maximum because it is less than arc_c_min, instead, reset arc_c_min
+        * to a lower value.
+        * zfs_arc_min will be handled by arc_tuning_update().
+        */
+       if (zfs_arc_max != 0 && zfs_arc_max >= MIN_ARC_MAX &&
+           zfs_arc_max < allmem) {
+               arc_c_max = zfs_arc_max;
+               if (arc_c_min >= arc_c_max) {
+                       arc_c_min = MAX(zfs_arc_max / 2,
+                           2ULL << SPA_MAXBLOCKSHIFT);
+               }
+       }
+#else
        /*
         * In userland, there's only the memory pressure that we artificially
         * create (see arc_available_memory()).  Don't let arc_c get too
@@ -10965,10 +10981,10 @@ EXPORT_SYMBOL(arc_add_prune_callback);
 EXPORT_SYMBOL(arc_remove_prune_callback);
 
 /* BEGIN CSTYLED */
-ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min, param_set_arc_long,
+ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min, param_set_arc_min,
        param_get_long, ZMOD_RW, "Min arc size");
 
-ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, max, param_set_arc_long,
+ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, max, param_set_arc_max,
        param_get_long, ZMOD_RW, "Max arc size");
 
 ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit, param_set_arc_long,