Buffer vs Cache
The Common Misconception#
Buffer is for write, Cache is for read → WRONG
Both go through the kernel’s page-allocator-backed cache, and both serve reads and writes. The real distinction is what kind of data each one holds, and where that data lives on disk:
- Buffer caches block-device I/O — filesystem metadata (superblock, inode tables, directory blocks, journal, …)
- Cache (the
cachecolumn infree) caches file content and kernel object slabs (dentry/inode caches)
Once you internalise that, the rest follows.
The Strict Definitions#
free’s output is the friendly summary; /proc/meminfo is the source of truth.
┌─────────────────────────────────────────────┐
│ Disk (/dev/vda1) │
│ │
│ ┌───────────┐ ┌─────────────────┐ │
│ │ Metadata │ │ File Content │ │
│ │ (the map) │ │ (the treasure) │ │
│ └─────┬─────┘ └────────┬────────┘ │
└────────┼────────────────────────┼───────────┘
│ │
▼ ▼
┌────────┐ ┌────────────┐
│ Buffer │ │ Page Cache │
│ │ │ │
│ Buffers│ │ Cached │ ← /proc/meminfo
└────────┘ └────────────┘
+
┌────────────────┐
│ Reclaimable │
│ Slab (dentry / │
│ inode caches) │
│ SReclaimable │ ← /proc/meminfo
└────────────────┘
◄──── "cache" in free ────►
| Term | Meaning | Source field |
|---|---|---|
| Buffer | Block-device I/O cache (filesystem metadata) | Buffers |
| Page Cache | File-backed pages: regular file content + tmpfs/shmem | Cached |
| Reclaimable Slab | Kernel object caches the kernel will hand back under pressure (dentry, inode, …) | SReclaimable |
cache (in free) |
Page Cache + Reclaimable Slab | Cached + SReclaimable |
buffers (in free) |
Buffer | Buffers |
Cache ≠ Page Cache. “Page cache” is a strict kernel subsystem (
Cached). “Cache” as reported byfreeis broader — it bundles page cache and reclaimable kernel slabs.
Mapping free ↔ /proc/meminfo#
$ free
total used free shared buff/cache available
Mem: 980508 183624 74136 348 722748 631876
$ cat /proc/meminfo | grep -E "^(Buffers|Cached|SReclaimable):"
Buffers: 85092 kB
Cached: 571860 kB
SReclaimable: 65796 kB
The arithmetic:
buffers (free) = Buffers = 85092 kB
cache (free) = Cached + SReclaimable = 571860 + 65796 = 637656 kB
buff/cache (free) = Buffers + Cached + SReclaimable = 722748 kB ✓
(Older free versions print buffers and cache as separate columns; newer ones merge them into buff/cache. Use free -w to see them split.)
What’s Inside Each Region#
| Region | What it caches | Examples | Grows when… |
|---|---|---|---|
Buffer (Buffers) |
Raw on-disk metadata blocks (read via the block device) | Superblock block, inode table blocks (raw bytes), directory data blocks (raw (name, inode#) entries), free-block bitmap, ext4 journal blocks |
mount, mkfs, fsck, dd if=/dev/vda1, opening many files |
Page Cache (Cached) |
File-backed pages | /var/log/syslog content, mmap’d files, tmpfs / shmem pages |
cat file, read(), write(), mmap |
Reclaimable Slab (SReclaimable) |
Parsed in-memory kernel structs the kernel can drop on demand | struct dentry (no on-disk form — parsed pathname component), struct inode (parsed from inode-table block, with extra runtime state), other reclaimable kmem |
ls, find, stat — anything that walks the filesystem tree |
Why the apparent overlap? “Inode” and “directory” each have two cache forms: the raw on-disk block lives in Buffer, while the parsed kernel struct (
struct inode,struct dentry) lives in Reclaimable Slab. The dentry is special — it has no on-disk form; what’s on disk is the directory’s data block, and the dentry is purely the in-memory parsed result.
Disk Memory
──── ──────
[ inode table block ] ──read()────► [ Buffer page ] ← raw bytes
│
│ parse
▼
[ struct inode ] ← Reclaimable Slab
(in inode_cache slab)
[ directory data block ] ──read()──► [ Buffer page ] ← raw bytes
│
│ parse
▼
[ struct dentry ] ← Reclaimable Slab
(in dentry slab)
A Concrete Example: cat /home/user/file.txt#
① lookup inode of "/" → Buffer (superblock, root inode block)
→ Slab (dentry "/" + inode struct)
② lookup "home" in "/" → Buffer (directory data block of "/")
→ Slab (dentry "home" + inode struct)
③ lookup "user" in "home" → Buffer (directory data block of "home")
→ Slab (dentry "user" + inode struct)
④ lookup "file.txt" in "user" → Buffer (directory block + inode block)
→ Slab (dentry "file.txt" + inode struct)
⑤ inode extent tree → blocks [1024, 1025, 1026]
⑥ read blocks 1024–1026 → Page Cache (the actual file bytes)
│
▼
copy_to_user() → terminal shows the content
Steps ①–④ are split between Buffer (raw on-disk metadata blocks) and Reclaimable Slab (the in-memory dentry/inode structs the VFS hands back on the next lookup). Step ⑥ is the only Page Cache work — the file content the user actually sees.
For a small file, the kernel does more metadata I/O than content I/O — it’s just invisible to you.
Verify with free + slabtop#
# baseline: drop everything
$ echo 3 > /proc/sys/vm/drop_caches && free -w
total used free shared buffers cache available
Mem: 980508 183624 750000 348 2000 44884 750000
# (1) read a FILE → page cache grows
$ cat /var/log/syslog > /dev/null && free -w
total used free shared buffers cache available
Mem: 980508 183624 700000 348 2000 94884 750000
# ↑
# page cache up
# (2) read raw BLOCK DEVICE → buffer grows
$ dd if=/dev/vda1 of=/dev/null bs=1M count=64 && free -w
total used free shared buffers cache available
Mem: 980508 183624 634000 348 67000 94884 750000
# ↑
# buffer up
# (3) walk a directory tree → reclaimable slab (dentries/inodes) grows
$ find /usr > /dev/null && free -w
total used free shared buffers cache available
Mem: 980508 183624 580000 348 67000 148884 750000
# ↑
# reclaimable slab up
# cross-check with slabtop
$ slabtop -o | head -5
Active / Total Objects (% used) : 412350 / 521240 (79.1%)
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
94350 76935 81% 0.19K 4493 21 17972K dentry
32760 31200 95% 1.05K 1170 28 37440K ext4_inode_cache
drop_caches Semantics#
echo 1 > /proc/sys/vm/drop_caches # page cache (incl. buffer pages — see note)
echo 2 > /proc/sys/vm/drop_caches # dentries + inodes (reclaimable slab)
echo 3 > /proc/sys/vm/drop_caches # both
| Value | Drops | free columns affected |
|---|---|---|
1 |
Page cache pages (which also backs buffers since 2.4+) | buffers, cache (the page-cache part) |
2 |
Dentry cache + inode cache (reclaimable slab) | cache (the slab part) |
3 |
Everything above | buffers + cache |
Use only for testing/troubleshooting. The kernel reclaims these automatically under memory pressure — manually dropping them in production just makes the next access slower.
Implementation Note: Buffer Is Backed by Page Cache (≥ Linux 2.4)#
Historically, Linux had two separate memory pools — the buffer cache (block-aligned) and the page cache (page-aligned) — which led to double-caching of the same data.
Since Linux 2.4, they were unified: a buffer_head is just a descriptor pointing into a page in the page cache.
Page Cache (one pool of 4KB pages)
┌────────────────────────────────────────┐
│ Page │ Page │ Page │ Page │ … │
└────▲───┴────▲───┴────────┴────▲───┴────┘
│ │ │
buffer_head buffer_head (file-content
(metadata) (metadata) page, no bh)
That’s why free reports them together as buff/cache, and why echo 1 > drop_caches reclaims both — they live in the same pool.
Source code: buffer_head (include/linux/buffer_head.h), page cache (mm/filemap.c)
Cheat Sheet#
| Question | Answer |
|---|---|
| Is “cache” the same as “page cache”? | No. cache in free = Cached + SReclaimable. Page cache is just the Cached part. |
| What does Buffer cache? | Filesystem metadata (superblock, inode tables, directory blocks, journal). |
| What does Page Cache cache? | File content (regular files, tmpfs, mmap’d files). |
What’s in SReclaimable? |
Dentry cache, inode cache, and other reclaimable kernel slabs. |
| Buffer = writes, Cache = reads? | No. Both serve reads and writes. The split is by data type, not direction. |
| Are Buffer and Page Cache separate memory pools? | No (since Linux 2.4). Buffer is backed by page cache pages via buffer_head descriptors. |
Should I worry about high buff/cache? |
No. It’s reclaimable. Watch available, not free. |
Reference#
- Linux Page Cache — kernel doc
/proc/meminfofields — kernel docdrop_caches— kernel docman free,man proc,man slabtop