public inbox for linux-ext4@vger.kernel.org
 help / color / mirror / Atom feed
From: Sean Smith <defendthedisabled@gmail.com>
To: linux-fsdevel@vger.kernel.org
Cc: linux-ext4@vger.kernel.org, linux-btrfs@vger.kernel.org,
	tytso@mit.edu, dsterba@suse.com, david@fromorbit.com,
	brauner@kernel.org, osandov@osandov.com, almaz@kernel.org,
	hirofumi@mail.parknet.co.jp, linkinjeon@kernel.org,
	Sean Smith <DefendTheDisabled@gmail.com>
Subject: [PATCH 4/6] ext4: add dedicated ptime field alongside i_crtime
Date: Sun,  5 Apr 2026 14:50:00 -0500	[thread overview]
Message-ID: <20260405195007.1306-5-DefendTheDisabled@gmail.com> (raw)
In-Reply-To: <20260405195007.1306-1-DefendTheDisabled@gmail.com>

Add i_ptime (__le32) and i_ptime_extra (__le32) to the ext4 on-disk
inode structure after i_projid. Total: 8 bytes in the extended inode
area. i_crtime remains untouched as immutable birth time.

This is a native-ptime implementation: ptime and btime are separate
fields. On 256-byte inodes (modern default), both fit easily. On
128-byte inodes, ptime is silently unavailable (same graceful
degradation as i_crtime via EXT4_FITS_IN_INODE).

Uses existing EXT4_EINODE_GET_XTIME/SET_XTIME macros for read/write.
Rename-over: when a file with ptime=0 replaces a file with ptime set,
inherit target ptime (same zero-sentinel logic as Btrfs).

Signed-off-by: Sean Smith <DefendTheDisabled@gmail.com>
---
 fs/ext4/ext4.h  |  3 +++
 fs/ext4/inode.c | 14 ++++++++++++++
 fs/ext4/namei.c | 13 +++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index f1c476303..5c2812637 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -860,6 +860,8 @@ struct ext4_inode {
 	__le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
 	__le32  i_version_hi;	/* high 32 bits for 64-bit version */
 	__le32	i_projid;	/* Project ID */
+	__le32	i_ptime;		/* Provenance time */
+	__le32	i_ptime_extra;	/* extra Provenance time (nsec << 2 | epoch) */
 };
 
 #define EXT4_EPOCH_BITS 2
@@ -1136,6 +1138,7 @@ struct ext4_inode_info {
 	 * struct timespec64 i_{a,c,m}time in the generic inode.
 	 */
 	struct timespec64 i_crtime;
+	struct timespec64 i_ptime;
 
 	/* mballoc */
 	atomic_t i_prealloc_active;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 625cfbf61..15b6b6dc6 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4753,6 +4753,7 @@ static int ext4_fill_raw_inode(struct inode *inode, struct ext4_inode *raw_inode
 	EXT4_INODE_SET_MTIME(inode, raw_inode);
 	EXT4_INODE_SET_ATIME(inode, raw_inode);
 	EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
+	EXT4_EINODE_SET_XTIME(i_ptime, ei, raw_inode);
 
 	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
 	raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF);
@@ -5409,6 +5410,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
 	EXT4_INODE_GET_ATIME(inode, raw_inode);
 	EXT4_INODE_GET_MTIME(inode, raw_inode);
 	EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
+	EXT4_EINODE_GET_XTIME(i_ptime, ei, raw_inode);
 
 	if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) {
 		u64 ivers = le32_to_cpu(raw_inode->i_disk_version);
@@ -6061,6 +6063,9 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 	if (!error) {
 		if (inc_ivers)
 			inode_inc_iversion(inode);
+		if (attr->ia_valid & ATTR_PTIME)
+			EXT4_I(inode)->i_ptime = attr->ia_ptime;
+
 		setattr_copy(idmap, inode, attr);
 		mark_inode_dirty(inode);
 	}
@@ -6114,6 +6119,15 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
 		stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
 	}
 
+	/* Report ptime from dedicated field, not crtime */
+	if ((request_mask & STATX_PTIME) &&
+	    EXT4_FITS_IN_INODE(raw_inode, ei, i_ptime) &&
+	    (ei->i_ptime.tv_sec || ei->i_ptime.tv_nsec)) {
+		stat->result_mask |= STATX_PTIME;
+		stat->ptime.tv_sec = ei->i_ptime.tv_sec;
+		stat->ptime.tv_nsec = ei->i_ptime.tv_nsec;
+	}
+
 	/*
 	 * Return the DIO alignment restrictions if requested.  We only return
 	 * this information when requested, since on encrypted files it might
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index c4b5e252a..1bfe4df24 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3942,6 +3942,19 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 	 * rename.
 	 */
 	inode_set_ctime_current(old.inode);
+
+	/* ptime rename-over: preserve ptime across atomic saves */
+	if (new.inode && S_ISREG(old.inode->i_mode) &&
+	    S_ISREG(new.inode->i_mode) && old.inode->i_nlink == 1 &&
+	    !(flags & RENAME_WHITEOUT)) {
+		struct ext4_inode_info *old_ei = EXT4_I(old.inode);
+		struct ext4_inode_info *new_ei = EXT4_I(new.inode);
+
+		if (!old_ei->i_ptime.tv_sec && !old_ei->i_ptime.tv_nsec &&
+		    (new_ei->i_ptime.tv_sec || new_ei->i_ptime.tv_nsec))
+			old_ei->i_ptime = new_ei->i_ptime;
+	}
+
 	retval = ext4_mark_inode_dirty(handle, old.inode);
 	if (unlikely(retval))
 		goto end_rename;
-- 
2.53.0


  parent reply	other threads:[~2026-04-05 19:50 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-05 19:49 [RFC PATCH v1 0/6] provenance_time (ptime): a new settable timestamp for cross-filesystem provenance Sean Smith
2026-04-05 19:49 ` [PATCH 1/6] vfs: add provenance_time (ptime) infrastructure Sean Smith
2026-04-05 19:49 ` [PATCH 2/6] btrfs: add provenance time (ptime) support Sean Smith
2026-04-05 19:49 ` [PATCH 3/6] ntfs3: map ptime to NTFS creation time with rename-over Sean Smith
2026-04-05 19:50 ` Sean Smith [this message]
2026-04-05 19:50 ` [PATCH 5/6] fat: map ptime to FAT " Sean Smith
2026-04-05 19:50 ` [PATCH 6/6] exfat: map ptime to exFAT " Sean Smith
2026-04-05 22:54 ` [RFC PATCH v1 0/6] provenance_time (ptime): a new settable timestamp for cross-filesystem provenance Theodore Tso
2026-04-07  0:05   ` Sean Smith
2026-04-07  1:42     ` Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260405195007.1306-5-DefendTheDisabled@gmail.com \
    --to=defendthedisabled@gmail.com \
    --cc=almaz@kernel.org \
    --cc=brauner@kernel.org \
    --cc=david@fromorbit.com \
    --cc=dsterba@suse.com \
    --cc=hirofumi@mail.parknet.co.jp \
    --cc=linkinjeon@kernel.org \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=osandov@osandov.com \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox