Re: [RFC PATCH v3 1/5] vfs: add provenance time (ptime)
From: Amir Goldstein
Date: Mon Nov 09 2026 - 09:45:27 EST
On Sat, Nov 7, 2026 at 6:09 PM koraynilay <koray.fra@xxxxxxxxx> wrote:
>
> On Sat Nov 7, 2026 at 5:48 PM CET, Amir Goldstein wrote:
> > On Sat, Nov 7, 2026 at 5:04 PM koraynilay <koray.fra@xxxxxxxxx> wrote:
> >>
> >> On Mon Nov 2, 2026 at 3:00 PM CET, Amir Goldstein wrote:
> >> > On Sun, Nov 1, 2026 at 2:57 AM koraynilay <koray.fra@xxxxxxxxx> wrote:
> >> >>
> >> >> Add provenance time (ptime), indicating the time when a file or
> >> >> directory was created. This is user-settable via file_setattr() and
> >> >> retrievable via statx(2) (using STATX_PTIME) or file_getattr().
> >> >>
> >> >> The semantics of when to preserve this new timestamp are the same as
> >> >> mtime, the idea being that there is a correspondence like this:
> >> >>
> >> >> ctime <-> btime
> >> >> mtime <-> ptime
> >> >>
> >> >> so every operation (copying, moving, ...) that currently preserves mtime
> >> >> should also preserve ptime.
> >> >>
> >> >> Furthermore, in order to avoid the legacy FS_IOC_FSSETXATTR accepting
> >> >> FS_XFLAG_PTIME, add an FS_FILE_ATTR_XFLAGS_MASK mask to support new
> >> >> xflags, and use it in fileattr_to_file_attr()/file_attr_to_fileattr() to
> >> >> allow ptime to be used with the file_setattr()/file_getattr() syscalls.
> >> >>
> >> >> [ This is a re-implementation of the initial patch[1] by Sean Smith
> >> >> <defendthedisabled@xxxxxxxxx>, following the advice[2] from Darrick J.
> >> >> Wong <djwong@xxxxxxxxxx> of using file_setattr() instead of updating
> >> >> utimensat() ]
> >> >>
> >> >> [1]: https://lore.kernel.org/20260405195007.1306-2-DefendTheDisabled@xxxxxxxxx
> >> >> [2]: https://lore.kernel.org/20260407014129.GC6192@frogsfrogsfrogs
> >> >>
> >> >> Assisted-by: Gemini:3.8-flash-high antigravity-cli-1.4.7
> >> >> Signed-off-by: koraynilay <koray.fra@xxxxxxxxx>
> >> >> ---
> >> >> fs/file_attr.c | 33 +++++++++++++++++++++++++++++++--
> >> >> fs/stat.c | 2 ++
> >> >> include/linux/fileattr.h | 5 +++++
> >> >> include/linux/stat.h | 1 +
> >> >> include/uapi/linux/fs.h | 8 +++++++-
> >> >> include/uapi/linux/stat.h | 7 ++++++-
> >> >> 6 files changed, 52 insertions(+), 4 deletions(-)
> >> >>
> >> >> diff --git a/fs/file_attr.c b/fs/file_attr.c
> >> >> index 833e03810b24..c0645cb22bf3 100644
> >> >> --- a/fs/file_attr.c
> >> >> +++ b/fs/file_attr.c
> >> >> @@ -102,7 +102,7 @@ EXPORT_SYMBOL(vfs_fileattr_get);
> >> >> static void fileattr_to_file_attr(const struct file_kattr *fa,
> >> >> struct file_attr *fattr)
> >> >> {
> >> >> - __u32 mask = FS_XFLAGS_MASK;
> >> >> + __u32 mask = FS_FILE_ATTR_XFLAGS_MASK;
> >> >>
> >> >> memset(fattr, 0, sizeof(struct file_attr));
> >> >> fattr->fa_xflags = fa->fsx_xflags & mask;
> >> >> @@ -110,6 +110,8 @@ static void fileattr_to_file_attr(const struct file_kattr *fa,
> >> >> fattr->fa_nextents = fa->fsx_nextents;
> >> >> fattr->fa_projid = fa->fsx_projid;
> >> >> fattr->fa_cowextsize = fa->fsx_cowextsize;
> >> >> + fattr->fa_ptime_sec = fa->fsx_ptime.tv_sec;
> >> >> + fattr->fa_ptime_nsec = fa->fsx_ptime.tv_nsec;
> >> >> }
> >> >>
> >> >> /**
> >> >> @@ -141,15 +143,20 @@ EXPORT_SYMBOL(copy_fsxattr_to_user);
> >> >> static int file_attr_to_fileattr(const struct file_attr *fattr,
> >> >> struct file_kattr *fa)
> >> >> {
> >> >> - __u64 mask = FS_XFLAGS_MASK;
> >> >> + __u64 mask = FS_FILE_ATTR_XFLAGS_MASK;
> >> >
> >> > That is not the correct way to extend this API.
> >> > This fixed mask was added as a placeholder for
> >> > "We intend to add support for more xflags to selective filesystems":
> >> > https://lore.kernel.org/linux-fsdevel/20250329143312.1350603-2-amir73il@xxxxxxxxx/
> >> >
> >> > Please see this POC patch for filesystems to publish their supported
> >> > xflags mask:
> >> > https://lore.kernel.org/linux-fsdevel/20250329143312.1350603-3-amir73il@xxxxxxxxx/
> >>
Re-reading and answering your original questions:
> >> Quick question, should _mask also be used for user-space -> VFS to advertise
> >> what it wants to change?
Yes absolutely.
> >> This would be useful for on/off flags,
Exactly.
All the Windows filesystems that want ptime, would most likely want the support
on/off HIDDEN/SYSTEM/ARCHIVE flags as well.
> >> but for ptime both fa->xflags and
> >> fa->xflags_mask would have the same meaning of "I want to change ptime,
> >> look at fa->ptime".
There needs to be no FS_XLAG_PTIME in fa->xflags,
just as there is no FS_XFLAG_PROJID in fa->xflags today.
However, since btrfs does not support setting projid, when we introduce
fa->xflags_mask, it would be elegant IMO to introduce the (new) flag
FS_XFLAG_PROJID which would be valid in fa->xflags_mask.
To be clear, currently upstream chattr (e2fsprogs) can set projid via
FS_IOC_FSSETXATTR ioctl (no xflags_mask) and upstream
xfs_io -c chattr (xfsprogs) can set projid via file_setattr() syscall
(no xflags_mask).
But if either utils were to be modified to support setting ptime, then it
would need to use file_setattr() syscall and set both FS_XLAG_PTIME
and FS_XFLAG_PROJID in xflags_mask when it wants to set a non-zero
value to those fields.
Specifically, the invocation of chattr -p <projid>, will no longer need to do
FS_IOC_FSGETXATTR to read all the unrelated flags for setting the projid.
> >> Should we make _mask the only way to advertise what the user wants to
> >> change,
Yes, unless _mask is zero, which then means set all the legacy values
which are frozen in the constant FS_XFLAGS_MASK.
> >> ignore xflags | PTIME in user-space -> VFS and use it only in FS
> >> -> VFS -> user-space to say "this fs supports PTIME for this file"
Close, but not exactly.
For GET, semantics are clear and follow statx precedents:
xflags_mask always means "supported" (like stx_attributes_mask).
For boolean flags, xflags is the value
For integer fields, an xflags bit means "value provided" (like stx_mask).
For SET, when xflags_mask!=0, a flag of 1 means "I want to set this value".
For boolean flags, if the flag's bit in xflags_mask is 0, the flag is
left untouched
(e.g. a chattr -p that only sets the project ID doesn't touch IMMUTABLE).
For integer fields, the meaning of xflags_mask 1 and xflags 0 would be
"I want to unset the value" which is not the same as "I want to set the value
to 0", because as you wrote, 0 is a valid value for ptime.
The question of whether a specific field can be unset or not is up for the
filesystem to decide, not the VFS.
For example, XFS already unset the value of cowextsize when flag
FS_XFLAG_COWEXTSIZE is 0, although the same could be done
with a 0 value to fa_cowextsize.
VFS does enforce that xflags & ~xflags_mask is EINVAL.
> >> (which will be always once support is added to an FS, so it would just
> >> be "this FS supports PTIME")?
It does not have to be an FS-wide property. some fs could have ptime
(or another attribute) support only on some files types.
> >>
> >
> > Sorry I was not able to parse your question.
> >
> > I think the mask should mean "this FS supports PTIME"
> > regardless if the user asked to get/set it or not.
>
> Yeah sorry, I'm just a bit confused because of all the similar names and
> concepts.
Me too... I needed to re-read all the threads from Feb 2025...
>
> (assuming btrfs supports ptime and ext4 doesn't)
>
> * filesystem -> VFS -> user-space, while in fileattr_to_file_attr():
>
> for btrfs, for all files[1]:
> fa->fa_xflags & FS_XFLAG_PTIME == 1
> fa->fa_xflags_mask & FS_XFLAG_PTIME == 1
Yes.
>
> for ext4, for all files:
> fa->fa_xflags & FS_XFLAG_PTIME == 0
> fa->fa_xflags_mask & FS_XFLAG_PTIME == 0
Yes.
>
> * user-space -> VFS -> filesystem, while in file_attr_to_fileattr():
>
> fattr->fa_xflags & FS_XFLAG_PTIME == ignored
This is debatable. IMO it should be 1 for value, 0 to unset existing value,
similar to removexattr() if you want to look at it this way.
> fattr->fa_xflags_mask & FS_XFLAG_PTIME == 1 if user wants to set it, otherwise 0
Yes. but now the user has to set any legacy field it wants to set in
fa_xflags_mask as well, because fa_xflags_mask is no longer zero.
so we need to introduce flag constants for legacy fields that do not
have xflags. I think that is only FS_XFLAG_PROJID.
>
> Would this be correct?
>
> Or would it be better to set FS_XFLAG_PTIME only in fa_xflags_mask, and
> never touch fa_xflags with it, which would make the above become:
>
>
> * filesystem -> VFS -> user-space, while in fileattr_to_file_attr():
>
> for btrfs, for all files[1]:
> fa->fa_xflags_mask & FS_XFLAG_PTIME == 1
>
> for ext4, for all files:
> fa->fa_xflags_mask & FS_XFLAG_PTIME == 0
>
> (and always fa->fa_xflags & FS_XFLAG_PTIME == 0)
>
> * user-space -> VFS -> filesystem, while in file_attr_to_fileattr():
>
> (fattr->fa_xflags & FS_XFLAG_PTIME == ignored)
> fattr->fa_xflags_mask & FS_XFLAG_PTIME == 1 if user wants to set it, otherwise 0
>
I prefer the former.
> This would mean that fa_xflags_mask is used like stx_mask both by the fs
> (to let the user know what it supports (a.k.a. what it's returning)) and
> by the user (to let the fs know what it's trying to set),
This is actually like stx_attributes_mask not stx_mask.
> and fa_xflags
> is used only for ON/OFF flags (like immutable).
Yes, on/off for flag values (like stx_attributes), but "value exists"
for field values (like stx_mask).
>
> Let me know if it's clearer.
>
Same.
Thanks,
Amir.