summaryrefslogtreecommitdiffstats
path: root/module/zfs/arc.c
diff options
context:
space:
mode:
authorGeorge Amanakis <[email protected]>2020-11-16 18:08:11 +0100
committerGitHub <[email protected]>2020-11-16 09:08:11 -0800
commit2c210f68189c6f781be050bfdc890cd6dc231fea (patch)
tree0e3a245fcbbe6b3e09349a77e4d6cb762ee84882 /module/zfs/arc.c
parent24c12b48a196265cf1837cd832b420476a208b47 (diff)
Fix ASSERT logic in l2arc_evict()
In case of cache device removal it is possible that at the end of l2arc_evict() we have l2ad_hand = l2ad_evict. This can lead to the following panic in case of a debug build: VERIFY3(dev->l2ad_hand < dev->l2ad_evict) failed (321920512 < 321920512) Call Trace: dump_stack+0x66/0x90 spl_panic+0xef/0x117 [spl] l2arc_remove_vdev+0x11d/0x290 [zfs] spa_load_l2cache+0x275/0x5b0 [zfs] spa_vdev_remove+0x4a5/0x6e0 [zfs] zfs_ioc_vdev_remove+0x59/0xa0 [zfs] zfsdev_ioctl_common+0x5b3/0x630 [zfs] zfsdev_ioctl+0x53/0xe0 [zfs] do_vfs_ioctl+0x42e/0x6b0 ksys_ioctl+0x5e/0x90 do_syscall_64+0x5b/0x1a0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 In case of cache device removal it also possible that l2ad_hand + distance > l2ad_end since we do not iterate l2arc_evict() and l2ad_hand is not reset. This has no functional consequence however as the cache device is about to be removed. Fix this by omitting the ASSERT in case of device removal. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: George Amanakis <[email protected]> Closes #11205
Diffstat (limited to 'module/zfs/arc.c')
-rw-r--r--module/zfs/arc.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c
index 850e8032f..42c09e2e5 100644
--- a/module/zfs/arc.c
+++ b/module/zfs/arc.c
@@ -8886,9 +8886,16 @@ out:
goto top;
}
- ASSERT3U(dev->l2ad_hand + distance, <, dev->l2ad_end);
- if (!dev->l2ad_first)
- ASSERT3U(dev->l2ad_hand, <, dev->l2ad_evict);
+ if (!all) {
+ /*
+ * In case of cache device removal (all) the following
+ * assertions may be violated without functional consequences
+ * as the device is about to be removed.
+ */
+ ASSERT3U(dev->l2ad_hand + distance, <, dev->l2ad_end);
+ if (!dev->l2ad_first)
+ ASSERT3U(dev->l2ad_hand, <, dev->l2ad_evict);
+ }
}
/*