当前位置:首页>Linux>Linux globalmem 字符设备驱动

Linux globalmem 字符设备驱动

  • 2026-02-10 08:22:46
Linux globalmem 字符设备驱动

一、驱动概述

globalmem 是一款经典的字符设备驱动示例,核心功能是在内核空间模拟一块固定大小的全局内存区域,提供用户空间与内核空间的数据交互接口(读、写、定位、IO控制)。本驱动基于 Linux 6.6 内核编写,适配内核最新接口规范,修正旧版本(如Linux 3.x/4.x)中过时的函数与宏定义,遵循内核编码规范,支持单设备实例,可轻松扩展为多设备实例。

Linux 6.6 内核适配要点:

  • 移除过时的 __devexit__devinit 宏(内核5.10+已废弃),统一使用 __init__exit

  • IO控制接口统一使用 unlocked_ioctlioctl 已废弃,内核强制要求)。

  • 内存分配优先使用 kzalloc(自带清0,避免野指针),释放对应使用 kfree,遵循内核内存管理规范。

  • 打印信息规范:使用 pr_info 替代 printk(KERN_INFO)pr_notice 替代 printk(KERN_NOTICE),提升代码可读性与兼容性。

  • 模块参数、设备号申请/释放、cdev 操作接口保持兼容,但需严格遵循内核错误处理流程(避免资源泄漏)。

二、完整驱动代码(globalmem.c)

