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 關係圖解:從結構體到層次樹構建

編輯:Linux 教學

核心結構體回顧

struct kobject {
    const char *name;
    struct list_head entry;      // 掛入 kset->list
    struct kobject *parent;      // 父物件
    struct kset *kset;           // 所屬集合
    struct kobj_type *ktype;     // 類型
    struct sysfs_dirent *sd;     // sysfs 目錄項
    struct kref kref;            // 參考計數
    // ...
};

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 加入 kset 過程 (步驟圖解)

步驟 1:kobject 初始化與關聯設定

// 呼叫 kobject_init(kobj, ktype)
kobj->kref = 1;
INIT_LIST_HEAD(&kobj->entry);
kobj->ktype = ktype;
kobj->kset = target_kset;        // ① 記錄所屬 kset
kobj->parent = &target_kset->kobj; // ② parent 指向 kset 內嵌 kobj
// ③ kobj->ktype 由 kset->ktype 提供 (若 kobj 自身未設定)

步驟 2:掛入 kset 列表

// kobject_add_internal()
list_add_tail(&kobj->entry, &target_kset->list);  // ④ 加入雙向鏈表尾部
// 同時增加父層級 kobject 參考計數
kobject_get(&target_kset->kobj);

步驟 3:sysfs 目錄建立

// create_dir()
/sys/.../target_kset_name/kobj_name/  ← 目錄建立
default_attrs 定義的屬性檔案同步建立

第二個 kobject 加入同一 kset

kobject_b->kset = kset_A;
kobject_b->parent = &kset_A->kobj;
kobject_b->ktype = kset_A->ktype;
list_add_tail(&kobject_b->entry, &kset_A->list);  // 接在 kobject_a 後面
// sysfs: /sys/.../kset_A/kobject_b/

列表順序即加入順序,遍歷用 list_for_each_entry。

kset 加入另一個 kset (巢狀集合)

kset 本身內嵌 kobject kobj,因此 **kset 加入 kset 實質是「內嵌 kobj 加入外層 kset」**:

// 將 kset_B 加入 kset_A
kset_B->kobj.kset = kset_A;
kset_B->kobj.parent = &kset_A->kobj;
kset_B->kobj.ktype = kset_A->ktype;  // 或自有 ktype
list_add_tail(&kset_B->kobj.entry, &kset_A->list);
// sysfs: /sys/.../kset_A/kset_B/ (目錄名 = kset_B->kobj.name)

此機制支援任意深度巢狀,構建 /sys/bus/usb/drivers/usb-storage 這類多層路徑。

完整關係圖 (文字版)

kset_A (subsys)
├── kobj (內嵌, 代表 kset_A 自身)
│   ├── name = "kset_A"
│   ├── parent = subsys_kobj
│   └── kset = subsys_kset
├── list → kobject_1 → kobject_2 → kset_B.kobj → kobject_3
│
├── kobject_1
│   ├── parent = &kset_A.kobj
│   ├── kset = kset_A
│   └── entry → in kset_A.list
│
├── kobject_2
│   ├── parent = &kset_A.kobj
│   ├── kset = kset_A
│   └── entry → in kset_A.list
│
└── kset_B (也是 kset, 同時是 kset_A 的成員)
    ├── kobj (內嵌)
    │   ├── name = "kset_B"
    │   ├── parent = &kset_A.kobj
    │   ├── kset = kset_A
    │   └── entry → in kset_A.list
    ├── list → kobject_4 → kobject_5
    │
    ├── kobject_4
    │   ├── parent = &kset_B.kobj
    │   ├── kset = kset_B
    │   └── entry → in kset_B.list
    │
    └── kobject_5 ...

關鍵不變量總結

規則說明
所有 kobject 必須有 kset 或 parent否則掛在 sysfs 根目錄 (kernel_kobj)
kobject->parent == kobject->kset->kobj若指定 kset,parent 自動指向 kset 內嵌 kobj
kset 成員列表只包含 kobjectkset 本身以內嵌 kobj 形式成為上層 kset 成員
ktype 繼承優先級:kobject->ktype > kset->ktypekobject 未設定 ktype 時使用 kset->ktype
參考計數傳遞子物件持有父物件參考,父釋放前必須所有子釋放

sysfs 對應驗證

# 假設上述結構已註冊
ls /sys/kernel/kset_A/
# 輸出: kobject_1  kobject_2  kset_B

ls /sys/kernel/kset_A/kset_B/
# 輸出: kobject_4  kobject_5

常見錯誤與除錯

  • 忘記 kobject_init() → kref 未初始化,kobject_put() 觸發 use-after-free。
  • 重複 kobject_add() → sysfs 目錄已存在返回 -EEXIST。
  • kset 未初始化 kobj → 必須先 kobject_init(&kset->kobj, ktype) 再 kset_add()。
  • 循環引用 → parent/kset 設定錯誤導致釋放死鎖,kobject_put() 永不歸零。

結語

kobject 是節點,kset 是容器,list_head 是連接線,parent/kset 指標定位座標。掌握「初始化 → 關聯設定 → 列表掛載 → sysfs 建立」四步驟,並理解巢狀 kset 以內嵌 kobj 形式遞歸加入,即可在腦中構建完整的 /sys 樹狀圖像,驅動開發時不再迷失。

Copyright © Windows教程網 All Rights Reserved