4.1 Overview

stratafs presents an ordered set of existing directories — its strata — as one merged directory tree. Each stratum is an ordinary directory on an ordinary filesystem, owned and written by whatever agent owns it, with no coordination with stratafs and no notification to it. The merged view reflects changes to any stratum without a remount.

It is a stacking filesystem in the strict sense: it stores no file data, no directory entries, and no security descriptors. Every object reachable through a stratafs mount is a real object on a real stratum, and every data and metadata operation is performed against that object. stratafs inodes carry no address-space operations, so there is no second page cache to keep coherent; reads, writes, mappings and splices are forwarded to a backing file opened on the provider.

Unlike overlayfs, stratafs has no whiteouts and no opaque-directory markers. There is no mechanism anywhere in the filesystem for recording that a name should be absent. That single omission accounts for most of what is unusual about it: removing a name can leave the name visible, some names cannot be removed at all, and several operations that succeed on an ordinary filesystem are refused here rather than faked. §4.8 collects the consequences.

4.1.1 Where it sits #

stratafs is not part of PKM. It is staged into the kernel tree as fs/stratafs, built by CONFIG_STRATAFS_FS — a boolean option, so it is linked into vmlinux — and registered by an fs_initcall. The option depends on CONFIG_SECURITY_PKM, because stratafs reaches KACS for every access decision and for the whole of the copy-up context. That reach is through <linux/kacs_stratafs.h>, a kernel-private header staged into include/linux whose symbols are deliberately not exported to modules: there is no userspace surface to the interface between the two, and no way for anything but the in-tree filesystem to enter it.

The filesystem type registers under the name stratafs, with the superblock magic 0x53545241 — ASCII STRA — and the flags FS_USERNS_MOUNT and FS_RENAME_DOES_D_MOVE. It takes no device; superblocks come from get_tree_nodev, so the device identifier reported for every object in a mount is an anonymous one belonging to the mount rather than to any stratum.

A small part of the filesystem is written in Rust. The crate stratafs-core is staged into the kernel alongside PKM's own Rust cores and holds three pure, allocation-free decisions: validating the stack-wide flag rules, selecting the provider from a presence bitmap, and routing one modifying operation. Everything else — the VFS glue, resolution, enumeration, copy-up — is C.

4.1.2 The model #

A mount is defined by its stratum stack: an ordered list of strata, highest-precedence first, fixed for the life of the mount. A stratum is identified by its path, not by the directory that path resolved to at mount time, which is what allows a package transaction to replace a whole stratum by renaming trees around underneath a live mount.

For a given name in a given directory, the provider is the highest-precedence stratum that holds it. A name whose provider is a directory, and which lower strata also hold as a directory, resolves to a merged directory whose entries are the union of theirs. A name whose provider is anything else masks every lower entry of that name completely, subtree and all.

At most one stratum carries the create flag. That create stratum receives newly created objects and is the destination of copy-up — the replication of an object into the create stratum so that a modification can be applied without touching the stratum that provides it. A stack may have no create stratum, in which case nothing can be created and nothing copied up.

Routing a modification is a decision about strata alone. It happens when the modifying operation is performed, never at open, and it never consults the caller: by the time an operation reaches stratafs, KACS has already decided the caller was entitled to perform it. §4.5.1 sets out why no other formulation is implementable.

4.1.3 What it delegates #

stratafs holds no security descriptors, so it makes no access decisions of its own about the objects it presents. The descriptor evaluated for an operation is the one on the object the operation will be performed against, and KACS reads it through the ordinary extended-attribute path, which the stacking layer forwards down to the provider. A stratafs mount cannot grant access its provider stratum would refuse.

A merged directory is the exception, because it stands for several real directories with several descriptors and forwarding yields only the provider's. Those checks stratafs performs itself, against every participating directory, requiring all of them to succeed (§4.6.2).

Copy-up is the other exception, in the opposite direction. It is machinery serving an operation that was already authorised, not an operation a caller requests, so it must introduce no new checks against whichever task happens to execute it. KACS provides a kernel-internal copy-up context for exactly this, described in full at §3.9.7; §4.6.3 covers the stratafs half.

4.1.4 This chapter #

§4.2 covers the stack, the mount options that define it, what a mounter must be entitled to, and absent strata. §4.3 covers resolution: providers, merging, type conflicts, and enumeration. §4.4 covers coherency — how uncoordinated change is observed, and the inode identity presented over it. §4.5 covers mutation: routing, copy-up, creation, removal, rename, links, locking and durability. §4.6 covers the security seam with KACS, and §4.7 the one interface stratafs synthesises for userspace. §4.8 collects the failure modes, including the divergences from ordinary filesystem behaviour that follow from having no whiteouts, and §4.A the constants.

Edit this page