/* * Linux 6.6 内核 globalmem 字符设备驱动 * 功能:模拟全局内存,支持读写、seek、IO控制(内存清空)、文件私有数据机制 * 遵循 GPLv2 协议,适配内核6.6接口规范 */#include<linux/module.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/cdev.h>#include<linux/slab.h>#include<linux/uaccess.h>#include<linux/ioctl.h>// 设备相关宏定义(Linux 6.6 推荐规范:使用幻数避免IO命令冲突)#define GLOBALMEM_MAGIC  'g'// 幻数(0~0xff,避免与内核现有幻数冲突)#define GLOBALMEM_SIZE   0x1000               // 全局内存大小(4KB)#define MEM_CLEAR        _IO(GLOBALMEM_MAGIC, 0) // IO控制命令:清空内存(无数据传输)#define GLOBALMEM_MAJOR  230                  // 预设主设备号(可通过模块参数修改)#define DEVICE_NAME      "globalmem"// 设备名称// 全局变量声明staticint globalmem_major = GLOBALMEM_MAJOR;  // 主设备号module_param(globalmem_major, int, S_IRUGO);  // 模块参数:允许用户空间修改主设备号MODULE_PARM_DESC(globalmem_major, "Major number of globalmem device (default: 230)");// 设备结构体(封装cdev和内存区域,体现内核面向对象封装思想)structglobalmem_dev {structcdevcdev;// 字符设备核心结构体unsignedchar mem[GLOBALMEM_SIZE];  // 模拟的全局内存区域};staticstructglobalmem_dev *globalmem_devp;// 设备结构体实例指针// 函数声明(驱动核心接口)staticintglobalmem_open(struct inode *inode, struct file *filp);staticintglobalmem_release(struct inode *inode, struct file *filp);staticssize_tglobalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos);staticssize_tglobalmem_write(struct file *filp, constchar __user *buf, size_t size, loff_t *ppos);staticloff_tglobalmem_llseek(struct file *filp, loff_t offset, int orig);staticlongglobalmem_ioctl(struct file *filp, unsignedint cmd, unsignedlong arg);// 文件操作结构体(关联驱动核心接口,Linux 6.6 无接口变更)staticconststructfile_operationsglobalmem_fops = {    .owner          = THIS_MODULE,          // 所属模块,避免模块被意外卸载    .llseek         = globalmem_llseek,     // 文件定位接口    .read           = globalmem_read,       // 读接口(用户->内核)    .write          = globalmem_write,       // 写接口(内核->用户)    .unlocked_ioctl = globalmem_ioctl,      // IO控制接口(无大内核锁,内核推荐)    .open           = globalmem_open,       // 设备打开接口    .release        = globalmem_release,    // 设备释放接口};/** * globalmem_open - 设备打开函数 * @inode:inode节点指针(关联设备文件的索引信息) * @filp:文件结构体指针(关联打开的设备文件) * 返回值:0-成功,负数-失败 * 功能:将设备结构体指针赋值给文件私有数据,供后续接口使用 */staticintglobalmem_open(struct inode *inode, struct file *filp){// 将文件私有数据指向设备结构体实例,后续read/write/ioctl可直接获取    filp->private_data = globalmem_devp;return0;  // 打开成功(无额外初始化操作)}/** * globalmem_release - 设备释放函数 * @inode:inode节点指针 * @filp:文件结构体指针 * 返回值:0-成功 * 功能:释放设备资源(本驱动无额外资源,仅返回成功) */staticintglobalmem_release(struct inode *inode, struct file *filp){return0;  // 释放成功}/** * globalmem_read - 设备读函数 * @filp:文件结构体指针 * @buf:用户空间缓冲区指针(存储读取的数据) * @size:用户请求读取的字节数 * @ppos:文件当前读写偏移量指针 * 返回值:成功读取的字节数,0-到达文件末尾,负数-失败 * 功能:将内核空间mem数组的数据拷贝到用户空间缓冲区 */staticssize_tglobalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){unsignedlong p = *ppos;          // 当前偏移量unsignedint count = size;        // 请求读取的字节数int ret = 0;                      // 返回值structglobalmem_dev *dev = filp->private_data;// 获取设备结构体实例// 边界检查:偏移量超出内存大小,返回0(表示到达文件末尾)if (p >= GLOBALMEM_SIZE)return0;// 调整读取字节数:避免超出内存剩余空间if (count > GLOBALMEM_SIZE - p)        count = GLOBALMEM_SIZE - p;// 将内核空间数据拷贝到用户空间(copy_to_user:内核->用户,失败返回未拷贝字节数)if (copy_to_user(buf, dev->mem + p, count)) {        ret = -EFAULT;  // 拷贝失败,返回错误码(坏地址)    } else {        *ppos += count; // 更新读写偏移量        ret = count;    // 返回成功读取的字节数        pr_info("read %u bytes from offset %lu\n", count, p);  // 打印日志(内核日志)    }return ret;}/** * globalmem_write - 设备写函数 * @filp:文件结构体指针 * @buf:用户空间缓冲区指针(存储要写入的数据) * @size:用户请求写入的字节数 * @ppos:文件当前读写偏移量指针 * 返回值:成功写入的字节数,负数-失败 * 功能:将用户空间缓冲区的数据拷贝到内核空间mem数组 */staticssize_tglobalmem_write(struct file *filp, constchar __user *buf, size_t size, loff_t *ppos){unsignedlong p = *ppos;          // 当前偏移量unsignedint count = size;        // 请求写入的字节数int ret = 0;                      // 返回值structglobalmem_dev *dev = filp->private_data;// 获取设备结构体实例// 边界检查:偏移量超出内存大小,返回0(无法写入)if (p >= GLOBALMEM_SIZE)return0;// 调整写入字节数:避免超出内存剩余空间if (count > GLOBALMEM_SIZE - p)        count = GLOBALMEM_SIZE - p;// 将用户空间数据拷贝到内核空间(copy_from_user:用户->内核,失败返回未拷贝字节数)if (copy_from_user(dev->mem + p, buf, count)) {        ret = -EFAULT;  // 拷贝失败,返回错误码(坏地址)    } else {        *ppos += count; // 更新读写偏移量        ret = count;    // 返回成功写入的字节数        pr_info("written %u bytes to offset %lu\n", count, p);  // 打印日志    }return ret;}/** * globalmem_llseek - 文件定位函数 * @filp:文件结构体指针 * @offset:用户请求的偏移量 * @orig:定位基准(0-文件开头,1-当前位置,2-文件末尾) * 返回值:新的偏移量,负数-失败 * 功能:修改文件当前读写偏移量,支持从开头、当前位置定位(Linux 6.6 支持文件末尾定位,本驱动暂不启用) */staticloff_tglobalmem_llseek(struct file *filp, loff_t offset, int orig){loff_t ret = 0;  // 新的偏移量switch (orig) {case0:  // 从文件开头定位(SEEK_SET)// 偏移量为负,非法请求if (offset < 0) {                ret = -EINVAL;break;            }// 偏移量超出内存大小,非法请求if ((unsignedint)offset > GLOBALMEM_SIZE) {                ret = -EINVAL;break;            }            filp->f_pos = (unsignedint)offset;  // 更新文件偏移量            ret = filp->f_pos;break;case1:  // 从当前位置定位(SEEK_CUR)// 偏移后超出内存大小,非法请求if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {                ret = -EINVAL;break;            }// 偏移后为负,非法请求if ((filp->f_pos + offset) < 0) {                ret = -EINVAL;break;            }            filp->f_pos += offset;  // 更新文件偏移量            ret = filp->f_pos;break;default:  // 不支持的定位基准,返回错误            ret = -EINVAL;break;    }return ret;}/** * globalmem_ioctl - IO控制函数 * @filp:文件结构体指针 * @cmd:用户请求的IO控制命令 * @arg:用户传递的参数(本驱动无参数,置0) * 返回值:0-成功,负数-失败 * 功能:处理用户空间发送的IO控制命令(本驱动仅支持MEM_CLEAR:清空内存) */staticlongglobalmem_ioctl(struct file *filp, unsignedint cmd, unsignedlong arg){structglobalmem_dev *dev = filp->private_data;// 获取设备结构体实例// 命令合法性检查:检查幻数和命令序号(避免命令冲突)if (_IOC_TYPE(cmd) != GLOBALMEM_MAGIC)return -EINVAL;if (_IOC_NR(cmd) > 0)return -EINVAL;// 处理具体命令switch (cmd) {case MEM_CLEAR:  // 清空全局内存memset(dev->mem, 0, GLOBALMEM_SIZE);  // 将mem数组清0            pr_info("globalmem: memory cleared successfully\n");break;default:  // 不支持的命令,返回错误return -EINVAL;    }return0;  // 命令执行成功}/** * globalmem_setup_cdev - 初始化cdev结构体并添加到内核 * @dev:设备结构体实例指针 * @index:次设备号索引(单设备为0) * 功能:初始化cdev、关联文件操作结构体、将cdev添加到内核字符设备链表 */staticvoidglobalmem_setup_cdev(struct globalmem_dev *dev, int index){dev_t devno = MKDEV(globalmem_major, index);  // 生成设备号(主设备号+次设备号)// 初始化cdev:关联设备结构体和文件操作结构体    cdev_init(&dev->cdev, &globalmem_fops);    dev->cdev.owner = THIS_MODULE;  // 关联所属模块// 将cdev添加到内核(注册字符设备),次设备号范围:index ~ index+0(单设备)int err = cdev_add(&dev->cdev, devno, 1);if (err) {        pr_notice("globalmem: error %d adding cdev%d\n", err, index);    }}/** * globalmem_init - 驱动初始化函数(模块加载时执行) * 返回值:0-成功,负数-失败 * 功能:申请设备号、分配设备结构体内存、初始化cdev、注册设备 */staticint __init globalmem_init(void){int ret;dev_t devno = MKDEV(globalmem_major, 0);  // 生成设备号(次设备号为0)// 申请设备号:两种方式(预设主设备号/动态分配)if (globalmem_major) {// 预设主设备号,申请指定设备号(次设备号0~0,单设备)        ret = register_chrdev_region(devno, 1, DEVICE_NAME);    } else {// 动态分配设备号(内核自动分配主设备号)        ret = alloc_chrdev_region(&devno, 01, DEVICE_NAME);        globalmem_major = MAJOR(devno);  // 获取动态分配的主设备号    }// 设备号申请失败,返回错误if (ret < 0)return ret;// 分配设备结构体内存(kzalloc:分配+清0,GFP_KERNEL:内核态常规内存分配)    globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);if (!globalmem_devp) {  // 内存分配失败        ret = -ENOMEM;goto fail_malloc;  // 跳转至错误处理,释放已申请的设备号    }// 初始化cdev并添加到内核(单设备,次设备号为0)    globalmem_setup_cdev(globalmem_devp, 0);    pr_info("globalmem: driver initialized successfully\n");    pr_info("globalmem: major number = %d\n", globalmem_major);return0;  // 初始化成功// 错误处理:内存分配失败,释放设备号fail_malloc:    unregister_chrdev_region(devno, 1);    pr_err("globalmem: failed to allocate memory, driver init failed\n");return ret;}/** * globalmem_exit - 驱动退出函数(模块卸载时执行) * 功能:从内核移除cdev、释放设备结构体内存、释放设备号,避免资源泄漏 */staticvoid __exit globalmem_exit(void){// 从内核移除cdev(注销字符设备)    cdev_del(&globalmem_devp->cdev);// 释放设备结构体内存    kfree(globalmem_devp);// 释放设备号    unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);    pr_info("globalmem: driver exited successfully\n");}// 模块加载/卸载入口(Linux 6.6 无接口变更)module_init(globalmem_init);module_exit(globalmem_exit);// 模块信息声明(遵循GPL协议,否则内核拒绝加载)MODULE_AUTHOR("Linux Driver Developer");MODULE_LICENSE("GPL v2");MODULE_DESCRIPTION("Global Memory Character Device Driver for Linux 6.6 Kernel");MODULE_VERSION("1.0");

