sysfs in Linux Kernel: The Correct Way to Expose Driver Attributes (2026 Guide)-Free Linux Kernel Development Course

← Previous Lecture  |  Next Lecture →

sysfs in Linux Kernel: The Correct Way to Expose Driver Attributes (2026 Guide)
Understand the modern device model, kernfs, and how to create sysfs attribute files the way current in-tree drivers actually do it
Level: Beginner–Intermediate
Kernel: 6.x LTS
Read Time: 14 min

Every professional Linux device driver exposes at least a few tunable settings or status values to user space, and the kernel community has one clear answer for how to do it: sysfs in Linux kernel development is the sanctioned, upstream-approved interface for device attributes — not procfs, and not a custom character device ioctl. This lesson explains what sysfs actually is, how it connects to the modern device model, and how to create attribute files using the APIs that are current on kernel 6.x.

free linux kernel development course free embedded systems course sysfs tutorial device_create_file Linux device model

What You Will Learn

  • What sysfs is and how it is backed by kernfs internally
  • The different “viewports” sysfs offers into the device model
  • How to create a sysfs attribute file with device_create_file()
  • Why modern drivers prefer attribute groups over one-off file creation
  • The “one value per file” rule and why it exists

Prerequisites

  • Completion of the previous procfs lecture in this free Linux kernel development course
  • Basic understanding of struct device and the Linux Device Model (bus, device, driver)
  • A working kernel module build setup

What Is sysfs?

sysfs is a virtual, in-memory filesystem, conventionally mounted at /sys, that exposes the kernel’s internal representation of every bus, device, and driver currently active on the system. Since kernel 3.14, sysfs has been implemented on top of a lightweight, generic virtual filesystem layer called kernfs, which was split out specifically so that sysfs and cgroupfs could share the same low-level tree-management code. As a driver author you never touch kernfs directly — you work through the sysfs and device-model APIs, and the kernel generates and tears down the actual files for you automatically as devices appear and disappear.

The Viewports Into the Device Model

Rather than one flat list, sysfs organizes the same underlying devices into several different views, each useful for a different purpose.

Viewport Path Purpose
Devices /sys/devices The canonical, authoritative tree of every device
Bus /sys/bus Devices grouped by the bus they are attached to (platform, USB, I2C, SPI…)
Class /sys/class Devices grouped by function (network, input, backlight…) regardless of bus
Block /sys/block Legacy view of block storage devices
How the same device appears in two viewports
/sys/devices/…/mydev ↔ Single real device object in the kernel ↔ /sys/class/mydrv/mydev (symlink)

Why sysfs, Not procfs, for Drivers

procfs has no structural convention: any driver could put arbitrarily formatted multi-value text into a single file, which made scripting against it fragile. sysfs enforces a simple, strict convention instead: one value per file. This single rule is what allows generic user-space tools such as udev and system monitoring utilities to reliably read and write individual attributes without parsing free-form text.

Creating a sysfs Attribute File

The classic, still-supported way to create a single sysfs file for a device is device_create_file(), which takes a struct device * and a struct device_attribute * describing the file’s name, permissions, and show/store callbacks.

#include <linux/device.h>

static ssize_t temperature_show(struct device *dev,
                                 struct device_attribute *attr,
                                 char *buf)
{
    int temp_millideg = 42000; /* read from real hardware here */

    return sysfs_emit(buf, "%d\n", temp_millideg);
}

static DEVICE_ATTR_RO(temperature);

static int mydrv_probe(struct platform_device *pdev)
{
    int ret;

    ret = device_create_file(&pdev->dev, &dev_attr_temperature);
    if (ret)
        return ret;

    return 0;
}

Two modernization notes worth calling out compared to older references:

  • sysfs_emit() replaced the older pattern of calling sprintf() directly into the sysfs buffer. It was introduced to guarantee the write never exceeds the fixed PAGE_SIZE buffer sysfs hands you, closing a whole class of overflow bugs.
  • DEVICE_ATTR_RO() / DEVICE_ATTR_RW() macros are now preferred over manually filling a device_attribute struct, since they automatically generate the correctly named dev_attr_* variable and wire up permissions consistently.

Grouping Attributes Instead of Creating Them One by One

