Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | Chinese translated version of Documentation/filesystems/sysfs.rst If you have any comment or update to the content, please contact the original document maintainer directly. However, if you have a problem communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Patrick Mochel <mochel@osdl.org> Mike Murphy <mamurph@cs.clemson.edu> Chinese maintainer: Fu Wei <tekkamanninja@gmail.com> --------------------------------------------------------------------- Documentation/filesystems/sysfs.rst 的中文翻译 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者。 英文版维护者: Patrick Mochel <mochel@osdl.org> Mike Murphy <mamurph@cs.clemson.edu> 中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 以下为正文 --------------------------------------------------------------------- sysfs - 用于导出内核对象(kobject)的文件系统 Patrick Mochel <mochel@osdl.org> Mike Murphy <mamurph@cs.clemson.edu> 修订: 16 August 2011 原始版本: 10 January 2003 sysfs 简介: ~~~~~~~~~~ sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导出内核 数据结构及其属性,以及它们之间的关联到用户空间的方法。 sysfs 始终与 kobject 的底层结构紧密相关。请阅读 Documentation/core-api/kobject.rst 文档以获得更多关于 kobject 接口的 信息。 使用 sysfs ~~~~~~~~~~~ 只要内核配置中定义了 CONFIG_SYSFS ,sysfs 总是被编译进内核。你可 通过以下命令挂载它: mount -t sysfs sysfs /sys 创建目录 ~~~~~~~~ 任何 kobject 在系统中注册,就会有一个目录在 sysfs 中被创建。这个 目录是作为该 kobject 的父对象所在目录的子目录创建的,以准确地传递 内核的对象层次到用户空间。sysfs 中的顶层目录代表着内核对象层次的 共同祖先;例如:某些对象属于某个子系统。 Sysfs 在与其目录关联的 kernfs_node 对象中内部保存一个指向实现 目录的 kobject 的指针。以前,这个 kobject 指针被 sysfs 直接用于 kobject 文件打开和关闭的引用计数。而现在的 sysfs 实现中,kobject 引用计数只能通过 sysfs_schedule_callback() 函数直接修改。 属性 ~~~~ kobject 的属性可在文件系统中以普通文件的形式导出。Sysfs 为属性定义 了面向文件 I/O 操作的方法,以提供对内核属性的读写。 属性应为 ASCII 码文本文件。以一个文件只存储一个属性值为宜。但一个 文件只包含一个属性值可能影响效率,所以一个包含相同数据类型的属性值 数组也被广泛地接受。 混合类型、表达多行数据以及一些怪异的数据格式会遭到强烈反对。这样做是 很丢脸的,而且其代码会在未通知作者的情况下被重写。 一个简单的属性结构定义如下: 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); 一个单独的属性结构并不包含读写其属性值的方法。子系统最好为增删特定 对象类型的属性定义自己的属性结构体和封装函数。 例如:驱动程序模型定义的 device_attribute 结构体如下: 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 *); 为了定义设备属性,同时定义了一下辅助宏: #define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) 例如:声明 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, }, }; 子系统特有的回调函数 ~~~~~~~~~~~~~~~~~~~ 当一个子系统定义一个新的属性类型时,必须实现一系列的 sysfs 操作, 以帮助读写调用实现属性所有者的显示和储存方法。 struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *, char *); ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); }; [子系统应已经定义了一个 struct kobj_type 结构体作为这个类型的 描述符,并在此保存 sysfs_ops 的指针。更多的信息参见 kobject 的 文档] sysfs 会为这个类型调用适当的方法。当一个文件被读写时,这个方法会 将一般的kobject 和 attribute 结构体指针转换为适当的指针类型后 调用相关联的函数。 示例: #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 = kobj_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) { printk("dev_attr_show: %pS returned bad count\n", 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 会分配一个大小为 (PAGE_SIZE) 的缓冲区并传递给这个方法。 Sysfs 将会为每次读写操作调用一次这个方法。这使得这些方法在执行时 会出现以下的行为: - 在读方面(read(2)),show() 方法应该填充整个缓冲区。回想属性 应只导出了一个属性值或是一个同类型属性值的数组,所以这个代价将 不会不太高。 这使得用户空间可以局部地读和任意的向前搜索整个文件。如果用户空间 向后搜索到零或使用‘0’偏移执行一个pread(2)操作,show()方法将 再次被调用,以重新填充缓存。 - 在写方面(write(2)),sysfs 希望在第一次写操作时得到整个缓冲区。 之后 Sysfs 传递整个缓冲区给 store() 方法。 当要写 sysfs 文件时,用户空间进程应首先读取整个文件,修该想要 改变的值,然后回写整个缓冲区。 在读写属性值时,属性方法的执行应操作相同的缓冲区。 注记: - 写操作导致的 show() 方法重载,会忽略当前文件位置。 - 缓冲区应总是 PAGE_SIZE 大小。对于i386,这个值为4096。 - show() 方法应该返回写入缓冲区的字节数,也就是 scnprintf()的 返回值。 - show() 方法在将格式化返回值返回用户空间的时候,禁止使用snprintf()。 如果可以保证不会发生缓冲区溢出,可以使用sprintf(),否则必须使用 scnprintf()。 - store() 应返回缓冲区的已用字节数。如果整个缓存都已填满,只需返回 count 参数。 - show() 或 store() 可以返回错误值。当得到一个非法值,必须返回一个 错误值。 - 一个传递给方法的对象将会通过 sysfs 调用对象内嵌的引用计数固定在 内存中。尽管如此,对象代表的物理实体(如设备)可能已不存在。如有必要, 应该实现一个检测机制。 一个简单的(未经实验证实的)设备属性实现如下: 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); (注意:真正的实现不允许用户空间设置设备名。) 顶层目录布局 ~~~~~~~~~~~~ sysfs 目录的安排显示了内核数据结构之间的关系。 顶层 sysfs 目录如下: block/ bus/ class/ dev/ devices/ firmware/ net/ fs/ devices/ 包含了一个设备树的文件系统表示。他直接映射了内部的内核 设备树,反映了设备的层次结构。 bus/ 包含了内核中各种总线类型的平面目录布局。每个总线目录包含两个 子目录: devices/ drivers/ devices/ 包含了系统中出现的每个设备的符号链接,他们指向 root/ 下的 设备目录。 drivers/ 包含了每个已为特定总线上的设备而挂载的驱动程序的目录(这里 假定驱动没有跨越多个总线类型)。 fs/ 包含了一个为文件系统设立的目录。现在每个想要导出属性的文件系统必须 在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.rst)。 dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有以 <major>:<minor> 格式命名的符号链接。这些符号链接指向 sysfs 目录 中相应的设备。/sys/dev 提供一个通过一个 stat(2) 操作结果,查找 设备 sysfs 接口快捷的方法。 更多有关 driver-model 的特性信息可以在 Documentation/driver-api/driver-model/ 中找到。 TODO: 完成这一节。 当前接口 ~~~~~~~~ 以下的接口层普遍存在于当前的sysfs中: - 设备 (include/linux/device.h) ---------------------------------- 结构体: 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); }; 声明: DEVICE_ATTR(_name, _mode, _show, _store); 增/删属性: int device_create_file(struct device *dev, const struct device_attribute * attr); void device_remove_file(struct device *dev, const struct device_attribute * attr); - 总线驱动程序 (include/linux/device.h) -------------------------------------- 结构体: 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); }; 声明: BUS_ATTR(_name, _mode, _show, _store) 增/删属性: int bus_create_file(struct bus_type *, struct bus_attribute *); void bus_remove_file(struct bus_type *, struct bus_attribute *); - 设备驱动程序 (include/linux/device.h) ----------------------------------------- 结构体: 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); }; 声明: DRIVER_ATTR(_name, _mode, _show, _store) 增/删属性: int driver_create_file(struct device_driver *, const struct driver_attribute *); void driver_remove_file(struct device_driver *, const struct driver_attribute *); 文档 ~~~~ sysfs 目录结构以及其中包含的属性定义了一个内核与用户空间之间的 ABI。 对于任何 ABI,其自身的稳定和适当的文档是非常重要的。所有新的 sysfs 属性必须在 Documentation/ABI 中有文档。详见 Documentation/ABI/README。 |