三、Makefile(Linux 6.6 内核编译适配)

编写适配 Linux 6.6 内核的 Makefile,确保驱动能够正确编译生成 .ko 模块(需指定内核源码路径)。

# Linux 6.6 内核 globalmem 驱动 Makefile# 说明:需修改 KERNELDIR 为本地 Linux 6.6 内核源码路径# 内核源码路径(请根据实际情况修改)KERNELDIR ?= /usr/src/linux-6.6.0# 当前驱动源码目录PWD := $(shell pwd)# 模块名称MODULE_NAME := globalmem# 编译规则:默认编译模块obj-m := $(MODULE_NAME).o# 编译命令:进入内核源码目录,执行模块编译all:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules# 清理编译生成的文件clean:$(MAKE) -C $(KERNELDIR) M=$(PWD) clean    rm -f *.ko.cmd *.mod.cmd *.o.cmd *.symvers

四、代码解析(Linux 6.6 适配重点)

1. 内核接口适配

Linux 6.6 内核对字符设备驱动的核心接口无重大变更,但废弃了部分旧接口,本驱动主要做了以下适配:

  • 打印函数:使用 pr_infopr_noticepr_err 替代 printk 带日志级别,这些函数是内核推荐的打印接口,自动关联模块信息,日志输出更规范。

  • IO控制命令:使用内核推荐的 _IO 宏生成命令码,通过幻数(GLOBALMEM_MAGIC)避免不同设备驱动的命令冲突,替代了旧版本中直接定义命令为 0x1 的不规范方式。

  • 废弃宏移除:移除了 __devexit__devinit 等内核 5.10+ 已废弃的宏,统一使用 __init(模块加载初始化)、__exit(模块卸载清理)。

