1. 程式人生 > >Kernel 裝置模型基礎框架kobject

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結構,實現引用計數,裝置層次結