[RFC PATCH v1 0/6] provenance_time (ptime): a new settable timestamp for cross-filesystem provenance

Sean Smith
2026-04-05T19:50:24Z

This series adds provenance_time (ptime) -- a new settable inode
timestamp that records when a file's content was first created,
preserving this date across copies, moves, and application saves.

This is a working implementation of the concept I proposed in my
RFC in March:
https://lore.kernel.org/linux-fsdevel/CAOx6djP4hb-Cd1Zk07SNfFfLc8irjNmbVqq+58h1Whz+h1wSFA@mail.gmail.com/T/#u

MOTIVATION

Linux has no mechanism to preserve original creation dates when
files move between filesystems. Every copy resets btime to "now."
For workflows involving document migration (NTFS to Btrfs, between
ext4 volumes, to USB drives), creation date provenance is lost.

Since the March RFC, I attempted an xattr-based workaround
(user.provenance_time) and found it structurally unworkable:

1. Application atomic saves destroy xattrs. Programs that save
via write-to-temp + rename() replace the inode, permanently
destroying all extended attributes. Only the VFS sees both
inodes during rename -- no userspace mechanism can intercept
this and copy metadata across.

2. Every tool in the copy chain must explicitly opt in to xattr
preservation. cp requires --preserve=xattr, rsync requires -X,
tar requires --xattrs. Each missing flag causes silent data
loss. Transparent preservation through arbitrary tool flows
is not achievable in userspace.

Atomic saves are the default behavior of mainstream applications
(LibreOffice, Vim, Kate, etc.).

DESIGN

ptime is a separate timestamp from btime. btime remains immutable
and forensic ("when was this inode born on this disk"). ptime is
settable and portable ("when was this content first created").

This resolves the 2019 impasse: Dave Chinner's forensic argument
for immutable btime is fully respected -- btime is untouched on
native Linux filesystems. Ted Ts'o's March 2025 concept of a
settable "crtime" alongside immutable btime is implemented in ext4
with dedicated i_ptime fields.

Two implementation categories:

Native (Btrfs, ext4): Dedicated on-disk ptime field. btime
remains immutable. Full nanosecond precision.

Mapped (ntfs3, FAT32/vfat, exFAT): ptime reads/writes the
existing creation time field. This matches Windows and macOS
behavior, where creation time is already settable via standard
APIs. No new on-disk structures needed.

Key VFS capability -- rename-over preservation: when rename()
overwrites an existing file, the kernel copies ptime from the
old file to the new file. This fixes the atomic-save xattr
destruction problem at its root, for every application on
every supported filesystem.

API

ptime is exposed through existing interfaces with minimal
additions:

- statx: STATX_PTIME (0x00040000U) returns ptime in stx_ptime
- utimensat: AT_UTIME_PTIME (0x20000) flag with times[2]
extension for setting ptime
- setattr_prepare: ATTR_PTIME (bit 19) / ATTR_PTIME_SET (bit 20)

The utimensat extension reuses Sandoval's 2019 pattern. For
upstream, an extensible-struct syscall (utimensat2, following
the clone3/openat2 convention) may be preferred -- I am open
to guidance on the API design.

Permissions follow the existing utimensat model: file owner
or CAP_FOWNER required.

TESTING

This has been running on EndeavourOS (kernel 6.19.11) for daily
use. Test coverage:

- 10 xfstests (7 generic VFS + 3 Btrfs-specific): basic
set/read, persistence, rename-over, permissions, utime-omit,
chmod/truncate survival, snapshots, nlink guards, compat_ro

- Runtime tests across all 5 filesystems: set/read, rename-over,
cp -a preservation, cross-FS copies (Btrfs, ext4, ntfs3,
FAT32, exFAT)

KNOWN LIMITATIONS

- XFS: deferred (separate inode structure analysis needed)
- Btrfs send/receive: not yet patched for ptime
- glibc utimensat() wrapper: cannot pass ptime; tools use raw
syscall()
- Btrfs compat_ro: writing ptime sets a compat_ro flag;
unpatched kernels refuse RW mount (correct Btrfs behavior)

The userspace ecosystem (patched cp, rsync, tar, KDE Dolphin)
and xfstests are available at:
https://github.com/DefendTheDisabled/linux-ptime

This implementation was developed using AI-assisted tooling for
code generation, iterative review, and test infrastructure. I am
responsible for review, testing, and sign-off.

Sean Smith (6):
vfs: add provenance_time (ptime) infrastructure
btrfs: add provenance time (ptime) support
ntfs3: map ptime to NTFS creation time with rename-over
ext4: add dedicated ptime field alongside i_crtime
fat: map ptime to FAT creation time with rename-over
exfat: map ptime to exFAT creation time with rename-over

fs/attr.c | 6 +++-
fs/btrfs/btrfs_inode.h | 4 +++
fs/btrfs/delayed-inode.c | 4 +++
fs/btrfs/fs.h | 3 +-
fs/btrfs/inode.c | 43 +++++++++++++++++++++++++
fs/btrfs/tree-log.c | 2 ++
fs/btrfs/volumes.c | 2 +-
fs/exfat/file.c | 9 ++++++
fs/exfat/namei.c | 21 +++++++++++--
fs/ext4/ext4.h | 3 ++
fs/ext4/inode.c | 14 +++++++++
fs/ext4/namei.c | 13 ++++++++
fs/fat/file.c | 6 ++++
fs/fat/namei_vfat.c | 20 ++++++++++--
fs/init.c | 2 +-
fs/ntfs3/file.c | 13 ++++++++
fs/ntfs3/frecord.c | 8 +++++
fs/ntfs3/namei.c | 14 +++++++++
fs/stat.c | 2 ++
fs/utimes.c | 56 +++++++++++++++++++++++++--------
include/linux/fs.h | 5 ++-
include/linux/stat.h | 1 +
include/uapi/linux/btrfs.h | 1 +
include/uapi/linux/btrfs_tree.h | 4 ++-
include/uapi/linux/fcntl.h | 3 ++
include/uapi/linux/stat.h | 4 ++-
init/initramfs.c | 2 +-
27 files changed, 239 insertions(+), 26 deletions(-)

--
2.53.0