Chinese translated version of Documentation/filesystems/sysfs.txt 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.txt çš„ä¸æ–‡ç¿»è¯‘ 如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ 交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 英文版维护者: 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/kobject.txt 文档以获得更多关于 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(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 会分é…一个大å°ä¸º (PAGE_SIZE) çš„ç¼“å†²åŒºå¹¶ä¼ é€’ç»™è¿™ä¸ªæ–¹æ³•ã€‚ Sysfs 将会为æ¯æ¬¡è¯»å†™æ“作调用一次这个方法。这使得这些方法在执行时 会出现以下的行为: - 在读方é¢ï¼ˆread(2)),show() 方法应该填充整个缓冲区。回想属性 应åªå¯¼å‡ºäº†ä¸€ä¸ªå±žæ€§å€¼æˆ–是一个åŒç±»åž‹å±žæ€§å€¼çš„数组,所以这个代价将 ä¸ä¼šä¸å¤ªé«˜ã€‚ 这使得用户空间å¯ä»¥å±€éƒ¨åœ°è¯»å’Œä»»æ„çš„å‘å‰æœç´¢æ•´ä¸ªæ–‡ä»¶ã€‚如果用户空间 å‘åŽæœç´¢åˆ°é›¶æˆ–使用‘0’å移执行一个pread(2)æ“作,show()方法将 å†æ¬¡è¢«è°ƒç”¨ï¼Œä»¥é‡æ–°å¡«å……缓å˜ã€‚ - 在写方é¢ï¼ˆwrite(2)),sysfs 希望在第一次写æ“作时得到整个缓冲区。 ä¹‹åŽ Sysfs ä¼ é€’æ•´ä¸ªç¼“å†²åŒºç»™ store() 方法。 当è¦å†™ sysfs 文件时,用户空间进程应首先读å–æ•´ä¸ªæ–‡ä»¶ï¼Œä¿®è¯¥æƒ³è¦ æ”¹å˜çš„值,然åŽå›žå†™æ•´ä¸ªç¼“冲区。 在读写属性值时,属性方法的执行应æ“作相åŒçš„缓冲区。 注记: - 写æ“作导致的 show() 方法é‡è½½ï¼Œä¼šå¿½ç•¥å½“å‰æ–‡ä»¶ä½ç½®ã€‚ - 缓冲区应总是 PAGE_SIZE 大å°ã€‚对于i386,这个值为4096。 - show() 方法应该返回写入缓冲区的å—节数,也就是 snprintf()çš„ 返回值。 - show() 应始终使用 snprintf()。 - 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.txt)。 dev/ 包å«ä¸¤ä¸ªå目录: char/ å’Œ block/。在这两个å目录ä¸ï¼Œæœ‰ä»¥ <major>:<minor> æ ¼å¼å‘½å的符å·é“¾æŽ¥ã€‚这些符å·é“¾æŽ¥æŒ‡å‘ sysfs 目录 ä¸ç›¸åº”的设备。/sys/dev æ供一个通过一个 stat(2) æ“作结果,查找 设备 sysfs 接å£å¿«æ·çš„方法。 更多有关 driver-model 的特性信æ¯å¯ä»¥åœ¨ Documentation/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。