当前位置:首页>Linux>【Linux 内核】设备模型基石:Kobject内核源码解析

【Linux 内核】设备模型基石:Kobject内核源码解析

  • 2026-08-19 10:08:12
【Linux 内核】设备模型基石:Kobject内核源码解析

在Linux内核里,设备模型(Device Model)是所有总线、设备、驱动、sysfs的统一骨架。而这套骨架底层的基石就是kobject。理解kobject,是读懂内核struct devicestruct driver等的前提。

一、kobject / kset / ktype 的关系

Greg Kroah-Hartman(kobject 的作者)写过一篇著名的文档Documentation/core-api/kobject.rst,开篇就点明:理解kobject的难点在于「没有明显切入点」,因为它总是和ksetktype互相引用

  • kobject = 对象:字段中包含名字、引用计数、能在sysfs中成为一个目录的内核对象。它通常内嵌进更大的结构体(如上一篇文章中的cdev结构体)

  • kset = 集合:一组kobject的容器,自身也内嵌一个kobject对象(在sysfs中是一个目录),并可以向用户空间广播uevent热插拔事件

  • ktype = 类型:描述这一类kobject的共同行为。它归零时怎么释放、在sysfs里有哪些默认属性、读写属性时调用哪些通用方法

⚠️内核中的任何一个结构体都只能内嵌一个kobject,内嵌多个对象会导致引用计数错误。

三者的层次可以这样理解:

  • 一个kobject属于且仅属于一个kset(通过kobj->kset获取上层分组)

  • 一个kobject必须有一个ktype(通过kobj->ktype,在kobject_init()时指定)

  • 一个kset在sysfs中是一个目录,它集合中的所有kobject目录都是它的子目录

  • kobject通过parent指针构建父子层次;当parent为空且属于某kset时,内核自动把kset内嵌的kobject当作它的父节点

二、内核源码中的结构体定义

本小节主要介绍两个内核结构体,kobjectkernfs_node

2.1 kobject

kobject本身不包含具体功能,而是嵌入到更大的数据结构中,赋予这些结构内核对象的特性。kobject为具体对象提供了三项核心服务:引用计数管理层级关系构建sysfs表示

职责一:管理对象生命周期(引用计数)

内核对象(如一个cdev字符设备)的生命周期管理需要知道谁在使用它,何时可以安全释放。kobject通过引用计数(reference count)解决这个问题。

  • 机制:内部嵌有一个struct kref类型的引用计数器

  • 操作:当内核中的某部分代码想要使用一个对象时,会调用kobject_get()增加其引用计数;使用完毕后,调用kobject_put()减少计数

  • 释放:当引用计数降为0时,表示没有任何代码在使用该对象,内核便会自动调用预先设定的release方法来安全地释放它,从而避免“野指针”和内存泄漏问题

职责二:构建对象层级结构(父子关系) 

内核中的设备、总线、驱动等并非杂乱无章,而是以树形结构组织。kobject通过父指针(parent pointer)实现

  • 机制:每个kobject都有一个parent指针,指向其父 kobject

  • 效果:这种父子关系在sysfs文件系统中被映射为目录的层级结构

职责三:与用户空间通信(sysfs 接口)

kobject是与sysfs虚拟文件系统交互的核心机制

  • 目录映射:当 kobject 被成功注册到内核后,sysfs中就会为其创建一个对应的目录

  • 属性文件:kobject可以携带“属性”(attribute),这些属性在 sysfs中表现为该目录下的普通文件

  • 交互方式:用户可以通过读写这些文件来查看内核对象的状态或修改配置。kobject是连接内核数据结构与用户空间文件系统的“桥梁”

源码位置:/lib/kobject.c

