diff options
author | pjd <pjd@FreeBSD.org> | 2005-08-31 19:45:11 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2005-08-31 19:45:11 +0000 |
commit | 06122c40eb6ecf6cf398d8e9492d0f7aa6e9cf21 (patch) | |
tree | c18482096b807525ce7fc1a2c1c03750e1eb58f6 /sys/dev | |
parent | 991cce17d6fc922ae716ac677575385a85ef761e (diff) | |
download | FreeBSD-src-06122c40eb6ecf6cf398d8e9492d0f7aa6e9cf21.zip FreeBSD-src-06122c40eb6ecf6cf398d8e9492d0f7aa6e9cf21.tar.gz |
- Add md_mtx lock to protect ID number and list of devices.
- Always check mdnew() return value, as even in !autounit case
kthread_create() can fail.
Those two changes fix serval panics provked by simple stress test.
Tested by: Kris The BugMagnet
MFC after: 3 days
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/md/md.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index 07fbbb3..cb21e4d 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -112,6 +112,8 @@ static g_access_t g_md_access; static int mdunits; static struct cdev *status_dev = 0; +static struct mtx md_mtx; +MTX_SYSINIT(md_mtx, &md_mtx, "md", MTX_DEF); static d_ioctl_t mdctlioctl; @@ -708,44 +710,54 @@ mdfind(int unit) { struct md_s *sc; - /* XXX: LOCK(unique unit numbers) */ + mtx_lock(&md_mtx); LIST_FOREACH(sc, &md_softc_list, list) { if (sc->unit == unit) break; } - /* XXX: UNLOCK(unique unit numbers) */ + mtx_unlock(&md_mtx); return (sc); } static struct md_s * -mdnew(int unit) +mdnew(int unit, int *errp) { - struct md_s *sc; + struct md_s *sc, *sc2; int error, max = -1; - /* XXX: LOCK(unique unit numbers) */ - LIST_FOREACH(sc, &md_softc_list, list) { - if (sc->unit == unit) { - /* XXX: UNLOCK(unique unit numbers) */ + sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO); + bioq_init(&sc->bio_queue); + mtx_init(&sc->queue_mtx, "md bio queue", NULL, MTX_DEF); + mtx_lock(&md_mtx); + LIST_FOREACH(sc2, &md_softc_list, list) { + if (sc2->unit == unit) { + mtx_unlock(&md_mtx); + mtx_destroy(&sc->queue_mtx); + free(sc, M_MD); + if (errp != NULL) + *errp = EBUSY; return (NULL); } - if (sc->unit > max) - max = sc->unit; + if (sc2->unit > max) + max = sc2->unit; } if (unit == -1) unit = max + 1; - sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO); sc->unit = unit; - bioq_init(&sc->bio_queue); - mtx_init(&sc->queue_mtx, "md bio queue", NULL, MTX_DEF); sprintf(sc->name, "md%d", unit); + LIST_INSERT_HEAD(&md_softc_list, sc, list); + mtx_unlock(&md_mtx); error = kthread_create(md_kthread, sc, &sc->procp, 0, 0,"%s", sc->name); if (error != 0) { + mtx_lock(&md_mtx); + LIST_REMOVE(sc, list); + mtx_unlock(&md_mtx); + mtx_destroy(&sc->queue_mtx); free(sc, M_MD); + if (errp != NULL) + *errp = error; return (NULL); } - LIST_INSERT_HEAD(&md_softc_list, sc, list); - /* XXX: UNLOCK(unique unit numbers) */ return (sc); } @@ -955,9 +967,9 @@ mddestroy(struct md_s *sc, struct thread *td) if (sc->uma) uma_zdestroy(sc->uma); - /* XXX: LOCK(unique unit numbers) */ + mtx_lock(&md_mtx); LIST_REMOVE(sc, list); - /* XXX: UNLOCK(unique unit numbers) */ + mtx_unlock(&md_mtx); free(sc, M_MD); return (0); } @@ -1061,14 +1073,14 @@ mdctlioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread default: return (EINVAL); } - if (mdio->md_options & MD_AUTOUNIT) { - sc = mdnew(-1); + if (mdio->md_options & MD_AUTOUNIT) + sc = mdnew(-1, &error); + else + sc = mdnew(mdio->md_unit, &error); + if (sc == NULL) + return (error); + if (mdio->md_options & MD_AUTOUNIT) mdio->md_unit = sc->unit; - } else { - sc = mdnew(mdio->md_unit); - if (sc == NULL) - return (EBUSY); - } sc->type = mdio->md_type; sc->mediasize = mdio->md_mediasize; if (mdio->md_sectorsize == 0) @@ -1142,7 +1154,7 @@ md_preloaded(u_char *image, size_t length) { struct md_s *sc; - sc = mdnew(-1); + sc = mdnew(-1, NULL); if (sc == NULL) return; sc->type = MD_PRELOAD; |