現在的位置: 首頁 > 技術文章 > 基礎知識 > 正文

關于linux設備模型kobject,kset,ktype

2014年06月12日 基礎知識 ⁄ 共 6430字 ⁄ 字號 評論 1 條
kobject

kobject

1?Kobject

1.1?簡介

Kobject 是Linux 2.6 引入的新的設備管理機制,在內核中由struct kobject數據結構進行描述通過這個數據結構使所有設備在底層都具有統一的接口,kobject提供基本的對象管 理,是構成Linux2.6設備模型的核心結構,它與sysfs文件系統緊密關聯,每個在內核中注 冊的kobject對象都對應于sysfs文件系統中的一個目錄。Kobject是組成設備模型的基本結 構。但是,它比較低調,從不單獨使用,都是嵌套在別的數據結構中。類似于C++中的基 類,它嵌入于更大的對象的對象中–所謂的容器–用來描述設備模型的組件。如bus, devices, drivers 都是典型的容器。這些容器就是通過kobject連接起來了,形成了 一個樹狀結構。這個樹狀結構就與/sys相對應。

kobject 結構為一些大的數據結構和子系統提供了基本的對象管理,避免了類似機能的重 復實現。這些機能包括

  • 對象引用計數.
  • 維護對象集合.
  • 對象上鎖.
  • 在用戶空間的表示.

1.2?定義

Kobject結構定義為:

struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct sysfs_dirent *sd;
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:
    kref域表示該對象引用的計數,內核通過kref實現對象引用計數管理,內核提供兩 個函數kobject_get()、kobject_put() 分別用于增加和減少引用計數,當引用計數為 0時,所有該對象使用的資源釋放。
  • Ktype:
    域是一個指向kobj type結構的指針,表示該對象的類型。
  • parent
    指針指向kobject的父對象。因此,kobject就會在內核中構造一個對象層次結構, 并且可以將對各對象間的關系表現出來,就如你看到的,這便是sysfs的真正面目: 一個用戶空間的文件系統,用來表示內核中kobject對象的層次結構。

1.3?相關函數

  • void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  • kobject初始化函數,用于初始化kobject結構,在一些例行的檢查之后,該 函數通過kobject_init_internal()來初始化kobjet的內部變量:初始化 kobjet的易用計數,初始化雙向鏈表entry,設置kobject的四個state變量。 隨后,將這個kobj的類型設置成了入參的ktype。
  • int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list vargs)
  • 設置指定kobject的名稱。
  • static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs)
  • 調用kobject_set_name_vargs來設置kobj的名字,設置kobj的parent,并調 用kobject_add_internal將該kobj加入到kset中。
  • static int kobject_add_internal(struct kobject *kobj)
  • 檢查并更新kobj的Parent。如果kobj沒有parent,但是其kset存在,則將該 kobj加入到kset的List中,然后將Kset的內嵌的kobjet 設置為這個kobj的 parent。隨后,調用create_dir在sysfs中創建節點, 并更新kobject的狀 態。
  • int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...)
  • 初始化并將kobjt添加到指定的kset里面去。內部調用了前面提到的 kobject_init_internal, kobject_add_internal等等。
  • struct kobject *kobject_get(struct kobject *kobj)
  • 將kobj 對象的引用計數加1,同時返回該對象的指針。
  • void kobject_put(struct kobject * kobj)
  • 將kobj對象的引用計數減1,如果引用計數降為0,則調用 kobject release()釋放該 kobject對象。
  • int kobject_add(struct kobject * kobj)
  • 將kobj對象加入Linux設備層次。掛接該kobject對 象到kset的list鏈中,增加父目錄 各級kobject的引用計數,在其 parent指向的目錄下創建文件節點,并啟動該類型內 核對象的hotplug函數。
  • int kobject_register(struct kobject * kobj)
  • kobject注冊函數。通過調用kobject init()初始化kobj,再調用kobject_add()完 成該內核對象的注冊。
  • void kobject_del(struct kobject * kobj)
  • 從Linux設備層次(hierarchy)中刪除kobj對 象。
  • void kobject_unregister(struct kobject * kobj)
  • kobject注銷函數。與kobject register()相反,它首先調用kobject del從設備層次 中刪除該對象,再調用kobject put()減少該對象的引用計數,如果引用計數降為0, 則釋放kobject對象。

