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_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 自身未設定)
// kobject_add_internal()
list_add_tail(&kobj->entry, &target_kset->list); // ④ 加入雙向鏈表尾部
// 同時增加父層級 kobject 參考計數
kobject_get(&target_kset->kobj);
// create_dir()
/sys/.../target_kset_name/kobj_name/ ← 目錄建立
default_attrs 定義的屬性檔案同步建立
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 本身內嵌 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 成員列表只包含 kobject | kset 本身以內嵌 kobj 形式成為上層 kset 成員 |
| ktype 繼承優先級:kobject->ktype > kset->ktype | kobject 未設定 ktype 時使用 kset->ktype |
| 參考計數傳遞 | 子物件持有父物件參考,父釋放前必須所有子釋放 |
# 假設上述結構已註冊
ls /sys/kernel/kset_A/
# 輸出: kobject_1 kobject_2 kset_B
ls /sys/kernel/kset_A/kset_B/
# 輸出: kobject_4 kobject_5
kref 未初始化,kobject_put() 觸發 use-after-free。sysfs 目錄已存在返回 -EEXIST。kobject_init(&kset->kobj, ktype) 再 kset_add()。kobject_put() 永不歸零。kobject 是節點,kset 是容器,list_head 是連接線,parent/kset 指標定位座標。掌握「初始化 → 關聯設定 → 列表掛載 → sysfs 建立」四步驟,並理解巢狀 kset 以內嵌 kobj 形式遞歸加入,即可在腦中構建完整的 /sys 樹狀圖像,驅動開發時不再迷失。
VMware 虛擬機 Linux 無法自動獲取 IP 解決方案:修正網卡啟動檢查邏輯
Linux screen 命令大師級指南:會話管理、長時任務與遠端斷線保護
Linux 系統無法登入排查實錄:limits.conf 參數設定過大導致服務異常
Linux 實戰:使用 extundelete 秒級恢復誤刪除的關鍵檔案
VMware Shared Folders 實現 Windows 宿主機與 Linux 客體機檔案互傳完整設定
Linux 虛擬機擴充硬碟空間完整指南:新增虛擬磁碟掛載、qemu-img resize 線上擴容、LVM 動態擴展