From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.128.41 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793138785; b=EwWw2stGv5lkbpIVzQXdkOZDIsRV3dHtcQe47rC1ntuE5pDXjnLrZLo/F/HlMw2DFydK PnuqWUi6l56lQvXzoh1BKhluWLb7zjb+/+zzHl1/K0l3LK9tR02Z5zkGM6NRoffj0yo6z Mv154bqClxpHJKP1bL163flISaurwyyy09DBBKvtXeReGi2QBUqNYRoFxwCC6Hj/kbckA ocFdtQhYxRaqbvMGT6IWFRjHFdOc7puAPcE53guDNBj9vkSAahkwu2+nzRSIW2+TODvp8 qWXxd793ATl12IeXFVEEFetQqqKnnlnxWqQegr7/RTbpoHlVfIVoVrpYEn0VkU7TVHg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793138785; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=KJA0Ab4y4XV4nkf+zcy3vs2gbR14WeGZC9I9U2lvy3k=; b=Jv2bas1dSN3dqQtcMSi0Iz2O081wfikXuyb0ctP5fdSFxFAw6XsL/dQ8sYeyV+U6l4OS FraRArNcsIIwTCL8dKAiMNgYLPz7dC4ke4b3mjvKcqYXvTevXkJAceNjeSGs7Jq5nI7mq cD3imAOuhTKWqRfPp9QR6yVtacQMBJTXYBSLICbjHmuJ4IR0kAn1Fh3dkYWI9yLnd5GNu rM3EpOALxmu9v2ti6GO/bauvTohrES0voLaLFDkOm2jtoFcK343ln9eSTt+AQOX6wf8wc nhXcEsPa2d74zMbUytjsbk4Q38WR741THtEkEps/8x1YMuh5QjQcXnW4SCOgqLcsBmg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=zahr34wS; arc=none smtp.remote-ip=209.85.128.41 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED7F3606A33D for ; Tue, 27 Oct 2026 22:06:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org ED7F3606A33D Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=zahr34wS Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-4a60f9474c4so4029735e9.0 for ; Tue, 27 Oct 2026 15:06:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793138783; x=1793743583; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=KJA0Ab4y4XV4nkf+zcy3vs2gbR14WeGZC9I9U2lvy3k=; b=zahr34wSrzVg0KvoehWXmJGpFAn5e46qXa1CWDc9bDCIdA6Bw40CT49u9IOwuXvjTk nyVgH+gqIeEGrIfsmxVhwBlnwsQPhLNxW9019gH4BruaudrISUVwn1A8mqyrw3biTO/O YUI5ToyFNZx7PsX6xoDwIBTvHc2SgvbXRjMieyAkPzrKJ4NOe0YpaSCponJFDFPoPAJs 4LkgmQ8401Z2XGg/qkeert2kW0KxfpDKHp8++44GMtL5QFB68tShU9ZZdgpABtlOtOR0 vTlRpE6oDLhpkbDiG/GyWu3owRCPXKWY7joefwf3E1s5vqJH7juI/1slBcqHfHoWNjsb 9c1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793138783; x=1793743583; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=KJA0Ab4y4XV4nkf+zcy3vs2gbR14WeGZC9I9U2lvy3k=; b=mzz1nBG9OE83Sbrt8ODOuMiJKKINkBRHKq6vBHnRqJ1IvvpUFX+UZ/cOaB+o/4xp4L U7/3/3FLKV605XJw0YItMCY88uPAMtqKacJ68S3WP+6uM7Yp4JS+a8kC57Q4CLitCWHU LEiYCVwytLlq2a1QuNxMp+qTQe8R1LMf6/bJBlZZr+zZ0xQJrT+ebMtNxd2xDO9ms9pI wVSfHaJ7az5XnNky7oXd9wLNPYbOoTWFKXGRlyOr9akpxJPaIH1jXw7rig/UeGYkf02P GVM2jBY0V1eYMzM3Md5hJoy0uByiAaekniAh71VkktAzC0s8KpWvJn4hx5C7w2NuvRpp f8Yg== X-Forwarded-Encrypted: i=1; AKwUvByi169n5JMVTRpifff+G42XP8IjfmIRIJIdHVfHq9UlH4321y8Zvpl2fIPrQjphE7ePSHzam0qH5qhQDw==@vger.kernel.org X-Gm-Message-State: AFq9FYLiuDPyGNghWTOuOvfli1l1ZZN5sIpVcOzW+leU7kudNlVvCRDZ 3qA6CqtjFFml36fMCDMI6ea/zBKpnA6R3l6fKVdfdUdCJY5aGz366guY X-Gm-Gg: AYBFou1pHdAbYWDwNF5g2FT57fITutG2MVffH0uXtZrtxvmkdjmTQI+eGA9rSUS+kpJ STPVV/86C9WKHoD/H7udK3/Js9IxEREBMH8w9NMEo7oA311GyYqTNXzjy4XTVH2TYbOkVabwqPz MYW7IKIb1cArEiLQnOoVTPMXZFzzgGAEEtZSxKqgnH22kU51e5IKw+e7DbuE1UTpxJ/21lCMol3 RK5S0q29fnxSCMmvcNYj4hKuubEbjCTGp1UrSNpwzM/vJsU9+b5RDt2tzYrYQT6+L9sHYRn9Dqm +OZdU2cfh1EZGAFioJ/2gRLAKXNp2r4pacGNfZeVGZHsO8E4W0IufjAbv6dBKEg7JahKYCeXKh5 w/JSIBwLlAItGeDvNa2Q8yivhWgX5nNe/cBNkMQ8Bk/5MO+c9LJ/pDz4beG72GkDKqTjCIO1sn2 ueA5h85j0LlZi+/K37faxRVNaEtnLcA3dwbuwAihMTqUM5TIJ+eBAjy72Z1Yu8qBxRm6vq5Cq80 1uI/i4gMixxu2rzdUkchqovxA9tro/bf1Qs7plFHhKo1z3XFyI= X-Received: by 2002:a05:600c:4e43:b0:4a6:42cc:bf65 with SMTP id 5b1f17b1804b1-4a96658730cmr6093585e9.17.1793138783296; Tue, 27 Oct 2026 15:06:23 -0700 (PDT) Received: from infinity ([2001:b07:5d26:7a6a:365a:60ff:fe0d:cfc6]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4a977edc08fsm1752495e9.4.2026.10.27.15.06.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:06:22 -0700 (PDT) From: koraynilay To: David Sterba , Alexander Viro , Christian Brauner Cc: Chris Mason , Jan Kara , "Darrick J . Wong" , Sean Smith , Andrey Albershteyn , linux-btrfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, koraynilay Subject: [RFC PATCH 2/2] btrfs: add provenance time (ptime) Date: Tue, 27 Oct 2026 23:05:32 +0100 Message-ID: <20261027220532.736352-3-koray.fra@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027220532.736352-1-koray.fra@gmail.com> References: <20261027220532.736352-1-koray.fra@gmail.com> X-Mailing-List: linux-btrfs@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Implement provenance time (ptime) in Btrfs, as introduced in the previous commit ("vfs: add provenance time (ptime)"). Update the on-disk format by claiming 12 bytes from the reserved[] space in btrfs_inode_item, putting ptime before other timestamps. Also add the fileattr_has_fsx_mask() helper to include/linux/fileattr.h to let filesystems check for unsupported xflags while allowing supported ones (like ptime). This helper can be used in the same way as fileattr_has_fsx(). Assisted-by: Gemini:3.8-flash-high antigravity-cli-1.4.7 Signed-off-by: koraynilay --- fs/btrfs/btrfs_inode.h | 4 ++++ fs/btrfs/delayed-inode.c | 6 ++++++ fs/btrfs/inode.c | 17 ++++++++++++++++- fs/btrfs/ioctl.c | 12 +++++++++++- fs/btrfs/print-tree.c | 1 + fs/btrfs/tree-log.c | 3 +++ include/linux/fileattr.h | 22 +++++++++++++++++++--- include/uapi/linux/btrfs_tree.h | 3 ++- 8 files changed, 62 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 0227789e911d..5afcf99b758c 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -332,6 +332,10 @@ struct btrfs_inode { u64 i_otime_sec; u32 i_otime_nsec; + /* File *data* creation (provenance) time. */ + s64 i_ptime_sec; + u32 i_ptime_nsec; + /* Hook into fs_info->delayed_iputs */ struct list_head delayed_iput; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 333ce8b52489..eef73ebb4a52 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1932,6 +1932,9 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans, btrfs_set_stack_timespec_sec(&inode_item->otime, inode->i_otime_sec); btrfs_set_stack_timespec_nsec(&inode_item->otime, inode->i_otime_nsec); + + btrfs_set_stack_timespec_sec(&inode_item->ptime, inode->i_ptime_sec); + btrfs_set_stack_timespec_nsec(&inode_item->ptime, inode->i_ptime_nsec); } int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) @@ -1981,6 +1984,9 @@ int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) inode->i_otime_sec = btrfs_stack_timespec_sec(&inode_item->otime); inode->i_otime_nsec = btrfs_stack_timespec_nsec(&inode_item->otime); + inode->i_ptime_sec = btrfs_stack_timespec_sec(&inode_item->ptime); + inode->i_ptime_nsec = btrfs_stack_timespec_nsec(&inode_item->ptime); + vfs_inode->i_generation = inode->generation; if (S_ISDIR(vfs_inode->i_mode)) inode->index_cnt = (u64)-1; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1272e0d01485..7c3cd06113bc 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4094,6 +4094,9 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path inode->i_otime_sec = btrfs_timespec_sec(leaf, &inode_item->otime); inode->i_otime_nsec = btrfs_timespec_nsec(leaf, &inode_item->otime); + inode->i_ptime_sec = btrfs_timespec_sec(leaf, &inode_item->ptime); + inode->i_ptime_nsec = btrfs_timespec_nsec(leaf, &inode_item->ptime); + inode_set_bytes(vfs_inode, btrfs_inode_nbytes(leaf, inode_item)); inode->generation = btrfs_inode_generation(leaf, inode_item); inode->last_trans = btrfs_inode_transid(leaf, inode_item); @@ -4286,6 +4289,9 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, btrfs_set_timespec_sec(leaf, &item->otime, BTRFS_I(inode)->i_otime_sec); btrfs_set_timespec_nsec(leaf, &item->otime, BTRFS_I(inode)->i_otime_nsec); + btrfs_set_timespec_sec(leaf, &item->ptime, BTRFS_I(inode)->i_ptime_sec); + btrfs_set_timespec_nsec(leaf, &item->ptime, BTRFS_I(inode)->i_ptime_nsec); + btrfs_set_inode_nbytes(leaf, item, inode_get_bytes(inode)); btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation); btrfs_set_inode_sequence(leaf, item, inode_peek_iversion(inode)); @@ -6025,6 +6031,8 @@ static struct btrfs_inode *new_simple_dir(struct inode *dir, inode_set_atime_to_ts(vfs_inode, inode_get_atime(dir)); inode->i_otime_sec = ts.tv_sec; inode->i_otime_nsec = ts.tv_nsec; + inode->i_ptime_sec = ts.tv_sec; + inode->i_ptime_nsec = ts.tv_nsec; vfs_inode->i_uid = dir->i_uid; vfs_inode->i_gid = dir->i_gid; @@ -6751,6 +6759,8 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, ts = simple_inode_init_ts(inode); BTRFS_I(inode)->i_otime_sec = ts.tv_sec; BTRFS_I(inode)->i_otime_nsec = ts.tv_nsec; + BTRFS_I(inode)->i_ptime_sec = ts.tv_sec; + BTRFS_I(inode)->i_ptime_nsec = ts.tv_nsec; /* * We're going to fill the inode item now, so at this point the inode @@ -8095,6 +8105,9 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ei->i_otime_sec = 0; ei->i_otime_nsec = 0; + ei->i_ptime_sec = 0; + ei->i_ptime_nsec = 0; + inode = &ei->vfs_inode; btrfs_extent_map_tree_init(&ei->extent_tree); @@ -8241,9 +8254,11 @@ static int btrfs_getattr(const struct mnt_idmap *idmap, u32 blocksize = btrfs_sb(inode->i_sb)->sectorsize; u32 bi_flags = BTRFS_I(inode)->flags; - stat->result_mask |= STATX_BTIME; + stat->result_mask |= (STATX_BTIME | STATX_PTIME); stat->btime.tv_sec = BTRFS_I(inode)->i_otime_sec; stat->btime.tv_nsec = BTRFS_I(inode)->i_otime_nsec; + stat->ptime.tv_sec = BTRFS_I(inode)->i_ptime_sec; + stat->ptime.tv_nsec = BTRFS_I(inode)->i_ptime_nsec; if (bi_flags & BTRFS_INODE_APPEND) stat->attributes |= STATX_ATTR_APPEND; if (bi_flags & BTRFS_INODE_COMPRESS) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f3e2afe221be..48598a99bddb 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -275,6 +275,9 @@ int btrfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) const struct btrfs_inode *inode = BTRFS_I(d_inode(dentry)); fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(inode)); + fa->fsx_ptime.tv_sec = inode->i_ptime_sec; + fa->fsx_ptime.tv_nsec = inode->i_ptime_nsec; + fa->fsx_xflags |= FS_XFLAG_PTIME; return 0; } @@ -294,7 +297,10 @@ int btrfs_fileattr_set(const struct mnt_idmap *idmap, if (btrfs_root_readonly(root)) return -EROFS; - if (fileattr_has_fsx(fa)) + /* We now support FS_XFLAG_PTIME, so exclude it from the unsupported + * check + */ + if (fileattr_has_fsx_mask(fa, FS_XFLAG_PTIME)) return -EOPNOTSUPP; fsflags = btrfs_mask_fsflags_for_type(&inode->vfs_inode, fa->flags); @@ -436,6 +442,10 @@ int btrfs_fileattr_set(const struct mnt_idmap *idmap, } update_flags: + if (fa->fsx_xflags & FS_XFLAG_PTIME) { + inode->i_ptime_sec = fa->fsx_ptime.tv_sec; + inode->i_ptime_nsec = fa->fsx_ptime.tv_nsec; + } inode->flags = inode_flags; btrfs_update_inode_mapping_flags(inode); btrfs_sync_inode_flags_to_i_flags(inode); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 53e726119ca7..ba385d0ed9ed 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -263,6 +263,7 @@ static void print_inode_item(const struct extent_buffer *eb, int i) print_timespec(eb, &ii->ctime, "\t\tctime ", "\n"); print_timespec(eb, &ii->mtime, "\t\tmtime ", "\n"); print_timespec(eb, &ii->otime, "\t\totime ", "\n"); + print_timespec(eb, &ii->ptime, "\t\tptime ", "\n"); } static void print_dir_item(const struct extent_buffer *eb, int i) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 1d9dfb63fc5a..72a4a92b40b9 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4631,6 +4631,9 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, btrfs_set_timespec_sec(leaf, &item->otime, inode->i_otime_sec); btrfs_set_timespec_nsec(leaf, &item->otime, inode->i_otime_nsec); + btrfs_set_timespec_sec(leaf, &item->ptime, inode->i_ptime_sec); + btrfs_set_timespec_nsec(leaf, &item->ptime, inode->i_ptime_nsec); + /* * We do not need to set the nbytes field, in fact during a fast fsync * its value may not even be correct, since a fast fsync does not wait diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h index 0b93f9609284..f45377fdaf38 100644 --- a/include/linux/fileattr.h +++ b/include/linux/fileattr.h @@ -64,6 +64,24 @@ int copy_fsxattr_to_user(const struct file_kattr *fa, struct fsxattr __user *ufa void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags); void fileattr_fill_flags(struct file_kattr *fa, u32 flags); + +/** + * fileattr_has_fsx_mask - check for extended flags/attributes + * @fa: fileattr pointer + * @allowed_xflags_mask: additional xflags permitted + * + * Return: true if any attributes are present that are not represented in + * ->flags or @allowed_xflags_mask. + */ +static inline bool fileattr_has_fsx_mask(const struct file_kattr *fa, + u32 allowed_xflags_mask) +{ + return fa->fsx_valid && + ((fa->fsx_xflags & ~(FS_XFLAG_COMMON | allowed_xflags_mask)) || + fa->fsx_extsize != 0 || fa->fsx_projid != 0 || + fa->fsx_cowextsize != 0); +} + /** * fileattr_has_fsx - check for extended flags/attributes * @fa: fileattr pointer @@ -73,9 +91,7 @@ void fileattr_fill_flags(struct file_kattr *fa, u32 flags); */ static inline bool fileattr_has_fsx(const struct file_kattr *fa) { - return fa->fsx_valid && - ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || fa->fsx_extsize != 0 || - fa->fsx_projid != 0 || fa->fsx_cowextsize != 0); + return fileattr_has_fsx_mask(fa, 0); } int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index 47ee52859b45..c360b3e95f45 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -900,7 +900,8 @@ struct btrfs_inode_item { * a little future expansion, for more than this we can * just grow the inode item and version it */ - __le64 reserved[4]; + __le32 reserved[5]; + struct btrfs_timespec ptime; struct btrfs_timespec atime; struct btrfs_timespec ctime; struct btrfs_timespec mtime; -- 2.56.0