Linux內核設計與實現---kobject sysfs

kobject sysfs

  • 1 kobject
  • 2 ktype
  • 3 kset
  • 4 subsystem
  • 5 別混淆了這些結構體
  • 6 管理和操作kobject
  • 7 引用計數
    • kref
  • 8 sysfs
    • sysfs中添加和刪除kobject
    • 向sysfs添加文件
  • 9 內核事件層

2.6內核增加了一個引人注目的新特性—同一設備模型。設備模型提供了獨立的機制專門表示設備,并描述在系統中的拓撲結構。

1 kobject

設備模型的核心部分就是kobject,它由struct kobject,定義于頭文件linux/kobject.h中。kobject類似于C#或java這些面向對象語言中的object對象類,提供了諸如計數、名稱和父指針等字段,可以創建對象的層次結構。

struct kobject {char			* k_name;char			name[KOBJ_NAME_LEN];struct kref		kref;struct list_head	entry;struct kobject		* parent;struct kset		* kset;struct kobj_type	* ktype;struct dentry		* dentry;
};

k_name指針指向kobject名稱,如果名稱長度小于KOBJ_NAME_LEN,那么該kobject的名稱就存放在name數組中,k_name指向數組頭,如果名稱長度大于KOBJ_NAME_LEN,則動態分配一個足夠大的緩沖區來存放kobject的名稱。KOBJ_NAME_LEN當前為20個字節。

parent指針指向kobject的父對象。因此,kobject就會在內核中構造一個對象層次結構,并且可以將多個對象間的關系表項出來。

dentry指針指向dentry結構體,在sysfs中該結構體就表示這個kobject。

kref實現了kobject的引用計數。

kobject通常是嵌入到其他結構體中的,其單獨意義其實并不大。當kobject被嵌入到其他結構體中時,該結構體便擁有了kobject提供的標準功能。

2 ktype

kobject對象中的ktype域,該結構體定義于頭文件linux/kobject.h中

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

ktype是為了描述一族kobject所具有的普遍特性。因此,不在需要每個kobject都分別定義自己的特性,而是將這些特性在ktype結構體中一次定義,然后所有“同類”的kobject都能共享一樣的特性。

release指針指向在kobject引用計數減為零時要被調用的析構函數。該函數負責釋放所有的kobject使用的內存和其他相關清理工作。

sysfs_ops變量指向sysfs_ops結構體。該結構體表述了sysfs文件讀寫是的特性。

default_attrs指向一個attribute結構體數組。這些結構體定義了該kobject相關的默認屬性。屬性描述了給定對象的特征,如果該kobject被導出到sysfs中,那么這些屬性都將相應地作為文件而導出。數組中的最后一項必須為NULL。

3 kset

kobject中的kset域,是kobject對象的集合體。把它看成是一個容器,可將所有相關的kobject對象,比如“全部的塊設備”置于一個位置。kset把kobject集中到一個集合中。

kset指針指向kset集合,kset集合由kset結構體表示,定義于頭文件linux/kobject.h中

struct kset {struct subsystem	* subsys;struct kobj_type	* ktype;struct list_head	list;struct kobject		kobj;struct kset_hotplug_ops	* hotplug_ops;
};

其中ktype指向kset集合中kobject對象的類型。list連接該集合中所有的kobject對象,kobj指向的kobject對象代表了該集合的基類。hotplug_ops指向一個用于處理集合中kobject對象的熱插拔操作的結構體。
subsys指針指向該結構體相關的struct subsystem結構體。

4 subsystem

subsystem在內核中代表高層概念,它是一個或多個kset的大集合。

struct subsystem {struct kset		kset;struct rw_semaphore	rwsem;
};

雖然subsystem結構體只指向一個kset,但是多個kset可以通過其subsys指針指向一個subsystem。這種單向關系意味著不可能僅僅通過一個subsystem結構體就找到所有的kset。

subsystem中的kset字段指向的是subsystem中默認的kset,任rwsem字段是一個讀寫信號量,該信號量用來對subsystem和它的所有的kset進行并發訪問保護。

5 別混淆了這些結構體

