summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjh <jh@FreeBSD.org>2010-07-22 10:24:28 +0000
committerjh <jh@FreeBSD.org>2010-07-22 10:24:28 +0000
commit1a7a2445e6bbfd74ee1f7f3095ae5b7eb66cf7ab (patch)
tree2b5864d1f16393ddd8680e810d2e08ff1f75dcff /sys/dev
parent8fd99f4ab50e3451e74d3c14d51c211dcea213a1 (diff)
downloadFreeBSD-src-1a7a2445e6bbfd74ee1f7f3095ae5b7eb66cf7ab.zip
FreeBSD-src-1a7a2445e6bbfd74ee1f7f3095ae5b7eb66cf7ab.tar.gz
Convert md(4) to use alloc_unr(9) and alloc_unr_specific(9) for unit
number allocation. The old approach had some problems such as it allowed an overflow to occur in the unit number calculation. PR: kern/122288
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/md/md.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 1fde20f..f50fff3 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -130,6 +130,7 @@ static void g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp
static int mdunits;
static struct cdev *status_dev = 0;
static struct sx md_sx;
+static struct unrhdr *md_uh;
static d_ioctl_t mdctlioctl;
@@ -748,20 +749,20 @@ mdfind(int unit)
static struct md_s *
mdnew(int unit, int *errp, enum md_types type)
{
- struct md_s *sc, *sc2;
- int error, max = -1;
+ struct md_s *sc;
+ int error;
*errp = 0;
- LIST_FOREACH(sc2, &md_softc_list, list) {
- if (unit == sc2->unit) {
- *errp = EBUSY;
- return (NULL);
- }
- if (unit == -1 && sc2->unit > max)
- max = sc2->unit;
- }
if (unit == -1)
- unit = max + 1;
+ unit = alloc_unr(md_uh);
+ else
+ unit = alloc_unr_specific(md_uh, unit);
+
+ if (unit == -1) {
+ *errp = EBUSY;
+ return (NULL);
+ }
+
sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO);
sc->type = type;
bioq_init(&sc->bio_queue);
@@ -774,6 +775,7 @@ mdnew(int unit, int *errp, enum md_types type)
return (sc);
LIST_REMOVE(sc, list);
mtx_destroy(&sc->queue_mtx);
+ free_unr(md_uh, sc->unit);
free(sc, M_MD);
*errp = error;
return (NULL);
@@ -1012,6 +1014,7 @@ mddestroy(struct md_s *sc, struct thread *td)
uma_zdestroy(sc->uma);
LIST_REMOVE(sc, list);
+ free_unr(md_uh, sc->unit);
free(sc, M_MD);
return (0);
}
@@ -1097,8 +1100,11 @@ xmdctlioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread
}
if (mdio->md_options & MD_AUTOUNIT)
sc = mdnew(-1, &error, mdio->md_type);
- else
+ else {
+ if (mdio->md_unit > INT_MAX)
+ return (EINVAL);
sc = mdnew(mdio->md_unit, &error, mdio->md_type);
+ }
if (sc == NULL)
return (error);
if (mdio->md_options & MD_AUTOUNIT)
@@ -1226,6 +1232,7 @@ g_md_init(struct g_class *mp __unused)
mod = NULL;
sx_init(&md_sx, "MD config lock");
g_topology_unlock();
+ md_uh = new_unrhdr(0, INT_MAX, NULL);
#ifdef MD_ROOT_SIZE
sx_xlock(&md_sx);
md_preloaded(mfs_root.start, sizeof(mfs_root.start));
@@ -1322,4 +1329,5 @@ g_md_fini(struct g_class *mp __unused)
sx_destroy(&md_sx);
if (status_dev != NULL)
destroy_dev(status_dev);
+ delete_unrhdr(md_uh);
}
OpenPOWER on IntegriCloud