From owner-svn-src-stable-10@FreeBSD.ORG Thu Sep 18 19:20:09 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 43CEB799; Thu, 18 Sep 2014 19:20:09 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2E00A7E0; Thu, 18 Sep 2014 19:20:09 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8IJK9iL009559; Thu, 18 Sep 2014 19:20:09 GMT (envelope-from grehan@FreeBSD.org) Received: (from grehan@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8IJK90l009558; Thu, 18 Sep 2014 19:20:09 GMT (envelope-from grehan@FreeBSD.org) Message-Id: <201409181920.s8IJK90l009558@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: grehan set sender to grehan@FreeBSD.org using -f From: Peter Grehan Date: Thu, 18 Sep 2014 19:20:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r271800 - stable/10/sys/dev/nmdm X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Sep 2014 19:20:09 -0000 Author: grehan Date: Thu Sep 18 19:20:08 2014 New Revision: 271800 URL: http://svnweb.freebsd.org/changeset/base/271800 Log: MFC nmdm driver changes, r259550 and r271350 r259550 (glebius): Make nmdm(4) destroy devices when both sides of a pair are disconnected. This makes it possible to kldunload nmdm.ko when there are no users of it. r271350: Fix issue with nmdm and leading zeros in device name. The nmdm code enforces a number between the 'nmdm' and 'A|B' portions of the device name. This is then used as a unit number, and sprintf'd back into the tty name. If leading zeros were used in the name, the created device name is different than the string used for the clone-open (e.g. /dev/nmdm0001A will result in /dev/nmdm1A). Since unit numbers are no longer required with the updated tty code, there seems to be no reason to force the string to be a number. The fix is to allow an arbitrary string between 'nmdm' and 'A|B', within the constraints of devfs names. This allows all existing user of numeric strings to continue to work, and also allows more meaningful names to be used, such as bhyve VM names. PR: 192281 Approved by: re (glebius) Modified: stable/10/sys/dev/nmdm/nmdm.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/nmdm/nmdm.c ============================================================================== --- stable/10/sys/dev/nmdm/nmdm.c Thu Sep 18 19:15:40 2014 (r271799) +++ stable/10/sys/dev/nmdm/nmdm.c Thu Sep 18 19:20:08 2014 (r271800) @@ -58,6 +58,8 @@ static tsw_inwakeup_t nmdm_outwakeup; static tsw_outwakeup_t nmdm_inwakeup; static tsw_param_t nmdm_param; static tsw_modem_t nmdm_modem; +static tsw_close_t nmdm_close; +static tsw_free_t nmdm_free; static struct ttydevsw nmdm_class = { .tsw_flags = TF_NOPREFIX, @@ -65,6 +67,8 @@ static struct ttydevsw nmdm_class = { .tsw_outwakeup = nmdm_outwakeup, .tsw_param = nmdm_param, .tsw_modem = nmdm_modem, + .tsw_close = nmdm_close, + .tsw_free = nmdm_free, }; static void nmdm_task_tty(void *, int); @@ -94,15 +98,83 @@ struct nmdmsoftc { static int nmdm_count = 0; -static struct nmdmsoftc * -nmdm_alloc(unsigned long unit) +static void +nmdm_close(struct tty *tp) +{ + struct nmdmpart *np; + struct nmdmpart *onp; + struct tty *otp; + + np = tty_softc(tp); + onp = np->np_other; + otp = onp->np_tty; + + /* If second part is opened, do not destroy ourselves. */ + if (tty_opened(otp)) + return; + + /* Shut down self. */ + tty_rel_gone(tp); + + /* Shut down second part. */ + tty_lock(tp); + onp = np->np_other; + if (onp == NULL) + return; + otp = onp->np_tty; + tty_rel_gone(otp); + tty_lock(tp); +} + +static void +nmdm_free(void *softc) +{ + struct nmdmpart *np = (struct nmdmpart *)softc; + struct nmdmsoftc *ns = np->np_pair; + + callout_drain(&np->np_callout); + taskqueue_drain(taskqueue_swi, &np->np_task); + + /* + * The function is called on both parts simultaneously. We serialize + * with help of ns_mtx. The first invocation should return and + * delegate freeing of resources to the second. + */ + mtx_lock(&ns->ns_mtx); + if (np->np_other != NULL) { + np->np_other->np_other = NULL; + mtx_unlock(&ns->ns_mtx); + return; + } + mtx_destroy(&ns->ns_mtx); + free(ns, M_NMDM); + atomic_subtract_int(&nmdm_count, 1); +} + +static void +nmdm_clone(void *arg, struct ucred *cred, char *name, int nameen, + struct cdev **dev) { struct nmdmsoftc *ns; struct tty *tp; + char *end; + int error; + char endc; - atomic_add_int(&nmdm_count, 1); + if (*dev != NULL) + return; + if (strncmp(name, "nmdm", 4) != 0) + return; + if (strlen(name) <= strlen("nmdmX")) + return; + + /* Device name must be "nmdm%s%c", where %c is 'A' or 'B'. */ + end = name + strlen(name) - 1; + endc = *end; + if (endc != 'A' && endc != 'B') + return; - ns = malloc(sizeof(*ns), M_NMDM, M_WAITOK|M_ZERO); + ns = malloc(sizeof(*ns), M_NMDM, M_WAITOK | M_ZERO); mtx_init(&ns->ns_mtx, "nmdm", NULL, MTX_DEF); /* Hook the pairs together. */ @@ -119,43 +191,38 @@ nmdm_alloc(unsigned long unit) /* Create device nodes. */ tp = ns->ns_part1.np_tty = tty_alloc_mutex(&nmdm_class, &ns->ns_part1, &ns->ns_mtx); - tty_makedev(tp, NULL, "nmdm%luA", unit); + *end = 'A'; + error = tty_makedevf(tp, NULL, endc == 'A' ? TTYMK_CLONING : 0, + "%s", name); + if (error) { + *end = endc; + mtx_destroy(&ns->ns_mtx); + free(ns, M_NMDM); + return; + } tp = ns->ns_part2.np_tty = tty_alloc_mutex(&nmdm_class, &ns->ns_part2, &ns->ns_mtx); - tty_makedev(tp, NULL, "nmdm%luB", unit); - - return (ns); -} - -static void -nmdm_clone(void *arg, struct ucred *cred, char *name, int nameen, - struct cdev **dev) -{ - unsigned long unit; - char *end; - struct nmdmsoftc *ns; - - if (*dev != NULL) - return; - if (strncmp(name, "nmdm", 4) != 0) - return; - - /* Device name must be "nmdm%lu%c", where %c is 'A' or 'B'. */ - name += 4; - unit = strtoul(name, &end, 10); - if (unit == ULONG_MAX || name == end) - return; - if ((end[0] != 'A' && end[0] != 'B') || end[1] != '\0') + *end = 'B'; + error = tty_makedevf(tp, NULL, endc == 'B' ? TTYMK_CLONING : 0, + "%s", name); + if (error) { + *end = endc; + mtx_lock(&ns->ns_mtx); + /* see nmdm_free() */ + ns->ns_part1.np_other = NULL; + atomic_add_int(&nmdm_count, 1); + tty_rel_gone(ns->ns_part1.np_tty); return; + } - /* XXX: pass privileges? */ - ns = nmdm_alloc(unit); - - if (end[0] == 'A') + if (endc == 'A') *dev = ns->ns_part1.np_tty->t_dev; else *dev = ns->ns_part2.np_tty->t_dev; + + *end = endc; + atomic_add_int(&nmdm_count, 1); } static void @@ -187,6 +254,10 @@ nmdm_task_tty(void *arg, int pending __u tp = np->np_tty; tty_lock(tp); + if (tty_gone(tp)) { + tty_unlock(tp); + return; + } otp = np->np_other->np_tty; KASSERT(otp != NULL, ("NULL otp in nmdmstart")); @@ -203,6 +274,12 @@ nmdm_task_tty(void *arg, int pending __u } } + /* This may happen when we are in detach process. */ + if (tty_gone(otp)) { + tty_unlock(otp); + return; + } + while (ttydisc_rint_poll(otp) > 0) { if (np->np_rate && !np->np_quota) break;