Skip to main content What Should sysfs, debugfs, and procfs Expose? | IoT Worker

What Should sysfs, debugfs, and procfs Expose?

Linux drivers often expose information through text files in addition to /dev/xxx and ioctl:

/sys/...
/sys/kernel/debug/...
/proc/...

They all support cat and echo, so it is tempting to place state, configuration, debug knobs, and statistics wherever convenient. That convenience becomes interface debt: test scripts depend on debugfs, product applications parse procfs, sysfs formats cannot be changed, and field tools do not know which interface is stable.

A practical boundary is:

sysfs: stable attribute ABI under the device model
debugfs: debugging and diagnostic entry points
procfs: global kernel information, process information, or historical compatibility

These are not three equivalent directories. They carry different levels of commitment.

sysfs Exposes Stable Attributes

sysfs is mounted at /sys and is closely tied to the Linux device model. Devices, drivers, buses, classes, and attributes can appear there.

Driver sysfs files should usually expose stable device attributes or controls, such as:

  • current mode
  • enable state
  • firmware version
  • simple readings such as temperature, voltage, or counters
  • read-only capability descriptions
  • clearly defined configuration values

The key property of sysfs is not that it is text. It is ABI stability. User-space scripts, udev rules, monitoring agents, and product applications may depend on it for years.

sysfs files should follow a few rules:

  • one file represents one attribute
  • simple format, preferably one line
  • clear units and value ranges
  • stable read/write semantics
  • meaningful error returns
  • no complex binary protocol
  • no frequent format changes

Once a sysfs interface enters product scripts, treat it as ABI. Do not casually rename it, change units, or change enum values.

sysfs Is Not a Complex Command Channel

sysfs is often abused as a command interface:

echo "reset 1 force now" > /sys/.../control
echo "dump all raw hex verbose" > /sys/.../debug

The semantics grow quickly. One file carries multiple commands, parameters, and return formats, and becomes a private protocol without versioning.

If user space needs high-rate data, complex commands, binary structures, or long transactions, consider:

  • char devices
  • netlink
  • ioctl
  • configfs
  • a proper subsystem interface
  • a user-space daemon with a stable API

sysfs is best for small, stable attributes. It should not become the driver’s universal console.

debugfs Is for Debugging, Not Product ABI

debugfs is usually mounted at /sys/kernel/debug. It is designed for debugging the kernel and drivers.

Drivers can place these in debugfs:

  • internal state snapshots
  • register dumps
  • debug counters
  • trace switches
  • fault injection
  • development diagnostics
  • statistics whose format should not be stable

debugfs is flexible: formats can be looser, directory layout can follow driver internals, and writable debug knobs are acceptable.

The cost of that freedom is that debugfs should not be treated as a stable product interface. It may be disabled in production kernels, blocked by permissions, or changed as debugging needs evolve.

Product applications should not depend on debugfs. Factory tests or field diagnostic tools may use it, but they should recognize that it is a diagnostic dependency, not a long-term ABI.

debugfs Still Needs Risk Control

debugfs is not risk-free just because it is for debugging.

Common problems include:

  • exposing sensitive registers or key-related state
  • writable entries that put hardware into dangerous states
  • large dumps causing memory or latency problems
  • reads without locking racing with interrupts, remove, or runtime PM
  • production images accidentally exposing debug controls
  • field scripts depending on unstable formats

debugfs files still need lifecycle handling. Directories must be removed when the device is removed. Runtime-suspended devices must either be resumed before hardware access or return a clear error. “Debug only” is not a reason to bypass concurrency and power management.

procfs is mounted at /proc. Historically, many drivers and subsystems exposed information there, but modern drivers should not use procfs as the default device attribute interface.

procfs fits:

  • process-related information
  • global kernel state
  • subsystem-level statistics
  • historical compatibility interfaces
  • system views that do not naturally belong to one device

Files such as /proc/meminfo, /proc/interrupts, and /proc/net/* are global views, not single attributes of one device.

If the content belongs to a device, prefer sysfs. If it is internal debug state, prefer debugfs. If it is global state or compatibility, procfs may be appropriate.

Choosing Between Them

Ask these questions:

Will product user space depend on this for a long time?
-> yes: prefer sysfs or an official subsystem ABI

Is this only for debug, dump, diagnosis, or temporary knobs?
-> yes: debugfs

Is this global kernel/process/subsystem information, or an existing procfs compatibility interface?
-> yes: procfs

Then look at the data shape:

  • single stable attribute: sysfs
  • multi-line debug state: debugfs
  • register dump: debugfs
  • device configuration: sysfs or subsystem interface
  • high-rate data stream: not sysfs/debugfs/procfs
  • complex transaction: not sysfs/debugfs/procfs
  • global statistics: procfs, debugfs, or an existing subsystem interface

The wrong choice is hard to undo. Once user space depends on a temporary file, it becomes a de facto ABI.

Do Not Bypass Existing Subsystem Interfaces

Many drivers should not invent new sysfs, debugfs, or procfs files because a kernel subsystem already provides a standard interface.

Examples:

  • input devices use the input subsystem
  • network devices use netdev, ethtool, and rtnetlink
  • IIO devices use IIO sysfs, buffers, and events
  • LEDs use the LED class
  • hardware monitors use hwmon sysfs
  • watchdogs use the watchdog subsystem
  • regulator, clock, and GPIO frameworks have their own APIs and debug views

Before creating /sys/.../my_status, check whether a standard subsystem ABI exists. Reusing it brings user-space tools, permissions, tests, and documentation.

Interface Semantics Must Be Clear

Wherever the file lives, a driver user-space interface should answer:

  • who reads or writes it
  • what units it uses
  • whether the value is instantaneous, cumulative, or configured
  • whether writes take effect immediately
  • what errors mean
  • what happens during suspend or remove
  • how concurrent writers are handled
  • whether the format is stable

This is especially important for sysfs because scripts, udev, and applications may freeze the format.

debugfs can be looser, but debug controls should not compromise product safety or stability.

Debugging Interface Misuse

When user space depends on /sys, /proc, or /sys/kernel/debug, inspect this chain:

is this file required by product logic
-> is the format stable
-> is there an existing subsystem ABI
-> is it only debug data
-> is debugfs enabled in production
-> are permissions and security boundaries reasonable
-> are remove / suspend races handled

Useful commands include:

find /sys -name '*name*'
udevadm info /sys/...
mount | grep debugfs
ls /sys/kernel/debug
cat /proc/mounts

If a product feature depends on a debugfs file, consider moving it to a formal ABI. If a sysfs file only dumps temporary register state, it likely belongs in debugfs.

The Real Boundary Is Commitment Level

The technical differences between sysfs, debugfs, and procfs matter. The engineering boundary is the level of commitment.

sysfs is for stable device attributes. debugfs is for diagnostics. procfs is for global and historical compatibility views. Treating debug interfaces as product interfaces makes kernel upgrades and production security harder. Putting complex protocols into sysfs creates ABI maintenance burden.

When exposing a driver interface to user space, decide how long the file must be supported before deciding where it belongs.