Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 裝置模型基石教學:kobject、kset、ktype、subsystem 與 sysfs 完整指南

編輯:Linux 教學

1. kobject — 核心物件

1.1 定義與角色

struct kobject 是裝置模型的原子單位,**不單獨使用**,嵌入於 struct device、struct cdev、struct device_driver 等容器中,提供:

  • 參考計數 (kref) 生命週期管理。
  • 層次關係 (parent) 構建樹狀拓撲。
  • 集合歸屬 (kset) 實現分組管理。
  • 類型描述 (ktype) 定義行為 (釋放、sysfs 屬性)。
  • 用戶空間映射 (sysfs_dirent) 對應 /sys 目錄。

1.2 結構體詳解

struct kobject {
    const char *name;                    // 物件名稱 (sysfs 目錄名)
    struct list_head entry;              // 掛入 kset->list
    struct kobject *parent;              // 父物件
    struct kset *kset;                   // 所屬集合
    struct kobj_type *ktype;             // 類型描述
    struct sysfs_dirent *sd;             // sysfs 目錄項
    struct kref kref;                    // 參考計數
    unsigned int state_initialized:1;    // 已初始化
    unsigned int state_in_sysfs:1;       // 已在 sysfs 中
    unsigned int state_add_uevent_sent:1;// add 事件已發送
    unsigned int state_remove_uevent_sent:1; // remove 事件已發送
    unsigned int uevent_suppress:1;      // 抑制 uevent
};

1.3 關鍵 API

函數用途
kobject_init(kobj, ktype)初始化 kref、list、state、ktype
kobject_set_name(kobj, fmt, ...)設定名稱
kobject_add(kobj, parent, fmt, ...)設定 parent/name,掛入 kset、建立 sysfs 目錄、發送 add uevent
kobject_init_and_add(kobj, ktype, parent, fmt, ...)上述三步合一
kobject_get(kobj)引用計數 +1
kobject_put(kobj)引用計數 -1,歸零調用 ktype->release()
kobject_del(kobj)從層次移除、sysfs 目錄刪除、發送 remove uevent
kobject_unregister(kobj)del + put

2. kobj_type — 類型描述

struct kobj_type {
    void (*release)(struct kobject *kobj);           // 釋放回調 (kref 歸零時)
    const struct sysfs_ops *sysfs_ops;               // 屬性讀寫操作表
    const struct attribute **default_attrs;          // 預設屬性陣列 (NULL 結尾)
};

sysfs_ops

struct sysfs_ops {
    ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buf);     // 讀屬性
    ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count); // 寫屬性
};

attribute

struct attribute {
    const char *name;        // 屬性檔名稱
    struct module *owner;    // 擁有模組
    mode_t mode;             // 權限 (S_IRUGO 等)
};

常用巨集: __ATTR_RO(name)、__ATTR_WO(name)、__ATTR_RW(name)、__ATTR(name, mode, show, store)。

3. kset — 物件集合

3.1 角色

  • 相同類型 kobject 的容器 (如「所有 USB 裝置」)。
  • 建立上層子系統與下層物件的關聯。
  • 決定物件在 /sys 中的父目錄位置。
  • 提供熱插拔事件操作 (uevent_ops)。

3.2 結構體

struct kset {
    struct subsystem *subsys;               // 所屬子系統 (舊架構)
    struct kobj_type *ktype;                // 成員共享類型
    struct list_head list;                  // 成員 kobject 雙向鏈表
    struct kobject kobj;                    // 內嵌 kobject (代表集合自身)
    struct kset_uevent_ops *uevent_ops;     // 熱插拔事件回調
};

3.3 API 對應

kset_init(kset)           → 初始化內嵌 kobj、list
kset_register(kset)       → kobject_register(&kset->kobj)
kset_unregister(kset)     → kobject_unregister(&kset->kobj)
kset_get/put(kset)        → 作用於內嵌 kobj
kset_find_obj(kset, name) → 在列表中按名稱查找 kobject

4. subsystem — 子系統 (歷史產物)

struct subsystem {
    struct kset kset;
    struct rw_semaphore rwsem;   // 保護 list 的讀寫鎖
};

