SPDX-License-Identifier: GPL-2.0 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> ç¹é«”ä¸æ–‡ç‰ˆæ ¡è¯è€…:胡皓文 Hu Haowen <src.res@email.cn> 以下爲æ£æ–‡ --------------------------------------------------------------------- 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)(const struct bus_type *, char * buf); ssize_t (*store)(const 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。