并发、缓冲、阻塞、轮询与生命周期

并发、缓冲、阻塞、轮询与生命周期

1. 执行上下文

字符驱动同时面对:

  • process context的open/read/write/ioctl/mmap;
  • IRQ/threaded IRQ;
  • workqueue/timer;
  • PM callback;
  • device remove;
  • async notification;
  • fork/dup后的共享file。

User copy可fault和睡眠,不能在spinlock/hardirq执行。

2. Per-device与Per-file

Per-device:

  • MMIO/IRQ;
  • hardware queue;
  • global configuration;
  • remove状态;
  • class/cdev。

Per-file:

  • read offset;
  • pending response;
  • mode/filter;
  • event cursor;
  • ownership;
  • references。

把per-file command response放全局buffer会导致用户间串线。

3. 阻塞Read

标准循环:

1
2
3
4
5
6
7
8
9
10
lock
while no data and device alive:
unlock
if O_NONBLOCK return -EAGAIN
wait_event_interruptible(condition)
if signal return -ERESTARTSYS
lock
if removed return EOF/-ENODEV
copy data
unlock

条件必须在锁下重查,waitqueue只负责通知,不保存事件。

4. Write Backpressure

Buffer满时:

  • nonblock返回-EAGAIN
  • blocking等待space;
  • device remove返回-ENODEV/EPIPE
  • signal可能返回short write。

Driver不能无限分配内存吸收用户数据。

5. Poll

poll_wait()注册waitqueue,再读取当前状态。常见返回:

  • EPOLLIN|EPOLLRDNORM:有数据;
  • EPOLLOUT|EPOLLWRNORM:有空间;
  • EPOLLERR:硬件/协议错误;
  • EPOLLHUP:对端或设备消失。

Wake时可带poll mask减少无效唤醒。

6. Ring Buffer

IRQ producer与process consumer:

  • spinlock保护head/tail;
  • release/acquire或barrier保证payload先于index可见;
  • 长copy可在锁外进行但要固定buffer ownership;
  • wrap和size必须防溢出;
  • overflow策略要明确drop/newest/oldest/error。

7. Ioctl

Ioctl配置常与read/write并发。需要:

  • mutex串行硬件模式;
  • 防止模式切换使pending buffer解释失效;
  • copy_from_user前检查size;
  • reserved清零;
  • compat转换;
  • command超时;
  • remove状态检查。

8. Mmap

Mmap建立后close不会自动撤销VMA。Driver要用VMA open/close引用对象,并在remove时:

  • 禁止新mmap;
  • 停止DMA;
  • 必要时zap mapping;
  • 等VMA引用;
  • 再释放pages/MMIO。

不要把包含其它寄存器的整页映射给用户。

9. Remove

安全状态机:

1
2
3
4
5
6
7
8
LIVE
-> DYING
-> unregister node/cdev
-> stop IRQ/DMA/work
-> wake all waiters
-> complete pending I/O
-> wait open/VMA refs
-> DEAD/free

只调用device_destroy()不会让已有fd失效。

10. Module引用

fops.owner=THIS_MODULE阻止open期间卸载模块代码,但不能解决:

  • platform remove释放private data;
  • USB/PCI热拔;
  • device-managed MMIO失效;
  • VMA长于fd;
    -异步callback。

需要kref、get_device()或明确disconnect对象。

11. PM

Open/read前runtime get,完成后autosuspend。阻塞read不能永久持电源引用,除非硬件必须持续监听。

Suspend应唤醒或冻结等待者,并保存能够恢复的状态。Resume后硬件queue可能丢失,需向用户报告。

12. 故障注入

测试:

  • 多进程并发;
  • nonblock/poll;
  • signal;
  • short user buffer;
  • device unplug;
  • suspend中I/O;
  • mmap后remove;
  • command timeout;
  • buffer overflow;
  • 32位compat应用。

文章互动

阅读 --

留言

0 条留言

正在加载留言…