diff --git a/sys/conf/majors b/sys/conf/majors index 62f5264e8a36..5671b38c30da 100644 --- a/sys/conf/majors +++ b/sys/conf/majors @@ -23,7 +23,6 @@ 5 *pts pseudo tty "tty" half 6 *ptc pseudo tty "master" half 7 *log system log -18 *nmdm nullmodem back-to-back tty ports 19 *tw X-10 power interface 22 *fd (/dev/stdin etc) 30 *snd sound driver system @@ -37,7 +36,6 @@ 42 *cx Cronyx/Sigma serial adapter 43 vn vnode "disk" device (retired) 46 - - -52 *tun IP tunnel device 54 OLDnic ISDN system 58 - Was dgb: Digiboard PC/Xe 62 worm SCSI "worm type" @@ -77,7 +75,6 @@ 139 wanrouter Sangoma Technologies Inc. (al.feldman@sangoma.com) 141 pcdmx PCDMX theatre lighting controller 142 skip SKIP port (security/skip) control device -149 *tap Ethernet tunneling device 154 *asr Adaptec SCSI RAID 155 phone Quicknet PhoneJACK and LineJACK cards for VoIP 159 *ata ATA control device diff --git a/sys/dev/nmdm/nmdm.c b/sys/dev/nmdm/nmdm.c index 3227b11f34e4..f3440dda9f1e 100644 --- a/sys/dev/nmdm/nmdm.c +++ b/sys/dev/nmdm/nmdm.c @@ -63,8 +63,7 @@ MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures"); static void nmdmstart(struct tty *tp); static void nmdmstop(struct tty *tp, int rw); static void wakeup_other(struct tty *tp, int flag); -static void nmdminit(int); -static int nmdmshutdown(void); +static void nmdminit(dev_t dev); static d_open_t nmdmopen; static d_close_t nmdmclose; @@ -72,7 +71,6 @@ static d_read_t nmdmread; static d_write_t nmdmwrite; static d_ioctl_t nmdmioctl; -#define CDEV_MAJOR 18 static struct cdevsw nmdm_cdevsw = { .d_open = nmdmopen, .d_close = nmdmclose, @@ -80,14 +78,14 @@ static struct cdevsw nmdm_cdevsw = { .d_write = nmdmwrite, .d_ioctl = nmdmioctl, .d_poll = ttypoll, - .d_name = "pts", - .d_maj = CDEV_MAJOR, - .d_flags = D_TTY, + .d_name = "nmdm", + .d_flags = D_TTY | D_PSEUDO, }; #define BUFSIZ 100 /* Chunk size iomoved to/from user */ #define NMDM_MAX_NUM 128 /* Artificially limit # devices. */ #define PF_STOPPED 0x10 /* user told stopped */ +#define BFLAG CLONE_FLAG0 struct softpart { struct tty nm_tty; @@ -97,11 +95,61 @@ struct softpart { }; struct nm_softc { - int pt_flags; - struct softpart part1, part2; - struct prison *pt_prison; + TAILQ_ENTRY(nm_softc) pt_list; + int pt_flags; + struct softpart part1, part2; + struct prison *pt_prison; }; +static struct clonedevs *nmdmclones; +static TAILQ_HEAD(,nm_softc) nmdmhead = TAILQ_HEAD_INITIALIZER(nmdmhead); + +static void +nmdm_clone(void *arg, char *name, int nameen, dev_t *dev) +{ + int i, unit; + char *p; + dev_t d1, d2; + + if (*dev != NODEV) + return; + if (strcmp(name, "nmdm") == 0) { + p = NULL; + unit = -1; + } else { + i = dev_stdclone(name, &p, "nmdm", &unit); + if (i == 0) + return; + if (p[0] != '\0' && p[0] != 'A' && p[0] != 'B') + return; + else if (p[0] != '\0' && p[1] != '\0') + return; + } + i = clone_create(&nmdmclones, &nmdm_cdevsw, &unit, &d1, 0); + if (i) { + d1 = make_dev(&nmdm_cdevsw, unit2minor(unit), + 0, 0, 0666, "nmdm%dA", unit); + if (d1 == NULL) + return; + d2 = make_dev(&nmdm_cdevsw, unit2minor(unit) | BFLAG, + 0, 0, 0666, "nmdm%dB", unit); + if (d2 == NULL) { + destroy_dev(d1); + return; + } + d2->si_drv2 = d1; + d1->si_drv2 = d2; + dev_depends(d1, d2); + dev_depends(d2, d1); + d1->si_flags |= SI_CHEAPCLONE; + d2->si_flags |= SI_CHEAPCLONE; + } + if (p != NULL && p[0] == 'B') + *dev = d1->si_drv2; + else + *dev = d1; +} + static void nmdm_crossover(struct nm_softc *pti, struct softpart *ourpart, @@ -123,24 +171,22 @@ do { \ * This function creates and initializes a pair of ttys. */ static void -nmdminit(n) - int n; +nmdminit(dev_t dev1) { - dev_t dev1, dev2; + dev_t dev2; struct nm_softc *pt; - /* For now we only map the lower 8 bits of the minor */ - if (n & ~0xff) - return; + dev2 = dev1->si_drv2; - pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK); - bzero(pt, sizeof(*pt)); - pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n, - 0, 0, 0666, "nmdm%dA", n); - pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1, - 0, 0, 0666, "nmdm%dB", n); + dev1->si_flags &= ~SI_CHEAPCLONE; + dev2->si_flags &= ~SI_CHEAPCLONE; + pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO); + TAILQ_INSERT_TAIL(&nmdmhead, pt, pt_list); dev1->si_drv1 = dev2->si_drv1 = pt; + + pt->part1.dev = dev1; + pt->part2.dev = dev2; dev1->si_tty = &pt->part1.nm_tty; dev2->si_tty = &pt->part2.nm_tty; ttyregister(&pt->part1.nm_tty); @@ -148,9 +194,9 @@ nmdminit(n) pt->part1.nm_tty.t_oproc = nmdmstart; pt->part2.nm_tty.t_oproc = nmdmstart; pt->part1.nm_tty.t_stop = nmdmstop; + pt->part2.nm_tty.t_stop = nmdmstop; pt->part2.nm_tty.t_dev = dev1; pt->part1.nm_tty.t_dev = dev2; - pt->part2.nm_tty.t_stop = nmdmstop; } /* @@ -161,39 +207,14 @@ nmdmopen(dev_t dev, int flag, int devtype, struct thread *td) { register struct tty *tp, *tp2; int error; - int minr; - dev_t nextdev; struct nm_softc *pti; - int is_b; - int pair; struct softpart *ourpart, *otherpart; - /* - * XXX: Gross hack for DEVFS: - * If we openned this device, ensure we have the - * next one too, so people can open it. - */ - minr = dev2unit(dev); - pair = minr >> 1; - is_b = minr & 1; - - if (pair < (NMDM_MAX_NUM - 1)) { - nextdev = makedev(major(dev), minr + 2); - if (!nextdev->si_drv1) { - nmdminit(pair + 1); - } - } else { /* Limit ourselves to 128 of them for now */ - if (pair > (NMDM_MAX_NUM - 1)) - return (ENXIO); - } - if (!dev->si_drv1) - nmdminit(pair); - - if (!dev->si_drv1) - return(ENXIO); - + if (dev->si_drv1 == NULL) + nmdminit(dev); pti = dev->si_drv1; - if (is_b) + + if (minor(dev) & BFLAG) tp = &pti->part2.nm_tty; else tp = &pti->part1.nm_tty; @@ -567,20 +588,27 @@ nmdm_crossover(struct nm_softc *pti, struct softpart *ourpart, static int nmdm_modevent(module_t mod, int type, void *data) { + static eventhandler_tag tag; + struct nm_softc *pt, *tpt; int error = 0; switch(type) { - case MOD_LOAD: /* start with 4 of them */ - nmdminit(0); - nmdminit(1); - nmdminit(2); - nmdminit(3); + case MOD_LOAD: + tag = EVENTHANDLER_REGISTER(dev_clone, nmdm_clone, 0, 1000); + if (tag == NULL) + return (ENOMEM); break; case MOD_SHUTDOWN: /* FALLTHROUGH */ case MOD_UNLOAD: - nmdmshutdown(); + EVENTHANDLER_DEREGISTER(dev_clone, tag); + TAILQ_FOREACH_SAFE(pt, &nmdmhead, pt_list, tpt) { + destroy_dev(pt->part1.dev); + TAILQ_REMOVE(&nmdmhead, pt, pt_list); + free(pt, M_NLMDM); + } + clone_cleanup(&nmdmclones); break; default: error = EOPNOTSUPP; @@ -588,31 +616,4 @@ nmdm_modevent(module_t mod, int type, void *data) return (error); } -/* - * Handle teardown of device - */ -static int -nmdmshutdown(void) -{ - int i; - dev_t nextdev1; - dev_t nextdev2; - void * ptr1; - - for(i = 0;( i < NMDM_MAX_NUM) ;i++) { - nextdev1 = makedev(CDEV_MAJOR, (i+i) ); - nextdev2 = makedev(CDEV_MAJOR, (i+i) + 1); - ptr1 = nextdev1->si_drv1; - if (ptr1) { - destroy_dev(nextdev1); - destroy_dev(nextdev2); - free(ptr1, M_NLMDM); - } else { - freedev(nextdev1); - freedev(nextdev2); - } - } - return(0); -} - DEV_MODULE(nmdm, nmdm_modevent, NULL); diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c index 4c4115d3ff53..2c1c3c6fd6ba 100644 --- a/sys/dev/snp/snp.c +++ b/sys/dev/snp/snp.c @@ -38,7 +38,6 @@ static d_write_t snpwrite; static d_ioctl_t snpioctl; static d_poll_t snppoll; -#define CDEV_MAJOR 53 static struct cdevsw snp_cdevsw = { .d_open = snpopen, .d_close = snpclose, @@ -47,7 +46,7 @@ static struct cdevsw snp_cdevsw = { .d_ioctl = snpioctl, .d_poll = snppoll, .d_name = "snp", - .d_maj = CDEV_MAJOR, + .d_flags = D_PSEUDO, }; static struct linesw snpdisc = { @@ -101,10 +100,9 @@ static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data"); * module load time. */ static int snooplinedisc; -static udev_t snpbasedev = NOUDEV; - static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist); +static struct clonedevs *snpclones; static struct tty *snpdevtotty(dev_t dev); static void snp_clone(void *arg, char *name, @@ -384,9 +382,7 @@ snpopen(dev, flag, mode, td) struct snoop *snp; if (dev->si_drv1 == NULL) { - if (!(dev->si_flags & SI_NAMED)) - make_dev(&snp_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, - 0600, "snp%d", dev2unit(dev)); + dev->si_flags &= ~SI_CHEAPCLONE; dev->si_drv1 = snp = malloc(sizeof(*snp), M_SNP, M_WAITOK | M_ZERO); snp->snp_unit = dev2unit(dev); @@ -466,6 +462,7 @@ snpclose(dev, flags, fmt, td) free(snp->snp_buf, M_SNP); snp->snp_flags &= ~SNOOP_OPEN; dev->si_drv1 = NULL; + destroy_dev(dev); return (snp_detach(snp)); } @@ -608,20 +605,18 @@ snp_clone(arg, name, namelen, dev) int namelen; dev_t *dev; { - int u; + int u, i; if (*dev != NODEV) return; if (dev_stdclone(name, NULL, "snp", &u) != 1) return; - *dev = make_dev(&snp_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600, - "snp%d", u); - if (snpbasedev == NOUDEV) - snpbasedev = (*dev)->si_udev; - else { + i = clone_create(&snpclones, &snp_cdevsw, &u, dev, 0); + if (i) + *dev = make_dev(&snp_cdevsw, unit2minor(u), + UID_ROOT, GID_WHEEL, 0600, "snp%d", u); + if (*dev != NULL) (*dev)->si_flags |= SI_CHEAPCLONE; - dev_depends(udev2dev(snpbasedev, 0), *dev); - } } static int @@ -642,8 +637,7 @@ snp_modevent(mod, type, data) if (!LIST_EMPTY(&snp_sclist)) return (EBUSY); EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); - if (snpbasedev != NOUDEV) - destroy_dev(udev2dev(snpbasedev, 0)); + clone_cleanup(&snpclones); ldisc_deregister(snooplinedisc); break; default: @@ -657,4 +651,4 @@ static moduledata_t snp_mod = { snp_modevent, NULL }; -DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR); +DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index c99173d79429..62033c7e366a 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -324,10 +324,22 @@ makeudev(int x, int y) } static void -prep_cdevsw(struct cdevsw *devsw) +find_major(struct cdevsw *devsw) { int i; + for (i = NUMCDEVSW - 1; i > 0; i--) + if (reserved_majors[i] != i) + break; + KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); + devsw->d_maj = i; + reserved_majors[i] = i; +} + +static void +prep_cdevsw(struct cdevsw *devsw) +{ + if (devsw->d_open == NULL) devsw->d_open = null_open; if (devsw->d_close == NULL) devsw->d_close = null_close; if (devsw->d_read == NULL) devsw->d_read = no_read; @@ -339,12 +351,7 @@ prep_cdevsw(struct cdevsw *devsw) if (devsw->d_dump == NULL) devsw->d_dump = no_dump; if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter; if (devsw->d_maj == MAJOR_AUTO) { - for (i = NUMCDEVSW - 1; i > 0; i--) - if (reserved_majors[i] != i) - break; - KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); - devsw->d_maj = i; - reserved_majors[i] = i; + find_major(devsw); } else { if (devsw->d_maj == 256) /* XXX: tty_cons.c is magic */ devsw->d_maj = 0; @@ -458,17 +465,22 @@ destroy_dev(dev_t dev) } devfs_destroy(dev); + dev->si_flags &= ~SI_NAMED; + if (dev->si_flags & SI_CHILD) { LIST_REMOVE(dev, si_siblings); dev->si_flags &= ~SI_CHILD; } while (!LIST_EMPTY(&dev->si_children)) destroy_dev(LIST_FIRST(&dev->si_children)); + if (dev->si_flags & SI_CLONELIST) { + LIST_REMOVE(dev, si_clone); + dev->si_flags &= ~SI_CLONELIST; + } dev->si_drv1 = 0; dev->si_drv2 = 0; dev->si_devsw = 0; bzero(&dev->__si_u, sizeof(dev->__si_u)); - dev->si_flags &= ~SI_NAMED; dev->si_flags &= ~SI_ALIAS; freedev(dev); } @@ -522,6 +534,115 @@ dev_stdclone(char *name, char **namep, const char *stem, int *unit) return (1); } +/* + * Helper functions for cloning device drivers. + * + * The objective here is to make it unnecessary for the device drivers to + * use rman or similar to manage their unit number space. Due to the way + * we do "on-demand" devices, using rman or other "private" methods + * will be very tricky to lock down properly once we lock down this file. + * + * Instead we give the drivers these routines which puts the dev_t's that + * are to be managed on their own list, and gives the driver the ability + * to ask for the first free unit number or a given specified unit number. + * + * In addition these routines support paired devices (pty, nmdm and similar) + * by respecting a number of "flag" bits in the minor number. + * + */ + +struct clonedevs { + LIST_HEAD(,cdev) head; +}; + +int +clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, dev_t *dp, u_int extra) +{ + struct clonedevs *cd; + dev_t dev, dl, de; + int unit, low, u; + + KASSERT(!(extra & CLONE_UNITMASK), + ("Illegal extra bits (0x%x) in clone_create", extra)); + KASSERT(*up <= CLONE_UNITMASK, + ("Too high unit (0x%x) in clone_create", *up)); + + if (csw->d_maj == MAJOR_AUTO) + find_major(csw); + /* if clonedevs have not been initialized, we do it here */ + cd = *cdp; + if (cd == NULL) { + cd = malloc(sizeof *cd, M_DEVBUF, M_WAITOK | M_ZERO); + LIST_INIT(&cd->head); + *cdp = cd; + } + + /* + * Search the list for a lot of things in one go: + * A preexisting match is returned immediately. + * The lowest free unit number if we are passed -1, and the place + * in the list where we should insert that new element. + * The place to insert a specified unit number, if applicable + * the end of the list. + */ + unit = *up; + low = 0; + de = dl = NULL; + LIST_FOREACH(dev, &cd->head, si_clone) { + u = dev2unit(dev); + if (u == (unit | extra)) { + *dp = dev; + return (0); + } + if (unit == -1 && u == low) { + low++; + de = dev; + continue; + } + if (u > unit) { + dl = dev; + break; + } + de = dev; + } + if (unit == -1) + unit = low; + dev = makedev(csw->d_maj, unit2minor(unit | extra)); + KASSERT(!(dev->si_flags & SI_CLONELIST), + ("Dev %p should not be on clonelist", dev)); + if (dl != NULL) + LIST_INSERT_BEFORE(dl, dev, si_clone); + else if (de != NULL) + LIST_INSERT_AFTER(de, dev, si_clone); + else + LIST_INSERT_HEAD(&cd->head, dev, si_clone); + dev->si_flags |= SI_CLONELIST; + *up = unit; + return (1); +} + +/* + * Kill everything still on the list. The driver should already have + * disposed of any softc hung of the dev_t's at this time. + */ +void +clone_cleanup(struct clonedevs **cdp) +{ + dev_t dev, tdev; + struct clonedevs *cd; + + cd = *cdp; + if (cd == NULL) + return; + LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { + KASSERT(dev->si_flags & SI_NAMED, + ("Driver has goofed in cloning underways udev %x", dev->si_udev)); + destroy_dev(dev); + } + free(cd, M_DEVBUF); + *cdp = NULL; +} + /* * Helper sysctl for devname(3). We're given a {u}dev_t and return * the name, if any, registered by the device driver. diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c index 82ae3b990390..f83243b39998 100644 --- a/sys/net/if_tap.c +++ b/sys/net/if_tap.c @@ -54,8 +54,6 @@ #include #include #include -#include /* XXX: Shouldn't really be required! */ -#include #include #include @@ -71,14 +69,12 @@ #define CDEV_NAME "tap" -#define CDEV_MAJOR 149 #define TAPDEBUG if (tapdebug) printf #define TAP "tap" #define VMNET "vmnet" #define TAPMAXUNIT 0x7fff -#define VMNET_DEV_MASK 0x00800000 - /* 0x007f00ff */ +#define VMNET_DEV_MASK CLONE_FLAG0 /* module */ static int tapmodevent(module_t, int, void *); @@ -108,15 +104,12 @@ static struct cdevsw tap_cdevsw = { .d_ioctl = tapioctl, .d_poll = tappoll, .d_name = CDEV_NAME, - .d_maj = CDEV_MAJOR, + .d_flags = D_PSEUDO, }; static int tapdebug = 0; /* debug flag */ static SLIST_HEAD(, tap_softc) taphead; /* first device */ -static udev_t tapbasedev = NOUDEV; /* base device */ -static struct rman tapdevunits[2]; /* device units */ -#define tapunits tapdevunits -#define vmnetunits (tapdevunits + 1) +static struct clonedevs *tapclones; MALLOC_DECLARE(M_TAP); MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); @@ -137,63 +130,27 @@ tapmodevent(mod, type, data) static eventhandler_tag eh_tag = NULL; struct tap_softc *tp = NULL; struct ifnet *ifp = NULL; - int error, s; + int s; switch (type) { case MOD_LOAD: - /* initialize resources */ - tapunits->rm_type = RMAN_ARRAY; - tapunits->rm_descr = "open tap units"; - vmnetunits->rm_type = RMAN_ARRAY; - vmnetunits->rm_descr = "open vmnet units"; - - error = rman_init(tapunits); - if (error != 0) - goto bail; - - error = rman_init(vmnetunits); - if (error != 0) - goto bail1; - - error = rman_manage_region(tapunits, 0, TAPMAXUNIT); - if (error != 0) - goto bail2; - - error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); - if (error != 0) - goto bail2; /* intitialize device */ SLIST_INIT(&taphead); eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); - if (eh_tag == NULL) { - error = ENOMEM; - goto bail2; - } - - + if (eh_tag == NULL) + return (ENOMEM); return (0); -bail2: - rman_fini(vmnetunits); -bail1: - rman_fini(tapunits); -bail: - return (error); case MOD_UNLOAD: SLIST_FOREACH(tp, &taphead, tap_next) - if (tp->tap_unit != NULL) + if (tp->tap_flags & TAP_OPEN) return (EBUSY); EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); - error = rman_fini(tapunits); - KASSERT((error == 0), ("Could not fini tap units")); - error = rman_fini(vmnetunits); - KASSERT((error == 0), ("Could not fini vmnet units")); - while ((tp = SLIST_FIRST(&taphead)) != NULL) { SLIST_REMOVE_HEAD(&taphead, tap_next); @@ -204,18 +161,14 @@ tapmodevent(mod, type, data) KASSERT(!(tp->tap_flags & TAP_OPEN), ("%s flags is out of sync", ifp->if_xname)); - /* XXX makedev check? nah.. not right now :) */ - + destroy_dev(tp->tap_dev); s = splimp(); ether_ifdetach(ifp); splx(s); free(tp, M_TAP); } - - if (tapbasedev != NOUDEV) - destroy_dev(udev2dev(tapbasedev, 0)); - + clone_cleanup(&tapclones); break; @@ -239,65 +192,35 @@ tapclone(arg, name, namelen, dev) int namelen; dev_t *dev; { - int unit, minor = 0 /* XXX avoid warning */ , error; + u_int extra; + int i, unit; char *device_name = name; - struct resource *r = NULL; if (*dev != NODEV) return; - if (strcmp(device_name, TAP) == 0) { - /* get first free tap unit */ - r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - unit = rman_get_start(r); - minor = unit2minor(unit); - } - else if (strcmp(device_name, VMNET) == 0) { - /* get first free vmnet unit */ - r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - unit = rman_get_start(r); - minor = unit2minor(unit) | VMNET_DEV_MASK; + device_name = TAP; + extra = 0; + if (strcmp(name, TAP) == 0) { + unit = -1; + } else if (strcmp(name, VMNET) == 0) { + device_name = VMNET; + extra = VMNET_DEV_MASK; + unit = -1; + } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { + device_name = VMNET; + extra = VMNET_DEV_MASK; + if (dev_stdclone(name, NULL, device_name, &unit) != 1) + return; } - if (r != NULL) { /* need cloning */ - TAPDEBUG("%s%d is available. minor = %#x\n", - device_name, unit, minor); - - error = rman_release_resource(r); - KASSERT((error == 0), ("Could not release tap/vmnet unit")); - - /* check if device for the unit has been created */ - *dev = makedev(CDEV_MAJOR, minor); - if ((*dev)->si_flags & SI_NAMED) { - TAPDEBUG("%s%d device exists. minor = %#x\n", - device_name, unit, minor); - return; /* device has been created */ - } - } else { /* try to match name/unit, first try tap then vmnet */ - device_name = TAP; - if (dev_stdclone(name, NULL, device_name, &unit) != 1) { - device_name = VMNET; - - if (dev_stdclone(name, NULL, device_name, &unit) != 1) - return; - - minor = unit2minor(unit) | VMNET_DEV_MASK; - } else - minor = unit2minor(unit); - } - - TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); - - *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", - device_name, unit); - - if (tapbasedev == NOUDEV) - tapbasedev = (*dev)->si_udev; - else { - (*dev)->si_flags |= SI_CHEAPCLONE; - dev_depends(udev2dev(tapbasedev, 0), *dev); + /* find any existing device, or allocate new unit number */ + i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); + if (i) { + *dev = make_dev(&tap_cdevsw, unit2minor(unit) | extra, + UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); + if (*dev != NULL) + (*dev)->si_flags |= SI_CHEAPCLONE; } } /* tapclone */ @@ -317,6 +240,8 @@ tapcreate(dev) int unit, s; char *name = NULL; + dev->si_flags &= ~SI_CHEAPCLONE; + /* allocate driver storage and create device */ MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); SLIST_INSERT_HEAD(&taphead, tp, tap_next); @@ -354,6 +279,7 @@ tapcreate(dev) ifp->if_snd.ifq_maxlen = ifqmaxlen; dev->si_drv1 = tp; + tp->tap_dev = dev; s = splimp(); ether_ifattach(ifp, tp->arpcom.ac_enaddr); @@ -380,24 +306,12 @@ tapopen(dev, flag, mode, td) { struct tap_softc *tp = NULL; int unit, error; - struct resource *r = NULL; if ((error = suser(td)) != 0) return (error); unit = dev2unit(dev) & TAPMAXUNIT; - if (minor(dev) & VMNET_DEV_MASK) - r = rman_reserve_resource(vmnetunits, unit, unit, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - else - r = rman_reserve_resource(tapunits, unit, unit, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - - if (r == NULL) - return (EBUSY); - - dev->si_flags &= ~SI_CHEAPCLONE; tp = dev->si_drv1; if (tp == NULL) { @@ -410,7 +324,6 @@ tapopen(dev, flag, mode, td) bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); - tp->tap_unit = r; tp->tap_pid = td->td_proc->p_pid; tp->tap_flags |= TAP_OPEN; @@ -433,12 +346,9 @@ tapclose(dev, foo, bar, td) int bar; struct thread *td; { - int s, error; struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = &tp->tap_if; - - KASSERT((tp->tap_unit != NULL), - ("%s is not open", ifp->if_xname)); + int s; /* junk all pending output */ IF_DRAIN(&ifp->if_snd); @@ -479,10 +389,6 @@ tapclose(dev, foo, bar, td) tp->tap_flags &= ~TAP_OPEN; tp->tap_pid = 0; - error = rman_release_resource(tp->tap_unit); - KASSERT((error == 0), - ("%s could not release unit", ifp->if_xname)); - tp->tap_unit = NULL; TAPDEBUG("%s is closed. minor = %#x\n", ifp->if_xname, minor(dev)); diff --git a/sys/net/if_tapvar.h b/sys/net/if_tapvar.h index 06e3bbdfe8a4..ae6c3cd442e1 100644 --- a/sys/net/if_tapvar.h +++ b/sys/net/if_tapvar.h @@ -61,6 +61,7 @@ struct tap_softc { struct selinfo tap_rsel; /* read select */ SLIST_ENTRY(tap_softc) tap_next; /* next device in chain */ + dev_t tap_dev; }; #endif /* !_NET_IF_TAPVAR_H_ */ diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 516d299f6d78..4a64da456072 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -41,9 +41,7 @@ #include #include #include -#include /* XXX Shouldn't really be required ! */ #include -#include #include #include @@ -53,17 +51,40 @@ #include #endif #include -#include #include +#include + +struct tun_softc { + TAILQ_ENTRY(tun_softc) tun_list; + int tun_unit; + dev_t tun_dev; + u_short tun_flags; /* misc flags */ +#define TUN_OPEN 0x0001 +#define TUN_INITED 0x0002 +#define TUN_RCOLL 0x0004 +#define TUN_IASET 0x0008 +#define TUN_DSTADDR 0x0010 +#define TUN_LMODE 0x0020 +#define TUN_RWAIT 0x0040 +#define TUN_ASYNC 0x0080 +#define TUN_IFHEAD 0x0100 + +#define TUN_READY (TUN_OPEN | TUN_INITED) + + struct proc *tun_proc; /* Owning process */ + struct ifnet tun_if; /* the interface */ + struct sigio *tun_sigio; /* information for async I/O */ + struct selinfo tun_rsel; /* read select */ +}; + #define TUNDEBUG if (tundebug) if_printf #define TUNNAME "tun" static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface"); static int tundebug = 0; -static struct tun_softc *tunhead = NULL; -static struct rman tununits; -static udev_t tunbasedev = NOUDEV; +static struct clonedevs *tunclones; +static TAILQ_HEAD(,tun_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead); SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); static void tunclone(void *arg, char *name, int namelen, dev_t *dev); @@ -82,7 +103,6 @@ static d_write_t tunwrite; static d_ioctl_t tunioctl; static d_poll_t tunpoll; -#define CDEV_MAJOR 52 static struct cdevsw tun_cdevsw = { .d_open = tunopen, .d_close = tunclose, @@ -91,44 +111,32 @@ static struct cdevsw tun_cdevsw = { .d_ioctl = tunioctl, .d_poll = tunpoll, .d_name = TUNNAME, - .d_maj = CDEV_MAJOR, + .d_flags = D_PSEUDO, }; static void tunclone(void *arg, char *name, int namelen, dev_t *dev) { - struct resource *r; - int err; - int u; + int u, i; if (*dev != NODEV) return; if (strcmp(name, TUNNAME) == 0) { - r = rman_reserve_resource(&tununits, 0, IF_MAXUNIT, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - u = rman_get_start(r); - err = rman_release_resource(r); - KASSERT(err == 0, ("Unexpected failure releasing resource")); - *dev = makedev(CDEV_MAJOR, unit2minor(u)); - if ((*dev)->si_flags & SI_NAMED) - return; /* Already make_dev()d */ + u = -1; } else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1) return; /* Don't recognise the name */ + if (u != -1 && u > IF_MAXUNIT) + return; /* Unit number too high */ - *dev = make_dev(&tun_cdevsw, unit2minor(u), - UID_ROOT, GID_WHEEL, 0600, "tun%d", u); - - /* - * All devices depend on tunbasedev so that we can simply - * destroy_dev() this device at module unload time to get - * rid of all our make_dev()d resources. - */ - if (tunbasedev == NOUDEV) - tunbasedev = (*dev)->si_udev; - else { - (*dev)->si_flags |= SI_CHEAPCLONE; - dev_depends(udev2dev(tunbasedev, 0), *dev); + /* find any existing device, or allocate new unit number */ + i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0); + if (i) { + /* No preexisting dev_t, create one */ + *dev = make_dev(&tun_cdevsw, unit2minor(u), + UID_UUCP, GID_DIALER, 0600, "tun%d", u); + if (*dev != NULL) + (*dev)->si_flags |= SI_CHEAPCLONE; } } @@ -138,57 +146,29 @@ tunmodevent(module_t mod, int type, void *data) static eventhandler_tag tag; struct tun_softc *tp; dev_t dev; - int err; switch (type) { case MOD_LOAD: tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000); if (tag == NULL) return (ENOMEM); - tununits.rm_type = RMAN_ARRAY; - tununits.rm_descr = "open if_tun units"; - err = rman_init(&tununits); - if (err != 0) { - EVENTHANDLER_DEREGISTER(dev_clone, tag); - return (err); - } - err = rman_manage_region(&tununits, 0, IF_MAXUNIT); - if (err != 0) { - printf("%s: tununits: rman_manage_region: Failed %d\n", - TUNNAME, err); - rman_fini(&tununits); - EVENTHANDLER_DEREGISTER(dev_clone, tag); - return (err); - } break; case MOD_UNLOAD: - err = rman_fini(&tununits); - if (err != 0) - return (err); EVENTHANDLER_DEREGISTER(dev_clone, tag); - while (tunhead != NULL) { - KASSERT((tunhead->tun_flags & TUN_OPEN) == 0, + while (!TAILQ_EMPTY(&tunhead)) { + tp = TAILQ_FIRST(&tunhead); + KASSERT((tp->tun_flags & TUN_OPEN) == 0, ("tununits is out of sync - unit %d", - tunhead->tun_if.if_dunit)); - tp = tunhead; - dev = makedev(tun_cdevsw.d_maj, - unit2minor(tp->tun_if.if_dunit)); - KASSERT(dev->si_drv1 == tp, ("Bad makedev result")); - tunhead = tp->next; + tp->tun_if.if_dunit)); + TAILQ_REMOVE(&tunhead, tp, tun_list); + dev = tp->tun_dev; bpfdetach(&tp->tun_if); if_detach(&tp->tun_if); - KASSERT(dev->si_flags & SI_NAMED, ("Missing make_dev")); + destroy_dev(dev); free(tp, M_TUN); } - - /* - * Destroying tunbasedev results in all of our make_dev()s - * conveniently going away. - */ - if (tunbasedev != NOUDEV) - destroy_dev(udev2dev(tunbasedev, 0)); - + clone_cleanup(&tunclones); break; } return 0; @@ -222,14 +202,12 @@ tuncreate(dev_t dev) struct tun_softc *sc; struct ifnet *ifp; - if (!(dev->si_flags & SI_NAMED)) - dev = make_dev(&tun_cdevsw, minor(dev), - UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev)); + dev->si_flags &= ~SI_CHEAPCLONE; MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO); sc->tun_flags = TUN_INITED; - sc->next = tunhead; - tunhead = sc; + sc->tun_dev = dev; + TAILQ_INSERT_TAIL(&tunhead, sc, tun_list); ifp = &sc->tun_if; if_initname(ifp, TUNNAME, dev2unit(dev)); @@ -249,32 +227,21 @@ tuncreate(dev_t dev) static int tunopen(dev_t dev, int flag, int mode, struct thread *td) { - struct resource *r; struct ifnet *ifp; struct tun_softc *tp; - int unit; - - unit = dev2unit(dev); - if (unit > IF_MAXUNIT) - return (ENXIO); - - r = rman_reserve_resource(&tununits, unit, unit, 1, - RF_ALLOCATED | RF_ACTIVE, NULL); - if (r == NULL) - return (EBUSY); - - dev->si_flags &= ~SI_CHEAPCLONE; tp = dev->si_drv1; if (!tp) { tuncreate(dev); tp = dev->si_drv1; } - KASSERT(!(tp->tun_flags & TUN_OPEN), ("Resource & flags out-of-sync")); - tp->tun_unit = r; - tp->tun_pid = td->td_proc->p_pid; - ifp = &tp->tun_if; + + if (tp->tun_proc != NULL && tp->tun_proc != td->td_proc) + return (EBUSY); + tp->tun_proc = td->td_proc; + tp->tun_flags |= TUN_OPEN; + ifp = &tp->tun_if; TUNDEBUG(ifp, "open\n"); return (0); @@ -290,14 +257,12 @@ tunclose(dev_t dev, int foo, int bar, struct thread *td) struct tun_softc *tp; struct ifnet *ifp; int s; - int err; tp = dev->si_drv1; ifp = &tp->tun_if; - KASSERT(tp->tun_unit, ("Unit %d not marked open", tp->tun_if.if_dunit)); tp->tun_flags &= ~TUN_OPEN; - tp->tun_pid = 0; + tp->tun_proc = NULL; /* * junk all pending output @@ -325,11 +290,7 @@ tunclose(dev_t dev, int foo, int bar, struct thread *td) funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); - TUNDEBUG (ifp, "closed\n"); - err = rman_release_resource(tp->tun_unit); - KASSERT(err == 0, ("Unit %d failed to release", tp->tun_if.if_dunit)); - return (0); } @@ -384,9 +345,9 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) switch(cmd) { case SIOCGIFSTATUS: ifs = (struct ifstat *)data; - if (tp->tun_pid) + if (tp->tun_proc) sprintf(ifs->ascii + strlen(ifs->ascii), - "\tOpened by PID %d\n", tp->tun_pid); + "\tOpened by PID %d\n", tp->tun_proc->p_pid); break; case SIOCSIFADDR: error = tuninit(ifp); @@ -573,7 +534,7 @@ tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) } break; case TUNSIFPID: - tp->tun_pid = curthread->td_proc->p_pid; + tp->tun_proc = curthread->td_proc; break; case FIONBIO: break; diff --git a/sys/net/if_tunvar.h b/sys/net/if_tunvar.h deleted file mode 100644 index cda53f0c3785..000000000000 --- a/sys/net/if_tunvar.h +++ /dev/null @@ -1,55 +0,0 @@ -/*- - * Copyright (c) 1998 Brian Somers - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NET_IF_TUNVAR_H_ -#define _NET_IF_TUNVAR_H_ - -struct tun_softc { - u_short tun_flags; /* misc flags */ -#define TUN_OPEN 0x0001 -#define TUN_INITED 0x0002 -#define TUN_RCOLL 0x0004 -#define TUN_IASET 0x0008 -#define TUN_DSTADDR 0x0010 -#define TUN_LMODE 0x0020 -#define TUN_RWAIT 0x0040 -#define TUN_ASYNC 0x0080 -#define TUN_IFHEAD 0x0100 - -#define TUN_READY (TUN_OPEN | TUN_INITED) - - pid_t tun_pid; /* PID of process to open */ - struct ifnet tun_if; /* the interface */ - struct sigio *tun_sigio; /* information for async I/O */ - struct selinfo tun_rsel; /* read select */ - - struct tun_softc *next; /* Next softc in list */ - struct resource *tun_unit; /* resource allocated for this unit */ -}; - -#endif /* !_NET_IF_TUNVAR_H_ */ diff --git a/sys/sys/conf.h b/sys/sys/conf.h index fb39f08b3962..a203c11fd0c8 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -64,10 +64,12 @@ struct cdev { #define SI_CONSOPEN 0x0040 /* opened by console */ #define SI_DUMPDEV 0x0080 /* is kernel dumpdev */ #define SI_CANDELETE 0x0100 /* can do BIO_DELETE */ +#define SI_CLONELIST 0x0200 /* on a clone list */ struct timespec si_atime; struct timespec si_ctime; struct timespec si_mtime; udev_t si_udev; + LIST_ENTRY(cdev) si_clone; LIST_ENTRY(cdev) si_hash; SLIST_HEAD(, vnode) si_hlist; LIST_HEAD(, cdev) si_children; @@ -125,6 +127,7 @@ struct buf; struct thread; struct uio; struct knote; +struct clonedevs; /* * Note: d_thread_t is provided as a transition aid for those drivers @@ -198,6 +201,7 @@ typedef int dumper_t( #define D_NAGGED 0x00020000 /* nagged about missing make_dev() */ #define D_TRACKCLOSE 0x00080000 /* track all closes */ #define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */ +#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */ #define D_NOGIANT 0x00400000 /* Doesn't want Giant */ /* @@ -274,6 +278,11 @@ static moduledata_t name##_mod = { \ DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE) +void clone_cleanup(struct clonedevs **); +#define CLONE_UNITMASK 0xfffff +#define CLONE_FLAG0 (CLONE_UNITMASK + 1) +int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_int extra); + int count_dev(dev_t _dev); void destroy_dev(dev_t _dev); struct cdevsw *devsw(dev_t _dev); diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index fb39f08b3962..a203c11fd0c8 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -64,10 +64,12 @@ struct cdev { #define SI_CONSOPEN 0x0040 /* opened by console */ #define SI_DUMPDEV 0x0080 /* is kernel dumpdev */ #define SI_CANDELETE 0x0100 /* can do BIO_DELETE */ +#define SI_CLONELIST 0x0200 /* on a clone list */ struct timespec si_atime; struct timespec si_ctime; struct timespec si_mtime; udev_t si_udev; + LIST_ENTRY(cdev) si_clone; LIST_ENTRY(cdev) si_hash; SLIST_HEAD(, vnode) si_hlist; LIST_HEAD(, cdev) si_children; @@ -125,6 +127,7 @@ struct buf; struct thread; struct uio; struct knote; +struct clonedevs; /* * Note: d_thread_t is provided as a transition aid for those drivers @@ -198,6 +201,7 @@ typedef int dumper_t( #define D_NAGGED 0x00020000 /* nagged about missing make_dev() */ #define D_TRACKCLOSE 0x00080000 /* track all closes */ #define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */ +#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */ #define D_NOGIANT 0x00400000 /* Doesn't want Giant */ /* @@ -274,6 +278,11 @@ static moduledata_t name##_mod = { \ DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE) +void clone_cleanup(struct clonedevs **); +#define CLONE_UNITMASK 0xfffff +#define CLONE_FLAG0 (CLONE_UNITMASK + 1) +int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_int extra); + int count_dev(dev_t _dev); void destroy_dev(dev_t _dev); struct cdevsw *devsw(dev_t _dev);