arc: apply arc_min tunables set before arc_init() has run

Tunables are applied as each parameter is registered, and zfs_arc_min is
registered before zfs_arc_max.  So param_set_arc_min() can run while
arc_c_max is still zero, and its upper bound check rejects every
non-zero value:

    Setting sysctl vfs.zfs.arc.min failed: 22

The value is dropped and the ARC floor falls back to allmem/32.
param_set_arc_max() is not affected, because it tests a lower bound
against arc_c_min, which a zero value satisfies.

Skip the upper bound while arc_c_max is zero and store the raw value.
arc_init() expects this: arc_set_limits() sets both limits, and the
arc_tuning_update() call after it applies zfs_arc_min.

Storing the value exposes a second bug.  The other arc handlers call
arc_tuning_update() unconditionally, so one registered before arc_init()
reaches WARN_IF_TUNING_IGNORED with both limits still zero and reports
the tunable as ignored, even though arc_init() applies it soon after:

    WARNING: ignoring tunable zfs_arc_min (using 0 instead)

Return early from arc_tuning_update() while arc_c_max is zero, which
covers every caller.  Also guard the writeback, so the tunable is not
overwritten with a zero limit.

This is the warning reported in #12504.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Abdelkader Boudih <[email protected]>
Closes #12504
Closes #19008
This commit is contained in:
Abdelkader Boudih authored and GitHub committed 2026-09-03 09:26:36 -07:00
1 parent 5280a08f6b
commit c47591d5da
2 files changed
+7 -3

No files matched your search

+4 -3
View File
@@ -198,7 +198,7 @@ param_set_arc_max(SYSCTL_HANDLER_ARGS)
arc_tuning_update(B_TRUE);
/* Update the sysctl to the tuned value */
if (val != 0)
if (val != 0 && arc_c_max != 0)
zfs_arc_max = arc_c_max;
return (0);
@@ -215,14 +215,15 @@ param_set_arc_min(SYSCTL_HANDLER_ARGS)
if (err != 0 || req->newptr == NULL)
return (SET_ERROR(err));
if (val != 0 && (val < 2ULL << SPA_MAXBLOCKSHIFT || val > arc_c_max))
if (val != 0 && (val < 2ULL << SPA_MAXBLOCKSHIFT ||
(arc_c_max != 0 && 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)
if (val != 0 && arc_c_max != 0)
zfs_arc_min = arc_c_min;
return (0);
+3
View File
@@ -7624,6 +7624,9 @@ arc_tuning_update(boolean_t verbose)
{
uint64_t allmem = arc_all_memory();
if (arc_c_max == 0)
return;
/* Valid range: 32M - <arc_c_max> */
if ((zfs_arc_min) && (zfs_arc_min != arc_c_min) &&
(zfs_arc_min >= 2ULL << SPA_MAXBLOCKSHIFT) &&