這里最重要的是kobject,它由struct kobject表示。kobject為我們引入了諸如計數、父子關系和對象名稱等基本對象道具,并且是以一個統一方式提供這些功能。不過kobject本身意義不大,需要被嵌入到其他數據結構中。

kobject與一個特定的ktype對象關聯,ktype由struct kobject_type結構體表示,在kobject中ktype字節指向該對象。ktype定義了一些kobject相關的默認特性:析構行為、sysfs行為以及其他一些默認屬性。

kset集合由struct kset結構體表示。kset提供了兩個功能。第一,其中嵌入的kobject作為kobject組合基類。第二,kset將相關的kobject集合在一起。在sysfs中,這些相關的kobject將以獨立的目錄出現在文件系統中。

subsystem表示的更為宏觀,它是包含kset的集合,由struct subsystem結構體表示。sysfs中的根目錄映射的便是subsystem。

這些數據結構的內在關系如下:
在這里插入圖片描述

6 管理和操作kobject

多數時候,驅動程序開發者并不直接處理kobject,因為kobject是被嵌入到一些特殊類型結構體中的,而且由相關的 設備驅動程序在幕后管理。

使用kobject的第一步需要先來聲明初始化它。kobject通過函數kobject_init進行初始化,該函數定義在文件linux/kobject.h中:

void kobject_init(struct kobject *kobj);

該函數的唯一參數就是需要初始化的kobject對象,在調用初始化函數前,kobject必須清空。如果kobject未被清空,那么只需要調用memset()即可。

在清理后,就可以安全地初始化parent和kset字段。

在這里插入圖片描述
初始化后,必須采用kobject_set_name()函數為kobject設置名稱:

int kobject_set_name(struct kobject *kobj,const char *fmt,...);

該函數利用了printf()和printk()風格的可變參數隊列來為kobject設置名稱。

初始化了kobject并設置名稱后,還需要為它設置kset字段以及可能的ktype字段(可選)。如果kset沒有被提供,那么僅需要設置ktype,否則kset中的ktype字段將優先被使用。

7 引用計數

kobject的主要功能之一就是為我們提供了一個同一的引用計數系統。初始化后,kobject的引用計數設置為1,只要引用計數不為0,那么該對象就會繼續保留在內存中。任何包含對象引用的代碼首先要增加該對象的引用計數,當代碼結束后則減少它的引用計數。增加引用計數稱為獲得(get)對象的引用,減少引用計數稱為釋放(put)對象的引用。當引用計數減少到0時,對象便可以被銷毀。

增加一個引用計數可通過kobject_get()函數完成:

struct kobject * kobject_get(struct kobject *kobj);

該函數正常情況下返回一個指向kobject的指針,如果失敗,返回NULL。

減少引用計數是通過kobject_put()完成:

void kobject_put(struct kobject *kobj);

如果對應的kobject的引用計數減少到0,則與該kobject關聯的ktype中的析構函數將被調用。

kref

kobject的引用計數是通過kref結構體實現的,該結構體定義在頭文件linux/kref.h中:

struct kref {atomic_t refcount;
};

其中唯一的字段是用來存放引用計數的原子變量。在使用kref之前,必須先通過kref_init來初始化它:

void kref_init(struct kref *kref)
{atomic_set(&kref->refcount,1);
}

這個函數簡單地將原子變量置為1,所以kref一旦被初始化,它表示的引用計數便固定為1。
要獲得對kref的引用,需要調用kref_get()函數

void kref_get(struct kref *kref)
{WARN_ON(!atomic_read(&kref->refcount));atomic_inc(&kref->refcount);
}

該函數增加引用計數值,它沒有返回值。減少對kref的引用,調用函數kref_put():

void kref_put(struct kref *kref,void (*release)(struct kref *kref))
{WARN_ON(release == NULL);WARN_ON(release == (void (*)(struct kref*))kfree);if(atomic_dec_and_test(&kref->refcount))release(kref);
}

該函數將使引用計數減1,如果減少到0,則調用作為參數提供的release函數,注意WARN_ON()聲明,提供的release函數不能簡單地采用kfree,它必須是一個僅接受一個kref結構體作為參數的特有函數,而且還沒有返回值。

