并发、队列、生命周期与错误恢复

并发、队列、生命周期与错误恢复

1. 执行上下文

每条活动USB/IP连接通常有:

  • 一个RX kthread;
  • 一个TX kthread;
  • 共享的全局单线程event workqueue;
  • Stub真实URB completion或VHCI giveback上下文;
  • sysfs管理进程上下文;
  • VUDC额外transfer timer。

Socket收发可睡眠,只在kthread中执行。真实URB completion仅移动链表并唤醒TX。

2. 公共同步

usbip_device

  • lock:status、event等短临界区;
  • sysfs_lock:连接建立/拆除与EH串行;
  • eh_waitq:等待event处理完成;
  • socket shutdown:唤醒阻塞中的RX/TX。

Event list由全局spinlock保护,workqueue对同一设备的多个事件合并。

3. Stub队列状态

一次SUBMIT对应的stub_priv始终位于:

1
priv_init -> priv_tx -> priv_free
  • priv_init:真实URB尚未全部完成;
  • priv_tx:可发送RET_SUBMIT;
  • priv_free:网络结果已发送,可释放。

UNLINK另有unlink_txunlink_free。所有链表由priv_lock保护,TX waitqueue由completion和unlink处理唤醒。

Scatter-gather拆分时,多个真实URB共享一个stub_priv。只有completed_urbs == num_urbs才能进入TX,聚合status必须保留首个有效错误。

4. VHCI队列状态

1
2
3
4
5
6
URB enqueue
-> priv_tx
-> TCP发送成功
-> priv_rx
-> RET_SUBMIT
-> giveback

urb->hcpriv指向vhci_priv,seqnum是网络请求主键。priv_lock保护submit和unlink链表,vhci->lock同时保护HCD endpoint链接、port status和设备连接状态。

锁内不能执行可能睡眠的socket操作;giveback也常需要临时释放全局锁,防止completion回调重入HCD。

5. Unlink状态机

URB取消与正常完成存在天然竞态:

1
2
3
CMD_UNLINK ----\
+-- 哪个先到均可能
RET_SUBMIT -----/

实现需要满足:

  • 一个URB只完成一次;
  • 目标seqnum找不到时不释放未知对象;
  • RET_UNLINK不等价于原URB一定没有RET_SUBMIT;
  • disconnect清理覆盖所有submit/unlink列表。

VHCI分别维护unlink_tx/unlink_rx;Stub在收到取消后调用usb_unlink_urb()并排队RET_UNLINK。

6. Event优先级

EH顺序固定:

  1. SHUTDOWN
  2. RESET
  3. UNUSABLE

原因是必须先停止socket线程和新I/O,才能安全清理URB及改变状态。BYE用于对象remove,阻止再加入新event。

7. 常见错误入口

  • usbip_recv()得到0:对端关闭;
  • send/recv返回负值:TCP错误;
  • header command非法:协议错误;
  • buffer/URB分配失败:malloc event;
  • usb_submit_urb()失败:submit event;
  • USB物理设备remove:removed event;
  • sysfs写入无效fd、非stream socket或已占用端口:立即返回错误。

这些错误通常会拆除整条设备连接,而不是只丢弃单个PDU,避免字节流失去消息边界后继续解析。

8. 生命周期规则

正确销毁顺序:

1
2
3
4
5
6
7
8
9
block new sysfs operations
-> shutdown socket
-> stop RX/TX
-> kill/giveback pending URBs
-> clear queues
-> drop socket/device references
-> reset/disconnect port
-> stop EH
-> free object

线程由kthread_create后额外get_task_struct(),退出时需kthread_stop_put()成对释放。

9. 内存与输入验证

网络头控制URB数量、transfer buffer和ISO descriptor分配,是高风险路径。已有保护包括:

  • ISO packet上限;
  • 负数检查;
  • endpoint和direction检查;
  • actual length不得超过transfer buffer;
  • VUDC按max packet估算packet上限;
  • 无效command触发连接错误。

审计时仍应重点检查整数乘法溢出、SG拆分、short read、异常actual length和disconnect并发。

10. PM语义

VHCI的bus suspend/resume仅改变软件HCD状态,不能保证远端物理设备、电源域或网络连接同步休眠。系统休眠前最好显式detach;否则恢复后TCP可能超时,最终表现为热拔插。

文章互动

阅读 --

留言

0 条留言

正在加载留言…