int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)

kobj_type中的另外一個重要成員是release()函式指標。當kobject的引用計數為零時該函式指標所指向的函式就會被呼叫,用於釋放相應的系統資源(一般來說是free memory)。由於kobject一般都是內嵌成員,在釋放記憶體時應當釋放所有的記憶體而非kobject自己,所以release指標會被kobj_ktype的派生類bus_ktype或device_ktype或driver_ktype過載。由於這種派生不屬於內嵌物件,所以在kobj_ktype和派生類直接的連線上沒有標註。

kset

struct kset {
        struct list_head list;
        spinlock_t list_lock;
        struct kobject kobj;
        const struct kset_uevent_ops *uevent_ops;
};
由於kset中內嵌了kobject,這兩個結構使用表示繼承關係的連線表示。在連線處標註了kobj,表示kobject在kset中的內嵌物件名為kobj。.
kset是一種容器型別,它的list成員串起了多個kobject,其中每個kobject的kset *kset指標又指向了kset。
kobject的parent和ket指標具有不同的含義。parent指向其在/sys裡的父目錄,而kset只是表示它所處的容器(可以為空)。例如每一個device的parent都指向父device,而從圖上可以看出kset都指向devices_kset(表示包含所有device的容器)。
在呼叫kobject_add()時,如果parent為空,則parent將會被賦值為kobject的kset指標,這時兩個指標(parent和kset)就指向相同的object。在圖中,如果一個結構體的parent指標沒有標出,則代表kset指標與parent指標相同。例如對bus_type結構體,它的parent和kset指標都指向bus_kset變數。

bus_type

圖中的bus_type類其實表示的是實際程式碼中的bus_type結構體加上subsys_private結構體。由於這兩個結構體共同描述了一條bus,並且兩個結構體中分別有指標指向對方,所以將它們作為一個整體考慮。
所有的bus_type的kset和parent指標(其實這些指標包含在bus_type所內嵌的kobject結構內)都指向一個叫做bus_kset的變數。這個變數就代表了/sys/bus目錄。因此我們能夠在該目錄下找到所有註冊過的bus的目錄。
在but_type中有兩個kset成員分別是devices_kset和drivers_kset,它們代表了相應bus目錄下的devices和drivers目錄。例如在/sys/bus/usb/下就有devices和drivers目錄。
另外還有兩個klist型別的成員是klist_devices和klist_drivers。這兩個連結串列分別串起了該bus所包含的的所有裝置和驅動。
bus_type相關的三個重要API分別是bus_register, device_register和driver_register。通過命名它們的含義已經非常清晰。

device

圖中的device結構代表了實際程式碼中的device結構和device_private結構。將兩者合併的原因與合併bus_type和subsys_private的原因一致。

每一個裝置都內嵌(或者說繼承)了一個device結構體。device結構中的bus指標指向相應的bus_type結構。driver指標則指向相應的device_driver結構。在表示多對一的關係時(一端為菱形的直線),標註表示了參與該關係的成員名稱。以device和device_driver的關係為例,標註為"n:driver  1:klist_devices",其中"n:driver"表示多的一方(device)中的driver指標指向一的一方(device_driver),其中"1:klist_devices"表示一的一方(device_driver)中的klist_devices串起了多的一方(device)。

device結構的kset指標指向devices_kset變數,該變數代表了/sys/devices目錄。

device結構的parent指標則指向了它的父device。

device結構中的p指標指向device_private結構,其定義如下所示。其中klist_children包含了所有該device的子device。前面談到過bus和driver都有一個連結串列連線了所有相關的device,device_private中的knode_*就放在該連結串列中。driver_data指向driver相關的資料結構。

struct device_private {
        struct klist klist_children;
        struct klist_node knode_parent;
        struct klist_node knode_driver;
        struct klist_node knode_bus;
        struct list_head deferred_probe;
        void *driver_data;
        struct device *device;
};


device_driver

圖中的device_driver結構其實代表了實際程式碼中的device_driver結構和driver_private結構。將兩者合併的原因與合併bus_type和subsys_private的原因一致。每一個device driver都由一個device_driver結構代表。該結構的bus指標指向相應的bus_type結構。
該結構包含許多函式指標成員用於被不同的裝置驅動過載,以實現相應的功能。

bus_ktype, device_ktype, driver_ktype

這三種類型都派生自kobj_type類。每一種派生類都與處在同一行並具有相同顏色的結構有著緊密的關係。例如bus_type的ktype指標(包含於嵌入結構kobject)就指向bus_ktype。bus_ktype包含了與bus相關的sysfs operation函式指標,並且包含用於釋放bus_ktype的release函式指標。

bus_attribute, device_attribute, driver_attribute

以bus_attribute為例,它通過包含attribute結構實現了對它的繼承。每一個attribute都代表了/sys下的一個檔案(又稱作attribute)。struct attribute定義了這個檔案的名稱、許可權等資訊。另外兩個函式指標則指向了讀寫該檔案(attribute)時將會呼叫的函式。
struct bus_attribute {
        struct attribute        attr;
        ssize_t (*show)(struct bus_type *bus, char *buf);
        ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
bus_attribute與bus_ktype是一種緊密協作的關係。以bus_register()中的程式碼為例,當下面的bus_create_file()被呼叫時,bus_attr_uevent將被作為bus的一個attribute註冊在核心裡,同時會有一個uevent檔案新增在bus的目錄下。
<pre name="code" class="cpp"><pre name="code" class="cpp">int bus_register(struct bus_type *bus)
{
	// ...
	retval = bus_create_file(bus, &bus_attr_uevent);
}

struct bus_attribute bus_attr_uevent = {
<span style="white-space:pre">	</span>{.name = "uevent", .mode = S_IWUSR},
<span style="white-space:pre">	</span>.show = NULL,
<span style="white-space:pre">	</span>.store = bus_uevnet_store,
}
當程序寫uevent檔案時,bus_type所對應的ktype(即bus_ktype)中的sysfs_op指向的函式就會被呼叫(例如bus_attr_show())。傳入的kobj和attr引數分別是bus_type和bus_attribute的內嵌成員。bus_attr_show()就會相應的將它們轉換成相應型別(即bus_type和bus_attribute)的指標,並且呼叫bus_attribute裡的store函式指標,也就是bus_uevent_store。