2. 核心功能模块

  • 设备结构体封装:将 cdev(字符设备核心)和 mem(全局内存)封装在 struct globalmem_dev 中,体现内核面向对象的封装思想,便于后续扩展(如添加多设备实例、中断处理等)。

  • 文件私有数据:在 globalmem_open 中,将设备结构体指针赋值给 filp->private_data,后续 readwriteioctl 等接口可直接通过该指针获取设备实例,无需全局变量遍历,提升效率且便于多设备扩展。

  • 设备号管理:支持两种设备号申请方式(预设主设备号/动态分配),动态分配可避免主设备号冲突,适配多驱动共存场景;模块卸载时,严格释放设备号和内存,避免资源泄漏。

  • 数据交互安全:使用 copy_to_user(内核->用户)和 copy_from_user(用户->内核)进行数据拷贝,这两个函数会检查用户空间地址合法性,避免内核崩溃,是内核用户空间与内核空间数据交互的标准接口。

3. 错误处理规范

Linux 6.6 内核对驱动错误处理要求更严格,本驱动遵循以下规范:

  • 设备号申请失败时,直接返回错误码,不进行后续操作。

  • 内存分配失败时,跳转至 fail_malloc 标签,释放已申请的设备号,避免资源泄漏。

  • IO控制命令、文件定位等操作,先进行合法性检查(如偏移量、命令幻数),非法请求返回对应错误码(-EINVAL-EFAULT),符合内核错误处理规范。

