On 20/11/18(Tue) 18:29, Anton Lindqvist wrote:
> On Tue, Nov 20, 2018 at 09:39:52AM +0000, Natasha Kerensikova wrote:
> > Hello,
> > 
> > Context:
> > 
> > I have a Thinkpad X220 with an integrated WWAN modem "Lenovo F5521gw",
> > which presents itself as USB devices umodem0-2, ucom0-2, and ugen0 on
> > uhub3. I don't really know whether uhub3 is part of the modem or part of
> > the motherboard where the modem is plugged.
> > 
> > In my day-to-day use of the modem, it sometimes randomly vanishes from
> > the USB bus, leaving only uhub3. I never bother to find out what really
> > happened, it came back by itself when I re-started pppd.
> > 
> > 
> > Problem Summary:
> > 
> > Since a recent update in CURRENT, whenever the modem disappears from
> > the USB bus, I get a kernel panic.
> > 
> > While the random vanishing are infrequent, I can reliably trigger the
> > same panic when requesting hibernation (either with ampd running and
> > calling ZZZ, or without ampd using the keyboard shortcut), presumably
> > because hibernation somehow turns off the modem.
> > 
> > So in effect, hibernation is now broken for me.
> > 
> > 
> > Problem Details:
> > 
> > The oldest affected version is:
> > OpenBSD 6.4-current (GENERIC.MP) #446: Sat Nov 17 17:41:16 MST 2018
> >     [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > 
> > The newest non-affected version is:
> > OpenBSD 6.3-current (GENERIC.MP) #91: Sat Jun  9 20:57:09 MDT 2018
> >     [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > (I'm not very good with regular updates on this machine, mostly because
> > I don't often have network access other than the WWAN with a small data
> > plan)
> > 
> > The full panic message is:
> > panic: free: size too small 16 <= 128 / 2 (0xffff80000056bc00) type USB
> > 
> > The number above is the same in all instances, even across kernel
> > re-linking and even snapshot updates.
> > 
> > Here is a transcription of the reproducible parts of the remaining of
> > the panic screen:
> > 
> > Stopped at      db_enter+0x12:  popq     %r11
> >     TID    PID    UID     PRFLAGS      PFLAGS  CPU  COMMAND
> > <some random process which seems unrelated>
> > i*??????  ?????     0     0x14000       0x200    2K usbtask
> > db_enter() at db_enter+0x12
> > panic() at panic+0x120
> > free(<random hex>,ffff80000051c800,ffff800000565500) at free+0x3cf
> > usb_free_device(0) at usb_free_device+0xf6
> > usbd_detach(<random hex>,<random hex>) at usbd_detach+0x81
> > 
> > The rest of the stack trace varies from instance to instance, but
> > usb_detach is called at least from uhub_port_connect (coming from
> > uhub_explore and usb_explore) or from config_detach (coming from
> > uhub_detach, then another usbd_detach, and uhub_detact).
> > 
> > In one instance (with config_detach), I checked the dmesg from ddb, and
> > it ends with:
> > uhub2 detached
> > uhub0 detached
> > ucom0 detached
> > umodem0 detached
> > ucom1 detached
> > umodem1 detached
> > ucom2 detached
> > umodem2 detached
> > ugen0 detached
> > 
> > I can provide photos or transcripts of specific instances if that can
> > help.
> 
> Ran into the same problem. Looks like one nsubdev assignment is
> happening outside the branch where the actual allocation is performed.
> With the diff below, suspend works again. Note, the diff is generated
> prior to the revert for clarity.

Thanks for analyse Anton, here's the full diff.

Index: usb_subr.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.145
diff -u -p -r1.145 usb_subr.c
--- usb_subr.c  20 Nov 2018 11:51:23 -0000      1.145
+++ usb_subr.c  21 Nov 2018 15:57:41 -0000
@@ -891,6 +891,7 @@ usbd_probe_and_attach(struct device *par
                        err = USBD_NOMEM;
                        goto fail;
                }
+               dev->nsubdev = 2;
                dev->subdevs[dev->ndevs++] = dv;
                dev->subdevs[dev->ndevs] = 0;
                err = USBD_NORMAL_COMPLETION;
@@ -933,6 +934,7 @@ usbd_probe_and_attach(struct device *par
                /* add 1 for possible ugen and 1 for NULL terminator */
                dev->subdevs = mallocarray(nifaces + 2, sizeof(dv), M_USB,
                    M_NOWAIT | M_ZERO);
+               dev->nsubdev = nifaces + 2;
                if (dev->subdevs == NULL) {
                        free(ifaces, M_USB, nifaces * sizeof(*ifaces));
                        err = USBD_NOMEM;
@@ -964,8 +966,9 @@ usbd_probe_and_attach(struct device *par
                                goto fail;
                }
 
-               free(dev->subdevs, M_USB, (nifaces + 2) * sizeof(dv));
+               free(dev->subdevs, M_USB, dev->nsubdev * sizeof(*dev->subdevs));
                dev->subdevs = NULL;
+               dev->nsubdev = 0;
        }
        /* No interfaces were attached in any of the configurations. */
 
@@ -989,6 +992,7 @@ generic:
                                err = USBD_NOMEM;
                                goto fail;
                        }
+                       dev->nsubdev = 2;
                }
                dev->subdevs[dev->ndevs++] = dv;
                dev->subdevs[dev->ndevs] = 0;
@@ -1407,8 +1411,7 @@ usb_free_device(struct usbd_device *dev)
        }
        if (dev->cdesc != NULL)
                free(dev->cdesc, M_USB, UGETW(dev->cdesc->wTotalLength));
-       if (dev->subdevs != NULL)
-               free(dev->subdevs, M_USB, 0);
+       free(dev->subdevs, M_USB, dev->nsubdev * sizeof(*dev->subdevs));
        dev->bus->devices[dev->address] = NULL;
 
        if (dev->vendor != NULL)
Index: usbdivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.78
diff -u -p -r1.78 usbdivar.h
--- usbdivar.h  20 Nov 2018 11:51:23 -0000      1.78
+++ usbdivar.h  21 Nov 2018 15:58:13 -0000
@@ -158,6 +158,7 @@ struct usbd_device {
        const struct usbd_quirks     *quirks;  /* device quirks, always set */
        struct usbd_hub        *hub;           /* only if this is a hub */
        struct device         **subdevs;       /* sub-devices, 0 terminated */
+       int                     nsubdev;       /* size of the `subdevs' array */
        int                     ndevs;         /* # of subdevs */
 
        char                   *serial;        /* serial number, can be NULL */

Reply via email to