現代核心 **直接使用 kset**,subsystem 已被廢棄僅為相容保留。bus_type、class 等直接內嵌 kset。

5. sysfs — 核心虛擬檔案系統

5.1 掛載與根目錄結構

mount -t sysfs sysfs /sys
# 根目錄七大標準子目錄
/sys/
├── block/        ← 區塊裝置 (sda, loop0...)
├── bus/          ← 總線視圖 (usb, pci, i2c, platform...)
├── class/        ← 功能類別視圖 (net, tty, block, input...)
├── devices/      ← 裝置拓撲樹 (完整親子關係)
├── firmware/     ← ACPI, EDD, EFI 等韌體介面
├── module/       ← 載入核心模組
└── power/        ← 系統級電源管理

5.2 kobject → sysfs 映射規則

  1. kobject_add() 時決定位置:
    • 有 parent → /sys/parent_path/name
    • 無 parent 但有 kset → /sys/kset_path/name
    • 兩者皆無 → /sys/name (掛在 kernel_kobj 下)
  2. 目錄建立後,default_attrs 陣列中每個 attribute 在目錄下建立同名檔案。
  3. 讀寫檔案 → sysfs_ops->show/store()。
  4. kobject_del() → 遞歸刪除目錄與屬性檔,發送 remove uevent。

5.3 向 sysfs 新增屬性檔 (兩種方式)

方式 A:靜態 default_attrs (在 ktype 中定義)

static struct attribute *my_attrs[] = {
    &dev_attr_foo.attr,
    &dev_attr_bar.attr,
    NULL
};
static struct kobj_type my_ktype = {
    .default_attrs = my_attrs,
    .sysfs_ops = &my_sysfs_ops,
    .release = my_release,
};

方式 B:動態群組 sysfs_create_group (運行時靈活增減)

static struct attribute *runtime_attrs[] = { &attr_baz.attr, NULL };
static struct attribute_group runtime_group = { .attrs = runtime_attrs };

// 在 kobject 已加入 sysfs 後
sysfs_create_group(kobj, &runtime_group);  // 新增
sysfs_remove_group(kobj, &runtime_group);  // 移除

6. 完整生命週期範例

// 1. 定義屬性
static ssize_t foo_show(struct kobject *k, struct attribute *a, char *buf) {
    return sprintf(buf, "foo value\n");
}
static ssize_t foo_store(struct kobject *k, struct attribute *a, const char *buf, size_t n) {
    // 解析 buf 更新內部狀態
    return n;
}
static struct attribute foo_attr = __ATTR_RW(foo);

// 2. 定義 ktype
static struct attribute *attrs[] = { &foo_attr, NULL };
static struct kobj_type my_ktype = {
    .default_attrs = attrs,
    .sysfs_ops = &kobj_sysfs_ops,  // 通用 ops
    .release = my_release,
};

// 3. 模組初始化
static struct kobject *my_kobj;
int __init my_init(void) {
    my_kobj = kobject_create_and_add("my_dev", kernel_kobj); // /sys/kernel/my_dev
    if (!my_kobj) return -ENOMEM;
    return 0;
}
void __exit my_exit(void) {
    kobject_put(my_kobj); // 觸發 release → kfree 容器
}

7. 總結圖表

容器結構 (device, cdev, driver...)
    │
    ├── embedded kobject
    │       ├── name, kref, parent, kset, ktype, sd
    │       │
    │       ├── kref → 生命週期 (get/put → release)
    │       ├── parent → 樹狀父節點
    │       ├── kset → 所屬集合 (列表成員)
    │       ├── ktype → 行為定義 (release, sysfs_ops, default_attrs)
    │       └── sd → sysfs 目錄項
    │
    └── sysfs 映射
            /sys/.../parent/name/  ← 目錄
            ├── attr1 (show/store)
            ├── attr2
            └── uevent (add/remove/change)

結語

kobject、kset、ktype、sysfs 四位一體,構建了 Linux 核心「物件導向」的裝置管理基礎設施。掌握其結構體欄位、API 流程、映射規則,能讓你在驅動開發中:正確註冊裝置、暴露可配置屬性、處理熱插拔事件、診斷 /sys 異常,打下堅實內功。

Copyright © Windows教程網 All Rights Reserved