上述的所有函數定義與聲明分別在文件lib/kref.c和文件linux/kref.h中。

8 sysfs

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

sysfs的訣竅是把kobject對象與目錄項緊緊聯系起來,這是通過kobject對象中的dentry域實現的。dentry結構體表示目錄項,通過連接kobject到指定的目錄項上,無疑方便地將kobject映射到該目錄上。從此,把kobject導出形成文件系統就變得如同在內存中構建目錄項一樣簡單。由于kobject被映射到目錄項,同時kobject形成一棵樹,因此sysfs的生成就很簡單了。

sysfs中添加和刪除kobject

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

int kobject_add(struct kobject *kobj);

kobject在sysfs中位置取決于kobject在對象層次結構中的位置。如果kobject的parent指針被設置,那么在sysfs中kobject將被映射為父目錄下的子目錄,如果parent沒有設置,那么kobject將被映射為kset->kobj中的子目錄。如果給定的kobject中parent或kset字段都沒有設置,那么就認為kobject沒有父對象,所以就會被映射成sysfs下的根級目錄。

你不必分別調用kobject_init()和kobject_add(),因為系統提供函數kobject_register()可幫助你一步到位:

int kobject_register(struct kobject *kobj);

該函數即初始化給定的kobject對象,同時又將其加入到對象層次結構體中。

從sysfs中刪除一個kobject對應文件目錄,需要使用函數kobject_del():

void kobject_del(struct kobject *kobj);

類似地,函數kobject_unregister()包含了kobjeect_del和kobject_put二者的功能:

void kobject_unregister(struct kobject *kobj);

上述四個函數都定義與文件lib/kobject.c中,聲明于文件linux/kobject.h中。

向sysfs添加文件

sysfs僅僅是一個漂亮的樹,但是沒有提供實際數據的文件。

默認的文件集合是通過kobject和kset中的ktype字段提供的。因此所有具有相同類型的kobject在它們對應的sysfs目錄下都擁有相同的默認文件集合,kobj_type字段含有一個字段,default_attrs,它是一個attribute結構體數組。這些屬性負責將內核數據映射成sysfs中的文件。

attribute結構體定義在文件linux/sysfs.h中:

struct attribute {char			* name;	/* 屬性名 */struct module 		* owner;	/* 所屬模塊,如果存在 */mode_t			mode;	/* 權限 */
};

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

sysfs_ops字段描述了如何使用他們,sysfs_ops字段指向了一個定義于文件linux/sysfs.h的同名的結構體:

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

show方法在讀操作時被調用。它會拷貝由attr提供的屬性值到buffer指定的緩沖區中,緩沖區大小為PAGE_SIZE字節。
store方法在寫操作時調用,它會從buffer中讀取size大小的字節,并將其存放入attr表示的屬性結構體變量中。

  • 創建新屬性
int sysfs_create_file(struct kobject *kobj,const struct attribute *attr);

sysfs_create_file來創建新屬性,通過attr參數指向相應的attribute結構體,而kobj則制定了屬性所在的kobject對象。

除了添加文件外,還有可能需要創建符號連接,在sysfs中創建一個符號連接相當簡單:

int sysfs_create_link(struct kobject *kobj,struct kobject *target,char *name);

該函數創建的符號連接名由name指定,連接則由kobj對應的目錄映射到target指定的目錄

  • 刪除新屬性
    刪除一個屬性需通過函數sysfs_remove_file完成:
sysfs_remove_file(struct kobject *kobj,const struct attribute *attr);

另外由sysfs_create_link()創建的符號連接可通過函數sysfs_remove_link刪除:

void sysfs_remove_link(struct kobject *kobj,char *name);

上述的四個函數在文件linux/kobject.h中聲明,sys_create_file和sysfs_remove_file函數定義于文件fs/sysfs/file.c中;sysfs_create_link和sysfs_remove_link函數定義在文件fs/sysfs/symlink.c中。

9 內核事件層

內核事件層把事件模擬為信號,從明確的kobject發出,所以每個事件源都是一個sysfs路徑。

每個事件都有一個可選的負載,相比傳遞任意一個表示負載的字符串到用戶空間而言,內核事件層使用sysfs屬性代表負載。

