zarcstat: detect attached L2ARC device with no data

zarcstat and zarcsummary detected L2ARC presence using the l2_size
kstat, which is data held in L2ARC, not whether a cache device is
attached. When a cache device was attached but empty (freshly added,
or fully evicted):

  - zarcstat rejected "-f l2*" with "Incompatible field specified!"
  - zarcsummary printed "L2ARC not detected, skipping section",
    hiding cumulative I/O history and health counters

Expose the existing l2arc_ndev counter as a new kstat l2_dev_count.
It is maintained by l2arc_add_vdev() and l2arc_remove_vdev(), so it
tracks attachment in real time. Use it in both tools, falling back to
l2_size for compatibility with older kernel modules.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
Closes #18499
This commit is contained in:
Ameer Hamza
2026-05-09 03:01:47 +05:00
committed by GitHub
parent 956deba27b
commit c7cfe0805c
4 changed files with 11 additions and 4 deletions
+3 -3
View File
@@ -565,10 +565,10 @@ def init():
update_hdr_intr()
# check if L2ARC exists
# check if L2ARC exists; fall back to l2_size for older kernels that
# do not export l2_ndev
snap_stats()
l2_size = cur.get("l2_size")
if l2_size:
if cur.get("l2_ndev") or cur.get("l2_size"):
l2exist = True
if desired_cols:
+4 -1
View File
@@ -856,7 +856,10 @@ def section_l2arc(kstats_dict):
# The L2ARC statistics live in the same section as the normal ARC stuff
arc_stats = isolate_section('arcstats', kstats_dict)
if arc_stats['l2_size'] == '0':
# Skip the section only when no cache device is attached. Fall back to
# l2_size for older kernels that do not export l2_ndev.
if arc_stats.get('l2_ndev', '0') == '0' and \
arc_stats['l2_size'] == '0':
print('L2ARC not detected, skipping section\n')
return
+2
View File
@@ -832,6 +832,8 @@ typedef struct arc_stats {
* due to ARC_FLAG_UNCACHED being set.
*/
kstat_named_t arcstat_uncached_evictable_metadata;
/* Number of L2ARC devices currently attached across all pools. */
kstat_named_t arcstat_l2_ndev;
kstat_named_t arcstat_l2_hits;
kstat_named_t arcstat_l2_misses;
/*
+2
View File
@@ -586,6 +586,7 @@ arc_stats_t arc_stats = {
{ "uncached_metadata", KSTAT_DATA_UINT64 },
{ "uncached_evictable_data", KSTAT_DATA_UINT64 },
{ "uncached_evictable_metadata", KSTAT_DATA_UINT64 },
{ "l2_ndev", KSTAT_DATA_UINT64 },
{ "l2_hits", KSTAT_DATA_UINT64 },
{ "l2_misses", KSTAT_DATA_UINT64 },
{ "l2_prefetch_asize", KSTAT_DATA_UINT64 },
@@ -7440,6 +7441,7 @@ arc_kstat_update(kstat_t *ksp, int rw)
aggsum_value(&arc_sums.arcstat_dnode_size);
as->arcstat_bonus_size.value.ui64 =
wmsum_value(&arc_sums.arcstat_bonus_size);
as->arcstat_l2_ndev.value.ui64 = l2arc_ndev;
as->arcstat_l2_hits.value.ui64 =
wmsum_value(&arc_sums.arcstat_l2_hits);
as->arcstat_l2_misses.value.ui64 =