來源:https://blog.csdn.net/qq_36412526/article/details/83751520
第一次接觸:sysfs, 這里記錄過程:
原文:Documenttation/filesystems/sysfs.txt sysfs-用於導出內核對象(kobject)的文件系統
sysfs是什么: sysfs是一個基於ram的內存文件系統(ramfs)。它提供了一種方法用於導出內核數據結構,屬性,以及它們兩者之間的聯系到用戶空間。 sysfs和kobject結構關聯。參考Documenttation/kobject.txt獲取更多kobject信息。
sysfs用法: 如果定義了CONFIG_SYSFS sysfs就會編譯進內核。可以用以下命令掛載: mount -t sysfs sysfs /sys
目錄創建 每個注冊在系統的kobject都會在sysfs創建一個目錄。創建的目錄位於kobject的parent目錄下,展現了kobject之間的內部層級關系。sysfs頂層的目錄表示共同的祖先目錄;比如object歸屬的subsystems。 sysfs內部保存了一個指向kobject的指針。過去kobject指針被sysfs直接用來處理引用次數在文件打開或關閉的時候。現在的sysfs實現了kobject的引用次數只能被函數sysfs_schedule_callback()修改。
屬性(attribute) attribute能為kobject導出普通文件的格式。sysfs用文件I/O操作來操作attribute定義的函數,提供了一種讀寫內核屬性的途徑。 attributes應該是ASCII文本文件,最好每個文件保存一個值。有人注意到一個文件保存一個值顯得效率不高,所以保存同類型的一組值也是普遍認可的。 混合類型、保存多行數據,且比較花哨的數據是不贊成的。這樣做會讓你在公眾面前丟臉且你的代碼會被毫無征兆地重寫。 attribute定義如下
struct attribute{
char *name;
struct module *owner;
mode_t mode;
};
int sysfs_create_file(struct kobject *kobj,const struct attribute *attr);
void sysfs_remove_file(struct kobject *kobj,const struct attribute *attr);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
空的attribute不含讀寫attribute的函數。子系統(subsystems)鼓勵定義自己的attribute結構體和包裝函數用於添加和刪除object的attribute。
舉例來說,設備驅動模型定義了device_attribute的結構體如下:
struct device_attribute{
struct attribute attr;
ssize_t (*show)(struct device *dev,struct device_attribute *attr,char *buf);
ssize_t (*strore)(struct device *dev,struct device_attibute *attr,char *buf,size_t count);
};
int device_create_file(struct device *,const struct device_attribute *);
void device_remove_file(struct device *,const struct device_attribute *);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
它同時定義了輔助宏來定義設備attributes:
#define DEVICE_ATTR(_name,_mode,_show,_store)\
struct device_attribute dev_attr_##_name =__ATTR(_name,_mode,_show,_store)
- 1
- 2
舉例,聲明
static DEVICE_ATTR(foo,S_IWUSR | S_IRUGO,show_foo,store_foo);
- 1
等效於:
static struct device_attribute dev_attr_foo =
.attr = {
.name = "foo",
.mode = S_IWUSR | S_IRUGO,
.show = show_foo,
.store = store_foo,
},
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
subsystem相關的callbacks
當subsystem定義了新的attribute類型,它必須實現一組自己的sysfs操作函數用於sysfs讀寫調用.
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
- 1
- 2
- 3
- 4
[subsystems 應該已經定義了一個kobj_type結構體作為類型描述符,它保存了sysfs_ops指針.詳情參考kobject文檔.]
當讀寫文件的時候,sysfs調用kobj_type的相應方法函數.該函數隨后轉換kobject和attribute指針到相應的指針類型,然后調用相應的方法函數. 舉例:
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct device_attribute *dev_attr = to_dev_attr(attr);
struct device *dev = to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->show)
ret = dev_attr->show(dev, dev_attr, buf);
if (ret >= (ssize_t)PAGE_SIZE) {
print_symbol("dev_attr_show: %s returned bad count\n",
(unsigned long)dev_attr->show);
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
讀/寫 attribute 數據 為了讀寫attribute,在聲明attribute的時候必須定義show()或store()函數.這些函數應該盡量簡單如device attribute定義的函數:
ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
- 1
- 2
- 3
IOW,這些函數只需要一個object,attribute,buffer作為參數. sysfs分配了一個buffer(PAGE_SIZE字節)並把它傳入這些函數.sysfs會在每次讀寫的時候調用這些函數.要求這些函數實現以下功能:
-on read(2),show()函數會填充整個buffer.一個attribute應該只導出一個值,或一組相似的值,因此這個效率不高. 這 使用戶空間可以部分讀且隨意向后搜索.如果用戶空間向前搜索到0或使用pread(2)在0位置讀,show()函數會被再次調用 並填充整個buffer.
-on write(2),sysfs在首次寫的時候傳遞整個buffer,sysfs然后傳遞整個buffer到store()函數. 當寫sysfs文件時,用戶空間先讀整個文件,然后修改,最后再寫回文件. attribute函數讀和寫的時候應該使用同一個buffer.
其他注意點:
-寫操作將導致show()函數被再次調用,不管當前文件位置在哪里.
-buffer的長度固定為PAGE_SIZE.在i386,長度為4096
-show()函數返回輸出到buffer的字節數.也就是scnprintf()函數的返回值
-show()函數應該使用scnprintf()函數
-store()函數應該返回buffer占用的字節數,如果整個buffer都被占用,應該返回count參數
-show()和store()函數可以返回錯誤,如果有錯誤的值,確保返回一個錯誤
-函數的參數object將被保存在內存中通過它的引用計數器計數.但object代表的實體不一定在內存中,如果有必要,要有方法檢測.
一個設備屬性的簡單的實現如下:
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
}
static ssize_t store_name(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
snprintf(dev->name, sizeof(dev->name), "%.*s",
(int)min(count, sizeof(dev->name) - 1), buf);
return count;
}
static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
(注意,實際上設備的名字不能在用戶空間更改.)
頂層目錄安排
sysfs目錄展現了內核數據結構之間的關系. 頂層目錄如下: block/ bus/ class/ dev/ devices/ firmware/ net/ fs/
devices/ 一個文件系統代表了設備樹(device tree).直接映射到內核的設備樹,它是device結構體的層級關系. bus/ 內核的多種總線類型的目錄布局.每個總線目錄含兩個子目錄: devices/ 系統里發現的每個設備的符號連接指向root/目錄下的 device目錄 drivers/ 特定總線上設備加載的驅動目錄 fs/ 某些文件系統的目錄.每個文件系統如果要導出attributes必須要創建它自己的目錄層級到fs/下 dev/ 里面有兩個目錄char/和block/.這兩個目錄里有命名為:的符號連接.這些符號連接到sysfs目錄下對應的device./sys/dev提供了一個快速的方式來查找sysfs中stat操作的結果
更多關於驅動模型的特征信息可以參考Documentation/driver-model/.
Current Interfaces
The following interface layers currently exist in sysfs:
- devices (include/linux/device.h)
Structure:
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Declaring:
DEVICE_ATTR(_name, _mode, _show, _store);
- 1
Creation/Removal:
int device_create_file(struct device *dev, const struct device_attribute * attr);
void device_remove_file(struct device *dev, const struct device_attribute * attr);
- 1
- 2
- 3
- bus drivers (include/linux/device.h)
Structure:
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
- 1
- 2
- 3
- 4
- 5
Declaring:
BUS_ATTR(_name, _mode, _show, _store)
- 1
Creation/Removal:
int bus_create_file(struct bus_type *, struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);
- 1
- 2
- 3
- device drivers (include/linux/device.h)
Structure:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *, char * buf);
ssize_t (*store)(struct device_driver *, const char * buf,
size_t count);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Declaring:
DRIVER_ATTR(_name, _mode, _show, _store)
- 1
- 2
Creation/Removal:
int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
- 1
- 2
- 3
文檔
sysfs目錄結構和每個目錄的attribute定義了一種ABI在內核和用戶空間.對於任何ABI,穩定和正確的文檔是很重要的.所有新的sysfs attributes必須配上文檔.參考Documentation/ABI/README閱讀更多的信息.