sysfs Device Attributes in Linux Kernel: DEVICE_ATTR Explained
Learn how kernel drivers expose read/write files under sysfs using device_attribute, updated for modern 6.x kernels
« Previous Lecture | Next Lecture »
Continuing our free Linux device drivers course, this tutorial covers sysfs device attributes in the Linux kernel, the mechanism drivers use to expose simple, human-readable read/write files under /sys. If you have ever run cat on a file in /sys/class or /sys/devices to read a hardware value, you have used a device attribute. By the end of this lecture you will be able to create your own sysfs attribute files the modern, kernel-recommended way.
What You Will Learn
Prerequisites
- Completion of the previous lecture on platform devices
- Basic understanding of the Linux Device Model (
struct device) - Comfort building and loading kernel modules
What Is sysfs?
sysfs is a virtual, in-memory filesystem, normally mounted at /sys, that exposes the kernel’s internal device model to user space as plain files and directories. Every struct device registered with the driver core automatically gets a directory in sysfs, and drivers can add extra files inside that directory to expose tunable parameters, status values, or simple counters, all readable with ordinary tools like cat and echo.
Anatomy of struct device_attribute
Each sysfs file backed by a device attribute is described by a small structure containing the file’s name, its permission bits, and two callback function pointers: one for reads and one for writes.
| attr (name + permissions) |
| show() — called on read |
| store() — called on write |
Rather than filling this structure in by hand, the kernel provides convenience macros. The most commonly used ones today are:
| Macro | Access | Requires |
|---|---|---|
| DEVICE_ATTR_RO(name) | Read only | name_show() |
| DEVICE_ATTR_WO(name) | Write only | name_store() |
| DEVICE_ATTR_RW(name) | Read and write | name_show() and name_store() |
Writing show() and store() Callbacks the Modern Way
Older kernel code frequently used plain sprintf() inside a show() callback. Current kernel guidelines recommend sysfs_emit() instead, since it automatically respects the one-page buffer limit that sysfs guarantees and avoids a class of buffer-overflow bugs. Here is an original example exposing a simple integer debug level as a read-write sysfs attribute.
#include <linux/device.h>
#include <linux/sysfs.h>
static int epdemo_debug_level;
static ssize_t debug_level_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%d\n", epdemo_debug_level);
}
static ssize_t debug_level_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int val, ret;
ret = kstrtoint(buf, 10, &val);
if (ret)
return ret;
if (val < 0 || val > 9)
return -EINVAL;
epdemo_debug_level = val;
return count;
}
static DEVICE_ATTR_RW(debug_level);
Note: Always validate input in store() with functions like kstrtoint() rather than trusting raw user input. Rejecting out-of-range values, as shown above, prevents the driver’s internal state from becoming inconsistent.
Creating and Removing the sysfs File
Once the attribute is defined, it must be attached to an actual device and cleaned up when the driver unloads.
ret = device_create_file(dev, &dev_attr_debug_level);
if (ret)
dev_err(dev, "failed to create sysfs attribute\n");
/* On cleanup */
device_remove_file(dev, &dev_attr_debug_level);
Read/Write Flow Between User Space and Kernel
| User runs cat / echo on sysfs file |
| ↓ |
| VFS routes call to sysfs |
| ↓ |
| Driver’s show() or store() callback runs |
Real-World Use Cases
- Exposing hardware sensor readings, such as temperature or voltage, as read-only attributes
- Tunable driver parameters like debug levels, polling intervals, or thresholds
- Triggering one-shot actions, such as a firmware reload, through a write-only attribute
Common Mistakes and Troubleshooting
| Mistake | Fix |
|---|---|
Using sprintf() in show() | Use sysfs_emit() to respect the sysfs page-size buffer limit |
| Not validating store() input | Use kstrtoint()/kstrtoul() and reject invalid ranges |
| Forgetting device_remove_file() on unload | Always pair create and remove calls |
| Setting overly permissive file modes | Only grant write access (0644 or stricter) where genuinely required |
Best Practices
- Prefer
sysfs_emit()oversprintf()/snprintf()in every new show() callback - Keep each sysfs file limited to a single, simple value, following the sysfs “one value per file” convention
- Always validate and range-check data received in store()
- Use attribute groups (
struct attribute_group) when a driver exposes many related files
Security Considerations
Any writable sysfs file is a potential entry point for a local attacker or a misbehaving user-space process. Never trust the contents of the buf parameter in store() blindly, always bound-check numeric input, and choose the narrowest file permission bits that satisfy the actual use case rather than defaulting to world-writable attributes.
Performance Considerations
sysfs callbacks should be lightweight and non-blocking wherever possible, since they may be called frequently by monitoring tools. Avoid heavy computation or long-running I/O directly inside show() or store(); offload such work to a workqueue if needed.
Summary: Key Takeaways
- sysfs exposes kernel device state to user space as simple files
struct device_attributepairs a file name with show()/store() callbacks- Use
DEVICE_ATTR_RW/RO/WOmacros instead of manual structure initialization - Prefer
sysfs_emit()oversprintf()on modern kernels - Always validate store() input and remove attributes on driver unload
Frequently Asked Questions
Q1. What is a sysfs device attribute?
It is a small structure pairing a sysfs file name and permissions with read (show) and write (store) callback functions.
Q2. Why use sysfs_emit() instead of sprintf()?
sysfs_emit() automatically enforces the one-page buffer limit that sysfs guarantees, preventing buffer overruns.
Q3. What is the difference between DEVICE_ATTR_RW and DEVICE_ATTR_RO?
DEVICE_ATTR_RW creates a file with both show() and store() callbacks; DEVICE_ATTR_RO only implements show().
Q4. How many values should one sysfs file hold?
By convention, exactly one value per file, to keep parsing simple and predictable for user space.
Q5. How do I remove a sysfs attribute?
Call device_remove_file() with the same device and attribute pointers used at creation.
Q6. Is this part of a free course?
Yes, this lecture is part of EmbeddedPathashala’s free Linux kernel and embedded systems course.
Continue Learning Linux Kernel Programming
This lecture is part of EmbeddedPathashala’s free Linux kernel development course covering device drivers, embedded systems, and Bluetooth/BLE programming.

2 Comments