/sys: Explanation & Insights
sysfs is a virtual filesystem that exposes the Linux kernel's model of devices, drivers, and buses as a tree of small readable files, most holding a single value each.
What It Is
/sys is the kernel's own model of your hardware, turned inside out so you can walk through it with cd.
Every disk, every network card, every CPU core, every USB port, the battery in a laptop — the kernel keeps an internal picture of all of it, how each piece connects to the next, and what state each one is in. /sys takes that picture and lays it out as directories and files. It isn't a description of your hardware written down somewhere and left to go stale; it's the kernel's live model, projected outward as folders you can list. Walk into /sys and you are walking through the kernel's understanding of the machine, rebuilt fresh every time you look.
Like its older sibling /proc, it's a virtual filesystem — nothing under here sits on a disk. It's assembled out of kernel memory on demand and vanishes the moment the machine powers off. You can see it's something unusual right from how it's mounted:
$ mount | grep sysfs
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
Look at those three flags in the middle — nosuid, nodev, noexec. They mean nothing in /sys can be run as a program, nothing here can pretend to be a device node, and nothing can quietly gain privileges. That's deliberate: /sys is pure information, and the kernel bolts the doors so nobody can smuggle an executable into what's meant to be a wall of facts.
And facts is exactly what they are. Reach into the tree and read one:
$ cat /sys/class/net/lo/mtu
65536
That's the whole file. One number, sitting alone, no label, no heading, no units — you're expected to know from the path (net/lo/mtu) that you asked the loopback interface for its maximum packet size, and the file just hands you the answer. Read the same interface's hardware address and you get another lonely fact:
$ cat /sys/class/net/lo/address
00:00:00:00:00:00
All zeros — and honestly so. lo is the loopback interface, the network the machine uses to talk to itself, and it has no card, no cable, no chip. A real network card would report the address burned into its silicon here; loopback has no hardware to name, so it reports the plain truth: nothing. These are the two things to hold onto about /sys — the values are real and live, and each one lives in its own tiny file with the meaning carried by the name above it.
Why It Matters
Here's the reason it deserves your attention even though you may never have opened it: /sys is upstream of half the things you already rely on.
Take /dev, the directory where your disks and terminals show up as files. The names in there — that a drive is /dev/nvme0n1 and not /dev/sda, that it has the right owner and permissions — are not decided by /dev itself. They're decided by udev, and udev works them out by reading /sys. When you plug in a USB stick and it appears a second later with a sensible name, what happened is that the kernel registered the new hardware into /sys, udev noticed, read the device's description straight out of the sysfs tree, and named it accordingly. Every stable disk name you've ever leaned on traces back through udev to a handful of files under here.
It's also where the kernel reports the state of hardware that has nothing to do with disks or networks. A laptop's power situation, for instance, is just more files:
$ ls /sys/class/power_supply
AC
BAT0
ucsi-source-psy-USBC000:001
ucsi-source-psy-USBC000:002
There's the mains adapter (AC), the battery (BAT0), and a couple of USB-C ports that can themselves deliver power. Read inside BAT0 and the kernel will tell you its charge, its health, whether it's charging right now — each as its own small file. The temperature and fan-speed readings a monitoring tool shows you come from exactly this kind of file, tucked under /sys/class/hwmon. When anything on Linux tells you how hot your CPU is running, it opened a file in here to find out.
And /sys isn't strictly read-only. A carefully chosen set of files are writable — the kernel's live tuning knobs — and writing to one changes the running system on the spot, no reboot required. That's a genuine everyday power, and a genuine everyday foot-gun; we'll come to both.
What's Inside
List the top of the tree and you get a dozen doorways, each opening onto a different way of looking at the same machine:
$ ls -l /sys
drwxr-xr-x 2 root root 0 Jul 7 08:54 block
drwxr-xr-x 52 root root 0 Jul 7 08:54 bus
drwxr-xr-x 76 root root 0 Jul 7 08:54 class
drwxr-xr-x 4 root root 0 Jul 7 08:54 dev
drwxr-xr-x 29 root root 0 Jul 7 08:54 devices
drwxr-xr-x 6 root root 0 Jul 7 08:54 firmware
drwxr-xr-x 8 root root 0 Jul 7 08:54 fs
drwxr-xr-x 2 root root 0 Jul 7 08:54 hypervisor
drwxr-xr-x 16 root root 0 Jul 7 08:54 kernel
drwxr-xr-x 352 root root 0 Jul 7 08:54 module
drwxr-xr-x 3 root root 0 Jul 7 08:54 power
You won't reach for all of these often, but knowing which one opens onto what is the difference between walking straight to a fact and wandering the tree hoping to trip over it:
devices— the real one. The complete tree of every device the kernel knows about, arranged by how the hardware is physically wired together. Everything else up here is, in one way or another, a shortcut into this.block— every block device (disks, partitions, volumes) gathered in one place, so you don't have to go hunting throughdevicesfor your drives.class— devices grouped by what they are: all the network interfaces undernet, all the disks underblock, all the power supplies underpower_supply, regardless of where they're plugged in.bus— devices grouped by which bus they hang off: everything on the PCI bus, everything on USB, and so on.dev— a lookup table keyed by the major/minor device numbers you'd see in/dev, for going from a number back to a device.module— one directory per loaded kernel module, with its parameters exposed as files (three hundred and fifty-two of them on this box — a fair measure of how much a modern kernel loads).firmware,fs,kernel,power,hypervisor— the firmware tables (ACPI and friends), per-filesystem tunables, assorted kernel internals, the system-wide power/suspend controls, and a corner that only fills in when the machine is running as a virtual guest.
The bus directory alone shows you how many kinds of interconnect a single computer juggles:
$ ls /sys/bus | head -10
acpi
auxiliary
cec
clockevents
clocksource
container
coreboot
cpu
cxl
dax
Most people picture a computer as having "a bus." It has dozens.
Three Maps of the Same Machine
Now the part that, once you see it, changes how you read the whole directory.
Look closely at one of those grouped views — class/block, the tidy folder of all your disks:
$ ls -l /sys/class/block
lrwxrwxrwx 1 root root 0 Jul 7 08:54 dm-0 -> ../../devices/virtual/block/dm-0
lrwxrwxrwx 1 root root 0 Jul 7 08:54 dm-1 -> ../../devices/virtual/block/dm-1
lrwxrwxrwx 1 root root 0 Jul 7 08:54 nvme0n1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:57:00.0/nvme/nvme0/nvme0n1
lrwxrwxrwx 1 root root 0 Jul 7 08:54 nvme0n1p1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:57:00.0/nvme/nvme0/nvme0n1/nvme0n1p1
Every single entry is an l — a symlink. Not one of them is really here. nvme0n1, your NVMe disk, isn't a disk sitting in a folder of disks; it's a signpost, and it points a very long way off: down through devices/, onto PCI bus 0000:00, into slot 1d.0, across to the device at 57:00.0, to the NVMe controller, to the nvme0 instance, and finally to the disk itself. That path is the disk's actual home — its real address, spelled out in the language of how it's plugged into the machine.
So class/block was never a place where disks live. It's a wall of signposts, all pointing into devices/, sorted by type for your convenience.
And bus/pci/devices is another wall of signposts to the very same places, sorted a different way:
$ ls -l /sys/bus/pci/devices | head -4
lrwxrwxrwx 1 root root 0 Jul 7 11:03 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0
lrwxrwxrwx 1 root root 0 Jul 7 10:50 0000:00:02.0 -> ../../../devices/pci0000:00/0000:00:02.0
lrwxrwxrwx 1 root root 0 Jul 7 11:03 0000:00:04.0 -> ../../../devices/pci0000:00/0000:00:04.0
Same trick, same destination — links diving back into devices/ — only this time filed by which slot on the PCI bus each one occupies.
Here is the thing worth carrying out of this page. Your one NVMe disk appears in /sys three times over: once in class/block (filed under disks), once in bus/pci/devices (filed under what it's plugged into), and once in devices/ (where it actually is). You could be forgiven, wandering through, for thinking you had three of them. But tug on any of the three ropes and they're all knotted to the same single point deep in devices/ — one real object, seen from three angles. class/ and bus/ are just indexes; devices/ is the book. And like any good index, they don't hold the thing itself — they only tell you which page to turn to.
That's why devices/ paths look so alien and the others look so neat: the neat ones were arranged for you, alphabetised by category. The alien one was arranged for the hardware, and it reads like a set of directions because that is precisely what it is — the route from the processor to the part, hop by hop.
Writing to /sys: The Tunables
A slice of /sys is writable, and this is where it stops being a window and becomes a control panel. The classic example is the CPU frequency governor — the policy that decides whether your cores run flat-out or throttle down to save power. It lives here:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
Read it and you get the current policy (powersave, performance, ondemand, and so on). Write to it and you change how the processor behaves, immediately, while the system runs:
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
No reboot, no config file, no daemon restart — the kernel reads the new value and acts on it before the prompt comes back. Whole categories of live tuning work this way: disabling a flaky device, changing a scheduler's behaviour, adjusting how aggressively the kernel reclaims memory. It's one of the quiet superpowers of running Linux — the machine will let you reach in and adjust it mid-flight.
Danger
The same door that lets you tune a running kernel lets you wreck it. Writing the wrong value to the wrong sysfs file can disable a disk, knock a network card offline, or hang the box outright — and there is no undo and often no warning, just a system that stops behaving. Worse, an
echointo/sysalmost never survives a reboot, so a "fix" you apply by hand vanishes on restart and a mistake you think you reverted can come back. Read the file before you write it, know exactly what the value means, and put anything you want to keep in the proper place (asysctlconfig, a udev rule, a boot parameter) rather than typing it into the live tree and hoping.
How I Inspect It
There's no special program for /sys. That's the whole point — it was built so the tools you already own would simply work on it, the same bet /proc makes. The moves I reach for:
# What kinds of thing does the kernel model? Start at the top.
ls /sys
# All the disks in one place, then follow one to its real home
ls -l /sys/class/block
readlink -f /sys/class/block/nvme0n1
# Read a live hardware fact (one value per file)
cat /sys/class/net/eth0/speed # link speed in Mb/s
cat /sys/class/net/eth0/operstate # up or down, right now
# Everything the kernel knows about one device, as files
ls /sys/class/net/eth0/
# The current CPU frequency policy
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
For disks specifically, you'll almost always reach for lsblk instead of grubbing through /sys by hand — but it's worth knowing that lsblk is itself just a friendly reader of /sys/block, the same way top is a reader of /proc. The nice tool and the raw tree are looking at the identical facts; one of them just draws you a table.
Note
readlink -f(orrealpath) is the single most useful command for making sense of/sys. Because so much of the tree is symlinks intodevices/, following a link to its true target is how you find out where a device physically is — which PCI slot, which USB port, which controller. When two "identical" disks are behaving differently and you need to know which is which, chasing the symlink is how you tell them apart.
History and Philosophy
/sys is younger than almost everything around it, and it was built on purpose to fix a mess.
For its first twenty years, Linux had /proc and used it for everything — process information, yes, but also memory stats, hardware details, tuning knobs, whatever needed exposing. It grew like a shed that everyone kept throwing tools into, and it grew without rules. One file might hand you a neat single number; the next crammed a whole table, mixed formats, and three unrelated facts into one blob you had to parse with care. It worked, but it was nobody's idea of tidy.
So when the kernel developers overhauled how Linux models hardware for the 2.6 release, they built a new filesystem to go with it, and this time they wrote down the rules first. The work was led by a developer named Patrick Mochel, starting in the 2.5 development series around late 2002; it was first called driverfs, then renamed sysfs once it outgrew drivers and started modelling the whole system. It shipped to the world in /sys with Linux 2.6 at the end of 2003 — and, not by coincidence, udev arrived at the same moment, because udev was built to read it.
The rule they wrote down is the one you met at the top of this page: one value per file. No tables, no mixed formats, no cramming — a sysfs attribute holds a single fact in plain text, and if you want another fact you open another file. The kernel's own documentation puts it bluntly: mixing types, multiple values, and fancy formatting in one file are all "heavily frowned upon." It's the discipline /proc never had, imposed from day one, and it's why writing a program to read /sys is so much less painful than parsing /proc — there's simply nothing to parse. (This is also the source of a lasting confusion worth clearing up: the kernel tuning knobs under /proc/sys are not part of /sys at all. Same three letters, different filesystems, born a decade apart. /proc/sys is the sysctl tree and belongs to /proc; /sys is sysfs.)
Underneath, there's a fact about /sys that's easy to walk right past. To actually run your machine, the kernel has to keep track of every part of it in memory — and for each device it holds a small bundle of bookkeeping: what the thing is, what it's plugged into, which driver is minding it. Those bundles are wired to each other exactly the way the hardware is: this device sits on that bus, that bus hangs off this bridge, and each bundle holds a pointer to its neighbours. The kernel has a name for one of these bundles — a kobject — and the running machine is, in good part, a great mesh of them referring to one another.
Now the join. When the kernel creates one of these bundles, sysfs hands it a directory — not a directory that describes it, a directory that is it. So the tree you've been walking under /sys was never a report the kernel wrote out about its hardware; it's those very bundles, the live ones the kernel is running your machine on, with their pointers turned into folders and symlinks. Almost every other window a computer gives you onto itself is a printout, generated after the fact and already a little stale by the time you read it. /sys is the rare one where the thing you're reading and the thing the machine is running on are the same thing. When you cd from a bus into a device, you're stepping along a pointer the kernel itself follows. You're not looking at a map of the kernel's mind. You're walking around inside it.
Cheat Sheet
| Command | What it tells you |
|---|---|
ls /sys |
The top-level views: devices, class, bus, block, and the rest |
ls -l /sys/class/block |
Every disk/partition, each a symlink into devices/ |
readlink -f /sys/class/block/nvme0n1 |
A device's real physical path (which slot/controller it is) |
cat /sys/class/net/<if>/address |
An interface's hardware (MAC) address |
cat /sys/class/net/<if>/speed |
Link speed in Mb/s |
cat /sys/class/net/<if>/operstate |
Whether the link is up or down right now |
ls /sys/class/power_supply |
Batteries, AC adapters, USB-C power sources |
ls /sys/bus |
Every kind of bus the machine has (PCI, USB, and dozens more) |
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor |
The current CPU frequency policy |
mount \| grep sysfs |
Confirm /sys is mounted, and see its hardening flags |
See Also
/proc— the older virtual filesystem, the ad-hoc predecessor/syswas built to be the disciplined answer to/dev— the device files that udev creates and names by reading/sys- udev — the daemon that turns sysfs descriptions into
/devnames and permissions - The root directory — where
/syshangs, and the tree it all descends from - kernel — whose live objects
/sysprojects outward as folders - PCI — the bus whose addresses give
devices/paths their strange shape - symlink — what nearly every entry under
class/andbus/really is lsblk— the friendly reader of/sys/block- sysctl — the tuning knobs under
/proc/sys, often confused with/sys
Every fact about your hardware's health — how hot the CPU is running, whether a fan is slowing, a disk starting to go — is sitting in one of these files right now, waiting for something to open it. Is anything?
CleverUptime watches the hardware facts that live in these files — CPU temperature, fan speed, the disks your data sits on — and tells you in plain words the moment one starts to drift, so you hear it from a dashboard instead of from a dead machine.
Want to see your own server's health right now? One command, no signup, no install.