From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A00E03B0AD7; Fri, 10 Jul 2026 08:53:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673627; cv=none; b=GjIW0dOHoOGyN5bkg/ENxjVIY4rw36bV5+fYEiirf5NvDS4RAHPIRmVgf8++dmWHXfAm6dPlddAE29bRzX53xKObsvy0Gi7xLHeIpd3A+7Nnjy8X8tl1jeyJ+NoWM75tONX73g9NxCbF83vS+YXT71oMNQzXGYBNmOr9s/ntWvA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783673627; c=relaxed/simple; bh=fJ3ds7sp5X2Z7MRJlIPcPeWqqcQJj8tgKWYQjNmWrpo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YHYlSwuxqrEiTo3B2piqRaCbteOksJ9tajeBzd/i+ZtOZz71xFtRSECj4DnXmCFKuypx8eRhPBChXU5EcctdkLNSZuhkRNMu5S7t73cYqGYFkf2JUyRWAuG3NTfdpeGalufIs6EBzI2mLJOUwmcBKhFcAYMjq9HFvImwsj1+FTo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PmtHHt5K; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PmtHHt5K" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A1611F000E9; Fri, 10 Jul 2026 08:53:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1783673625; bh=kL8VGnh7ljhPkiDmZ9sLKlAncJEgXPbXDH7MRlFFQLA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=PmtHHt5Ky2Hkb0lTfstKPPBvjw6CoVk36I64uGxTtYkfiy9hqaBb7HkTgbf10GEki pmSeMhenJQozUO7KhLO5eFZ9CpsMqDZDV2e4ajWXrMQkqjK/6HIs+K8hB7jWpdOpiG cz+WFzluv7m02Nx9WVmi7Xgv4PE8pAxOd7y20trTYXkT6PUI5Ebhqz/Eq/I9dfRDVD bmL3PS5YfdEunfKUKslAYKKBalCY6Gi5tcgdintiL4+KH2iAyllhvpKSuwrsKf0+PW /s0WPdEhh/AntbuiJdHFpo62xgMguox+GKhHIGG3ZluazFvM+1qumPjscm8wIcR3E6 nxhmpgb9cpWZw== From: Andrey Albershteyn To: linux-xfs@vger.kernel.org, fsverity@lists.linux.dev, linux-fsdevel@vger.kernel.org, ebiggers@kernel.org Cc: Andrey Albershteyn , hch@lst.de, linux-ext4@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-btrfs@vger.kernel.org, djwong@kernel.org Subject: [PATCH v11 07/20] xfs: introduce fsverity on-disk changes Date: Fri, 10 Jul 2026 10:52:35 +0200 Message-ID: <20260710085256.3464201-8-aalbersh@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260710085256.3464201-1-aalbersh@kernel.org> References: <20260710085256.3464201-1-aalbersh@kernel.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce XFS_DIFLAG2_VERITY for inodes with fsverity. This flag indicates that inode has fs-verity enabled (i.e. descriptor exist, tree is built and file is read-only). Introduce XFS_SB_FEAT_RO_COMPAT_VERITY for filesystems having fsverity inodes. As on-disk changes applies to fsverity inodes only, let older kernels read-only access. This will be enabled in the further patch after full fsverity support. Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Andrey Albershteyn --- fs/xfs/libxfs/xfs_format.h | 30 +++++++++++++++++++++++++++++- fs/xfs/libxfs/xfs_inode_buf.c | 8 ++++++++ fs/xfs/libxfs/xfs_inode_util.c | 5 ++++- fs/xfs/libxfs/xfs_sb.c | 2 ++ fs/xfs/xfs_iops.c | 5 ++++- fs/xfs/xfs_mount.h | 2 ++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index dd0ed046fbe9..7b0511eb03d0 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -374,6 +374,7 @@ xfs_sb_has_compat_feature( #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ #define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3) /* inobt block counts */ +#define XFS_SB_FEAT_RO_COMPAT_VERITY (1 << 4) /* fs-verity */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ @@ -1230,16 +1231,21 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) */ #define XFS_DIFLAG2_METADATA_BIT 5 +/* inodes sealed with fs-verity */ +#define XFS_DIFLAG2_VERITY_BIT 6 + #define XFS_DIFLAG2_DAX (1ULL << XFS_DIFLAG2_DAX_BIT) #define XFS_DIFLAG2_REFLINK (1ULL << XFS_DIFLAG2_REFLINK_BIT) #define XFS_DIFLAG2_COWEXTSIZE (1ULL << XFS_DIFLAG2_COWEXTSIZE_BIT) #define XFS_DIFLAG2_BIGTIME (1ULL << XFS_DIFLAG2_BIGTIME_BIT) #define XFS_DIFLAG2_NREXT64 (1ULL << XFS_DIFLAG2_NREXT64_BIT) #define XFS_DIFLAG2_METADATA (1ULL << XFS_DIFLAG2_METADATA_BIT) +#define XFS_DIFLAG2_VERITY (1ULL << XFS_DIFLAG2_VERITY_BIT) #define XFS_DIFLAG2_ANY \ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ - XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA) + XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA | \ + XFS_DIFLAG2_VERITY) static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip) { @@ -2027,4 +2033,26 @@ struct xfs_acl { #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) +/* + * At maximum of 8 levels with 128 hashes per block (32 bytes SHA-256) maximum + * tree size is ((128^8 − 1)/(128 − 1)) = 567*10^12 blocks. This should fit in + * 53 bits address space. + * + * At this Merkle tree size we can cover 295EB large file. This is much larger + * than the currently supported file size. + * + * For sha512 the largest file we can cover ends at 1 << 50 offset, this is also + * good. + */ +#define XFS_FSVERITY_LARGEST_FILE ((loff_t)1ULL << 53) + +/* + * Alignment of the fsverity metadata placement. This is largest supported PAGE + * SIZE for fsverity. This is used to space out data and metadata in page cache. + * The spacing is necessary for non-exposure of metadata to userspace and + * correct merkle tree synethesis in the iomap. + */ +#define XFS_FSVERITY_START_ALIGN (65536) + + #endif /* __XFS_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index 336ef843f2fe..bd80a19f2e09 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -760,6 +760,14 @@ xfs_dinode_verify( !xfs_has_rtreflink(mp)) return __this_address; + /* only regular files can have fsverity */ + if (flags2 & XFS_DIFLAG2_VERITY) { + if (!xfs_has_verity(mp)) + return __this_address; + if (!S_ISREG(mode)) + return __this_address; + } + if (xfs_has_zoned(mp) && dip->di_metatype == cpu_to_be16(XFS_METAFILE_RTRMAP)) { if (be32_to_cpu(dip->di_used_blocks) > mp->m_sb.sb_rgextents) diff --git a/fs/xfs/libxfs/xfs_inode_util.c b/fs/xfs/libxfs/xfs_inode_util.c index 258ac3d0d486..5a516bd31c31 100644 --- a/fs/xfs/libxfs/xfs_inode_util.c +++ b/fs/xfs/libxfs/xfs_inode_util.c @@ -74,7 +74,8 @@ xfs_flags2diflags2( uint64_t di_flags2 = (ip->i_diflags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_BIGTIME | - XFS_DIFLAG2_NREXT64)); + XFS_DIFLAG2_NREXT64 | + XFS_DIFLAG2_VERITY)); if (xflags & FS_XFLAG_DAX) di_flags2 |= XFS_DIFLAG2_DAX; @@ -126,6 +127,8 @@ xfs_ip2xflags( flags |= FS_XFLAG_DAX; if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) flags |= FS_XFLAG_COWEXTSIZE; + if (ip->i_diflags2 & XFS_DIFLAG2_VERITY) + flags |= FS_XFLAG_VERITY; } if (xfs_inode_has_attr_fork(ip)) diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 47322adb7690..a15510ebd2f1 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -165,6 +165,8 @@ xfs_sb_version_to_features( features |= XFS_FEAT_REFLINK; if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_INOBTCNT) features |= XFS_FEAT_INOBTCNT; + if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_VERITY) + features |= XFS_FEAT_VERITY; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) features |= XFS_FEAT_FTYPE; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 6339f4956ecb..11dc1a485ca7 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -1398,12 +1398,15 @@ xfs_diflags_to_iflags( flags |= S_NOATIME; if (init && xfs_inode_should_enable_dax(ip)) flags |= S_DAX; + if (xflags & FS_XFLAG_VERITY) + flags |= S_VERITY; /* * S_DAX can only be set during inode initialization and is never set by * the VFS, so we cannot mask off S_DAX in i_flags. */ - inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | S_SYNC | S_NOATIME); + inode->i_flags &= + ~(S_IMMUTABLE | S_APPEND | S_SYNC | S_NOATIME | S_VERITY); inode->i_flags |= flags; } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 66a02d1b9ad7..9ed7d091093d 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -388,6 +388,7 @@ typedef struct xfs_mount { #define XFS_FEAT_EXCHANGE_RANGE (1ULL << 27) /* exchange range */ #define XFS_FEAT_METADIR (1ULL << 28) /* metadata directory tree */ #define XFS_FEAT_ZONED (1ULL << 29) /* zoned RT device */ +#define XFS_FEAT_VERITY (1ULL << 30) /* fs-verity */ /* Mount features */ #define XFS_FEAT_NOLIFETIME (1ULL << 47) /* disable lifetime hints */ @@ -445,6 +446,7 @@ __XFS_HAS_FEAT(exchange_range, EXCHANGE_RANGE) __XFS_HAS_FEAT(metadir, METADIR) __XFS_HAS_FEAT(zoned, ZONED) __XFS_HAS_FEAT(nolifetime, NOLIFETIME) +__XFS_HAS_FEAT(verity, VERITY) static inline bool xfs_has_rtgroups(const struct xfs_mount *mp) { -- 2.54.0