git: 3fe5069ce2bf - main - virtio_p9fs: Fix kernel panic on module unload

From: Alex Richardson <arichardson_at_FreeBSD.org>
Date: Thu, 07 May 2026 05:02:53 UTC
The branch main has been updated by arichardson:

URL: https://cgit.FreeBSD.org/src/commit/?id=3fe5069ce2bf5b2702f3be6531ce6a05c584e64d

commit 3fe5069ce2bf5b2702f3be6531ce6a05c584e64d
Author:     Alex Richardson <arichardson@FreeBSD.org>
AuthorDate: 2026-05-07 04:21:23 +0000
Commit:     Alex Richardson <arichardson@FreeBSD.org>
CommitDate: 2026-05-07 04:23:03 +0000

    virtio_p9fs: Fix kernel panic on module unload
    
    The virtio_p9fs module event handler can be invoked multiple times.
    Previously, this caused p9_init_zones() and p9_register_trans() to be
    executed multiple times, leaking UMA zones and corrupting the transport
    list. During module unload, p9_destroy_zones() was also called multiple
    times on the same zone pointers, triggering a duplicate free kernel panic
    in uma_zdestroy().
    
    This patch introduces a static reference counter in vt9p_modevent() to
    ensure the zones and transports are only initialized and destroyed exactly
    once, aligning with the approach used by other virtio drivers like vtnet.
    
    Reviewed by:    kib, markj
    MFC after:      1 week
    Differential Revision: https://reviews.freebsd.org/D56497
---
 sys/dev/virtio/p9fs/virtio_p9fs.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/sys/dev/virtio/p9fs/virtio_p9fs.c b/sys/dev/virtio/p9fs/virtio_p9fs.c
index 2b276a60aa9a..f76b135c042d 100644
--- a/sys/dev/virtio/p9fs/virtio_p9fs.c
+++ b/sys/dev/virtio/p9fs/virtio_p9fs.c
@@ -464,16 +464,22 @@ static int
 vt9p_modevent(module_t mod, int type, void *unused)
 {
 	int error;
+	static int loaded = 0;
 
 	error = 0;
 
 	switch (type) {
 	case MOD_LOAD:
-		p9_init_zones();
-		p9_register_trans(&vt9p_trans);
+		if (loaded++ == 0) {
+			p9_init_zones();
+			p9_register_trans(&vt9p_trans);
+		}
 		break;
 	case MOD_UNLOAD:
-		p9_destroy_zones();
+		if (--loaded == 0) {
+			p9_unregister_trans(&vt9p_trans);
+			p9_destroy_zones();
+		}
 		break;
 	case MOD_SHUTDOWN:
 		break;