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;

Reply via email to