2?Kobj type

kobject對象被關聯到一種特殊的類型,即ktype。 ktype由kobj_type結構體表示,定義于 <linux/kobject.h>中:

struct kobj_type {
void (*release)(struct kobject *kobj);
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};

 

release指針
指向在kobject引用計數減至0時要被調用的析構函數。該函 數負責釋放 所有kobject使用的內存和其它相關清理工作。
ktype
是為了描述一族kobject所具有的普遍特性。因此,不再需要 每個kobject都分別定 義自己的特性,而是將這些普遍的特性在ktype結構體中一次定義,然后所有“同類”的 kobject都能共享一樣的特性。
default_attrs

指向一個attribute結構體數組。這些結構體定義了該 kobject相關的默認 屬性。屬性給定了對象的特征,如果該kobject被導出到sysfs中,那么這些屬性都將相應 的作為文件而導出。其定義如下:

struct attribute {
const char *name;
struct module *owner;
mode_t mode;
};

其中name字段提供了該屬性的名稱,最終出現在sysfs中的 文件名就是它。owner字段在存 在所屬模塊的情況下指向其所屬的module結構體。如果一個模塊沒有該屬性,那么該字段 為NULL。mode字段類型為modet,他表示sysfs中該文件的權限。

該數據結構以文件的形式輸出到sysfs的目錄當中。在 kobject對應的目錄下面。文件 名就是name。文件讀寫的方法對應于kobj_type中的sysfs_ops。

sysfs_ops

指向sysfs操作表和一個sysfs文件系統缺省屬性列表,定 義如下:

struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};

Sysfs操作表包括兩個函數store()和show()。

  • show

當用戶態讀取屬性時,show()函數被調 用,show()方法在讀操作時被調用。它會拷貝由 attr提供的屬性值到buffer指定的緩沖區,緩沖區大小為PAGESIZE字節;該 函數若執?行成功,返回寫入buffer的字節數,失敗,返回負的錯誤碼。

  • store store()方法在寫操作時調用,它會從buffer中讀取size大小的字節,并將其放入 attr表示的屬性結構體變量中。

3?kset

3.1?簡介

kset是kobject對象的集合體。把它看 成一個容器,可將所有相關的kobject對象,比 如“全部的塊設備”置于同一位置。其最重要的作用是建立上層(sub-system)和下層的(kobject)的關聯性。

kobject 也會利用它了分辨自已是屬于那一個類型,然後在/sys 下建立正確的目錄位置。而kset 的優先權 比較高,kobject會利用自已的*kset 找到自已所屬的kset,並把*ktype 指定成該kset下 的ktype,除非沒有定義kset,才會用ktype來建立關系。

Kobject通過kset組織成層次化的結 構,kset是具有相同類型的kobject的集合,在內核中 用kset數據結構表示,定義為:

struct kset {
struct subsystem * subsys; 所在的subsystem的指針
struct kobj type * ktype; 指向該kset對象類型描述符的指針
struct list head list; 用于連接該kset中所有kobject的鏈表頭
struct kobject kobj; 嵌入的kobject,用于計數,并被因為父類
struct kset hotplug ops * hotplug ops; 指向熱插拔操作表的指針
};

其中:

  • 包含在kset中的所有kobject被組織成一個雙向循環鏈 表,list域正是該鏈表的頭。
  • Ktype域指向一個kobj type結構,被該kset中的所有kobject共享,表示這些對象的類 型。
  • Kset數據結構還內嵌了一個kobject對象(由kobj域表 示),所有屬于這個kset 的

