A backend service opens the same configuration file for every request:
Without caching, each open could require the file system to rediscover srv, catalog, config, and features.json, then reload metadata for every object along the route.
Linux avoids most of that repeated namespace work with two related VFS caches:
The dentry cache answers “what object does this name reach here?” while the inode cache answers “what do we already know about this object?”
These caches accelerate path lookup and metadata access. They do not cache regular-file contents; file-data caching is a separate mechanism.
A pathname is resolved one component at a time:
Resolving /srv/catalog/config/features.json means four separate lookups, not one. Each component has to be found before the next can be searched.
For each component, the kernel needs a relationship resembling:
On a cold lookup, answering this can require file-system-specific directory work. A local file system may inspect directory metadata. A remote file system may need client/server communication. A synthetic file system may generate the relationship from kernel state.
Real workloads repeat paths. A service loads the same configuration, shared libraries, certificates, templates, and log directories. Shells repeatedly search common executable paths. Build tools inspect the same source tree.
Remembering prior results turns repeated directory work into in-memory lookup:
The path still passes through normal resolver rules and permission checks. Caching changes how the kernel obtains component and metadata information, not what the pathname means.
A component name alone is not enough to identify a namespace entry.
Both paths contain config.json:
They are different because their parent directories differ.
Conceptually, the dentry cache key includes:
The result is a child dentry:
Linux uses hashed lookup structures so the resolver does not need to scan every cached name globally. Details of the hash tables and locking can evolve, but the logical key remains tied to a parent-and-name context.
Case-insensitive or otherwise specialized file systems can provide comparison and hashing behavior appropriate to their naming rules. VFS caching must preserve the file system's semantics rather than imposing one universal string comparison.
A positive dentry refers to an inode:
On a repeated lookup, VFS can find the dentry and continue from its inode without asking the file-system implementation to rediscover the same directory association.
Hard links naturally produce multiple positive dentries that lead to one inode:
The dentry represents a name relationship. The inode represents shared object identity and metadata.
Caching success is intuitive. Linux can also cache a name that was not found.
A negative dentry represents:
Suppose a service repeatedly checks:
and the optional file does not exist. Without negative caching, each check could repeat the same directory lookup. A negative dentry lets the resolver answer the repeated miss from in-memory namespace state.
Negative does not mean permanent. If a process creates override.json, the namespace operation updates the relevant state so future resolution can reach the new inode.
Negative dentries are especially valuable for workloads that probe optional files or search several directories for one name. They can also grow under workloads that test many unique nonexistent names, so they remain reclaimable cache objects rather than permanent records.
An inode number is meaningful only within a file-system instance. Conceptually, the inode cache finds an in-memory VFS inode using:
The cached inode carries the common object view:
For a local inode-based file system, a miss can require loading persistent inode metadata. A remote file system can obtain attributes from a server. A synthetic file system can construct them from live kernel state.
Once the VFS inode exists, several dentries and open file objects can refer to it:
References arrive from two directions. The inode stays alive while any of them remains, which is why an open file survives having all its names removed.
The inode cache prevents the kernel from creating unrelated in-memory metadata objects for every name and every open of the same underlying object.
The two caches are related but not interchangeable.
| Cache | Logical key | Cached result | Main question |
|---|---|---|---|
| Dentry cache | Parent dentry plus component name | Name association, possibly negative | What does this name reach here? |
| Inode cache | File-system instance plus inode number | Object metadata and operations | What object is this? |
| File-data cache | Inode-associated address-space mapping plus file offset | File-content bytes | What bytes are in this file range? |
The third row is included only to draw the boundary. Caching file contents has different data structures, write behavior, and memory-management rules.
A warm dentry lookup does not guarantee that the file's data bytes are in memory. A cached inode can report metadata while reading the file still requires obtaining its contents elsewhere.
Conversely, retaining data associated with an open file does not make every pathname component used to reach it permanently cached.
Suppose all components of:
have positive cached dentries.
The resolver still follows the logical path:
It can obtain component associations from the dentry cache, but it must still honor:
A cached dentry is not an authorization grant. If directory permissions change, the kernel does not let a process bypass them merely because it has seen the path before.
Caching also does not remove the system call. An application calling stat() one hundred thousand times still crosses into the kernel one hundred thousand times. The cache reduces work performed after entry.
For one component, the lookup path can be modeled as:
“Usable” matters. Some file systems must revalidate cached namespace or attribute information. A remote server can change independently of the local client, and file-system-specific rules determine when cached results need confirmation.
VFS provides the common object and cache framework. The file system contributes the validity rules required by its semantics.
Create, unlink, and rename change the relationships represented by dentries.
Before creation:
After a successful create:
The old “not found” result cannot continue to answer the name.
Before unlink:
After unlink, new resolution must not find that name. An already open file object can still refer to inode 8412, so removing the dentry relationship is not the same as destroying every in-memory inode reference.
Rename changes which parent-and-name association reaches an object. The cache state must reflect the new namespace without retargeting existing open file objects.
Local namespace-changing operations pass through VFS and the owning file system, allowing their in-memory state to be updated as part of the operation.
Operations such as chmod(), chown(), truncate, and write can change inode metadata.
The active VFS inode is the kernel's working representation of that object. If one process changes the mode, another process querying the same live object should not receive an indefinitely stale mode merely because the inode was cached.
chmod changes the mode, the in-memory inode metadata reflects the change, and a later stat observes the updated mode.
Persistent file systems must eventually represent required metadata changes in their durable format. That persistence step is separate from the value of retaining an in-memory inode for fast lookup.
Remote file systems are more complex because another client or the server can change metadata outside this kernel's VFS operations. Attribute caches can require timeout- or protocol-based revalidation. The exact consistency contract belongs to the remote file-system implementation and mount configuration.
VFS objects use reference tracking because other kernel objects can depend on them.
A dentry can be referenced by:
An inode can be referenced by dentries, open file objects, mappings, or file-system work.
While an object is actively required, the kernel cannot simply free its memory. After external references disappear, the object can remain as an unused cache entry so a later lookup can reuse it.
The middle state is what makes the cache useful. An object with no active users is kept anyway, so the next reference can skip the lookup entirely.
Reclaiming the in-memory dentry does not unlink a file. Reclaiming an unused in-memory inode does not delete its persistent inode. It removes a runtime cache representation that can be reconstructed when needed.
Linux allocates dentries and in-memory inode objects from kernel slab caches. Walking a large directory tree can therefore increase slab memory.
This is often useful memory, not a leak. The cached namespace can make future operations much faster.
When memory is needed elsewhere, kernel shrinkers can reclaim eligible unused dentries, inodes, and other cache objects. Active references remain protected. Objects with pending state may require additional work before they can be reclaimed.
The exact reclaim ordering and list implementation can change across kernel versions. The stable model is:
Using available RAM for metadata cache is generally beneficial. A low MemFree value alone does not prove that dentry or inode cache growth is harmful.
A cold lookup lacks the relevant reusable dentry or inode state:
On a cache miss, the path component requires a file-system directory lookup, and the kernel then constructs the dentry and inode state.
A warm lookup finds reusable in-memory state:
On a cache hit, resolution continues using the existing VFS objects.
Warm lookup can avoid storage metadata reads, remote requests, and repeated directory parsing. It still incurs pathname walking, checks, locking, and syscall overhead.
The first operation in an application is not necessarily cold. Another process, service startup, system scanner, or earlier command may already have populated the system-wide kernel cache.
Likewise, a second operation is not guaranteed warm. Memory pressure, file-system validity rules, and namespace changes can require reclaim or revalidation.
“Cold” and “warm” are descriptions of observed cache state, not properties permanently attached to a pathname.
Loading simulation...
Consider a language runtime searching for an optional module:
If the first two paths are absent, negative dentries can make later searches cheaper. The runtime still tries each pathname, but the kernel can answer stable misses without repeating all underlying directory work.
This pattern appears in:
Negative caching is not free. A workload generating millions of unique random nonexistent names can create namespace-cache pressure. Reclaim prevents those failures from becoming permanent memory consumption.
A workload with millions of tiny files can use more kernel metadata memory than its byte count suggests.
Each active or cached path can involve dentries. Each distinct file object can involve an in-memory inode. Directory and file-system-specific metadata add more overhead.
This is one reason object stores, package caches, mail queues, and build trees with huge file counts can behave differently from a few large database files.
Keeping frequently used files open can avoid repeated final-component lookup, and directory descriptors with openat() can provide stable starting points. These techniques do not eliminate the system's need to manage the namespace, but they can reduce repeated application-level path work.
Linux exposes high-level dentry counters:
The line contains several numbers. The first is the approximate number of allocated dentries, and the second is the approximate number of currently unused dentries. Remaining fields are kernel cache-management details and can vary in practical relevance.
Inode counters are available through:
The first values describe total allocated in-memory inode objects and those currently unused or freeable. These are runtime kernel counts, not the persistent free-inode capacity reported by:
That distinction is important:
Inspect slab totals:
SReclaimable includes potentially reclaimable slab objects such as some dentry and inode caches, but it also includes other kernel caches. It is not a dentry-only counter.
For a cache-by-cache view:
Names such as dentry, inode_cache, and file-system-specific inode caches can appear. Exact names and sizes depend on the kernel and mounted file systems.
These counters change continuously on an active machine. Compare trends and workload phases rather than treating one snapshot as a leak diagnosis.
Record cache counters:
Walk a bounded part of /etc:
Read the counters again:
The allocated counts may increase because the walk touched names and metadata. They may also change because of unrelated system work or immediate reclaim. This is an observation, not a deterministic benchmark.
Avoid forcing cache drops as a routine performance technique. Discarding useful caches makes later work colder and can cause a system-wide latency spike. Controlled benchmark environments sometimes drop caches to construct a cold starting point, but doing so requires administrative authority and affects unrelated workloads.
The following program repeatedly calls stat() on one fixed path. It accepts either an existing or missing path, making positive and negative repeated lookups observable.
Compile and run:
The exact times are machine- and workload-dependent. The first unmeasured lookup establishes the expected result and commonly warms the relevant final path before timing, so this program measures repeated lookup rather than cold-versus-warm difference.
Trace the existing-path run:
The summary still shows roughly one metadata syscall per iteration. Dentry and inode caching reduce internal lookup work; they do not remove calls issued by the application.
The benchmark cannot isolate every kernel cost, and compiler, CPU, security policy, mount type, and concurrent activity affect results. Its purpose is to connect repeated stat() calls with reuse inside the kernel, not to establish a universal nanosecond target.
The dentry cache retains mappings from a parent dentry and component name to a child dentry. Positive dentries refer to inodes, while negative dentries remember failed lookups. The inode cache retains common in-memory metadata and operations keyed by file-system instance and object identity.
Path resolution can reuse these objects instead of repeating file-system-specific directory and metadata work. It still walks components, crosses mounts, follows link rules, checks permissions, and enters the kernel for every application syscall.
Create, unlink, rename, and metadata changes update or invalidate relevant cache state. Remote file systems can require additional revalidation because state may change outside the local kernel.
Unused dentries and inodes consume kernel slab memory but are generally reclaimable under pressure. Reclaiming them removes runtime cache objects, not persistent files. Linux exposes approximate dentry, inode, and slab counters through /proc and slab tools.
The central mental model is:
Dentries cache names, inodes cache objects, and both can be reconstructed when reclaim removes their in-memory representations.
5 quizzes