From bee314a798b9495bfa8368952461301fb7080a61 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 17 Mar 2022 12:14:00 -0500 Subject: [PATCH] module: freebsd: avoid a taking a destroyed lock in zfs_zevent bits At shutdown time, we drain all of the zevents and set the ZEVENT_SHUTDOWN flag. On FreeBSD, we may end up calling zfs_zevent_destroy() after the zevent_lock has been destroyed while the sysevent thread is winding down; we observe ESHUTDOWN, then back out. Events have already been drained, so just inline the kmem_free call in sysevent_worker() to avoid the race, and document the assumption that zfs_zevent_destroy doesn't do anything else useful at that point. This fixes a panic that can occur at module unload time. Reviewed-by: Ryan Moeller Reviewed-by: Brian Behlendorf Signed-off-by: Kyle Evans Closes #13220 --- module/os/freebsd/spl/spl_sysevent.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/module/os/freebsd/spl/spl_sysevent.c b/module/os/freebsd/spl/spl_sysevent.c index d5d50080f..16188c71b 100644 --- a/module/os/freebsd/spl/spl_sysevent.c +++ b/module/os/freebsd/spl/spl_sysevent.c @@ -250,7 +250,17 @@ sysevent_worker(void *arg __unused) nvlist_free(event); } } - zfs_zevent_destroy(ze); + + /* + * We avoid zfs_zevent_destroy() here because we're otherwise racing + * against fm_fini() destroying the zevent_lock. zfs_zevent_destroy() + * will currently only clear `ze->ze_zevent` from an event list then + * free `ze`, so just inline the free() here -- events have already + * been drained. + */ + VERIFY3P(ze->ze_zevent, ==, NULL); + kmem_free(ze, sizeof (zfs_zevent_t)); + kthread_exit(); }