在內核代碼中向用戶空間發送信號使用函數kobject_uevent():

int kobject_uevent(struct kobject *kobj,enum kobject_action action struct attribute *attr);

第一個參數指定發送該信號的kobject對象,實際的內核事件將包含該kobject映射到sysfs的路徑。
第二個參數指定來描述該信號的動作。實際的內核事件將包含一個映射成枚舉類型kobject_action的字符串。該函數不是直接提供一個字符串,而是利用一個枚舉變量來提高可重用性和保證類型安全,而且也消除了打字錯誤或別的其他錯誤,該枚舉變量定義于文件linux/kobject_uevent.c中,其形式為KOBJ_foo。當前值包含KOBJ_MOUNT、KOBJ_UNMOUNT、KOBJ_ADD等,這些值分別映射"mount"、“unmonut”、“add”等。
最后一個參數是指向attribute結構體的可選指針,它可看作為事件的“負載”。

該函數分配內存,所以可以睡眠。但在內核中實現了原子和非原子操作兩個版本,其不同在于原子操作使用GFP_ATOMIC標志分配內存。

int kobject_uevent_atomic(struct kobject *kobj,enum kobject_action action,struct attribute *attr);

這兩個函數分別定義和聲明在文件lib/kobject_uevent.c于文件linux/kobject_uevent.h中

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379601.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379601.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379601.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開發Windows Mobile今日插件 -- 內存電量,桌面便箋,桌面記單詞

本篇文章講解的是開發 Windows Mobile 上的今日插件。關于是今日插件,在 PPC 或者 SP SDK 的幫助文檔中有相關的章節介紹,在網絡上也有一些帖子和資源講解。在這里簡要回顧一下。今日插件就是在windows mobile的桌面上顯示的條目,例如系統提供…

c語言中將函數指針作為形參_在C中將有效指針作為NULL指針

c語言中將函數指針作為形參Prerequisite: An Example of Null pointer in C 先決條件: C中的空指針示例 Any pointer that contains a valid memory address can be made as a NULL pointer by assigning 0. 通過分配0,可以將包含有效內存地址的任何指…

[轉]一個清華計算機博士生的退學申請

偶然間在網上看到這篇帖子,回想起自己的求學經歷,思索良久。。。 本想找到原帖及作者,但是幾經搜索,發現原帖出自科學網,已被刪除。對此,我還能說啥?! http://www.sciencenet.cn/m/u…

算法---遞歸

遞歸結題三部曲 何為遞歸?程序反復調用自身即是遞歸。 我自己在剛開始解決遞歸問題的時候,總是會去糾結這一層函數做了什么,它調用自身后的下一層函數又做了什么…然后就會覺得實現一個遞歸解法十分復雜,根本就無從下手。 相信…

給定條件找最小值c語言程序_根據給定條件最小化n的最小步驟

給定條件找最小值c語言程序Problem statement: 問題陳述: Given a number n, count minimum steps to minimize it to 1 performing the following operations: 給定數字n ,執行以下操作,計算最少的步驟以將其最小化為1: Operat…

提高C#編程水平不可不讀的50個要訣

提高C#編程水平的50個要點 1.總是用屬性 (Property) 來代替可訪問的數據成員 2.在 readonly 和 const 之間,優先使用 readonly 3.在 as 和 強制類型轉換之間,優先使用 as 操作符 4.使用條件屬性 (Conditional Attributes) 來代替條件編譯語句 #if 5.總是…

那個年代的蘇聯歌曲

小時候,不時聽父親提起電影《這里的黎明靜悄悄》,怎么也想不到如此美麗的名字為什么要和戰爭聯系起來。后來在大學看了這部電影之后,開始認為這名字是合適的,因為電影講的是女性——戰場中的女性,各自都懷揣著愛情去保…

linux系統編程---進程總結

進程控制總結1 進程創建的三種方式forkvfrokclone2 進程終止進程正常退出returnexit_exit進程異常退出進程收到某個信號,而該信號使進程終止abort3 進程等待進程等待的方法waitwaitpid4 進程替換替換原理替換函數制作一個簡單的shell1 進程創建的三種方式 參考文章…