五、驱动编译与测试(Linux 6.6 环境)

1. 编译前提

  • 安装 Linux 6.6 内核源码(需与当前系统内核版本一致)。

  • 安装内核编译依赖工具:sudo apt install gcc make linux-headers-6.6.0(Ubuntu/Debian 系统)。

  • 修改 Makefile 中的 KERNELDIR,指向本地 Linux 6.6 内核源码路径。

2. 编译驱动

# 进入驱动源码目录cd /path/to/globalmem-driver# 执行编译make# 编译成功后,生成 globalmem.ko 模块文件

3. 加载与测试驱动

# 加载驱动模块(需root权限)sudo insmod globalmem.ko# 查看模块是否加载成功lsmod | grep globalmem# 查看设备号(确认主设备号为230或动态分配的号码)cat /proc/devices | grep globalmem# 创建设备节点(主设备号230,次设备号0)sudo mknod /dev/globalmem c 230 0# 修改设备节点权限(允许普通用户读写)sudo chmod 666 /dev/globalmem# 测试驱动功能# 1. 写数据到设备echo"hello linux 6.6 globalmem" > /dev/globalmem# 2. 读设备数据(验证写功能)cat /dev/globalmem# 3. 清空设备内存(IO控制命令)sudo ioctl /dev/globalmem $(echo -n -e "\x01\x67\x00\x00\x00\x00\x00\x00")# 4. 再次读设备数据(验证清空功能,应无输出)cat /dev/globalmem# 卸载驱动模块sudo rmmod globalmem# 删除设备节点sudo rm /dev/globalmem

六、多设备实例扩展(可选)

基于本驱动,可轻松扩展为支持多个 globalmem 设备实例(修改以下部分即可,适配 Linux 6.6 内核):

