From 32b7c9a433930842533064d829ba214aadf6a67d Mon Sep 17 00:00:00 2001 From: phk Date: Sat, 21 Feb 2004 20:29:52 +0000 Subject: [PATCH] Device megapatch 2/6: This commit adds a couple of functions for pseudodrivers to use for implementing cloning in a manner we will be able to lock down (shortly). Basically what happens is that pseudo drivers get a way to ask for "give me the dev_t with this unit number" or alternatively "give me a dev_t with the lowest guaranteed free unit number" (there is unfortunately a lot of non-POLA in the exact numeric value of this number, just live with it for now) Managing the unit number space this way removes the need to use rman(9) to do so in the drivers this greatly simplifies the code in the drivers because even using rman(9) they still needed to manage their dev_t's anyway. I have taken the if_tun, if_tap, snp and nmdm drivers through the mill, partly because they (ab)used makedev(), but mostly because together they represent three different problems for device-cloning: if_tun and snp is the plain case: just give me a device. if_tap has two kinds of devices, with a flag for device type. nmdm has paired devices (ala pty) can you can clone either of them. --- sys/conf/majors | 3 - sys/dev/nmdm/nmdm.c | 169 ++++++++++++++++++++++--------------------- sys/dev/snp/snp.c | 30 +++----- sys/kern/kern_conf.c | 137 +++++++++++++++++++++++++++++++++-- sys/net/if_tap.c | 164 +++++++++-------------------------------- sys/net/if_tapvar.h | 1 + sys/net/if_tun.c | 161 ++++++++++++++++------------------------- sys/net/if_tunvar.h | 55 -------------- sys/sys/conf.h | 9 +++ sys/sys/linedisc.h | 9 +++ 10 files changed, 341 insertions(+), 397 deletions(-) delete mode 100644 sys/net/if_tunvar.h 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);