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;