/* * Linux 6.6 内核 globalmem 字符设备驱动(多设备实例版) * 功能:支持5个独立设备实例,每个实例拥有独立全局内存,支持读写、seek、IO控制 * 遵循 GPLv2 协议,适配内核6.6接口规范,可直接编译使用 */#include<linux/module.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/cdev.h>#include<linux/slab.h>#include<linux/uaccess.h>#include<linux/ioctl.h>#include<linux/container_of.h>  // 多设备必备,用于通过cdev获取设备实例// 设备相关宏定义(多设备适配)#define GLOBALMEM_MAGIC  'g'// 幻数(避免IO命令冲突)#define GLOBALMEM_SIZE   0x1000               // 单个设备全局内存大小(4KB)#define MEM_CLEAR        _IO(GLOBALMEM_MAGIC, 0) // IO控制命令:清空内存#define GLOBALMEM_MAJOR  230                  // 预设主设备号(可通过模块参数修改)#define DEVICE_NAME      "globalmem"// 设备名称前缀#define DEVICE_NUM       5                    // 多设备实例数量(5个,次设备号0~4)// 全局变量声明staticint globalmem_major = GLOBALMEM_MAJOR;  // 主设备号module_param(globalmem_major, int, S_IRUGO);  // 模块参数:允许修改主设备号MODULE_PARM_DESC(globalmem_major, "Major number of globalmem device (default: 230)");// 设备结构体(多设备适配,每个实例独立)structglobalmem_dev {structcdevcdev;// 字符设备核心结构体unsignedchar mem[GLOBALMEM_SIZE];  // 单个设备的独立全局内存int dev_idx;               // 设备索引(0~4,区分不同设备实例)};staticstructglobalmem_dev *globalmem_devp;// 设备结构体数组指针(存储多个实例)// 函数声明(驱动核心接口,多设备通用)staticintglobalmem_open(struct inode *inode, struct file *filp);staticintglobalmem_release(struct inode *inode, struct file *filp);staticssize_tglobalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos);staticssize_tglobalmem_write(struct file *filp, constchar __user *buf, size_t size, loff_t *ppos);staticloff_tglobalmem_llseek(struct file *filp, loff_t offset, int orig);staticlongglobalmem_ioctl(struct file *filp, unsignedint cmd, unsignedlong arg);// 文件操作结构体(多设备通用,无修改)staticconststructfile_operationsglobalmem_fops = {    .owner          = THIS_MODULE,    .llseek         = globalmem_llseek,    .read           = globalmem_read,    .write          = globalmem_write,    .unlocked_ioctl = globalmem_ioctl,    .open           = globalmem_open,    .release        = globalmem_release,};/** * globalmem_open - 设备打开函数(多设备适配) * 核心:通过container_of获取当前打开的设备实例,避免全局变量遍历 */staticintglobalmem_open(struct inode *inode, struct file *filp){// 通过inode的i_cdev成员,反向获取对应的设备结构体实例(多设备关键)structglobalmem_dev *dev = container_of(inode->i_cdevstructglobalmem_devcdev);    filp->private_data = dev;  // 绑定设备实例到文件私有数据    pr_info("globalmem: device %d opened successfully\n", dev->dev_idx);return0;}/** * globalmem_release - 设备释放函数(多设备通用) */staticintglobalmem_release(struct inode *inode, struct file *filp){structglobalmem_dev *dev = filp->private_data;    pr_info("globalmem: device %d released successfully\n", dev->dev_idx);return0;}/** * globalmem_read - 设备读函数(多设备通用,操作当前设备实例的内存) */staticssize_tglobalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){unsignedlong p = *ppos;unsignedint count = size;int ret = 0;structglobalmem_dev *dev = filp->private_data;// 获取当前设备实例if (p >= GLOBALMEM_SIZE)return0;if (count > GLOBALMEM_SIZE - p)        count = GLOBALMEM_SIZE - p;if (copy_to_user(buf, dev->mem + p, count)) {        ret = -EFAULT;    } else {        *ppos += count;        ret = count;        pr_info("globalmem: device %d read %u bytes from offset %lu\n", dev->dev_idx, count, p);    }return ret;}/** * globalmem_write - 设备写函数(多设备通用,操作当前设备实例的内存) */staticssize_tglobalmem_write(struct file *filp, constchar __user *buf, size_t size, loff_t *ppos){unsignedlong p = *ppos;unsignedint count = size;int ret = 0;structglobalmem_dev *dev = filp->private_data;// 获取当前设备实例if (p >= GLOBALMEM_SIZE)return0;if (count > GLOBALMEM_SIZE - p)        count = GLOBALMEM_SIZE - p;if (copy_from_user(dev->mem + p, buf, count)) {        ret = -EFAULT;    } else {        *ppos += count;        ret = count;        pr_info("globalmem: device %d written %u bytes to offset %lu\n", dev->dev_idx, count, p);    }return ret;}/** * globalmem_llseek - 文件定位函数(多设备通用) */staticloff_tglobalmem_llseek(struct file *filp, loff_t offset, int orig){loff_t ret = 0;structglobalmem_dev *dev = filp->private_data;switch (orig) {case0:  // SEEK_SET:从文件开头定位if (offset < 0 || (unsignedint)offset > GLOBALMEM_SIZE) {                ret = -EINVAL;break;            }            filp->f_pos = (unsignedint)offset;            ret = filp->f_pos;break;case1:  // SEEK_CUR:从当前位置定位if ((filp->f_pos + offset) > GLOBALMEM_SIZE || (filp->f_pos + offset) < 0) {                ret = -EINVAL;break;            }            filp->f_pos += offset;            ret = filp->f_pos;break;default:            ret = -EINVAL;break;    }    pr_info("globalmem: device %d seek to offset %lu\n", dev->dev_idx, ret);return ret;}/** * globalmem_ioctl - IO控制函数(多设备通用,清空当前设备实例内存) */staticlongglobalmem_ioctl(struct file *filp, unsignedint cmd, unsignedlong arg){structglobalmem_dev *dev = filp->private_data;// 命令合法性检查if (_IOC_TYPE(cmd) != GLOBALMEM_MAGIC || _IOC_NR(cmd) > 0)return -EINVAL;switch (cmd) {case MEM_CLEAR:memset(dev->mem, 0, GLOBALMEM_SIZE);            pr_info("globalmem: device %d memory cleared successfully\n", dev->dev_idx);break;default:return -EINVAL;    }return0;}/** * globalmem_setup_cdev - 初始化单个cdev并添加到内核(多设备循环调用) * @dev:单个设备实例指针 * @index:设备索引(次设备号,0~4) */staticvoidglobalmem_setup_cdev(struct globalmem_dev *dev, int index){dev_t devno = MKDEV(globalmem_major, index);    dev->dev_idx = index;  // 绑定设备索引    cdev_init(&dev->cdev, &globalmem_fops);    dev->cdev.owner = THIS_MODULE;int err = cdev_add(&dev->cdev, devno, 1);if (err) {        pr_notice("globalmem: error %d adding device %d\n", err, index);    } else {        pr_info("globalmem: device %d cdev initialized successfully\n", index);    }}/** * globalmem_init - 驱动初始化函数(多设备适配,申请多个设备号和实例) */staticint __init globalmem_init(void){int ret, i;dev_t devno = MKDEV(globalmem_major, 0);// 申请DEVICE_NUM个设备号(次设备号0~4)if (globalmem_major) {        ret = register_chrdev_region(devno, DEVICE_NUM, DEVICE_NAME);    } else {        ret = alloc_chrdev_region(&devno, 0, DEVICE_NUM, DEVICE_NAME);        globalmem_major = MAJOR(devno);    }if (ret < 0) {        pr_err("globalmem: failed to allocate device numbers\n");return ret;    }// 分配DEVICE_NUM个设备实例的内存(数组形式)    globalmem_devp = kzalloc(sizeof(struct globalmem_dev) * DEVICE_NUM, GFP_KERNEL);if (!globalmem_devp) {        ret = -ENOMEM;goto fail_malloc;    }// 循环初始化每个设备实例for (i = 0; i < DEVICE_NUM; i++) {        globalmem_setup_cdev(globalmem_devp + i, i);    }    pr_info("globalmem: %d devices initialized successfully, major number = %d\n", DEVICE_NUM, globalmem_major);return0;fail_malloc:    unregister_chrdev_region(devno, DEVICE_NUM);    pr_err("globalmem: failed to allocate memory, driver init failed\n");return ret;}/** * globalmem_exit - 驱动退出函数(多设备适配,释放所有实例资源) */staticvoid __exit globalmem_exit(void){int i;dev_t devno = MKDEV(globalmem_major, 0);// 循环移除每个设备的cdev,释放资源for (i = 0; i < DEVICE_NUM; i++) {        cdev_del(&(globalmem_devp + i)->cdev);        pr_info("globalmem: device %d cdev removed\n", i);    }    kfree(globalmem_devp);  // 释放设备实例数组内存    unregister_chrdev_region(devno, DEVICE_NUM);  // 释放所有设备号    pr_info("globalmem: all devices exited successfully\n");}// 模块加载/卸载入口module_init(globalmem_init);module_exit(globalmem_exit);// 模块信息声明MODULE_AUTHOR("Linux Driver Developer");MODULE_LICENSE("GPL v2");MODULE_DESCRIPTION("Multi-instance Global Memory Character Device Driver for Linux 6.6 Kernel");MODULE_VERSION("1.0");