kobject對象的parent域均 指向這個內嵌的對象。

  • kset還依賴于kobj維護引用計數:kset的引用計數 實際上就是內嵌的 kobject對象的引用計數。

3.2?相關函數

ksetinit()
完成指定kset的初始化
ksetget() 和ksetput()
分別增加和減少kset對象的 引用計數。

Ksetadd() 和ksetdel()
?

函數分別實現將指定keset 對象加入設備層次和從其中刪除;

ksetregister() 和ksetunregister()
完成 kset的注冊和注銷。

4?subsystem

4.1?簡介

如果說kset 是管理kobject 的集合,那么,subsystem 就是管理kset 的集合。 它描述系統中某一類設備子系統,如block subsys表示所有的塊設備,對應于sysfs文件系統中的 block目錄。類似的,devices subsys對應于sysfs中的devices目錄,描述系統中所有的 設備。Subsystem由struct subsystem數據結構描述,定義為:

struct subsystem {
struct kset kset; 內嵌的kset對象
struct rw semaphore rwsem; 互斥訪問信號量
};

可以看出,subsystem 與kset的區別就是多了一個信號量,所以在后來的代碼中,subsystem已經完全被kset取締了。

每個kset屬于某個 subsystem,通過設置kset結構中的subsys域指向指定的subsystem可以 將一個kset加入到該subsystem。所有掛接到同一subsystem的kset共享同一個rwsem信號 量,用于同步訪問kset中的鏈表。

4.2?相關函數

subsystem有一組類似 的函數,分別是:

void subsysteminit(struct subsystem *subsys);

int subsystemregister(struct subsystem *subsys);

void subsystemunregister(struct subsystem *subsys);

struct subsystem *subsysget(struct subsystem *subsys)

void subsysput(struct subsystem *subsys);

5?sysfs

sysfs文件系統是一個處于 內存中的虛擬文件系統,它為我們提供了kobject對象層次結 構的視圖。幫助用戶可以一個簡單文件系統的方式來觀察系統中各種設備的拓撲結 構。借助屬性對象,kobject可用導出文件的方式,將內核變量提供給用戶讀取或 寫入。

sysfs的訣竅是把 kobject對象與目錄項緊密聯系起來,這點是通過kobject中的 dentry(directory entry)字段實現的。前面提到,dentry結構體表示目錄 項,通過連接kobject到指定的目錄項上,無疑方便的將kobject映射到該目錄上。 好了,kobject其實已經形成了一棵樹了——就是我們心愛的對象模型體系。

sysfs的根目錄下包含了七 個子目錄:block、bus、class、devices、firmware、 module和power。block目錄下的每個子目錄都對應著系統中的一個塊設備。反過 來,每個目錄下又都包含了該塊設備的所有分區。bus目錄提供了一個系統總線視 圖。class目錄包含了以高層功能邏輯組織起來的系統設備視圖。devices目錄是 系統中設備拓撲結構視圖,它直接映射出了內核中設備結構體的組織層次。 firmware目錄包含一些諸如ACPI、EDD、EFI等低層子系統的特殊樹。power目錄包 含了系統范圍的電源管理數據。

5.1?sysfs中添加和刪除kobject

僅僅初始化一個kobject 是不能自動將其導出到sysfs中的,想要把kobject導入 sysfs,需要用到函數kobjectadd():

int kobject_add(struct kobject *kobj);

kobject在sysfs中 的位置取決于kobject在對象層次結構中的位置。如果kobject 的父指針被設置,那么在sysfs中kobject 將被映射為其父目錄下的子目錄,如果 parent沒有設置,那么kobject將被映射到kset->kobj中的子目錄。兩者都未設 置,映射為 sysfs下的根級目錄。

5.2?向sysfs中添加文件

我們已經看到kobject被 映射為文件目錄,而且所有的對象層次結構都優雅的、一 個不少的映射成為sys下的目錄結構。但是里面的文件是什么?sysfs僅僅是一個 漂亮的樹,但是沒有提供實際數據的文件。

二八杠讨论心得
×