Module Name: src
Committed By: riastradh
Date: Fri Apr 21 18:24:19 UTC 2023
Modified Files:
src/sys/dev/dkwedge: dk.c
Log Message:
dk(4): Avoid holding dkwedges_lock while allocating array.
This is not great -- we shouldn't be choosing the unit number here
anyway; we should just let autoconf do it for us -- but it's better
than potentially blocking any dk_openlock or dk_rawlock (which are
sometimes held when waiting for dkwedges_lock) for memory allocation.
To generate a diff of this commit:
cvs rdiff -u -r1.126 -r1.127 src/sys/dev/dkwedge/dk.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/dev/dkwedge/dk.c
diff -u src/sys/dev/dkwedge/dk.c:1.126 src/sys/dev/dkwedge/dk.c:1.127
--- src/sys/dev/dkwedge/dk.c:1.126 Fri Apr 21 18:09:38 2023
+++ src/sys/dev/dkwedge/dk.c Fri Apr 21 18:24:19 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dk.c,v 1.126 2023/04/21 18:09:38 riastradh Exp $ */
+/* $NetBSD: dk.c,v 1.127 2023/04/21 18:24:19 riastradh Exp $ */
/*-
* Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.126 2023/04/21 18:09:38 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.127 2023/04/21 18:24:19 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_dkwedge.h"
@@ -242,21 +242,49 @@ dkwedge_compute_pdev(const char *pname,
* dkwedge_array_expand:
*
* Expand the dkwedges array.
+ *
+ * Releases and reacquires dkwedges_lock as a writer.
*/
-static void
+static int
dkwedge_array_expand(void)
{
- int newcnt = ndkwedges + 16;
- struct dkwedge_softc **newarray, **oldarray;
+ const unsigned incr = 16;
+ unsigned newcnt, oldcnt;
+ struct dkwedge_softc **newarray = NULL, **oldarray = NULL;
+
+ KASSERT(rw_write_held(&dkwedges_lock));
+
+ oldcnt = ndkwedges;
+ oldarray = dkwedges;
+
+ if (oldcnt >= INT_MAX - incr)
+ return ENFILE; /* XXX */
+ newcnt = oldcnt + incr;
+
+ rw_exit(&dkwedges_lock);
newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE,
M_WAITOK|M_ZERO);
- if ((oldarray = dkwedges) != NULL)
+ rw_enter(&dkwedges_lock, RW_WRITER);
+
+ if (ndkwedges != oldcnt || dkwedges != oldarray) {
+ oldarray = NULL; /* already recycled */
+ goto out;
+ }
+
+ if (oldarray != NULL)
memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray));
dkwedges = newarray;
+ newarray = NULL; /* transferred to dkwedges */
ndkwedges = newcnt;
+
+out: rw_exit(&dkwedges_lock);
if (oldarray != NULL)
free(oldarray, M_DKWEDGE);
+ if (newarray != NULL)
+ free(newarray, M_DKWEDGE);
+ rw_enter(&dkwedges_lock, RW_WRITER);
+ return 0;
}
static void
@@ -434,9 +462,11 @@ dkwedge_add(struct dkwedge_info *dkw)
if (error)
break;
KASSERT(unit == ndkwedges);
- if (scpp == NULL)
- dkwedge_array_expand();
- else {
+ if (scpp == NULL) {
+ error = dkwedge_array_expand();
+ if (error)
+ break;
+ } else {
KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]);
*scpp = sc;
break;