Kernel 裝置模型基礎框架kobject
Linux裝置模型的基礎框架是基於 kobject, kset 和 kobj_type 三個基礎資料結構實現的。這篇主要分析這三個基礎資料結構的作用,以及相互之間的關係。
1,kobject:
struct kobject {
const char *name; // 該kobject的名字,用於 sysfs 檔案系統下的資料夾名字
struct list_head entry; // 同類型 kobject 連結串列節點
struct kobject *parent; // 指向父節點 kset 的 kobject
struct kset *kset; // 同類型kobject的集合
struct kobj_type *ktype; // kobject的屬性操作方法,以及 release 方法
struct kernfs_node *sd; /* sysfs directory entry */ // 該 kobject 在sysfs檔案系統下的節點
struct kref kref; // 引用計數
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
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;
};
kobject 是最基礎的資料結構,從上述欄位定義中,可以看出這個結構包含如下功能:
(1)引用計數功能。一個kobject可能代表一個匯流排,裝置或驅動等,這些例項在核心空間可能會被多個排程實體或物件指標引用,因此用一個引用計數結構 kref 來記錄當前有多少物件引用該 kobject,當 kref 的引用計數減為0時,核心介面自動呼叫使用者指定的release介面銷燬該kobject物件。kref 資料結構的本質就是一個atomic型別的物件,核心提供了 kref_get() 和 kref_put() 兩個介面用於對引用計數自增和自減:
struct kref {
refcount_t refcount;
};
typedef struct refcount_struct {
atomic_t refs; // 本質上就是一個 atomic 型別的欄位
} refcount_t;
介面:
static inline void kref_get(struct kref *kref)
{
refcount_inc(&kref->refcount); // kref 自增
}
static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
if (refcount_dec_and_test(&kref->refcount)) { // kref 自減
release(kref); // 如果減完之後為0,釋放該 kref 物件
return 1;
}
return 0;
}
(2)連結串列組織結構功能。多個kobject物件連結在一個kset下,形成一個迴圈雙向連結串列。欄位entry是雙向連結串列節點,kset指向該kobject所屬的kset,parent一般指向kset中的kobject。
(3)sysfs介面。一個kobject表示sysfs檔案系統中的一個目錄,方便使用者在使用者態訪問核心態資料結構。欄位sd表示該kobject在sysfs中的入口項,name表示kobject表示的目錄名稱,ktype表示該目錄的操作介面,包含kobject物件的release介面,以及該目錄下屬性檔案的讀寫介面。
2,kset:
struct kset {
struct list_head list; // 用於連線所有kset的連結串列節點
spinlock_t list_lock;
struct kobject kobj; // 一個kset本質上也是一個 kobject
const struct kset_uevent_ops *uevent_ops; // 核心事件上報使用者態介面,一般用於驅動的熱插拔事件上報
} __randomize_layout;
一個kset表示所有同類型的kobject的集合。kset內部通過包含一個kobject,用來同其下掛的所有kobject組成一個雙向迴圈連結串列。同時其下掛的所有kobject的parent都指向kset中包含的這個kobject。uevent_ops是核心事件上報使用者態機制,多用於裝置和驅動的熱插拔事件上報。
3,kobj_type:
struct kobj_type {
void (*release)(struct kobject *kobj); // 同類型kobject物件的釋放介面
const struct sysfs_ops *sysfs_ops; // kobject屬性檔案的讀寫介面
struct attribute **default_attrs; // kobject的屬性
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
一個kobj_type主要用來定義kobject的屬性檔案的讀寫介面,以及kobject物件的釋放操作。
2,通過上述分析,我們可以畫出 kobject,kset 和 kobj_type之間的關係:
3,總結一下:kobject/kset通常用於其他物件結構的內建結構,如裝置和驅動資料結構通常都包含一個kobject結構,實現引用計數,裝置層次結