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 與 sysfs 關係圖解

編輯:Linux 教學

為何引入裝置模型?

Linux 2.6 前,裝置驅動缺乏統一架構,裝置拓撲關係分散在各子系統,用戶空間難以統一檢視。裝置模型 以 kobject 為核心,建立統一的物件層次樹,映射至 sysfs (/sys),實現:

  • 核心物件統一管理(參考計數、鎖、生命週期)。
  • 裝置拓撲關係清晰表達(總線、裝置、驅動、類別)。
  • 用戶空間透過檔案系統介面檢視/配置裝置屬性。
  • 熱插拔事件自動觸發 uevent 通知 udev。

核心資料結構

1. kobject — 基礎物件

struct kobject {
    const char *name;           // 物件名稱
    struct list_head entry;     // 掛載至 kset 列表
    struct kobject *parent;     // 父物件 (形成樹狀)
    struct kset *kset;          // 所屬集合
    struct kobj_type *ktype;    // 類型描述 (釋放、sysfs ops、預設屬性)
    struct sysfs_dirent *sd;    // sysfs 目錄項
    struct kref kref;           // 參考計數
    unsigned int state_initialized:1;
    unsigned int state_in_sysfs:1;
    unsigned int state_add_uevent_sent:1;
    unsigned int state_remove_uevent_sent:1;
    unsigned int uevent_suppress:1;
};

關鍵欄位:

  • kref:kobject_get()/kobject_put() 管理生命週期,歸零觸發 ktype->release()。
  • parent:構建樹狀層次,對應 /sys 目錄階層。
  • kset:歸屬集合,決定在 /sys 中的父目錄位置。
  • ktype:定義物件行為(釋放、屬性讀寫、預設屬性)。

2. kobj_type — 類型描述

struct kobj_type {
    void (*release)(struct kobject *kobj);           // 釋放回調
    const struct sysfs_ops *sysfs_ops;               // 屬性讀寫操作
    const struct attribute **default_attrs;          // 預設屬性陣列
};

sysfs_ops 定義:

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

attribute 對應 /sys/.../屬性檔:

struct attribute {
    const char *name;       // 檔案名
    struct module *owner;   // 擁有模組
    mode_t mode;            // 權限 (如 0444 唯讀)
};

3. kset — 物件集合

struct kset {
    struct subsystem *subsys;          // 所屬子系統 (舊架構殘留)
    struct kobj_type *ktype;           // 集合內物件共享類型
    struct list_head list;             // 成員 kobject 雙向鏈表
    struct kobject kobj;               // 內嵌 kobject (作為集合本身的物件)
    struct kset_uevent_ops *uevent_ops;// 熱插拔事件操作
};

關鍵機制:

  • 所有成員 kobject->parent 指向內嵌 kobj,形成「集合目錄」語意。
  • kset->list 串聯所有成員,kset_add() 執行 list_add_tail()。
  • kset 本身也是 kobject,可嵌套形成多層集合。

4. subsystem — 子系統 (已併入 kset)

struct subsystem {
    struct kset kset;
    struct rw_semaphore rwsem;  // 唯一差異:保護 list 的讀寫鎖
};

現代核心直接使用 kset,subsystem 僅為相容保留。

關鍵 API 速查

操作kobjectkset
初始化kobject_init(kobj, ktype)kset_init(kset)
設定名稱kobject_set_name(kobj, fmt, ...)內嵌 kobj 同理
加入層次kobject_add(kobj, parent, fmt, ...)kset_add(kset)
註冊 (初始化+加入)kobject_register(kobj)kset_register(kset)
取得參考kobject_get(kobj)kset_get(kset) (實為內嵌 kobj)
釋放參考kobject_put(kobj)kset_put(kset)
移除層次kobject_del(kobj)kset_del(kset)
註銷 (移除+釋放)kobject_unregister(kobj)kset_unregister(kset)

sysfs 映射規則

  1. kobject_add() 時,根據 parent 或 kset->kobj 決定在 /sys 下建立目錄。
  2. 目錄名 = kobject->name。
  3. default_attrs 中的每個 attribute 在目錄下建立同名檔案,讀寫分別調用 sysfs_ops->show/store。
  4. uevent 事件:kobject_add() 觸發 add,kobject_del() 觸發 remove,kset_uevent_ops 可自訂環境變數。

物件關係圖解 (文字版)

/sys (sysfs 根目錄)
├── bus/              ← bus_type 子系統 (kset)
│   ├── usb/          ← usb_bus_type (kobject 在 bus kset 內)
│   │   ├── devices/  ← usb 裝置 kset
│   │   │   ├── 1-1/  ← usb 裝置 kobject
│   │   │   └── 1-2/
│   │   └── drivers/  ← usb 驅動 kset
│   │       ├── usb-storage/
│   │       └── usbhid/
│   └── pci/          ← pci_bus_type
├── class/            ← class 子系統
│   ├── block/        ← 區塊裝置類別
│   ├── net/          ← 網路介面類別
│   └── tty/          ← 終端類別
├── devices/          ← 全域裝置拓撲樹 (platform_bus 等)
└── module/           ← 載入模組 kset

嵌入模式:容器物件

kobject **從不單獨存在**,而是嵌入業務結構體:

struct cdev {           // 字元裝置
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    dev_t dev;
    // ...
};

struct device {         // 通用裝置
    struct kobject kobj;
    struct device *parent;
    struct bus_type *bus;
    struct device_driver *driver;
    // ...
};

struct device_driver {  // 驅動
    struct kobject kobj;
    struct bus_type *bus;
    // ...
};

取得容器指標:container_of(kobj_ptr, container_type, kobj_field_name)。

實戰:建立一個簡單 kobject 輸出屬性

// 1. 定義屬性
static struct kobj_attribute foo_attr = __ATTR_RW(foo);  // 0644 權限

// 2. 定義屬性群組
static struct attribute *attrs[] = { &foo_attr.attr, NULL };
static struct attribute_group attr_group = { .attrs = attrs };

// 3. 定義 ktype
static struct kobj_type my_ktype = {
    .release = my_release,
    .sysfs_ops = &my_sysfs_ops,
    .default_attrs = attrs,
};

// 4. 模組初始化建立 kobject
static struct kobject *my_kobj;
int __init my_init(void) {
    my_kobj = kobject_create_and_add("my_device", kernel_kobj); // 掛在 /sys/kernel/my_device
    if (!my_kobj) return -ENOMEM;
    return sysfs_create_group(my_kobj, &attr_group); // 建立屬性檔
}
void __exit my_exit(void) {
    kobject_put(my_kobj); // 觸發 release
}

結語

kobject/kset/ktype 是 Linux 裝置模型的「原子」、「分子」、「化學式」。理解它們如何構建樹狀層次、映射至 sysfs、管理生命週期與熱插拔,是深入核心驅動開發、分析裝置拓撲、編寫 udev 規則的必經之路。

Copyright © Windows教程網 All Rights Reserved