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 */