訪問sysfs資訊的規則

核心匯出的 sysfs 匯出內部核心實現細節,並且依賴於內部核心結構和佈局。核心開發人員一致認為 Linux 核心不提供穩定的內部 API。因此,sysfs 介面的某些方面可能在核心發行版之間不穩定。

為了最大限度地減少由於新核心發行版而破壞 sysfs 使用者(在大多數情況下是低階使用者空間應用程式)的風險,sysfs 使用者必須遵循一些規則,以儘可能抽象的方式訪問此檔案系統。當前的 udev 和 HAL 程式已經實現了這一點,並且鼓勵使用者儘可能插入這些程式提供的抽象,而不是直接訪問 sysfs。

但是,如果您確實想要或需要直接訪問 sysfs,請遵循以下規則,然後您的程式應該可以與未來的 sysfs 介面版本一起使用。

  • 不要使用 libsysfs

    它對 sysfs 做出了一些不正確的假設。它的 API 不提供任何抽象,它在其自己的 API 中公開了所有核心驅動程式核心的實現細節。因此,它並不比自己讀取目錄和開啟檔案更好。而且,它沒有積極維護,在反映當前核心開發方面。提供穩定介面給sysfs的目標已經失敗;它造成的問題比它解決的更多。它違反了本文件中的許多規則。

  • sysfs 始終位於 /sys

    解析 /proc/mounts 是在浪費時間。其他的掛載點是您不應該嘗試解決的系統配置錯誤。對於測試用例,可能支援一個 SYSFS_PATH 環境變數來覆蓋應用程式的行為,但永遠不要嘗試搜尋 sysfs。如果您不是早期啟動指令碼,則永遠不要嘗試掛載它。

  • 裝置只是“裝置”

    在使用者空間中,沒有什麼像類裝置、匯流排裝置、物理裝置、介面等你可以依賴的東西。一切都只是一個簡單的“裝置”。類裝置、匯流排裝置、物理裝置......型別只是核心實現細節,應用程式在 sysfs 中查詢裝置時不應該期望它們。

    裝置的屬性是

    • devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0)

      • 與裝置建立和刪除時核心傳送的事件中的 DEVPATH 值相同

      • 該裝置在那個時間點的唯一鍵

      • 不帶前導 /sys 的裝置目錄的核心路徑,並且始終以斜槓開頭

      • devpath 的所有元素都必須是真實目錄。指向 /sys/devices 的符號連結必須始終解析為其真實目標,並且必須使用目標路徑來訪問該裝置。這樣,裝置的 devpath 與事件時使用的核心的 devpath 相匹配。

      • 將符號連結值用作 devpath 字串中的元素是應用程式中的一個 bug

    • 核心名稱 (sda, tty, 0000:00:1f.2, ...)

      • 目錄名,與 devpath 的最後一個元素相同

      • 應用程式需要處理名稱中的空格和字元,如 !

    • 子系統 (block, tty, pci, ...)

      • 簡單字串,永遠不是路徑或連結

      • 透過讀取“subsystem”連結並僅使用目標路徑的最後一個元素來檢索

    • 驅動程式 (tg3, ata_piix, uhci_hcd)

      • 一個簡單的字串,可能包含空格,永遠不是路徑或連結

      • 它透過讀取“driver”連結並僅使用目標路徑的最後一個元素來檢索

      • 沒有“driver”連結的裝置只是沒有驅動程式;在子裝置上下文中複製驅動程式值是應用程式中的一個 bug

    • 屬性

      • 裝置目錄中的檔案或同一裝置目錄的子目錄下的檔案

      • 訪問透過指向另一個裝置的符號連結(如“device”連結)訪問的屬性是應用程式中的一個 bug

    其他一切都只是核心驅動程式核心實現細節,不應假定在核心發行版之間保持穩定。

  • 父裝置的屬性永遠不屬於子裝置。

    始終檢視父裝置本身以確定裝置上下文屬性。如果裝置 eth0sda 沒有“driver”連結,則此裝置沒有驅動程式。它的值為空。永遠不要將父裝置的任何屬性複製到子裝置中。父裝置屬性可能會動態更改,而不會通知子裝置。

  • 單個裝置樹中的層次結構

    sysfs 中只有一個有效的位置可以檢查層次結構,那就是:/sys/devices. 計劃將所有裝置目錄都放在此目錄下的樹中。

  • 按子系統分類

    目前有三個用於裝置分類的地方:/sys/block, /sys/class/sys/bus. 計劃這些目錄本身不包含任何裝置目錄,而只包含指向統一 /sys/devices 樹的符號連結的扁平列表。所有三個地方都有完全不同的規則來訪問裝置資訊。計劃將所有三個分類目錄合併到一個位置,即 /sys/subsystem,遵循匯流排目錄的佈局。所有匯流排和類,包括轉換後的塊子系統,都將顯示在那裡。屬於子系統的裝置將在 /sys/subsystem/<name>/devices 的“devices”目錄中建立一個符號連結。

    如果 /sys/subsystem 存在,則可以忽略 /sys/bus/sys/class/sys/block。如果它不存在,您始終需要掃描所有三個地方,因為只要裝置仍然可以透過相同的子系統名稱訪問,核心就可以自由地將子系統從一個地方移動到另一個地方。

    假設 /sys/class/<subsystem>/sys/bus/<subsystem>,或者 /sys/block/sys/class/block 是不可互換的是應用程式中的一個 bug。

  • 位於 /sys/class/block/sys/subsystem/block 的轉換後的塊子系統將在同一級別包含磁碟和分割槽的連結,而不是在層次結構中。假設塊子系統僅包含磁碟而不是同一扁平列表中的分割槽裝置是應用程式中的一個 bug。

  • “device”-link 和 <subsystem>:<kernel name>-links

    永遠不要依賴 “device”-link。“device”-link 是舊佈局的解決方法,在這種佈局中,類裝置不是像匯流排裝置一樣在 /sys/devices/ 中建立的。如果裝置目錄的連結解析未在 /sys/devices/ 中結束,則可以使用 “device”-link 在 /sys/devices/ 中查詢父裝置。這是 “device”-link 的唯一有效用途;它絕不能作為元素出現在任何路徑中。假設 /sys/devices/ 中的裝置存在 “device”-link 是應用程式中的一個 bug。訪問 /sys/class/net/eth0/device 是應用程式中的一個 bug。

    永遠不要依賴於返回到 /sys/class 目錄的類特定的連結。這些連結也是一個解決方法,用於解決類裝置不是在 /sys/devices. 中建立的設計錯誤。如果裝置目錄不包含子裝置的目錄,則可以使用這些連結在 /sys/class. 中查詢子裝置。這是這些連結的唯一有效用途;它們絕不能作為元素出現在任何路徑中。假設 /sys/devices 樹中實際子裝置目錄的裝置存在這些連結是應用程式中的一個 bug。

    計劃在所有類裝置目錄都位於 /sys/devices. 中時刪除所有這些連結。

  • 裝置鏈中裝置的位置可能會改變。

    永遠不要依賴於 devpath 中的特定父裝置位置或父裝置鏈。核心可以自由地將裝置插入鏈中。您必須始終透過其子系統值請求您正在尋找的父裝置。您需要向上遍歷鏈,直到找到與預期子系統匹配的裝置。依賴於父裝置的特定位置或使用 ../ 訪問父鏈的相對路徑是應用程式中的一個 bug。

  • 在讀取和寫入 sysfs 裝置屬性檔案時,避免依賴

    儘可能避免依賴於特定的錯誤程式碼。 這最大限度地減少了與核心中錯誤處理實現的耦合。

    通常,讀取或寫入 sysfs 裝置屬性失敗應儘可能傳播錯誤。 常見錯誤包括但不限於:

    -EIO:不支援讀取或儲存操作,通常由 sysfs 系統本身返回,如果讀取或儲存指標為 NULL

    -ENXIO:讀取或儲存操作失敗

    如果沒有充分的理由,錯誤程式碼不會更改,如果對錯誤程式碼的更改導致使用者空間中斷,則會修復它,否則會恢復有問題的更改。

    但是,使用者空間應用程式可以預期,在給定屬性的上下文中,在沒有版本屬性更改的情況下,屬性檔案的格式和內容保持一致。