Module Name: src Committed By: snj Date: Fri Apr 10 18:12:53 UTC 2009
Modified Files: src/sys/dev/ir [netbsd-5]: irframe_tty.c Log Message: Pull up following revision(s) (requested by mlelstv in ticket #684): sys/dev/ir/irframe_tty.c: revision 1.56 Avoid crash under LOCKDEBUG by destroying a mutex correctly. Also: move mutex init/destroy into attach/detach functions and handle case where line discipline is closed before the irframe device. Fixes PR kern/40271. To generate a diff of this commit: cvs rdiff -u -r1.54 -r1.54.8.1 src/sys/dev/ir/irframe_tty.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ir/irframe_tty.c diff -u src/sys/dev/ir/irframe_tty.c:1.54 src/sys/dev/ir/irframe_tty.c:1.54.8.1 --- src/sys/dev/ir/irframe_tty.c:1.54 Sun May 25 19:22:21 2008 +++ src/sys/dev/ir/irframe_tty.c Fri Apr 10 18:12:53 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: irframe_tty.c,v 1.54 2008/05/25 19:22:21 ad Exp $ */ +/* $NetBSD: irframe_tty.c,v 1.54.8.1 2009/04/10 18:12:53 snj Exp $ */ /* * TODO @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: irframe_tty.c,v 1.54 2008/05/25 19:22:21 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: irframe_tty.c,v 1.54.8.1 2009/04/10 18:12:53 snj Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -148,6 +148,7 @@ static void irt_setspeed(struct tty *, u_int); static void irt_setline(struct tty *, u_int); static void irt_delay(struct tty *, u_int); +static void irt_buffer(struct irframet_softc *, u_int); static const struct irframe_methods irframet_methods = { irframet_open, irframet_close, irframet_read, irframet_write, @@ -218,9 +219,16 @@ static void irframet_attach(device_t parent, device_t self, void *aux) { + struct irframet_softc *sc = device_private(self); /* pseudo-device attachment does not print name */ aprint_normal("%s", device_xname(self)); + + callout_init(&sc->sc_timeout, 0); + mutex_init(&sc->sc_wr_lk, MUTEX_DEFAULT, IPL_NONE); + selinit(&sc->sc_rsel); + selinit(&sc->sc_wsel); + #if 0 /* XXX can't do it yet because pseudo-devices don't get aux */ struct ir_attach_args ia; @@ -234,8 +242,19 @@ static int irframet_detach(struct device *dev, int flags) { + struct irframet_softc *sc = device_private(dev); + int rc; + + callout_stop(&sc->sc_timeout); + + rc = irframe_detach(dev, flags); - return (irframe_detach(dev, flags)); + callout_destroy(&sc->sc_timeout); + mutex_destroy(&sc->sc_wr_lk); + seldestroy(&sc->sc_wsel); + seldestroy(&sc->sc_rsel); + + return rc; } /* @@ -326,8 +345,8 @@ ttyflush(tp, FREAD | FWRITE); mutex_spin_exit(&tty_lock); /* XXX */ ttyldisc_release(tp->t_linesw); - tp->t_linesw = ttyldisc_default(); - if (sc != NULL) { + tp->t_linesw = ttyldisc_default(); if (sc != NULL) { + irt_buffer(sc, 0); tp->t_sc = NULL; aprint_normal("%s detached from tty%02d\n", device_xname(sc->sc_irp.sc_dev), minor(tp->t_dev)); @@ -402,6 +421,35 @@ return (0); } +static void +irt_buffer(struct irframet_softc *sc, u_int maxsize) +{ + int i; + + DPRINTF(("%s: sc=%p, maxsize=%u\n", __func__, sc, maxsize)); + + if (sc->sc_params.maxsize != maxsize) { + sc->sc_params.maxsize = maxsize; + if (sc->sc_inbuf != NULL) + free(sc->sc_inbuf, M_DEVBUF); + for (i = 0; i < MAXFRAMES; i++) + if (sc->sc_frames[i].buf != NULL) + free(sc->sc_frames[i].buf, M_DEVBUF); + if (sc->sc_params.maxsize != 0) { + sc->sc_inbuf = malloc(sc->sc_params.maxsize+2, + M_DEVBUF, M_WAITOK); + for (i = 0; i < MAXFRAMES; i++) + sc->sc_frames[i].buf = + malloc(sc->sc_params.maxsize, + M_DEVBUF, M_WAITOK); + } else { + sc->sc_inbuf = NULL; + for (i = 0; i < MAXFRAMES; i++) + sc->sc_frames[i].buf = NULL; + } + } +} + void irt_frame(struct irframet_softc *sc, u_char *tbuf, u_int len) { @@ -529,7 +577,6 @@ { struct tty *tp = h; struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc; - static bool again; DPRINTF(("%s: tp=%p\n", __func__, tp)); @@ -541,15 +588,6 @@ sc->sc_framei = 0; sc->sc_frameo = 0; - /* XXX */ - if (!again) { - again = true; - callout_init(&sc->sc_timeout, 0); - mutex_init(&sc->sc_wr_lk, MUTEX_DEFAULT, IPL_NONE); - selinit(&sc->sc_rsel); - selinit(&sc->sc_wsel); - } - return (0); } @@ -559,22 +597,17 @@ { struct tty *tp = h; struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc; - int i, s; + int s; DPRINTF(("%s: tp=%p\n", __func__, tp)); + /* line discipline was closed */ + if (sc == NULL) + return (0); + callout_stop(&sc->sc_timeout); s = splir(); - if (sc->sc_inbuf != NULL) { - free(sc->sc_inbuf, M_DEVBUF); - sc->sc_inbuf = NULL; - } - for (i = 0; i < MAXFRAMES; i++) { - if (sc->sc_frames[i].buf != NULL) { - free(sc->sc_frames[i].buf, M_DEVBUF); - sc->sc_frames[i].buf = NULL; - } - } + irt_buffer(sc, 0); splx(s); return (0); @@ -830,7 +863,6 @@ { struct tty *tp = h; struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc; - int i; DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n", __func__, tp, p->speed, p->ebofs, p->maxsize)); @@ -845,27 +877,7 @@ /* Max size checked in irframe.c */ sc->sc_params.ebofs = p->ebofs; - /* Max size checked in irframe.c */ - if (sc->sc_params.maxsize != p->maxsize) { - sc->sc_params.maxsize = p->maxsize; - if (sc->sc_inbuf != NULL) - free(sc->sc_inbuf, M_DEVBUF); - for (i = 0; i < MAXFRAMES; i++) - if (sc->sc_frames[i].buf != NULL) - free(sc->sc_frames[i].buf, M_DEVBUF); - if (sc->sc_params.maxsize != 0) { - sc->sc_inbuf = malloc(sc->sc_params.maxsize+2, - M_DEVBUF, M_WAITOK); - for (i = 0; i < MAXFRAMES; i++) - sc->sc_frames[i].buf = - malloc(sc->sc_params.maxsize, - M_DEVBUF, M_WAITOK); - } else { - sc->sc_inbuf = NULL; - for (i = 0; i < MAXFRAMES; i++) - sc->sc_frames[i].buf = NULL; - } - } + irt_buffer(sc, p->maxsize); sc->sc_framestate = FRAME_OUTSIDE; return (0);