Module Name:    src
Committed By:   jdolecek
Date:           Sun Apr 12 08:51:41 UTC 2020

Modified Files:
        src/sys/kern: vfs_wapbl.c

Log Message:
fix race between wapbl_discard() and wapbl_biodone() on forced
unmount on shutdown with slow I/O device

wapbl_discard() needs to hold both wl_mtx and bufcache_lock while
manipulating wl_entries - the rw lock is not enough, because
wapbl_biodone() only takes wl_mtx while removing the finished entry
from list

wapbl_biodone() must take bufcache_lock before reading we->we_wapbl,
so it's blocked until wapbl_discard() finishes, and takes !wl path
appropriately

this is supposed to fix panic on shutdown:
[ 67549.6304123] forcefully unmounting / (/dev/wd0a)...
...
[ 67549.7272030] panic: mutex_vector_enter,510: uninitialized lock 
(lock=0xffffa722a4f4f5b0, from=ffffffff80a884fa)
...
[ 67549.7272030] wapbl_biodone() at netbsd:wapbl_biodone+0x4d
[ 67549.7272030] biointr() at netbsd:biointr+0x7d
[ 67549.7272030] softint_dispatch() at netbsd:softint_dispatch+0x12c
[ 67549.7272030] Xsoftintr() at netbsd:Xsoftintr+0x4f


To generate a diff of this commit:
cvs rdiff -u -r1.106 -r1.107 src/sys/kern/vfs_wapbl.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_wapbl.c
diff -u src/sys/kern/vfs_wapbl.c:1.106 src/sys/kern/vfs_wapbl.c:1.107
--- src/sys/kern/vfs_wapbl.c:1.106	Mon Mar 16 21:20:10 2020
+++ src/sys/kern/vfs_wapbl.c	Sun Apr 12 08:51:41 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_wapbl.c,v 1.106 2020/03/16 21:20:10 pgoyette Exp $	*/
+/*	$NetBSD: vfs_wapbl.c,v 1.107 2020/04/12 08:51:41 jdolecek Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2008, 2009 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
 #define WAPBL_INTERNAL
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.106 2020/03/16 21:20:10 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.107 2020/04/12 08:51:41 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/bitops.h>
@@ -226,7 +226,7 @@ struct wapbl {
 	u_long wl_inohashmask;
 	int wl_inohashcnt;
 
-	SIMPLEQ_HEAD(, wapbl_entry) wl_entries; /* On disk transaction
+	SIMPLEQ_HEAD(, wapbl_entry) wl_entries; /* m: On disk transaction
 						   accounting */
 
 	/* buffers for wapbl_buffered_write() */
@@ -786,12 +786,10 @@ wapbl_discard(struct wapbl *wl)
 			mutex_enter(&wl->wl_mtx);
 		}
 	}
-	mutex_exit(&wl->wl_mtx);
-	mutex_exit(&bufcache_lock);
 
 	/*
 	 * Remove references to this wl from wl_entries, free any which
-	 * no longer have buffers, others will be freed in wapbl_biodone
+	 * no longer have buffers, others will be freed in wapbl_biodone()
 	 * when they no longer have any buffers.
 	 */
 	while ((we = SIMPLEQ_FIRST(&wl->wl_entries)) != NULL) {
@@ -807,6 +805,9 @@ wapbl_discard(struct wapbl *wl)
 		}
 	}
 
+	mutex_exit(&wl->wl_mtx);
+	mutex_exit(&bufcache_lock);
+
 	/* Discard list of deallocs */
 	while ((wd = TAILQ_FIRST(&wl->wl_dealloclist)) != NULL)
 		wapbl_deallocation_free(wl, wd, true);
@@ -1604,11 +1605,15 @@ void
 wapbl_biodone(struct buf *bp)
 {
 	struct wapbl_entry *we = bp->b_private;
-	struct wapbl *wl = we->we_wapbl;
+	struct wapbl *wl;
 #ifdef WAPBL_DEBUG_BUFBYTES
 	const int bufsize = bp->b_bufsize;
 #endif
 
+	mutex_enter(&bufcache_lock);
+	wl = we->we_wapbl;
+	mutex_exit(&bufcache_lock);
+
 	/*
 	 * Handle possible flushing of buffers after log has been
 	 * decomissioned.

Reply via email to