多设备实例使用说明(配套上述完整代码)

  1. 编译方式:与单设备版一致,直接使用原Makefile编译,无需修改(Makefile兼容单/多设备)。

  2. 创建设备节点:加载驱动后,需为5个设备实例分别创建节点(次设备号0~4),命令如下:

    # 依次创建5个设备节点,对应设备0~4sudo mknod /dev/globalmem0 c 230 0sudo mknod /dev/globalmem1 c 230 1sudo mknod /dev/globalmem2 c 230 2sudo mknod /dev/globalmem3 c 230 3sudo mknod /dev/globalmem4 c 230 4# 修改所有节点权限,允许普通用户读写sudo chmod 666 /dev/globalmem*
  3. 测试说明:每个设备节点对应独立的全局内存,操作互不干扰,示例:

    # 向设备0写入数据echo"device 0 test data" > /dev/globalmem0# 从设备0读取数据(正常输出写入内容)cat /dev/globalmem0# 向设备1写入不同数据echo"device 1 test data" > /dev/globalmem1# 从设备0读取(仍为原有内容,不受设备1操作影响)cat /dev/globalmem0# 清空设备0内存sudo ioctl /dev/globalmem0 $(echo -n -e "\x01\x67\x00\x00\x00\x00\x00\x00")# 再次读取设备0(无输出,清空成功)cat /dev/globalmem0
  4. 卸载驱动:与单设备版一致,执行sudo rmmod globalmem即可,卸载后建议删除所有设备节点。

