sysfs是一個內存文件系統,他提供了內核與用戶之間的數據屬性和連接交互,sysfs與kobject聯繫緊密。
內核編譯的時候要 CONFIG_SYSFS
mount -t sysfs sysfs /sys
每一個註冊的kobject都有一個目錄在sysfs,這個目錄地址在kobj的父對象目錄下,表徵爲層級,頂層目錄表現爲最高層級。
sysfs_dirent對象下面有一個指向kobj的指針,這個指針之前是用來作引用計數用的,現如今引用計數只被sysfs_schedule_callback()修改。
屬性被當做普通文件形式暴露出來。可以通過普通文件io讀寫內核屬性。
屬性應該是asc碼 txt文件,最好一個文件只有一個值,明顯這種機制不夠用,所以也允許多個值的情況。
struct attribute { char * name;
struct module *owner;
umode_t mode;
};
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
一個光的屬性不包含讀寫函數,子系統需要自己分裝。
例如:
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);
};
int device_create_file(struct device *, const struct device_attribute *);
void device_remove_file(struct device *, const struct device_attribute *);
It also defines this helper for defining device attributes:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
For example, declaring
static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
static struct device_attribute dev_attr_foo = { .attr= { .name = "foo",
.mode = S_IWUSR | S_IRUGO,
.show = show_foo,
.store = store_foo, },
};
當子系統定義了一個新的屬性類型,那他必須自己實現讀寫函數來調用打印和保存方法。
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
子系統必須先定義kobj_type用來保存sysfs_ops指針。
當文件被讀或者寫了,sysfs會調用正確的方法。
#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;
}
爲了讀寫屬性,show和store函數必須被賦值,函數類型需要要與設備屬性的一樣
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);
sysfs申請一個頁表來發送數據,每次讀寫只會調用一次底層函數,因此有如下的要求:
讀的時候,show函數必須要填滿整個buffer,回想一個屬性只能傳一個或者一組值,這樣效率纔不會太低。
這樣允許用戶空間 局部的讀和seek整個文件,如果用戶seek到0 或者pread 0 ,那麼show函數會再次調用,充填buffer
寫的時候,sysfs認爲整個buffer都有內容,傳遞整個buffer到store函數
寫的時候,先讀出來,修改 在寫回去
讀寫的buffer需要用同一個buffer
寫會使得show刷新不管文件pos
buffer永遠一個頁表大小
show函數會返回buffer字符的數量 ,實現是靠scnprintf函數
store函數返回不超過一個頁表大小數據,
讀寫會返回錯誤值
對象會被sysfs保存在內存中,實際對象是否存在不得而知。
A very simple (and naive) implementation of a device attribute is:
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);
(Note that the real implementation doesn't allow userspace to set the name for a device.)
sysfs目錄結構直接暴露了內核數據結構層級。
devices/ 表徵設備樹
bus/ bus類型 都有
devices/ 指向根目錄下的設備目錄
drivers/ 包含 每個啓動的驅動
dev/ 包含 char 和 block 裏面有 <major>:<minor>鏈接,指向設備目錄,stat 命令就是用的這裏
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); };
Declaring:
DEVICE_ATTR(_name, _mode, _show, _store);
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);
- 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); };
Declaring:
BUS_ATTR(_name, _mode, _show, _store)
Creation/Removal:
int bus_create_file(struct bus_type *, struct bus_attribute *); void bus_remove_file(struct bus_type *, struct bus_attribute *);
- 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); };
Declaring:
DRIVER_ATTR(_name, _mode, _show, _store)
Creation/Removal:
int driver_create_file(struct device_driver *, const struct driver_attribute *); void driver_remove_file(struct device_driver *, const struct driver_attribute *);