首先报错代码如下,assert的时候,status 并不是NAK
1 | if (xfer->iso_xfer) { |
首先查看redirect代码,发现正常情况下iso请求,是不会置为NAK状态的,怀疑这个请求是失效的。
基于之前对于qemu多线程可能引起问题的推断,继续查看core文件和代码尝试排查
首先根据core文件,获取Endpoint信息



可以看到Endpoint 对应的type是255,说明是已经失效的Ednpoint
通过Endpoint,获取device信息

再回过头来分析出错代码
在线程1中,从epctx中取retry指向的xfer,并对其进行重试
1 | static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) |
线程2中,收到来自客户端的请求,请求断开连接
其中代码,先进行detach操作
再进行usbredir_init_endpoints,这个操作,是唯一一个会把工作中的endpoint置为type是255的地方
1 | static void usbredir_device_disconnect(void *priv) |
所以,如果xhci的detach操作,没能达到下面任意一个,就有可能出问题
- 停止xhci_kick_epctx操作
- 清空retry节点下的xfer
- 必须保证在usbredir_init_endpoints之前执行完前面的
下面先来看detach做了什么
1 | static void xhci_detach(USBPort *usbport) |
可以看到分别作了xhci_detach_slot和xhci_port_update两件事
先看 xhci_detach_slot
1 | /* cleanup slot state on usb device detach */ |
可以明显看到释放 epctx->transfers 下的xfer
下面就确认epctx->transfers 和epctx->retry是否有交集
1 | static XHCITransfer *xhci_ep_alloc_xfer(XHCIEPContext *epctx, |
1 | static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) |
还是这个函数xhci_kick_epctx
可以看到retry 指向的是xhci_ep_alloc_xfer 申请出来的xfer,实际上就是transfers链下面的
由此可见,至少retry指向的节点是被释放了的,但是retry自身却暂时还没找到设置为NULL的地方
1 | static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) |
除了xhci_kick_epctx自身之外,只在这里找到了retry的NULL设置
会过头来再看函数调用,发现detach的时候有调用,说明是释放了的。
- xhci_detach
- xhci_detach_slot
- xhci_ep_nuke_xfers
- xhci_ep_nuke_one_xfer
- xhci_ep_nuke_xfers
- xhci_detach_slot
那么问题原因就清楚了,应该是因为多线程导致
xhci_kick_epctx执行过程中,已经获取了retry指向的xfer
线程切换到disconnect,调用xhci_detach函数导致xfer失效
继续切会xhci_kick_epctx,对xfer进行操作,导致访问非法指针中的无效数据出错
- 本文作者: crazyboy
- 本文链接: http://crazyboy.www.crazyboy.info/blog/blog/2022/05/06/it/linux/qemu/qemu-iso-abort6/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!