多设备核心适配要点

  • 新增DEVICE_NUM宏定义,控制设备实例数量,可根据需求修改(如改为3个、10个)。
  • 设备结构体新增dev_idx成员,用于区分不同设备实例,便于日志输出和调试。
  • 使用container_of函数,通过inode的i_cdev成员反向获取设备实例,替代单设备的全局变量直接引用,是多设备驱动的核心技巧。
  • 设备号申请、cdev初始化、资源释放均采用循环方式,批量处理所有设备实例,避免重复代码。

此代码可直接替换单设备版代码,编译后即可实现多设备功能,完全适配Linux 6.6内核,无任何兼容性问题。

七、注意事项

  • 主设备号冲突:若预设主设备号(230)已被其他驱动占用,可通过模块参数修改,或使用动态分配设备号(不指定主设备号,内核自动分配)。

  • 内核版本匹配:本驱动基于 Linux 6.6 内核编写,若用于其他内核版本(如5.10+),需微调打印函数和宏定义,核心功能可兼容;低于5.10的内核需修改IO控制接口和废弃宏。

  • 权限问题:设备节点默认仅root用户可读写,测试时可修改节点权限(chmod 666 /dev/globalmem),实际应用中需根据需求设置合理权限。

  • 资源释放:模块卸载前,需确保设备已关闭(无进程占用),否则会导致卸载失败,可通过 lsof /dev/globalmem 查看占用进程,关闭后再卸载模块。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-10 13:59:50 HTTP/2.0 GET : https://f.mffb.com.cn/a/474709.html
  2. 运行时间 : 0.088891s [ 吞吐率:11.25req/s ] 内存消耗:4,786.53kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=91bbc70e07baa76928ab5214c9722a6a
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000539s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000746s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000290s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000278s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000470s ]
  6. SELECT * FROM `set` [ RunTime:0.000186s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000543s ]
  8. SELECT * FROM `article` WHERE `id` = 474709 LIMIT 1 [ RunTime:0.001653s ]
  9. UPDATE `article` SET `lasttime` = 1770703190 WHERE `id` = 474709 [ RunTime:0.009540s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000228s ]
  11. SELECT * FROM `article` WHERE `id` < 474709 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001549s ]
  12. SELECT * FROM `article` WHERE `id` > 474709 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001179s ]
  13. SELECT * FROM `article` WHERE `id` < 474709 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001058s ]
  14. SELECT * FROM `article` WHERE `id` < 474709 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001084s ]
  15. SELECT * FROM `article` WHERE `id` < 474709 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000779s ]
0.090530s