Real-world drivers rarely stop at one attribute. Calling device_create_file() repeatedly for every attribute, and remembering to call device_remove_file() for each one on teardown, is error-prone. The modern recommended pattern is to bundle related attributes into a struct attribute_group and pass that group to the device at registration time, so the kernel core creates and destroys all of them together as a single atomic step.

Architecture: Device Model Building Blocks

Bus → Device → Driver relationship
Bus
(platform, I2C, USB…)
→ Device
(struct device)
→ Driver bound to it
(struct device_driver)

Every specialized device type — platform_device, i2c_client, usb_device, and similar structures — embeds a generic struct device inside itself. That embedded structure is what you pass into sysfs attribute APIs, which is why sysfs integrates so cleanly regardless of what kind of bus your hardware sits on.

Real-World Use Case

A typical embedded sensor driver exposes read-only attributes such as current temperature or firmware version, and read-write attributes such as sampling rate or power mode, all as separate sysfs files grouped under the device’s own directory. This lets a system administrator or a shell script simply cat or echo a value without writing any custom tooling.

Common Mistakes and Troubleshooting

Mistake Fix
Using sprintf() instead of sysfs_emit() in a show callback Switch to sysfs_emit() to stay within the PAGE_SIZE buffer safely
Packing multiple values into one attribute file Split into one file per value to follow sysfs convention
Forgetting to remove attribute files on device removal Use attribute groups so removal happens automatically with the device

Best Practices

  • Prefer attribute groups over individual device_create_file() calls for anything beyond one attribute
  • Always use sysfs_emit() in show callbacks on current kernels
  • Keep each file to a single, simply-parsable value
  • Set permissions as restrictively as the use case allows

Performance Considerations

sysfs reads and writes go through user-context callbacks, so avoid blocking operations or heavy computation inside show/store functions; cache values where possible and refresh them on a timer or interrupt instead of doing expensive work on every read.

Security Considerations

Never expose raw kernel addresses through a sysfs file. Validate all input length and content in store callbacks before acting on it, since any user with file permission can write arbitrary strings, and always double-check the permission bits you assign match the sensitivity of the underlying operation.

Summary / Key Takeaways

  • sysfs is the kernel-recommended interface for device attributes, built on kernfs since kernel 3.14
  • It exposes the same devices through multiple viewports: devices, bus, class, and block
  • Use sysfs_emit() and DEVICE_ATTR_* macros on current kernels instead of older sprintf-based patterns
  • Group related attributes with struct attribute_group for cleaner creation and teardown

Conclusion

With this lesson, you now understand sysfs in Linux kernel programming well enough to expose clean, convention-following attribute files from your own drivers. Combined with the previous procfs lecture, you have the full picture of why the kernel community moved driver interfacing away from procfs and standardized on sysfs and the device model. Continue with the next lecture in this free Linux kernel development course to see a complete platform device example built from scratch.

Frequently Asked Questions

Q1. What is the difference between sysfs and procfs?

procfs is a general text-based interface historically used for process and misc kernel info, while sysfs is a structured, one-value-per-file interface specifically tied to the device model and recommended for driver attributes.

Q2. Is sysfs backed by a real filesystem on disk?

No, sysfs is entirely in-memory and virtual, generated dynamically as devices appear and removed as they disappear.

Q3. What is kernfs?

kernfs is a shared, generic virtual filesystem layer introduced in kernel 3.14 that both sysfs and cgroupfs build on top of.

Q4. Why should I use sysfs_emit() instead of sprintf()?

sysfs_emit() guarantees the output never exceeds the fixed PAGE_SIZE buffer that sysfs provides, preventing a class of buffer overflow bugs common in older driver code.

Q5. Can one sysfs file hold multiple values?

Technically yes, but it violates sysfs convention and breaks compatibility with generic tooling; the accepted rule is one value per file.

Q6. What are attribute groups used for?

They let you register and unregister a whole set of related sysfs attributes as a single atomic operation instead of managing each file individually.

Q7. Do I need a real hardware device to experiment with sysfs?

No, you can create a simple platform device in your own module purely to obtain a valid struct device to attach sysfs files to, which is exactly what the next lecture demonstrates.

This lesson is part of EmbeddedPathashala’s free Linux kernel development course, part of our broader free embedded systems course covering drivers from first principles.

Browse the Free Course Next Lecture: Platform Devices →

← Previous Lecture  |  Next Lecture →

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *