3. 字符设备驱动开发面试要点
字符设备驱动是 Linux 驱动开发面试的必考模块,占据基础题 70% 以上。本节聚焦四个核心考点:设备号分配、file_operations 结构体、cdev 注册流程、并发控制。面试官常要求口述完整注册流程,并追问竞态场景。
常规问答卡片
Q1:字符设备驱动中如何分配设备号?动态分配和静态分配的适用场景?
考察点:是否理解主次设备号、接口函数区别、实际项目选择倾向。
回答框架:先给出两种方式 API → 说明区别 → 结合实际场景建议。
示例回答:动态分配用 alloc_chrdev_region(&dev, 0, 1, "mydrv"),内核自动分配主设备号;静态分配用 register_chrdev_region(dev, 1, "mydrv") 需已知编号。项目初期推荐动态分配避免冲突,产品定型后也可固定主设备号。
可能追问:主设备号和次设备号各多少位?cat /proc/devices 能查到什么?
Q2:请列举 file_operations 中至少 5 个常用回调函数,并说明其调用时机和典型实现。
考察点:对驱动与 VFS 交互模型的理解深度;是否区分阻塞与非阻塞。
回答框架:分层列举 open/release → read/write → unlocked_ioctl/llseek → mmap 等。
示例回答:open 初始化私有数据;release 释放资源;read 将内核数据拷贝到用户空间(copy_to_user);write 从用户空间接收数据(copy_from_user);unlocked_ioctl 处理自定义命令;llseek 更改文件偏移。
可能追问:为什么现在推荐 unlocked_ioctl 而不是 ioctl?.owner 成员为何要设为 THIS_MODULE?
Q3:cdev 注册的完整步骤是怎样的?当多个进程同时 write 时会遇到什么问题?如何解决?
考察点:是否掌握 cdev_init + cdev_add 链路;并发控制方案选择。
回答框架:注册步骤三步 → 竞态问题描述 → 保护方案(自旋锁/互斥体/原子操作)。
示例回答:步骤:cdev_init → cdev.owner = THIS_MODULE → cdev_add。多进程并发 write 可能导致数据错乱,使用 mutex_lock 保护临界区:在 write 开头加锁、末尾解锁,确保一次只有一个进程写入。
可能追问:spin_lock 和 mutex 如何选择?中断上下文能否用 mutex?
项目案例章节
项目名称:多通道高速数据采集字符驱动
| 业务背景 | 工业检测设备,需要采集8路ADC数据并通过PCIe传输到用户态分析软件 |
| 规模指标 | 采样率 200K/s × 8通道,每秒产生约 3.2MB 数据;用户态 4 个并发进程读取 |
| 技术栈 | Linux 5.10,字符驱动框架,mmap,RCU锁,wait_queue,FPGA DMA |
| 核心难点 | ① 高频写入不丢数据;② 多进程无锁读取;③ 中断顶半部与底半部数据同步 |
| 面试高频追问 | |
| • 为什么选择 RCU 而不是读写锁?RCU 在什么场景下效率更高? • mmap 如何确保 DMA buffer 不跨页? • 如果采样率提升到 1M/s,你的方案哪里会成为瓶颈? | |
| 可迁移回答话术 | |
| “在这个项目中,我主要负责字符驱动核心模块。数据从FPGA经DMA写入内核预分配缓冲区,驱动通过字符设备暴露mmap接口实现零拷贝。针对多进程读竞争,我设计了RCU保护采样数据指针更新,读端无锁化,写端在更新完指针后再老数据无引用时释放。最终在高负载下丢包率控制在0.01%以内。” | |
章节 3/30 · 字符设备驱动开发面试要点