
设备驱动开发的10个常见错误与正确模式从内存泄漏到并发安全作者钟伊人 | 日期2026-07-29 | Week5 总结与避坑模块一内存管理类错误错误1-3错误1未释放DMA映射导致内存泄漏DMA直接内存访问是驱动开发的核心机制。许多开发者只关注kmalloc的释放忽略了DMA映射。这会导致物理内存不可回收系统运行时间越长越慢。/* ❌ 错误模式DMA映射泄漏 */ #include linux/dma-mapping.h #include linux/device.h #include linux/slab.h struct my_dma_buf { void *cpu_addr; dma_addr_t dma_handle; size_t size; }; static int bad_dma_example(struct device *dev) { struct my_dma_buf *buf; buf kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return -ENOMEM; buf-size 4096; buf-cpu_addr dma_alloc_coherent(dev, buf-size, buf-dma_handle, GFP_KERNEL); if (!buf-cpu_addr) { kfree(buf); return -ENOMEM; } /* 使用DMA缓冲区... */ do_something_with_dma(buf-cpu_addr); /* ❌ 错误只释放了buf没有释放DMA映射 */ kfree(buf); return 0; } /* ✅ 正确模式配对释放DMA映射 */ static int good_dma_example(struct device *dev) { struct my_dma_buf *buf; int ret 0; buf kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return -ENOMEM; buf-size 4096; buf-cpu_addr dma_alloc_coherent(dev, buf-size, buf-dma_handle, GFP_KERNEL); if (!buf-cpu_addr) { kfree(buf); return -ENOMEM; } /* 使用DMA缓冲区... */ ret do_something_with_dma(buf-cpu_addr); /* ✅ 正确先释放DMA映射再释放结构体 */ dma_free_coherent(dev, buf-size, buf-cpu_addr, buf-dma_handle); kfree(buf); return ret; } /* ✅✅ 生产级模式使用devm_自动管理资源 */ static int best_dma_example(struct device *dev) { struct my_dma_buf *buf; /* devm_kmalloc设备解绑时自动释放 */ buf devm_kmalloc(dev, sizeof(*buf), GFP_KERNEL); if (!buf) return -ENOMEM; buf-size 4096; /* devm_dma_alloc设备解绑时自动释放DMA映射 */ buf-cpu_addr dmam_alloc_coherent(dev, buf-size, buf-dma_handle, GFP_KERNEL); if (!buf-cpu_addr) return -ENOMEM; /* devm自动清理已分配的资源 */ /* 使用DMA缓冲区... */ return do_something_with_dma(buf-cpu_addr); /* 无需手动释放设备解绑时自动完成 */ }错误2kfree与kvfree混用kmalloc分配的内存必须用kfree释放。vmalloc分配的内存必须用vfree释放。kvmalloc内核4.12分配的内存必须用kvfree释放。混用会导致内核崩溃。/* ❌ 错误模式混用释放函数 */ static void bad_free_example(void) { void *ptr1 kmalloc(1024, GFP_KERNEL); void *ptr2 vmalloc(4096); void *ptr3 kvmalloc(8192, GFP_KERNEL); /* ❌ 错误 */ vfree(ptr1); /* kmalloc的内存不能用vfree释放 */ kfree(ptr2); /* vmalloc的内存不能用kfree释放 */ kfree(ptr3); /* kvmalloc的内存不能用kfree释放 */ } /* ✅ 正确模式配对使用分配/释放函数 */ static void good_free_example(void) { void *ptr1 kmalloc(1024, GFP_KERNEL); void *ptr2 vmalloc(4096); void *ptr3 kvmalloc(8192, GFP_KERNEL); /* ✅ 正确 */ kfree(ptr1); vfree(ptr2); kvfree(ptr3); /* 必须用kvfree */ } /* ✅ 生产级封装安全的释放函数 */ /** * 安全释放内存自动检测分配类型 * 内核5.8支持kmem_is_## 这里用更安全的方式 */ static inline void safe_kvfree(const void *addr) { /* 在不确定时用kvfree它能处理kmalloc和vmalloc两种情况 */ /* 注意仅适用于kvmalloc分配的内存 */ kvfree(addr); } /** * 内存分配包装器统一使用kvmalloc * 让释放只用kvfree避免混用问题 */ #define my_alloc(size) kvmalloc(size, GFP_KERNEL) #define my_free(ptr) kvfree(ptr)错误3在原子上下文中睡眠这是驱动开发中最危险的错误之一。在中断处理程序、持有自旋锁时调用可能睡眠的函数。会导致系统死锁或内核BUG。/* ❌ 错误模式在原子上下文中睡眠 */ #include linux/spinlock.h #include linux/interrupt.h #include linux/slab.h static DEFINE_SPINLOCK(my_lock); static irqreturn_t bad_irq_handler(int irq, void *data) { void *ptr; spin_lock(my_lock); /* ❌ 致命错误在持有自旋锁时调用可能睡眠的函数 */ ptr kmalloc(1024, GFP_KERNEL); /* GFP_KERNEL可能睡眠 */ do_something(ptr); /* ❌ 致命错误在中断上下文中调用可能睡眠的函数 */ ptr kmalloc(1024, GFP_KERNEL); /* 中断上下文不允许睡眠 */ spin_unlock(my_lock); return IRQ_HANDLED; } /* ✅ 正确模式区分上下文使用正确的GFP标志 */ static irqreturn_t good_irq_handler(int irq, void *data) { void *ptr; unsigned long flags; /* 中断上下文使用GFP_ATOMIC不会睡眠 */ ptr kmalloc(1024, GFP_ATOMIC); if (!ptr) return IRQ_NONE; /* 持有自旋锁时不能调用任何可能睡眠的函数 */ spin_lock_irqsave(my_lock, flags); do_something_atomic(ptr); /* 只调用原子操作 */ spin_unlock_irqrestore(my_lock, flags); kfree(ptr); return IRQ_HANDLED; } /** * GFP标志选择指南 * * GFP_KERNEL - 进程上下文可以睡眠最常见 * GFP_ATOMIC - 原子上下文中断、软中断、持有自旋锁 * GFP_NOWAIT - 不睡眠不等待比ATOMIC更轻量 * GFP_USER - 为用户空间分配可触发换页 * GFP_DMA - 为DMA分配16MB物理内存 * GFP_NOIO - 不能启动I/O存储驱动用 * GFP_NOFS - 不能启动文件系统操作文件系统驱动用 */ /* ✅ 生产级在可能睡眠前释放自旋锁 */ static int good_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct my_data *data file-private_data; void *big_buffer; int ret; /* 情况1需要先获取锁但后续需要大内存分配 */ mutex_lock(data-lock); /* 如果需要大块内存先释放锁再分配 */ mutex_unlock(data-lock); big_buffer kmalloc(64 * 1024, GFP_KERNEL); /* 可能睡眠在锁外 */ if (!big_buffer) return -ENOMEM; /* 重新获取锁使用已分配的内存 */ mutex_lock(data-lock); ret process_with_buffer(data, big_buffer); mutex_unlock(data-lock); kfree(big_buffer); return ret; }Mermaid内存分配函数选择流程模块二并发安全类错误错误4-6错误4竞态条件Race Condition忽视驱动程序运行在多线程环境中。多个进程可能同时打开同一设备。中断可能随时打断开续执行。忽视并发保护是系统不稳定的主要原因。/* ❌ 错误模式无并发保护 */ struct my_device { void *buffer; size_t buffer_size; int is_open; /* ❌ 没有保护 */ }; static int bad_open(struct inode *inode, struct file *file) { struct my_device *dev get_device(inode); /* ❌ 两个进程可能同时读到 is_open 0 */ if (dev-is_open) { return -EBUSY; /* 实际上可能两个进程都通过检查 */ } dev-is_open 1; dev-buffer kmalloc(4096, GFP_KERNEL); return 0; } /* ✅ 正确模式使用互斥锁保护 */ struct my_device { void *buffer; size_t buffer_size; int is_open; struct mutex lock; /* ✅ 互斥锁 */ }; static int good_open(struct inode *inode, struct file *file) { struct my_device *dev get_device(inode); int ret; /* ✅ 获取互斥锁 */ mutex_lock(dev-lock); if (dev-is_open) { ret -EBUSY; goto unlock; } dev-is_open 1; dev-buffer kmalloc(4096, GFP_KERNEL); if (!dev-buffer) { dev-is_open 0; ret -ENOMEM; goto unlock; } ret 0; unlock: mutex_unlock(dev-lock); return ret; } /* ✅ 生产级使用原子变量替代简单标志位 */ struct my_device_atomic { void *buffer; atomic_t open_count; /* ✅ 原子变量 */ struct mutex op_lock; /* ✅ 保护实际操作 */ }; static int best_open(struct inode *inode, struct file *file) { struct my_device_atomic *dev get_device(inode); /* ✅ 原子方式检查并设置类似自旋锁的try_once语义 */ if (atomic_inc_return(dev-open_count) ! 1) { atomic_dec(dev-open_count); return -EBUSY; /* 已经有其他进程打开了 */ } /* 此时确定只有当前进程打开了设备 */ mutex_lock(dev-op_lock); dev-buffer kmalloc(4096, GFP_KERNEL); if (!dev-buffer) { mutex_unlock(dev-op_lock); atomic_dec(dev-open_count); return -ENOMEM; } mutex_unlock(dev-op_lock); return 0; }错误5死锁Deadlock的常见模式死锁比竞态条件更难调试。常见的死锁模式包括锁顺序不一致、递归获取同一锁、持有锁时等待。/* ❌ 错误模式1锁顺序不一致导致死锁 */ struct my_driver { struct mutex lock_a; struct mutex lock_b; }; /* 线程1执行路径 */ static void thread1_path(struct my_driver *drv) { mutex_lock(drv-lock_a); /* ... 做一些操作 ... */ mutex_lock(drv-lock_b); /* 先A后B */ /* ... */ mutex_unlock(drv-lock_b); mutex_unlock(drv-lock_a); } /* 线程2执行路径 */ static void thread2_path(struct my_driver *drv) { mutex_lock(drv-lock_b); /* ... 做一些操作 ... */ mutex_lock(drv-lock_a); /* 先B后A → 死锁 */ /* ... */ mutex_unlock(drv-lock_a); mutex_unlock(drv-lock_b); } /* ✅ 正确模式统一锁获取顺序 */ /* 定义全局锁顺序按地址排序是一种简单方法 */ enum lock_order { LOCK_ORDER_A 1, LOCK_ORDER_B 2, }; static void take_locks_in_order(struct my_driver *drv) { /* ✅ 永远按相同顺序获取锁 */ mutex_lock(drv-lock_a); /* 先A */ mutex_lock(drv-lock_b); /* 后B */ } static void release_locks_in_reverse_order(struct my_driver *drv) { /* ✅ 按相反顺序释放锁 */ mutex_unlock(drv-lock_b); mutex_unlock(drv-lock_a); } /* ❌ 错误模式2在持有锁时等待用户空间 */ static ssize_t bad_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev file-private_data; int ret; mutex_lock(dev-lock); /* ❌ 等待用户空间事件时持有锁 → 死锁风险 */ wait_event(dev-wait_queue, dev-ready); /* 复制用户数据可能失败并重试 */ ret copy_from_user(dev-buffer, buf, count); mutex_unlock(dev-lock); return ret ? -EFAULT : count; } /* ✅ 正确模式在持有锁时不等待 */ static ssize_t good_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev file-private_data; void *tmp_buf; int ret; /* ✅ 先等待再获取锁 */ wait_event(dev-wait_queue, dev-ready); /* ✅ 先复制用户数据在锁外 */ tmp_buf kmalloc(count, GFP_KERNEL); if (!tmp_buf) return -ENOMEM; if (copy_from_user(tmp_buf, buf, count)) { kfree(tmp_buf); return -EFAULT; } /* ✅ 获取锁快速操作释放锁 */ mutex_lock(dev-lock); memcpy(dev-buffer, tmp_buf, count); dev-buffer_size count; mutex_unlock(dev-lock); kfree(tmp_buf); return count; }错误6不正确地使用自旋锁自旋锁和保护对象生命周期的锁不能混用。自旋锁持有期间不能调用copy_to_user/copy_from_user。/* ❌ 错误模式在自旋锁保护下访问用户空间 */ static ssize_t bad_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev file-private_data; size_t to_copy; spin_lock(dev-spinlock); to_copy min(count, dev-data_size - *ppos); /* ❌ 致命错误自旋锁持有期间调用可能睡眠的函数 */ if (copy_to_user(buf, dev-data *ppos, to_copy)) { spin_unlock(dev-spinlock); return -EFAULT; } *ppos to_copy; spin_unlock(dev-spinlock); return to_copy; } /* ✅ 正确模式自旋锁只保护极短的操作 */ static ssize_t good_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct my_device *dev file-private_data; void *tmp_buf; size_t to_copy; int ret; /* ✅ 分配临时缓冲区在锁外 */ tmp_buf kmalloc(count, GFP_KERNEL); if (!tmp_buf) return -ENOMEM; spin_lock_irqsave(dev-spinlock, flags); to_copy min(count, dev-data_size - *ppos); /* ✅ 自旋锁内只做内存拷贝内核空间到内核空间 */ memcpy(tmp_buf, dev-data *ppos, to_copy); spin_unlock_irqrestore(dev-spinlock, flags); /* ✅ 锁外访问用户空间 */ if (copy_to_user(buf, tmp_buf, to_copy)) { kfree(tmp_buf); return -EFAULT; } *ppos to_copy; kfree(tmp_buf); return to_copy; } /** * 自旋锁 vs 互斥锁选择指南 * * 自旋锁适用场景 * - 保护的操作极短几微秒 * - 中断上下文需要保护 * - 不能睡眠的原子上下文 * * 互斥锁适用场景 * - 保护的操作可能耗时毫秒级 * - 需要调用可能睡眠的函数 * - 进程上下文 * * 永远不要在持有自旋锁时调用 * - kmalloc(GFP_KERNEL) * - copy_to_user / copy_from_user * - 任何可能触发调度的函数 */模块三错误处理与资源管理错误7-8错误7资源分配失败后的不完整回滚驱动程序的probe函数可能需要申请多种资源。任何一种资源申请失败都必须完整释放已申请的资源。这是Linux内核编程最容易出现泄漏的地方。/* ❌ 错误模式资源申请失败时不回滚 */ static int bad_probe(struct platform_device *pdev) { struct my_device *dev; int ret; dev devm_kzalloc(pdev-dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* 申请资源1IRQ */ ret request_irq(irq_num, my_handler, 0, mydev, dev); if (ret) return ret; /* ❌ 错误没有释放dev虽然这里用devm没问题 */ /* 申请资源2I/O内存 */ dev-regs devm_ioremap_resource(pdev-dev, res); if (IS_ERR(dev-regs)) { return PTR_ERR(dev-regs); /* ❌ 错误没有释放IRQ */ } /* 申请资源3DMA */ ret dma_set_mask_and_coherent(pdev-dev, DMA_BIT_MASK(32)); if (ret) return ret; /* ❌ 错误没有释放IRQ和I/O内存 */ return 0; } /* ✅ 正确模式使用goto进行统一错误处理 */ static int good_probe(struct platform_device *pdev) { struct my_device *dev; int ret; dev devm_kzalloc(pdev-dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* 申请资源1IRQ */ ret request_irq(irq_num, my_handler, 0, mydev, dev); if (ret) goto err_free_dev; /* 申请资源2I/O内存 */ dev-regs devm_ioremap_resource(pdev-dev, res); if (IS_ERR(dev-regs)) { ret PTR_ERR(dev-regs); goto err_free_irq; } /* 申请资源3DMA */ ret dma_set_mask_and_coherent(pdev-dev, DMA_BIT_MASK(32)); if (ret) goto err_unmap_io; /* 注册字符设备 */ ret register_chrdev(0, mydev, my_fops); if (ret 0) goto err_clear_dma; dev-major ret; platform_set_drvdata(pdev, dev); return 0; /* 错误回滚按相反顺序释放资源 */ err_clear_dma: dma_set_mask_and_coherent(pdev-dev, 0); err_unmap_io: /* devm_资源会自动释放无需手动处理 */ err_free_irq: free_irq(irq_num, dev); err_free_dev: /* devm_分配会自动释放 */ return ret; } /* ✅✅ 生产级使用devm_系列函数自动管理资源 */ static int best_probe(struct platform_device *pdev) { struct my_device *dev; int ret; /* 使用devm_系列设备解绑时自动释放 */ dev devm_kzalloc(pdev-dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* devm_request_irq自动释放IRQ */ ret devm_request_irq(pdev-dev, irq_num, my_handler, 0, mydev, dev); if (ret) return ret; /* 所有devm_资源自动释放 */ /* devm_ioremap_resource自动取消映射 */ dev-regs devm_ioremap_resource(pdev-dev, res); if (IS_ERR(dev-regs)) return PTR_ERR(dev-regs); /* devm_分配DMA缓冲区自动释放 */ dev-dma_buf dmam_alloc_coherent(pdev-dev, 4096, dev-dma_handle, GFP_KERNEL); if (!dev-dma_buf) return -ENOMEM; /* 只有非devm_资源才需要手动管理 */ dev-cdev cdev_alloc(); if (!dev-cdev) { /* devm_资源自动释放 */ return -ENOMEM; } cdev_init(dev-cdev, my_fops); ret cdev_add(dev-cdev, dev-devno, 1); if (ret) { cdev_del(dev-cdev); /* 手动释放非devm_资源 */ return ret; } platform_set_drvdata(pdev, dev); return 0; /* 成功后所有资源由系统管理 */ } static int best_remove(struct platform_device *pdev) { struct my_device *dev platform_get_drvdata(pdev); /* 只需要释放非devm_资源 */ if (dev-cdev) cdev_del(dev-cdev); /* devm_资源自动释放无需手动处理 */ return 0; }错误8忽略函数的返回值内核中几乎所有函数都可能失败。忽略错误处理是导致系统不稳定的主要原因。/* ❌ 错误模式忽略返回值 */ static void bad_example(struct device *dev) { struct class *cls; struct device *device; /* ❌ 错误忽略class_create的返回值 */ cls class_create(THIS_MODULE, myclass); /* 如果失败cls是ERR_PTR后续使用会崩溃 */ /* ❌ 错误忽略device_create的返回值 */ device device_create(cls, NULL, dev-devno, NULL, mydevice); /* 如果失败device是ERR_PTR */ } /* ✅ 正确模式检查所有返回值 */ static int good_example(struct device *dev) { struct class *cls; struct device *device; int ret 0; cls class_create(THIS_MODULE, myclass); if (IS_ERR(cls)) { ret PTR_ERR(cls); dev_err(dev, 创建class失败: %d\n, ret); return ret; } device device_create(cls, NULL, dev-devno, NULL, mydevice); if (IS_ERR(device)) { ret PTR_ERR(device); dev_err(dev, 创建设备失败: %d\n, ret); goto err_destroy_class; } return 0; err_destroy_class: class_destroy(cls); return ret; } /* ✅ 生产级封装常用操作减少错误检查代码量 */ /** * 安全版本的设备创建 * 自动处理错误回滚 */ static struct device *safe_device_create(struct class *cls, struct device *parent, dev_t devno, const char *fmt, ...) { struct device *dev; va_list args; char name[64]; va_start(args, fmt); vsnprintf(name, sizeof(name), fmt, args); va_end(args); dev device_create(cls, parent, devno, NULL, %s, name); if (IS_ERR(dev)) { pr_err(设备创建失败: %s, err%ld\n, name, PTR_ERR(dev)); return dev; } return dev; } #define CHECK_AND_RETURN(ptr, label) \ do { \ if (IS_ERR(ptr)) { \ ret PTR_ERR(ptr); \ dev_err(dev, %s:%d 失败: %d\n, __func__, __LINE__, ret); \ goto label; \ } \ } while (0)模块四硬件交互类错误错误9-10错误9不正确的I/O访问 Barrier缺失硬件寄存器访问需要正确的内存屏障Memory Barrier。CPU可能会重排指令导致设备看到错误的寄存器写入顺序。/* ❌ 错误模式无内存屏障的寄存器访问 */ static void bad_hw_init(struct my_device *dev) { /* ❌ 错误CPU可能重排这些写入 */ writel(0x01, dev-regs-ctrl); /* 使能设备 */ writel(0x100, dev-regs-size); /* 设置大小 */ writel(0x01, dev-regs-start); /* 启动设备 */ /* 硬件可能先看到start1但ctrl还未使能 → 故障 */ } /* ✅ 正确模式使用内存屏障 */ static void good_hw_init(struct my_device *dev) { writel(0x01, dev-regs-ctrl); /* ✅ 写屏障确保ctrl写入在size写入之前完成 */ wmb(); writel(0x100, dev-regs-size); wmb(); writel(0x01, dev-regs-start); wmb(); } /* ✅ 生产级使用relaxed访问显式屏障性能更优 */ static void best_hw_init(struct my_device *dev) { /* readl_relaxed/writel_relaxed无屏障更快 */ /* 适合在已有屏障保护的代码路径中使用 */ writel_relaxed(0x01, dev-regs-ctrl); writel_relaxed(0x100, dev-regs-size); writel_relaxed(0x01, dev-regs-start); /* ✅ 在关键路径末尾加一次屏障 */ wmb(); /* 确保三个寄存器按顺序写入硬件 */ } /** * 内存屏障使用指南 * * wmb() - 写屏障确保之前的写操作在后之前的写操作之后完成 * rmb() - 读屏障确保之前的读操作在之后的读操作之前完成 * mb() - 全屏障读写都保证顺序 * * 常见需要屏障的场景 * 1. 硬件寄存器编程必须先写配置再写启动位 * 2. DMA描述符更新必须先写数据再写就绪标志 * 3. 锁实现必须与锁操作配合使用 * * 注意readl/writel自带屏障relaxed版本不带 * 在x86上普通load/store本来就是有序的 * 在ARM/POWER上必须使用屏障 */错误10中断处理程序中的不正确操作中断处理程序运行在原子上下文。不能调用可能睡眠的函数。不能执行耗时操作。/* ❌ 错误模式在中断处理程序中做太多事情 */ static irqreturn_t bad_irq_handler(int irq, void *data) { struct my_device *dev data; /* ❌ 错误1调用可能睡眠的函数 */ spin_lock(dev-lock); /* 应该用spin_lock_irqsave */ /* ... */ spin_unlock(dev-lock); /* ❌ 错误2执行耗时操作延迟设备中断响应 */ for (int i 0; i 1000000; i) { process_data(dev-rx_buffer[i]); } /* ❌ 错误3在中断中访问用户空间 */ copy_to_user(dev-user_buf, dev-rx_buffer, 1024); return IRQ_HANDLED; } /* ✅ 正确模式中断处理程序只做最少工作 */ static irqreturn_t good_irq_handler(int irq, void *data) { struct my_device *dev data; unsigned long flags; int handled 0; /* ✅ 使用irqsave版本的自旋锁 */ spin_lock_irqsave(dev-lock, flags); /* ✅ 只做最少工作读取状态寄存器清除中断 */ if (readl(dev-regs-int_status) INT_RX_READY) { /* 将接收到的数据放入缓冲区 */ dev-rx_count readl(dev-regs-rx_len); memcpy(dev-rx_buffer, dev-regs-rx_data, dev-rx_count); /* 清除中断标志 */ writel(INT_RX_READY, dev-regs-int_clear); handled 1; /* ✅ 调度下半部tasklet或workqueue处理数据 */ tasklet_schedule(dev-rx_tasklet); } spin_unlock_irqrestore(dev-lock, flags); return handled ? IRQ_HANDLED : IRQ_NONE; } /* 下半部可以执行耗时操作 */ static void rx_tasklet(unsigned long data) { struct my_device *dev (struct my_device *)data; /* ✅ 在这里可以执行耗时操作 */ process_received_data(dev-rx_buffer, dev-rx_count); /* ✅ 可以调用可能睡眠的函数如果是workqueue */ wake_up_interruptible(dev-read_queue); } /* ✅ 生产级使用request_threaded_irq threaded IRQ */ /** * 现代内核推荐使用threaded IRQ * 硬IRQ只做最少工作剩余工作在线程中完成 * 线程可以睡眠、可以被调度 */ static irqreturn_t top_half_handler(int irq, void *data) { struct my_device *dev data; /* 只清除中断返回IRQ_WAKE_THREAD */ writel(INT_ALL, dev-regs-int_clear); return IRQ_WAKE_THREAD; } static irqreturn_t bottom_half_handler(int irq, void *data) { struct my_device *dev data; /* 在这里处理实际工作可以睡眠 */ process_all_pending_events(dev); return IRQ_HANDLED; } static int setup_threaded_irq(struct my_device *dev, int irq) { return request_threaded_irq(irq, top_half_handler, /* 硬IRQ */ bottom_half_handler, /* 线程 */ IRQF_ONESHOT, mydev, dev); }模块五正确模式总结与检查清单十大错误速查表编号错误类型症状正确模式1DMA映射泄漏系统运行越慢devm_dma_alloc自动管理2kfree/kvfree混用内核崩溃统一用kvmallockvfree3原子上下文睡眠死锁/BUG使用GFP_ATOMIC4竞态条件数据损坏mutex/atomic_t保护5死锁系统悬挂统一锁顺序6自旋锁误用崩溃/性能差自旋锁只保护极短操作7资源泄漏模块无法卸载devm_goto错误处理8忽略返回值随机崩溃所有函数返回值必须检查9缺少内存屏障硬件异常wmb()/rmb()/mb()10中断处理不当系统无响应硬IRQ只做最少工作Mermaid驱动开发正确流程生产级驱动开发检查清单#!/usr/bin/env python3 驱动代码审查检查清单 在提交代码前运行此检查 CHECKLIST [ (内存管理, [ 所有kmalloc是否有对应的kfree, 所有dma_alloc_coherent是否有对应的dma_free_coherent, 是否优先使用devm_系列函数, kvmalloc的内存是否用kvfree释放, ]), (并发安全, [ 全局变量是否有锁保护, 锁的获取顺序是否全局一致, 是否在持有自旋锁时调用可能睡眠的函数, 是否在原子上下文中使用GFP_KERNEL, ]), (中断处理, [ 中断处理程序是否只做最少工作, 是否使用threaded IRQ, 中断处理程序中是否调用copy_to/from_user, 是否正确的清除中断标志, ]), (错误处理, [ 所有函数返回值是否都检查了, probe失败是否有完整的资源回滚, 是否使用goto进行统一错误处理, ]), (硬件交互, [ 寄存器编程是否有必要的内存屏障, readl/writel是否用对了还是应该用relaxed版本, 是否正确处理了硬件超时, ]), ] def print_checklist(): for category, items in CHECKLIST: print(f\n {category} ) for i, item in enumerate(items, 1): print(f [ ] {item}) if __name__ __main__: print(驱动代码审查检查清单) print( * 50) print_checklist() print(\n * 50) print(每项打勾后再提交代码)纯技术总结内存管理三大坑DMA映射泄漏用devm_dma_alloc、kfree/kvfree混用统一kvmallockvfree、原子上下文睡眠用GFP_ATOMIC并发安全互斥锁保护open/read/write原子变量保护简单标志统一锁顺序防死锁自旋锁只保护微秒级操作资源回滚probe函数用goto统一错误处理优先devm_自动管理资源remove只需释放非devm_资源硬件交互寄存器编程加wmb()屏障readl/writel自带屏障relaxed版本需手动加屏障中断处理硬IRQ只做最少工作读状态清中断耗时操作放threaded IRQ或tasklet完整代码已在各模块中给出可直接用于生产环境驱动开发