銀行賬務轉賬系統(事務處理)

流程如下: 創建項目工程如下: transfer包下的代碼如下: package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils;pu…

【msdn wpf forum翻譯】TextBox中文本 中對齊 的方法

原文鏈接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/49864e35-1dbf-4292-a361-93f1a8400558問題:TextBox中文本中對齊,使用 TextBox.HorizontalContentAlignment"Center"行不通(TextBox.VerticalConte…

wifi操作及實例

1.什么事WIFI 利用無線路由器上網的協議2.獲取WIFI網卡的狀態 WIFI網卡的狀態是由一系列的整形常量來表示的 有狀態: 網卡不可用WIFI_STATE_DISABLED 對應值為1 網卡正在關閉WIFI_STATE_DISABLING 對應值為0 網卡可用WIFI_STATE_ENABLED 對應的值為3 …

c語言 函數的參數傳遞示例_C語言中帶有示例的remove()函數

c語言 函數的參數傳遞示例C語言中的remove()函數 (remove() function in C) The remove() function is defined in the <stdio.h> header file. remove()函數在<stdio.h>頭文件中定義。 Prototype: 原型&#xff1a; int remove(const char* filename);Parameter…

使用ThreadLocal綁定連接資源(事務)

dao層代碼如下&#xff1a; package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils; import beyond.utils.MyDataSourceUtils;public class TransferDa…

算法---棧和隊列

棧和隊列1 棧棧的順序存儲棧的鏈式存儲2 隊列隊列的順序存儲隊列的鏈式存儲3 棧和隊列的應用用棧實現隊列用隊列實現棧最小棧1 棧 參考文章&#xff1a; https://zhuanlan.zhihu.com/p/346164833 https://zhuanlan.zhihu.com/p/120965372#:~:text%E6%A0%88%E6%98%AF%E4%B8%80%…

學習網站LIST

面向對象的腳本語言Rubyhttp://rubycn.ce-lab.net/20020101.htmlRUBY文檔中心http://www.moer.net/ruby/doc/TCL腳本http://www.tclchina.com/Python快速入門http://wiki.woodpecker.org.cn/moin/WeiZhong/2006-01-17Python 研究(Dive Into Python)http://www.woodpecker.org.c…

再次參加(第七屆)商學院徒步戈壁挑戰賽,賦詞幾首

2012年5月21-25日&#xff0c;再次踏上甘肅莫賀延磧戈壁&#xff0c;參加第七屆商學院徒步戈壁挑戰賽。時隔五年&#xff0c;時空轉換。 少年游 ——戈壁緣 江南物華&#xff0c;遠水碧山&#xff0c;燈火相掩映。暮宴朝歡&#xff0c;酒綠燈紅&#xff0c;躑躅夜歸人。 孤城落…

Java StackTraceElement toString()方法與示例

StackTraceElement類的toString()方法 (StackTraceElement Class toString() method) toString() method is available in java.lang package. toString()方法在java.lang包中可用。 toString() method is used to represent stack trace element as a string or in other word…

增刪改查

web層代碼如下&#xff1a; package beyondwsq.web;import java.io.IOException; import java.sql.SQLException; import java.util.List;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; imp…

在WebBrowser中通過模擬鍵盤鼠標操控網頁中的文件上傳控件

引言 這兩天沉迷了Google SketchUp&#xff0c;剛剛玩夠&#xff0c;一時興起&#xff0c;研究了一下WebBrowser。 我在《WebBrowser控件使用技巧分享》一文中曾談到過“我現在可以通過WebBrowser實現對各種Html元素的操控&#xff0c;唯獨無法控制Html的上傳控件”&#xff0c…

編寫最簡單的字符設備驅動

編寫最簡單的字符設備驅動1 編寫驅動代碼2 編寫makefile3 編譯和加載驅動4 編寫應用程序測試驅動參考文章&#xff1a; linux驅動開發第1講&#xff1a;帶你編寫一個最簡單的字符設備驅動 linux驅動開發第2講&#xff1a;應用層的write如何調用到驅動中的write 1 編寫驅動代碼…