renameat2() with RENAME_EXCHANGE changes two existing directory entries as one atomic rename operation. Before the call, each pathname reaches its original object; after a successful call, each pathname reaches the object formerly named by the other path. There is no successful intermediate state in which one of the two names has merely been removed or overwritten.
That property is distinct from ordinary rename(). A conventional rename can atomically replace a destination, but replacement discards the destination name from the namespace. Exchange preserves both named objects and swaps their positions.
Both pathnames must already exist
RENAME_EXCHANGE requires an object at both oldpath and newpath. If the destination path does not exist, the operation fails rather than degrading into an ordinary rename.
The namespace transition is therefore:
before:
oldpath -> inode A
newpath -> inode B
renameat2(..., RENAME_EXCHANGE)
after success:
oldpath -> inode B
newpath -> inode AThis is useful when two complete filesystem states need to trade visible names without temporarily parking one under a third pathname. The atomic property applies to the exchange operation itself, not to arbitrary work performed before or after it.
Exchange does not exchange file contents
The operation changes directory entries. It does not copy bytes between files, merge metadata, or rewrite open file descriptions.
An open file descriptor continues to refer to the same opened file object after the pathname exchange. Code that opened oldpath before the call does not have its descriptor redirected to the object that later appears at oldpath.
This separates pathname identity from an already established descriptor reference:
fd = open("oldpath", ...)
RENAME_EXCHANGE(oldpath, newpath)
fd -> original object A
lookup(oldpath) -> object B
lookup(newpath) -> object AProcesses that hold descriptors and processes that perform fresh pathname lookup can therefore observe different namespace generations without either reference being internally inconsistent.
Different object types are permitted by the exchange flag
For RENAME_EXCHANGE, both paths must exist, but the two objects may have different types. Linux documents cases such as exchanging a non-empty directory with a symbolic link.
That is a stronger namespace operation than ordinary replacement rules suggest. Software using the call cannot safely infer that the object found at a stable pathname retains its previous type after another actor performs an exchange.
The usual permission, mount, and filesystem constraints on rename operations still apply. Atomic exchange is not a bypass around pathname resolution or filesystem policy.
The operation remains bounded by one mounted filesystem
Rename operations do not move an object across mounted filesystem boundaries. RENAME_EXCHANGE does not turn cross-filesystem movement into an atomic operation.
A design that places the two paths on different mounted filesystems therefore cannot use this flag as a general transaction primitive. Copying data to another filesystem and then changing names is a separate sequence with different failure and durability properties.
The atomic namespace guarantee should also not be confused with persistent storage ordering. A successful system call establishes the visible namespace result required by the rename semantics. Crash durability depends on filesystem behavior and on any synchronization operations required by the application.
RENAME_NOREPLACE and RENAME_EXCHANGE express incompatible transitions
RENAME_NOREPLACE requests failure when the destination already exists. RENAME_EXCHANGE requires the destination to exist so that it can participate in the swap.
Linux rejects a call that combines those flags. They describe mutually incompatible destination rules:
RENAME_NOREPLACE:
newpath absent -> rename may proceed
newpath present -> fail
RENAME_EXCHANGE:
newpath absent -> fail
newpath present -> exchange may proceedTreating flags as independent feature switches would miss this semantic conflict. The flags select different rename transitions rather than layering arbitrary modifiers onto one operation.
Atomic visibility does not create a multi-operation transaction
A common use for exchange is publication: prepare a complete replacement tree under one name, then exchange it with the currently visible tree. The swap prevents observers from encountering a pathname gap between the two names.
The preparation phase is still outside the exchange. Changes made while building the replacement can fail independently, and cleanup of the old object after the swap is another operation. If an application needs crash-consistent publication, its durability protocol must account for file data, directory updates, and the filesystem’s persistence guarantees.
RENAME_EXCHANGE provides a narrow and valuable primitive: two existing names change referents together. Its atomic boundary ends at that namespace transition.