You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理主设备号已知、次设备号未知的Linux字符设备

主设备号已知、次设备号未知的字符设备处理方案

针对你不需要为闲置次设备预分配内存的需求,按实际业务场景选择以下实现即可:

场景1:所有次设备逻辑/状态完全共享(适配你的Hello World需求)

如果无论用哪个次设备号打开该设备,行为完全一致,不需要为次设备做独立状态隔离,直接占用整个主设备号的次设备范围即可:

  • 注册设备号时直接申请主设备号255下的全部256个次设备号
  • 仅初始化1个cdev实例,将其绑定到整个次设备号范围,所有次设备的访问都会路由到同一套操作逻辑,完全无内存浪费。

场景2:不同次设备需要独立状态隔离

如果不同次设备需要单独统计打开次数、存储私有数据,使用按需分配方案即可:

  • 预先注册主设备号255的全部256个次设备号,不预分配设备结构数组
  • 在open回调中通过iminor(inode)获取当前打开的次设备号,用指针数组/哈希表存储已分配的次设备结构,首次打开对应次设备时才动态分配结构实例,后续访问直接复用
  • 可在release回调中判断次设备的引用计数,引用归0时释放对应结构,最大化内存利用率。
现有代码修正版(适配场景1,满足打开输出Hello World要求)

你的原始代码存在设备号注册与cdev绑定不匹配、内存泄漏、未实现Hello World输出等问题,修正后代码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/printk.h>
#include <linux/uaccess.h>

MODULE_LICENSE("GPL");

static struct _device
{
    size_t openCount, totalDataWritten;
    struct cdev c_dev;
};

static struct _device myDevice; // 直接用全局结构体,不需要动态分配
static const int major = 255;
static const char *name = "solution_node";

static int devOpen(struct inode * n, struct file * f)
{
    myDevice.openCount++;          
    pr_info("Hello World\n"); // 打开设备时在内核日志输出Hello World
    return 0;
}

static ssize_t devWrite(struct file * n, char const __user * c, size_t size, loff_t *l)
{
    myDevice.totalDataWritten += size;
    return size;
}

static ssize_t devRead(struct file *fp, char __user *buf, size_t size, loff_t *off)
{
    char tmpbuf[64]; // 小缓冲直接用栈,避免kmalloc泄漏
    int len = snprintf(tmpbuf, sizeof(tmpbuf), "%zu %zu\n", myDevice.openCount, myDevice.totalDataWritten);
    if (*off >= len)
        return 0;
    if (size > len - *off)
        size = len - *off;
    if (copy_to_user(buf, tmpbuf + *off, size))
        return -EFAULT;
    *off += size;
    return size;
}

static struct file_operations devOPS = 
{
    .owner = THIS_MODULE,
    .open = devOpen,
    .write = devWrite,
    .read = devRead,        
}; 

static int __init deviceInit(void)
{
    dev_t devID = MKDEV(major, 0);
    // 注册整个主设备号下的256个次设备号
    if (register_chrdev_region(devID, 256, name) != 0) {
        pr_err("Failed to register chrdev region\n");
        return -EIO;
    }

    cdev_init(&myDevice.c_dev, &devOPS);
    myDevice.c_dev.owner = THIS_MODULE;
    myDevice.openCount = 0;
    myDevice.totalDataWritten = 0;

    // 绑定cdev到全部256个次设备
    if (cdev_add(&myDevice.c_dev, devID, 256)) {
        unregister_chrdev_region(devID, 256);
        pr_err("Failed to add cdev\n");
        return -EIO;
    }   
        
    return 0;
}

static void __exit deviceExit(void)
{
    cdev_del(&myDevice.c_dev);
    unregister_chrdev_region(MKDEV(major, 0), 256);
}

module_init(deviceInit);
module_exit(deviceExit);

内容的提问来源于stack exchange,提问作者WelcomeToMyTutorial

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 22:57:04