Skip to content

RFC provenance_time (ptime): a new settable timestamp for cross-filesystem provenance

Sean Smith linux-btrfs linux-ext4 linux-fsdevel 1 version In review

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 RFC Latest6 patches 10 repliesIn review

Patches in v1 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/6vfs: add provenance_time (ptime) infrastructurefs/attr.c fs/btrfs/volumes.c fs/init.c +7 more+64 -190 replies
2/6btrfs: add provenance time (ptime) supportfs/btrfs/btrfs_inode.h fs/btrfs/delayed-inode.c fs/btrfs/fs.h +4 more+58 -20 replies
3/6ntfs3: map ptime to NTFS creation time with rename-overfs/ntfs3/file.c fs/ntfs3/frecord.c fs/ntfs3/namei.c+35 -00 replies
4/6ext4: add dedicated ptime field alongside i_crtimefs/ext4/ext4.h fs/ext4/inode.c fs/ext4/namei.c+30 -00 replies
5/6fat: map ptime to FAT creation time with rename-overfs/fat/file.c fs/fat/namei_vfat.c+24 -20 replies
6/6exfat: map ptime to exFAT creation time with rename-overfs/btrfs/inode.c fs/exfat/file.c fs/exfat/namei.c+29 -40 replies

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

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

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(-)
Signature · 1 line
2.53.0