structkobject {    const char *name;         // 对象名称,会作为 sysfs 目录名    struct list_head entry;   // 用于将该对象加入 kset 的链表    struct kobject *parent;   // 指向父对象的指针,构建层次结构    struct kset *kset;        // 指向所属的 kset 集合    struct kobj_type *ktype;  // 指向对象类型描述符,定义共同行为    struct kernfs_node *sd;   // 指向 sysfs 中对应的目录项(VFS 层节点)    struct kref kref;         // 引用计数,管理对象生命周期    unsigned int state_initialized:1// 初始化状态位    unsigned int state_in_sysfs:1;    // 是否已添加到 sysfs    unsigned int state_add_uevent_sent:1;   // 添加事件已发送标志    unsigned int state_remove_uevent_sent:1;// 移除事件已发送标志    unsigned int uevent_suppress:1;   // 是否抑制发送 uevent 事件};

🔍 扩充:最后5个1 bit字段state_*是kobject的生命周期状态:

  • initialized标记是否完成初始化;

  • in_sysfs标记是否已在sysfs创建目录;

  • add/remove_uevent保证添加和事件各只发一次;

  • uevent_suppress则允许驱动临时抑制事件(比如对象还在内部调整、不希望用户空间过早看到)

大多数内核对象结构体内部都内嵌了一个kobject成员。例如:

源码位置:include/linux/device.h

structdevice {    struct device *parent;    struct device_privatet *p;    struct kobject kobj// <-- device 通过内嵌 kobject 接入设备模型    const char *init_name;    const struct device_type *type;    struct bus_type *bus;    struct device_driver *driver;dev_tdevt;    struct class *class;    void (*release)(structdevice *dev);    /* ... 省略 ... */};// 从 kobject 反推所在 device(典型用法)struct device *dev = container_of(kobjstruct devicekobj);

2.2 kernfs_node

核心功能

在Linux内核中,kernfs_node是kernfs子系统定义的数据结构,是构建kernfs层次结构的基本单元。无论是/sys下的一个子目录,还是一个普通属性文件,在kernfs内部都由一个kernfs_node结构体来表示

桥梁作用

kernfs_node是连接内核对象模型(kobject)和用户空间文件系统(sysfs)的桥梁。 当一个kobject被注册并需要在sysfs中创建目录时,kernfs会创建一个对应的kernfs_node。这个kernfs_node会存储一个指向其背后kobject的指针。反过来,kobject结构体中也有一个名为sd(sysfs directory entry)的成员,指向关联的kernfs_node。 通过这种双向关联,kernfs_node将内核对象(kobject)与其在sysfs中的表示(目录或文件)联系在一起

源码位置:include/linux/kernfs.h

// 定义在 include/linux/kernfs.hstruct kernfs_node {    const char *name;  /* 节点名称(目录名/文件名) */    struct rb_node rb/* 红黑树节点,用于在父目录中按名称查找 */    struct kernfs_node *parent/* 指向父节点的指针 */    unsigned int hash/* 名称哈希值,加速查找 */    const void *ns;    /* 命名空间标签,用于支持命名空间隔离 */    union {        struct kernfs_elem_dir dir;         /* 目录特有信息 */        struct kernfs_elem_symlink symlink/* 符号链接特有信息 */        struct kernfs_elem_attr attr;       /* 文件(属性)特有信息 */    };    void *priv;         /* 私有数据,可以存储kobject */    unsigned int flags/* 节点标志(类型、状态等) */    umode_t mode;    union kernfs_node_id id;    struct kernfs_iattrs *iattr/* inode 属性(权限、时间戳等),延迟分配 */    atomic_t count;     /* 引用计数,管理生命周期 */    atomic_t active;    /* 活动引用计数,用于保护正在进行的操作 */};

🔍 扩充:kernfs与sysfs的分层:早期的sysfs直接基于ramfs/kobject实现,代码耦合严重。内核后来抽出了独立的kernfs层(sysfs、cgroup、pstore、tracefs都建在它之上)

VFS接口(用户空间)  →  

sysfs层(把kobject映射到目录/文件) →  

kernfs层(伪文件系统树)

kobject与kernfs_node 是双向绑定:kobj->sd 指向目录节点,kn->priv 指回 kobject(后面源码会看到)

三、kobject_create_and_add 

本小节介绍内核内核提供的工具函数,用来辅助理解内核kobject结构体的功能之一,通过sysfs虚拟文件系统实现与用户空间的通信。该工具函数动态创建一个kobject,并将其注册到sysfs中,实现在/sys下创建一个目录节点。该函数的调用链,以及对上一小节介绍的两个结构体对象进行的操作如下:

kobject_create_and_add() 

├── kobject_create()           // 1. 创建并初始化kobject 

│    └── kzalloc()             // 1.1 分配内存 

│    └── kobject_init()        // 1.2 初始化结构体 

│          ├── kref_init()     // 1.2.1 初始化引用计数为1 

│          └── INIT_LIST_HEAD()// 1.2.2 初始化链表节点 

└── kobject_add()              // 2. 添加到内核并关联sysfs 

     └── kobject_add_varg()    // 2.1 处理可变参数 

          └── kobject_set_name_vargs()  // 2.1.1 设置kobject的名称 

          └── kobject_add_internal()    // 2.2 核心添加操作 

               ├── kset检查,加入kset链表  // 2.2.1 处理父子关系

               └── create_dir()         // 2.2.2 在sysfs中创建目录 

                    ├── sysfs_create_dir()    // 在sysfs中创建目录项 

                    ├── populate_dir()        // 填充default_attrs属性 

                    └── sysfs_create_groups() // 填充default_groups属性

kobject结构体

  • 1. 初始化kobject对象

  • 2. 分配kobject->ktype成员变量指向默认操作函数

  • 7. 将kobject->sd指向目录节点对象kernfs_node。至此,kobject 和 kernfs_node 完成了双向绑定

kernfs_node结构体

  • 3. 初始化kernfs_node对象

  • 4. 为kobject创建目录节点

  • 5. 将kernfs_node->priv指向kobject对象

  • 6. 配置kernfs_node->ns命名空间

源码位置:/lib/kobject.c

/*** 动态创建kobject并将其注册到sysfs* @name: kobject的名称* @parent: 该kobject的父kobject指针*/struct kobject *kobject_create_and_add(const char *namestruct kobject *parent){    struct kobject *kobj;    int retval;    // 第一步:动态创建并初始化一个kobject    kobj = kobject_create();    if (!kobj)        return NULL;    // 第二步:将创建好的kobject添加到设备模型并注册到sysfs    retval = kobject_add(kobjparent"%s"name);    if (retval) {        printk(KERN_WARNING"%s: kobject_add error: %d\n",                    __FUNCTION__retval);        // 如果添加失败,释放引用计数,触发清理        kobject_put(kobj);        kobj = NULL;    }    return kobj;}EXPORT_SYMBOL_GPL(kobject_create_and_add);

3.1 kobject_create

kobject_create用于动态分配并初始化一个kobject实例:

  • 分配内存:通过kzalloc()在堆上为struct kobject分配内存,并将其全部清零

  • 初始化对象:调用kobject_init()对新分配的对象进行初始化,同时将ktype设置为预定义的、静态的dynamic_kobj_ktype

源码位置:/lib/kobject.c

structkobject *kobject_create(void){    struct kobject *kobj;    kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);    if (!kobj)        return NULL;    // 使用默认的 dynamic_kobj_ktype 进行初始化    kobject_init(kobj, &dynamic_kobj_ktype);    return kobj;}EXPORT_SYMBOL_GPL(kobject_create);

3.1.1 对象行为:kobj_sys_ops

kobject_init函数传入的全局变量dynamic_kobj_ktype定义如下:

源码位置:/lib/kobject.c

staticconststructkobj_typedynamic_kobj_ktype = {

    // 引用计数器为0时,释放内存
    .release = dynamic_kobj_release    .sysfs_ops = &kobj_sysfs_ops,};

kobj_sysfs_ops本身一直是内核中一个全局的、标准的sysfs操作函数集。它的作用是为那些没有自定义sysfs_ops的 kobject 提供一套默认的、通用的读写方法:

源码位置:/lib/kobject.c

conststructsysfs_opskobj_sysfs_ops = {    .show = kobj_attr_show,     // 取出数据    .store = kobj_attr_store,   // 存入数据};

3.1.2 核心机制:读写操作转发

kobj_attr_showkobj_attr_store这两个是静态函数。它们的核心逻辑是转发。它们自己不处理具体的读写操作,而是从标准的属性struct attribute推导出更具体的struct kobj_attribute,然后调用后者中由开发者定义的showstore函数

源码位置:/lib/kobject.c

// 读操作转发函数static ssize_t kobj_attr_show(struct kobject *kobjstruct attribute *attr,                            char *buf){    struct kobj_attribute *kattr;    ssize_t ret = -EIO;    // 通过 container_of 从基础类型 attribute 获取包含它的 kobj_attribute    kattr = container_of(attrstruct kobj_attributeattr);    if (kattr->show)        ret = kattr->show(kobjkattrbuf); // 调用开发者自定义的 show 函数    returnret;}// 写操作转发函数 (逻辑完全相同)static ssize_t kobj_attr_store(struct kobject *kobjstruct attribute *attr,                            const char *bufsize_t count){    struct kobj_attribute *kattr;    ssize_t ret = -EIO;    kattr = container_of(attrstruct kobj_attributeattr);    if (kattr->store)        ret = kattr->store(kobjkattrbufcount); // 调用开发者自定义的 store 函数    return ret;}
💡container_of sysfs的回调使用通用的struct attribute *,但开发者使用的带函数指针struct kobj_attribute *。内核通过container_of宏,从成员attr反推出外层结构体,从而找回用户定义的 show/store。这是c语言实现面向对象多态的手法

3.1.3 转发机制:kobj_attribute

为了实现上述的转发机制,内核定义了struct kobj_attribute。它是一个标准属性(struct attribute)加上对应的两个读取和写入操作函数指针

源码位置:include/linux/sysfs.h

structkobj_attribute {    struct attribute attr// 嵌入一个标准属性,包含 char* name 和 short mode    ssize_t (*show)(struct kobject *kobjstruct kobj_attribute *attr,                char *buf);    ssize_t (*store)(struct kobject *kobjstruct kobj_attribute *attr,                const char *bufsize_t count);};

3.2 kobject_add

kobject_add是Linux内核设备模型中将一个已初始化的kobject正式注册到系统中的函数。它配置了kobjectname字段,负责将kobject连接到设备模型的树形结构中,并在sysfs中创建对应的目录

源码位置:/lib/kobject.c

intkobject_add(struct kobject *kobjstruct kobject *parentconst char *fmt, ...) {va_listargs;    int retval;    // 检查空指针等    va_start(argfmt);    retval = kobject_add_varg(kobjparentfmtargs);    va_end(args);    return retval;}

内部的函数调用链为:

调用链(伪代码)

kobject_add()    --> kobject_add_varg()     // 处理变参,设置名称        --> kobject_add_internal() // 核心实现            --> create_dir()   // 创建 sysfs 目录

3.2.1 kobject_add_internal 函数

该函数是kobject_add函数中调用的核心函数:

  • kobject对象的父节点计数器增加

  • 判断如果kobject存在kset,并且kobject没有设置父节点,则将kset设置为父节点

  • parent节点下创建目录

源码位置:/lib/kobject.c

staticint kobject_add_internal(struct kobject *kobj) {    int error = 0;    struct kobject *parent;    // 省略错误检查...    parent = kobject_get(kobj->parent); // 增加 parent 的 kref 引用计数    if (kobj->kset) {        if (!parent)            parent = kobject_get(&kobj->kset->kobj); // 如果未设置 parent,则使用 kset 的 kobject 作为 parent        kobj_kset_join(kobj); // 将 kobject 加入 kset 的链表        kobj->parent = parent;    }    // 在父目录 parent 下创建目录    error = create_dir(kobj);    return error;}
🔍 扩充:parent与kset的优先级 内核设计的顺序:显式parent优先;只有当parent为空且属于某个kset时,内核才用kset->kobj顶上父节点。这就是为什么很多子系统只要把kobj->kset设好,就能自动在正确目录下建出子目录,无需手动指定 parent

3.2.2 create_dir 函数

源码位置:/lib/kobject.c

// 定义在 /lib//kobject.c 文件中static int create_dir(struct kobject *kobj) {    const struct kobj_type *ktype = get_ktype(kobj);    const struct kobj_ns_type_operations *ops;    // 1.为kobj创建目录节点    sysfs_create_dir_ns(kobjkobject_namespace(kobj));    // 2.实际上没有操作    populate_dir(kobj);    if (ktype)        sysfs_create_groups(kobjktype->default_groups);}
3.2.2.1 sysfs_create_dir_ns 创建目录节点

sysfs文件系统中为kobject创建目录节点,后续所有属性文件都在此目录下创建。

此函数将kobject->sd成员变量设置为kn当前创建的目录节点

源码位置:/lib/kobject.c

/*** @kobj: 目标 kobject* @ns: 命名空间标签(可选)* 返回值:成功返回 0,失败返回负错误码。*/int sysfs_create_dir_ns(struct kobject *kobjconst void *ns){    struct kernfs_node *parent, *kn;    kuid_t uid;    kgid_t gid;    /* 如果 kobject 有父对象,则父目录为父 kobject 的 kernfs 节点;否则为 sysfs 根目录 */    if (kobj->parent)        parent = kobj->parent->sd;    else        parent = sysfs_root_kn;    /* 获取该 kobject 目录的所有者(uid/gid) */    kobject_get_ownership(kobj, &uid, &gid);    /* 调用 kernfs 创建目录节点 */    kn = kernfs_create_dir_ns(parentkobject_name(kobj),            S_IRWXU | S_IRUGO | S_IXUGO,            uidgidkobjns);    if (IS_ERR(kn)) {        if (PTR_ERR(kn) == -EEXIST)            sysfs_warn_dup(kobject_name(kobj));        return PTR_ERR(kn);    }    /* 将新创建的 kernfs 节点指针保存到 kobject 中 */    kobj->sd = kn;    return 0;}EXPORT_SYMBOL_GPL(sysfs_create_dir_ns);
3.2.2.2 kernfs_create_dir_ns 文件系统目录物理创建

该函数完成kernfs_node内核节点的创建,并将其挂入父目录的红黑树中。

  • 该函数配置了kernfs_node->priv为调用时传入的kobj

  • 该函数配置了命名空间

源码位置:fs/kernfs/dir.c

structkernfs_node *kernfs_create_dir_ns(structkernfs_node *parent,                constchar *name,                umode_t mode,                kuid_t uid,                kgid_t gid,                void *priv,                constvoid *ns){    struct kernfs_node *kn;    int rc;    /* 1. 参数校验:父节点必须存在 */    if (!parent)        return ERR_PTR(-EINVAL);    /* 2. 创建新的 kernfs 节点,类型为目录 */    kn = kernfs_new_node(parentnamemode | S_IFDIRuidgid,                    KERNFS_DIR);    if (!kn)        return ERR_PTR(-ENOMEM);    /* 3. 设置私有数据和命名空间标签 */    kn->priv = priv;    kn->ns = ns;    /* 4. 将新节点添加到父目录的红黑树中 */    rc = kernfs_add_one(kn);    if (rc) {        kernfs_put(kn);        return ERR_PTR(rc);    }    /* 5. 返回新节点 */    return kn;}EXPORT_SYMBOL_GPL(kernfs_create_dir_ns);
🔍 扩充:红黑树+哈希,查找O(logn) kernfs 用红黑树kn->rb)在父目录下按名字组织子节点,配合kn->hash名字哈希,使按名查找目录项高效且稳定。同时kn->ns命名空间标签让同一父目录下可以存在同名但不同命名空间的节点(例如不同网络命名空间里的网络设备在sysfs中互不冲突)

3.2.3 populate_dir

该函数是在kobject注册时自动调用的内部辅助函数,用于创建“默认属性”

  • 工作方式:kobjectkobj_type中获取default_attrs数组,然后循环调用sysfs_create_file(),为每个属性在sysfs目录下创建一个普通文件

  • 特点:所有文件都直接放在kobject的sysfs目录下,结构“扁平”。它没有原子性保障——如果创建第N个文件失败,之前创建的文件不会被自动回滚,可能留下不完整的状态

由于kobject_create_and_add()函数创建kobject时没有定义属性文件,所以不会执行

源码位置:/lib/kobject.c

/*** @kobj: 目标 kobject* 返回值:成功返回 0,失败返回负错误码。*/static int populate_dir(struct kobject *kobj){    struct kobj_type *t = get_ktype(kobj);    const struct attribute *attr;    int error = 0;    int i;    if (t && t->default_attrs) {        for (i = 0; (attr = t->default_attrs[i]) != NULLi++) {            error = sysfs_create_file(kobjattr);            if (error)                break;        }    if (error)        while (--i >= 0)            sysfs_remove_file(kobjt->default_attrs[i]);    }    return error;}

3.2.4 sysfs_create_groups

该函数是内核sysfs核心API,用于在指定kobject下创建一个或多个属性组

  • 工作方式:它接收一个attribute_group指针数组(以 NULL 结束)。每个组可以包含多个属性,并拥有独立的子目录(指定name),能对属性进行分类管理。

  • 原子性与错误处理:具备原子性。创建过程中任何一步出错,它会自动移除所有已创建的组,将sysfs状态回滚到函数调用之前

  • 使用场景:它是当前驱动开发的主流方式。在kobjectdevice注册时,常通过ktype->default_groupsdevice->groups来使用,实现属性的统一管理和自动清理

由于kobject_create_and_add()函数创建kobject时没有定义属性文件,所以不会执行

源码位置:/lib/kobject.c

/*** @kobj: 目标 kobject* @groups: 以 NULL 结尾的属性组指针数组* 返回值:成功返回 0,失败返回负错误码。*/int __must_check sysfs_create_groups(struct kobject *kobj,        const struct attribute_group **groups){    int ierror = 0;    if (!groups)        return0;    for (i = 0groups[i] && !errori++)        error = Internal_create_group(kobjupdategroups[i]);    if (error)        while (--i >= 0)            sysfs_remove_group(kobjgroups[i]);    return error;}EXPORT_SYMBOL_GPL(sysfs_create_groups);

四、引用计数kref与对象生命周期

kobject的自动释放能力,底层来自struct krefkref本质就是对一个atomic_t原子计数器的封装,支持无锁的get/多线程安全的put

include/linux/kref.h

// include/linux/kref.hstruct kref {    atomic_t refcount;};static inline void kref_init(struct kref *kref){    atomic_set(&kref->refcount1);}static inline void kref_get(struct kref *kref){    atomic_inc(&kref->refcount);}

源码定义在lib/kref.ckref_get原子加一;kref_put原子减一并测试,若减到 0 就调用用户传入的release回调释放对象

lib/kref.c(简化)

// lib/kref.c (简化自内核实现)void kref_get(struct kref *kref){    WARN_ON(!atomic_read(&kref->refcount));    atomic_inc(&kref->refcount);    smp_mb__after_atomic();}int kref_put(struct kref *krefvoid (*release)(struct kref *kref)){    WARN_ON(release == NULL);    if (atomic_dec_and_test(&kref->refcount)) {        release(kref); /* 计数归零,释放对象 */        return 1;    }    return 0;}

kobject在自己的kref之上封装了kobject_get/kobject_put,并在put归零时走kobject_releasekobject_cleanup,最终调用用户ktype->release里定义的释放函数:

lib/kobject.c

// lib/kobject.cstruct kobject *kobject_get(struct kobject *kobj){    if (kobj)        kref_get(&kobj->kref);    return kobj;}void kobject_put(struct kobject *kobj){    if (kobj) {        if (!kobj->state_initialized)            WARN(1KERN_WARNING"kobject: '%s' is not initialized, "                    "yet kobject_put() is being called.\n",        kobject_name(kobj));        kref_put(&kobj->krefkobject_release);    }}static void kobject_release(struct kref *kref){    kobject_cleanup(container_of(krefstruct kobjectkref));}

五、kset与uevent热插拔机制

kset是kobject的集合容器。它本身内嵌一个kobject(所以也会在sysfs中占一个目录),并持有一组uevent_ops回调,负责在集合内对象增删时向用户空间广播事件

include/linux/kobject.h

// include/linux/kobject.hstruct kset {    struct list_head list// 链表头,串起本集合内所有 kobjectspinlock_t list_lock;  // 保护链表的自旋锁    struct kobject kobj;   // kset 内嵌的 kobject,自身在 sysfs 中也占一个目录    const struct kset_uevent_ops *uevent_ops// uevent 过滤/构造回调};struct kset_uevent_ops {    int (*filter)(struct kset *ksetstruct kobject *kobj); // 是否允许发送    const char *(*name)(struct kset*ksetstruct kobject *kobj);    int (*uevent)(struct kset *ksetstruct kobject *kobj, struct kobj_uevent_env *env); // 追加环境变量};

典型的 kset 创建方式:

lib/kobject.c

// lib/kobject.cstruct kset *kset_create_and_add(const char *name,        const struct kset_uevent_ops *uevent_ops,        struct kobject *parent_kobj){    struct kset *kset;    int error;kset = kset_create(nameuevent_opsparent_kobj);    if (!kset)        return NULL;    error = kset_register(kset);    if (error) {        kfree(kset);        return NULL;    }    return kset;}EXPORT_SYMBOL_GPL(kset_create_and_add);

当设备插入/拔出时,内核通过kobject_uevent()触发事件。下面是kobject_uevent_env的部分代码,包含一次uevent的完整生命周期:

lib/kobject_uevent.c(裁剪)

// lib/kobject_uevent.c (核心调用链裁剪)int kobject_uevent(struct kobject *kobjenum kobject_actionaction){    return kobject_uevent_env(kobjactionNULL);}int kobject_uevent_env(struct kobject *kobjenum kobject_actionaction,        char *envp_ext[]){    struct kobj_uevent_env *env;    const char *action_string = kobject_actions[action];    const char *devpath = NULL;    struct kset *kset = NULL;    /* 1. 向上回溯,找到所属的最顶层 kset */    struct kobject *top_kobj = kobj;    while (!top_kobj->kset && top_kobj->parent)        top_kobj = top_kobj->parent;    if (!top_kobj->kset)        return -EINVAL/* 没有 kset 就无法发送 uevent */    kset = top_kobj->kset;    /* 2. uevent_suppress 为真则丢弃事件 */    if (kobj->uevent_suppress)        return 0;    /* 3. 通过 kset->uevent_ops->filter 决定该对象是否允许上报 */    if (kset->uevent_ops && kset->uevent_ops->filter)        if (!kset->uevent_ops->filter(ksetkobj))            return 0;    /* 4. 构造环境变量:ACTION / DEVPATH / SUBSYSTEM / SEQNUM ... */    add_uevent_var(env"ACTION=%s"action_string);    add_uevent_var(env"DEVPATH=%s"devpath);    add_uevent_var(env"SEQNUM=%llu", ++uevent_seqnum);    /* 5. 通过 Netlink 广播到用户空间 (NETLINK_KOBJECT_UEVENT = 15) */    return kobject_uevent_net_broadcast(kobjenvaction_stringdevpath);}

🌐 uevent如何到达用户空间

内核通过Netlink协议NETLINK_KOBJECT_UEVENT把事件广播出去,用户空间的udev/systemd-udevd监听该 socket,按规则(/etc/udev/rules.d)匹配ACTIONSUBSYSTEMDEVPATH等环境变量,执行建节点、加载模块、跑脚本等动作

六、container_of —— 内核面向对象的基石

前面多次看到container_of。它是设备模型以成员反推宿主的宏,也是C语言实现继承/多态的基石:只要结构体里内嵌了某成员,就能从成员的指针反推出外层大结构体的指针

include/linux/kernel.h

// include/linux/kernel.h#definecontainer_of(ptrtypemember) ({ \    consttypeof(((type *)0)->member) * __mptr = (ptr); \    (type *)((char *)__mptr - offsetof(typemember)); })// 实际使用示例:从 attribute 反推包含它的 kobj_attributestructkobj_attribute *kattr;kattr = container_of(attrstructkobj_attributeattr);

七、写一个内核模块,在sysfs导出可读写属性

本小节完成内核模块的一个简单案例。模块加载后会在/sys/kernel/kobject_example下创建foobazbar 三个文件,向文件写数字即可读出,相当于给用户空间开了一个配置内核变量的窗口

sp-kobject-example.c

#include<linux/module.h>#include <linux/kernel.h>#include <linux/kobject.h>#include <linux/sysfs.h>#include <linux/init.h>static int foo;static int baz;static int bar;static ssize_t foo_show(struct kobject *kobjstruct kobj_attribute *attrchar *buf){    return sprintf(buf"%d\n"foo);}static ssize_t foo_store(struct kobject *kobjstruct kobj_attribute *attr,                const char *bufsize_t count){    sscanf(buf"%d", &foo);    return count;}static struct kobj_attribute foo_attribute = __ATTR(foo0666foo_showfoo_store);static ssize_t b_show(struct kobject *kobjstruct kobj_attribute *attrchar *buf){    int var;    if (strcmp(attr->attr.name"baz") == 0)        var = baz;    else        var = bar;    return sprintf(buf"%d\n"var);}static ssize_t b_store(struct kobject *kobjstruct kobj_attribute *attr,                const char *bufsize_t count){    int var;    sscanf(buf"%d", &var);    if (strcmp(attr->attr.name"baz") == 0)        baz = var;    else        bar = var;    return count;}static struct kobj_attribute baz_attribute = __ATTR(baz0666b_showb_store);static struct kobj_attribute bar_attribute = __ATTR(bar0666b_showb_store);static struct attribute *attrs[] = {    &foo_attribute.attr,    &baz_attribute.attr,    &bar_attribute.attr,    NULL,};static struct attribute_groupattr_group = {    .attrs = attrs,};static struct kobject *example_kobj;static int __init example_init(void){    int retval;    example_kobj = kobject_create_and_add("kobject_example"kernel_kobj);    if (!example_kobj)        return -ENOMEM;    retval = sysfs_create_group(example_kobj, &attr_group);    if (retval)        kobject_put(example_kobj);    return retval;}static void __exit example_exit(void){    kobject_put(example_kobj);}module_init(example_init);module_exit(example_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Greg Kroah-Hartman");

模块加载后可以查看创建的3个属性文件

ls /sys/kernel/kobject_example/

通过echo和cat命令可以对属性文件进行操作

八、device / driver 内嵌 kobject

前面说过kobject几乎不单独存在。以struct device为例,其内部内嵌了struct kobject kobj,因此每个设备自动获得:引用计数、sysfs 目录(/sys/devices/...)、uevent 能力,以及通过container_of(kobj, struct device, kobj)从kobject反推回device的能力。

include/linux/device.h(节选)

// include/linux/device.h (节选)struct device {    struct device *parent;    struct device_private *p;    struct kobject kobj// <-- device 通过内嵌 kobject 接入设备模型    const char *init_name;    const struct device_type *type;    struct bus_type *bus;    struct device_driver *driver;    dev_t devt;    struct class *class;    void (*release)(structdevice *dev);    /* ... */};// 从 kobject 反推所在 device(典型用法)struct device *dev = container_of(kobjstruct devicekobj);

总线、设备、驱动、class全都内嵌kobject,它们能在同一棵sysfs树里被统一管理,也能用同一套引用计数/uevent机制

文章内容为作者过往学习的笔记,接下来会按期更新,预计下一期更新与kobject紧密相关的属性kobj_attribute。如果本文对你有帮助,欢迎点赞、在看、转发,让更多 Linux 开发者受益 🚀

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 22:32:33 HTTP/2.0 GET : https://f.mffb.com.cn/a/505284.html
  2. 运行时间 : 0.121240s [ 吞吐率:8.25req/s ] 内存消耗:5,151.38kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=ca603f68378061c9a91261e65c974411
  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.000635s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000738s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.008415s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000303s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000655s ]
  6. SELECT * FROM `set` [ RunTime:0.000284s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000682s ]
  8. SELECT * FROM `article` WHERE `id` = 505284 LIMIT 1 [ RunTime:0.001158s ]
  9. UPDATE `article` SET `lasttime` = 1787322753 WHERE `id` = 505284 [ RunTime:0.013702s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000276s ]
  11. SELECT * FROM `article` WHERE `id` < 505284 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000492s ]
  12. SELECT * FROM `article` WHERE `id` > 505284 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000449s ]
  13. SELECT * FROM `article` WHERE `id` < 505284 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000945s ]
  14. SELECT * FROM `article` WHERE `id` < 505284 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.011115s ]
  15. SELECT * FROM `article` WHERE `id` < 505284 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001035s ]
0.122797s