Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2218302/?format=api
{ "id": 2218302, "url": "http://patchwork.ozlabs.org/api/patches/2218302/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260331212827.2631020-16-aalbersh@kernel.org/", "project": { "id": 8, "url": "http://patchwork.ozlabs.org/api/projects/8/?format=api", "name": "Linux ext4 filesystem development", "link_name": "linux-ext4", "list_id": "linux-ext4.vger.kernel.org", "list_email": "linux-ext4@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260331212827.2631020-16-aalbersh@kernel.org>", "list_archive_url": null, "date": "2026-03-31T21:28:16", "name": "[v6,15/22] xfs: add fs-verity support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "15e47187e9d5d5ebcd381616d4c7858de45eab2d", "submitter": { "id": 92821, "url": "http://patchwork.ozlabs.org/api/people/92821/?format=api", "name": "Andrey Albershteyn", "email": "aalbersh@kernel.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260331212827.2631020-16-aalbersh@kernel.org/mbox/", "series": [ { "id": 498255, "url": "http://patchwork.ozlabs.org/api/series/498255/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/list/?series=498255", "date": "2026-03-31T21:28:01", "name": "fs-verity support for XFS with post EOF merkle tree", "version": 6, "mbox": "http://patchwork.ozlabs.org/series/498255/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2218302/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2218302/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <SRS0=qiLm=B7=vger.kernel.org=linux-ext4+bounces-15562-patchwork-incoming=ozlabs.org@ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-ext4@vger.kernel.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "patchwork-incoming@ozlabs.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=G6y64lP8;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=2404:9400:2221:ea00::3; helo=mail.ozlabs.org;\n envelope-from=srs0=qilm=b7=vger.kernel.org=linux-ext4+bounces-15562-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)", "gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=\"2600:3c15:e001:75::12fc:5321\"\n arc.chain=subspace.kernel.org", "gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org", "gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=G6y64lP8;\n\tdkim-atps=neutral", "gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15562-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"G6y64lP8\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201" ], "Received": [ "from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4flhSF5m3rz1yCp\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 01 Apr 2026 08:43:09 +1100 (AEDT)", "from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4flhSF5FqQz4wGT\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 01 Apr 2026 08:43:09 +1100 (AEDT)", "by gandalf.ozlabs.org (Postfix)\n\tid 4flhSF58qQz58df; Wed, 01 Apr 2026 08:43:09 +1100 (AEDT)", "from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4flhSB1CLDz4wGT\n\tfor <patchwork-incoming@ozlabs.org>; Wed, 01 Apr 2026 08:43:06 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 789A730D1843\n\tfor <patchwork-incoming@ozlabs.org>; Tue, 31 Mar 2026 21:30:53 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id B4A434657F5;\n\tTue, 31 Mar 2026 21:29:20 +0000 (UTC)", "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 72FDC45348A;\n\tTue, 31 Mar 2026 21:29:20 +0000 (UTC)", "by smtp.kernel.org (Postfix) with ESMTPSA id ACB00C2BCB0;\n\tTue, 31 Mar 2026 21:29:17 +0000 (UTC)" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1774993389; cv=pass;\n\tb=pLftyr6dI4EkhMzZ8ORykDthr6E0oak5VzchJauGKX3wwj3pbnTNPVyBVvAls5zn5KqeCJCyRAKVa//Jp+L5rfGZHXNLnE/v1zrP/KhhW8LJa4XjZUm+6X0caCUZ0Y//BVWmaSaIYcDXOiLkVZzr1d3nMsh9vN81a9KlbcNJl0vCDmtS4Fk6MeSKpVYb4WtZvm/e1wqQO9zSR7pyP+z1bz5EeSmMwwK+34wF22oaqpfvbsRLBU+CghYyaNNL1V2sBensVAfPtRYJAvbSWqQ2t+4gnu+jCDYoJ1NpTig/W4UvJrsiYFXW0vPvAz37q2DGVDzGMzQdXG1r5sKAJHpSXw==", "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774992560; cv=none;\n b=n5Jkjwv7tuaPV9Rflo4HgBuV8WmoEjY3/tt0jJAS1slFx84udEzgbqLzJVauYMuHLzIata1+HYxu0JEWDWyyUOxY7sENJ2DlK4XbBRBNMoAVuiJ1SCGzYTD70Lsar0/MhfvRsK97gU0LMReSbhz8Ga4wK0D/jcNwJ28Oa78CZUw=" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1774993389; c=relaxed/relaxed;\n\tbh=jvbgcPaZ+gTcm2COYBvsfMAKs/ZVXtqY7bUAfIDZ7qs=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=ijHsaxuFhC+1g2Z3mjr4qglvjPW6VHG0jRXaAc25BMGbiF74Dmkw4lLvaX7xeuxuNZmHxBVtbmpTsJkBo1N6xypVmrzCxoXCEWnJXUB6lmIjoH6UuteWRXM87IhXb3n/Nrbhx9szBHuapEliN4SjU8E9A0GmW89f5RuUcuePAh2czu2/+icPIiFHpoHc+tAQtaUXVz/BuHK2H97EK3YOCkrX9XPilZDLoUDEniRWFOgq2U+1x9G+hk5st8LsOOC7zV9uPcZNNOmxQDNaFETmtMV/wIacMNzMrqydvJZtJYJS5EalucI8Y2XXrpeS6437DcLamOwLC71e1r+TQDGpWw==", "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774992560; c=relaxed/simple;\n\tbh=VduCrUW9uvCKE8r8y0eKlfmUscT23wW4YbfQYJ1RYFs=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=Ul7IHF0UjVSKlZVxxc+J83+g7Zv76JMm1EbkrnK/J+Qi+hphPtGjffyhikv5tSMnZeOuDclz7aI2U+86GfQdYOdrJpQ6Pkxmnb+zU/3G6CiROyttWo+lz4UErp575cdKG1bmGHCl+8XhK2HZG9KdTWGvn87pC9sYUNbaBqYe+cY=" ], "ARC-Authentication-Results": [ "i=2; gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org;\n dkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=G6y64lP8; dkim-atps=neutral;\n spf=pass (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15562-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org", "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=G6y64lP8; arc=none smtp.client-ip=10.30.226.201" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1774992560;\n\tbh=VduCrUW9uvCKE8r8y0eKlfmUscT23wW4YbfQYJ1RYFs=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=G6y64lP8mQZ6S/71Uqa0HTKP4ECv52BZz5roQQjQHcWMSsNIGZxvtqxDsKJbEBsG5\n\t Ssj6NhhhxyenorbOQBqmunisgN9PFruOMf7gGUvanPbW4HRXHyDIXViPVFLl/sZJBD\n\t wbtZHYxzIeEFMTavYtCxs7roKs/+LeJxWgpRL0qYPwhr0bRtOBAhvhYFXVM6j4zL8h\n\t UF9cq0p7wWqBa9eqSlVwxTruG1h4NQ/9uOrzS+a7hajAdcqQ/9hCsyppE8iOzF7oBk\n\t lRdNDfl+t8zNw/ZOebPQfuNawKY1xjGCtYiVtv0HCMha8LmmOxF6aFMZGePRKLu72D\n\t ubXZ0CNgkDRAQ==", "From": "Andrey Albershteyn <aalbersh@kernel.org>", "To": "linux-xfs@vger.kernel.org,\n\tfsverity@lists.linux.dev,\n\tlinux-fsdevel@vger.kernel.org,\n\tebiggers@kernel.org", "Cc": "Andrey Albershteyn <aalbersh@kernel.org>,\n\thch@lst.de,\n\tlinux-ext4@vger.kernel.org,\n\tlinux-f2fs-devel@lists.sourceforge.net,\n\tlinux-btrfs@vger.kernel.org,\n\tdjwong@kernel.org", "Subject": "[PATCH v6 15/22] xfs: add fs-verity support", "Date": "Tue, 31 Mar 2026 23:28:16 +0200", "Message-ID": "<20260331212827.2631020-16-aalbersh@kernel.org>", "X-Mailer": "git-send-email 2.51.2", "In-Reply-To": "<20260331212827.2631020-1-aalbersh@kernel.org>", "References": "<20260331212827.2631020-1-aalbersh@kernel.org>", "Precedence": "bulk", "X-Mailing-List": "linux-ext4@vger.kernel.org", "List-Id": "<linux-ext4.vger.kernel.org>", "List-Subscribe": "<mailto:linux-ext4+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-ext4+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Spam-Status": "No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1", "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org" }, "content": "Add integration with fs-verity. XFS stores fs-verity descriptor and\nMerkle tree in the inode data fork at first block aligned to 64k past\nEOF.\n\nThe Merkle tree reading/writing is done through iomap interface. The\ndata itself is read to the inode's page cache. When XFS reads from this\nregion iomap doesn't call into fsverity to verify it against Merkle\ntree. For data, verification is done at ioend completion in a workqueue.\n\nWhen fs-verity is enabled on an inode, the XFS_IVERITY_CONSTRUCTION\nflag is set meaning that the Merkle tree is being build. The\ninitialization ends with storing of verity descriptor and setting\ninode on-disk flag (XFS_DIFLAG2_VERITY). Lastly, the\nXFS_IVERITY_CONSTRUCTION is dropped and I_VERITY is set on inode.\n\nThe descriptor is stored in a new block aligned to 64k after the last\nMerkle tree block. The size of the descriptor is stored at the end of\nthe last descriptor block (descriptor can be multiple blocks).\n\nReviewed-by: Christoph Hellwig <hch@lst.de>\nSigned-off-by: Andrey Albershteyn <aalbersh@kernel.org>\n---\n fs/xfs/xfs_bmap_util.c | 8 +\n fs/xfs/xfs_fsverity.c | 349 ++++++++++++++++++++++++++++++++++++++++-\n fs/xfs/xfs_fsverity.h | 2 +\n fs/xfs/xfs_message.c | 4 +\n fs/xfs/xfs_message.h | 1 +\n fs/xfs/xfs_mount.h | 2 +\n fs/xfs/xfs_super.c | 7 +\n 7 files changed, 372 insertions(+), 1 deletion(-)", "diff": "diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c\nindex 0ab00615f1ad..18348f4fd2aa 100644\n--- a/fs/xfs/xfs_bmap_util.c\n+++ b/fs/xfs/xfs_bmap_util.c\n@@ -31,6 +31,7 @@\n #include \"xfs_rtbitmap.h\"\n #include \"xfs_rtgroup.h\"\n #include \"xfs_zone_alloc.h\"\n+#include <linux/fsverity.h>\n \n /* Kernel only BMAP related definitions and functions */\n \n@@ -553,6 +554,13 @@ xfs_can_free_eofblocks(\n \tif (last_fsb <= end_fsb)\n \t\treturn false;\n \n+\t/*\n+\t * Nothing to clean on fsverity inodes as they don't use prealloc and\n+\t * there no delalloc as only written data is fsverity metadata\n+\t */\n+\tif (IS_VERITY(VFS_I(ip)))\n+\t\treturn false;\n+\n \t/*\n \t * Check if there is an post-EOF extent to free. If there are any\n \t * delalloc blocks attached to the inode (data fork delalloc\ndiff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c\nindex b983e20bb5e1..5a6a48fcf843 100644\n--- a/fs/xfs/xfs_fsverity.c\n+++ b/fs/xfs/xfs_fsverity.c\n@@ -4,14 +4,26 @@\n */\n #include \"xfs_platform.h\"\n #include \"xfs_format.h\"\n-#include \"xfs_inode.h\"\n #include \"xfs_shared.h\"\n #include \"xfs_trans_resv.h\"\n #include \"xfs_mount.h\"\n #include \"xfs_fsverity.h\"\n+#include \"xfs_da_format.h\"\n+#include \"xfs_da_btree.h\"\n+#include \"xfs_inode.h\"\n+#include \"xfs_log_format.h\"\n+#include \"xfs_bmap_util.h\"\n+#include \"xfs_log_format.h\"\n+#include \"xfs_trans.h\"\n+#include \"xfs_trace.h\"\n+#include \"xfs_quota.h\"\n #include \"xfs_fsverity.h\"\n+#include \"xfs_iomap.h\"\n+#include \"xfs_error.h\"\n+#include \"xfs_health.h\"\n #include <linux/fsverity.h>\n #include <linux/iomap.h>\n+#include <linux/pagemap.h>\n \n loff_t\n xfs_fsverity_metadata_offset(\n@@ -28,3 +40,338 @@ xfs_fsverity_is_file_data(\n \treturn fsverity_active(VFS_IC(ip)) &&\n \t\t\toffset < xfs_fsverity_metadata_offset(ip);\n }\n+\n+/*\n+ * Retrieve the verity descriptor.\n+ */\n+static int\n+xfs_fsverity_get_descriptor(\n+\tstruct inode\t\t*inode,\n+\tvoid\t\t\t*buf,\n+\tsize_t\t\t\tbuf_size)\n+{\n+\tstruct xfs_inode\t*ip = XFS_I(inode);\n+\tstruct xfs_mount\t*mp = ip->i_mount;\n+\t__be32\t\t\td_desc_size;\n+\tu32\t\t\tdesc_size;\n+\tu64\t\t\tdesc_size_pos;\n+\tint\t\t\terror;\n+\tu64\t\t\tdesc_pos;\n+\tstruct xfs_bmbt_irec\trec;\n+\tint\t\t\tis_empty;\n+\tuint32_t\t\tblocksize = i_blocksize(VFS_I(ip));\n+\txfs_fileoff_t\t\tlast_block_offset;\n+\n+\tASSERT(inode->i_flags & S_VERITY);\n+\terror = xfs_bmap_last_extent(NULL, ip, XFS_DATA_FORK, &rec, &is_empty);\n+\tif (error)\n+\t\treturn error;\n+\n+\tif (is_empty)\n+\t\treturn -ENODATA;\n+\n+\tlast_block_offset =\n+\t\tXFS_FSB_TO_B(mp, rec.br_startoff + rec.br_blockcount);\n+\tif (last_block_offset < xfs_fsverity_metadata_offset(ip))\n+\t\treturn -ENODATA;\n+\n+\tdesc_size_pos = last_block_offset - sizeof(__be32);\n+\terror = fsverity_pagecache_read(inode, (char *)&d_desc_size,\n+\t\t\tsizeof(d_desc_size), desc_size_pos);\n+\tif (error)\n+\t\treturn error;\n+\n+\tdesc_size = be32_to_cpu(d_desc_size);\n+\tif (XFS_IS_CORRUPT(mp, desc_size > FS_VERITY_MAX_DESCRIPTOR_SIZE))\n+\t\treturn -ERANGE;\n+\tif (XFS_IS_CORRUPT(mp, desc_size > desc_size_pos))\n+\t\treturn -ERANGE;\n+\n+\tif (!buf_size)\n+\t\treturn desc_size;\n+\n+\tif (XFS_IS_CORRUPT(mp, desc_size > buf_size))\n+\t\treturn -ERANGE;\n+\n+\tdesc_pos = round_down(desc_size_pos - desc_size, blocksize);\n+\terror = fsverity_pagecache_read(inode, buf, desc_size, desc_pos);\n+\tif (error)\n+\t\treturn error;\n+\n+\treturn desc_size;\n+}\n+\n+static int\n+xfs_fsverity_write_descriptor(\n+\tstruct file\t\t*file,\n+\tconst void\t\t*desc,\n+\tu32\t\t\tdesc_size,\n+\tu64\t\t\tmerkle_tree_size)\n+{\n+\tint\t\t\terror;\n+\tstruct inode\t\t*inode = file_inode(file);\n+\tstruct xfs_inode\t*ip = XFS_I(inode);\n+\tunsigned int\t\tblksize = ip->i_mount->m_attr_geo->blksize;\n+\tu64\t\t\ttree_last_block =\n+\t\t\txfs_fsverity_metadata_offset(ip) + merkle_tree_size;\n+\tu64\t\t\tdesc_pos =\n+\t\t\tround_up(tree_last_block, XFS_FSVERITY_START_ALIGN);\n+\tu64\t\t\tdesc_end = desc_pos + desc_size;\n+\t__be32\t\t\tdesc_size_disk = cpu_to_be32(desc_size);\n+\tu64\t\t\tdesc_size_pos =\n+\t\t\tround_up(desc_end + sizeof(desc_size_disk), blksize) -\n+\t\t\tsizeof(desc_size_disk);\n+\n+\terror = iomap_fsverity_write(file, desc_size_pos, sizeof(__be32),\n+\t\t\t(const void *)&desc_size_disk,\n+\t\t\t&xfs_buffered_write_iomap_ops,\n+\t\t\t&xfs_iomap_write_ops);\n+\tif (error)\n+\t\treturn error;\n+\n+\treturn iomap_fsverity_write(file, desc_pos, desc_size, desc,\n+\t\t\t&xfs_buffered_write_iomap_ops,\n+\t\t\t&xfs_iomap_write_ops);\n+}\n+\n+/*\n+ * Try to remove all the fsverity metadata after a failed enablement.\n+ */\n+static int\n+xfs_fsverity_delete_metadata(\n+\tstruct xfs_inode\t*ip)\n+{\n+\tstruct xfs_trans\t*tp;\n+\tstruct xfs_mount\t*mp = ip->i_mount;\n+\tint\t\t\terror;\n+\n+\terror = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);\n+\tif (error)\n+\t\treturn error;\n+\n+\txfs_ilock(ip, XFS_ILOCK_EXCL);\n+\txfs_trans_ijoin(tp, ip, 0);\n+\n+\t/*\n+\t * We removing post EOF data, no need to update i_size as fsverity\n+\t * didn't move i_size in the first place\n+\t */\n+\terror = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, XFS_ISIZE(ip));\n+\tif (error)\n+\t\tgoto err_cancel;\n+\n+\terror = xfs_trans_commit(tp);\n+\tif (error)\n+\t\tgoto err_cancel;\n+\txfs_iunlock(ip, XFS_ILOCK_EXCL);\n+\n+\treturn error;\n+\n+err_cancel:\n+\txfs_iunlock(ip, XFS_ILOCK_EXCL);\n+\txfs_trans_cancel(tp);\n+\treturn error;\n+}\n+\n+\n+/*\n+ * Prepare to enable fsverity by clearing old metadata.\n+ */\n+static int\n+xfs_fsverity_begin_enable(\n+\tstruct file\t\t*filp)\n+{\n+\tstruct inode\t\t*inode = file_inode(filp);\n+\tstruct xfs_inode\t*ip = XFS_I(inode);\n+\tint\t\t\terror;\n+\n+\txfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);\n+\n+\tif (IS_DAX(inode))\n+\t\treturn -EINVAL;\n+\n+\tif (inode->i_size > XFS_FSVERITY_LARGEST_FILE)\n+\t\treturn -EFBIG;\n+\n+\t/*\n+\t * Flush pagecache before building Merkle tree. Inode is locked and no\n+\t * further writes will happen to the file except fsverity metadata\n+\t */\n+\terror = filemap_write_and_wait(inode->i_mapping);\n+\tif (error)\n+\t\treturn error;\n+\n+\tif (xfs_iflags_test_and_set(ip, XFS_VERITY_CONSTRUCTION))\n+\t\treturn -EBUSY;\n+\n+\terror = xfs_qm_dqattach(ip);\n+\tif (error)\n+\t\treturn error;\n+\n+\treturn xfs_fsverity_delete_metadata(ip);\n+}\n+\n+/*\n+ * Complete (or fail) the process of enabling fsverity.\n+ */\n+static int\n+xfs_fsverity_end_enable(\n+\tstruct file\t\t*file,\n+\tconst void\t\t*desc,\n+\tsize_t\t\t\tdesc_size,\n+\tu64\t\t\tmerkle_tree_size)\n+{\n+\tstruct inode\t\t*inode = file_inode(file);\n+\tstruct xfs_inode\t*ip = XFS_I(inode);\n+\tstruct xfs_mount\t*mp = ip->i_mount;\n+\tstruct xfs_trans\t*tp;\n+\tint\t\t\terror = 0;\n+\tloff_t\t\t\trange_start = xfs_fsverity_metadata_offset(ip);\n+\n+\txfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);\n+\n+\t/* fs-verity failed, just cleanup */\n+\tif (desc == NULL)\n+\t\tgoto out;\n+\n+\terror = xfs_fsverity_write_descriptor(file, desc, desc_size,\n+\t\t\tmerkle_tree_size);\n+\tif (error)\n+\t\tgoto out;\n+\n+\t/*\n+\t * Wait for Merkle tree get written to disk before setting on-disk inode\n+\t * flag and clearing XFS_VERITY_CONSTRUCTION\n+\t */\n+\terror = filemap_write_and_wait_range(inode->i_mapping, range_start,\n+\t\t\tLLONG_MAX);\n+\tif (error)\n+\t\tgoto out;\n+\n+\t/*\n+\t * Proactively drop any delayed allocations in COW fork, the fsverity\n+\t * files are read-only\n+\t */\n+\tif (xfs_is_cow_inode(ip))\n+\t\txfs_bmap_punch_delalloc_range(ip, XFS_COW_FORK, 0, LLONG_MAX,\n+\t\t\t\tNULL);\n+\n+\t/*\n+\t * Set fsverity inode flag\n+\t */\n+\terror = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange,\n+\t\t\t0, 0, false, &tp);\n+\tif (error)\n+\t\tgoto out;\n+\n+\t/*\n+\t * Ensure that we've persisted the verity information before we enable\n+\t * it on the inode and tell the caller we have sealed the inode.\n+\t */\n+\tip->i_diflags2 |= XFS_DIFLAG2_VERITY;\n+\n+\txfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);\n+\txfs_trans_set_sync(tp);\n+\n+\terror = xfs_trans_commit(tp);\n+\txfs_iunlock(ip, XFS_ILOCK_EXCL);\n+\n+\tif (!error)\n+\t\tinode->i_flags |= S_VERITY;\n+\n+out:\n+\tif (error) {\n+\t\tint\terror2;\n+\n+\t\terror2 = xfs_fsverity_delete_metadata(ip);\n+\t\tif (error2)\n+\t\t\txfs_alert(ip->i_mount,\n+\"ino 0x%llx failed to clean up new fsverity metadata, err %d\",\n+\t\t\t\t\tip->i_ino, error2);\n+\t}\n+\n+\txfs_iflags_clear(ip, XFS_VERITY_CONSTRUCTION);\n+\treturn error;\n+}\n+\n+/*\n+ * Retrieve a merkle tree block.\n+ */\n+static struct page *\n+xfs_fsverity_read_merkle(\n+\tstruct inode\t\t*inode,\n+\tpgoff_t\t\t\tindex)\n+{\n+\tindex += xfs_fsverity_metadata_offset(XFS_I(inode)) >> PAGE_SHIFT;\n+\n+\treturn generic_read_merkle_tree_page(inode, index);\n+}\n+\n+/*\n+ * Retrieve a merkle tree block.\n+ */\n+static void\n+xfs_fsverity_readahead_merkle_tree(\n+\tstruct inode\t\t*inode,\n+\tpgoff_t\t\t\tindex,\n+\tunsigned long\t\tnr_pages)\n+{\n+\tindex += xfs_fsverity_metadata_offset(XFS_I(inode)) >> PAGE_SHIFT;\n+\n+\tgeneric_readahead_merkle_tree(inode, index, nr_pages);\n+}\n+\n+/*\n+ * Write a merkle tree block.\n+ */\n+static int\n+xfs_fsverity_write_merkle(\n+\tstruct file\t\t*file,\n+\tconst void\t\t*buf,\n+\tu64\t\t\tpos,\n+\tunsigned int\t\tsize,\n+\tconst u8\t\t*zero_digest,\n+\tunsigned int\t\tdigest_size)\n+{\n+\tstruct inode\t\t*inode = file_inode(file);\n+\tstruct xfs_inode\t*ip = XFS_I(inode);\n+\tloff_t\t\t\tposition = pos +\n+\t\txfs_fsverity_metadata_offset(ip);\n+\tconst char\t\t*p;\n+\tunsigned int\t\ti;\n+\n+\tif (position + size > inode->i_sb->s_maxbytes)\n+\t\treturn -EFBIG;\n+\n+\t/*\n+\t * If this is a block full of hashes of zeroed blocks, don't bother\n+\t * storing the block. We can synthesize them later.\n+\t *\n+\t * However, do this only in case Merkle tree block == fs block size.\n+\t * Iomap synthesizes these blocks based on holes in the merkle tree. We\n+\t * won't be able to tell if something need to be synthesizes for the\n+\t * range in the fs block. For example, for 4k filesystem block\n+\t *\n+\t *\t[ 1k | zero hashes | zero hashes | 1k ]\n+\t *\n+\t * Iomap won't know about these empty blocks.\n+\t */\n+\tfor (i = 0, p = buf; i < size; i += digest_size, p += digest_size)\n+\t\tif (memcmp(p, zero_digest, digest_size))\n+\t\t\tbreak;\n+\tif (i == size && size == ip->i_mount->m_sb.sb_blocksize)\n+\t\treturn 0;\n+\n+\treturn iomap_fsverity_write(file, position, size, buf,\n+\t\t\t&xfs_buffered_write_iomap_ops,\n+\t\t\t&xfs_iomap_write_ops);\n+}\n+\n+const struct fsverity_operations xfs_fsverity_ops = {\n+\t.begin_enable_verity\t\t= xfs_fsverity_begin_enable,\n+\t.end_enable_verity\t\t= xfs_fsverity_end_enable,\n+\t.get_verity_descriptor\t\t= xfs_fsverity_get_descriptor,\n+\t.read_merkle_tree_page\t\t= xfs_fsverity_read_merkle,\n+\t.readahead_merkle_tree\t\t= xfs_fsverity_readahead_merkle_tree,\n+\t.write_merkle_tree_block\t= xfs_fsverity_write_merkle,\n+};\ndiff --git a/fs/xfs/xfs_fsverity.h b/fs/xfs/xfs_fsverity.h\nindex ec77ba571106..6a981e20a75b 100644\n--- a/fs/xfs/xfs_fsverity.h\n+++ b/fs/xfs/xfs_fsverity.h\n@@ -6,8 +6,10 @@\n #define __XFS_FSVERITY_H__\n \n #include \"xfs_platform.h\"\n+#include <linux/fsverity.h>\n \n #ifdef CONFIG_FS_VERITY\n+extern const struct fsverity_operations xfs_fsverity_ops;\n loff_t xfs_fsverity_metadata_offset(const struct xfs_inode *ip);\n bool xfs_fsverity_is_file_data(const struct xfs_inode *ip, loff_t offset);\n #else\ndiff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c\nindex fd297082aeb8..9818d8f8f239 100644\n--- a/fs/xfs/xfs_message.c\n+++ b/fs/xfs/xfs_message.c\n@@ -153,6 +153,10 @@ xfs_warn_experimental(\n \t\t\t.opstate\t= XFS_OPSTATE_WARNED_ZONED,\n \t\t\t.name\t\t= \"zoned RT device\",\n \t\t},\n+\t\t[XFS_EXPERIMENTAL_FSVERITY] = {\n+\t\t\t.opstate\t= XFS_OPSTATE_WARNED_FSVERITY,\n+\t\t\t.name\t\t= \"fsverity\",\n+\t\t},\n \t};\n \tASSERT(feat >= 0 && feat < XFS_EXPERIMENTAL_MAX);\n \tBUILD_BUG_ON(ARRAY_SIZE(features) != XFS_EXPERIMENTAL_MAX);\ndiff --git a/fs/xfs/xfs_message.h b/fs/xfs/xfs_message.h\nindex 49b0ef40d299..083403944f11 100644\n--- a/fs/xfs/xfs_message.h\n+++ b/fs/xfs/xfs_message.h\n@@ -94,6 +94,7 @@ enum xfs_experimental_feat {\n \tXFS_EXPERIMENTAL_SHRINK,\n \tXFS_EXPERIMENTAL_LARP,\n \tXFS_EXPERIMENTAL_ZONED,\n+\tXFS_EXPERIMENTAL_FSVERITY,\n \n \tXFS_EXPERIMENTAL_MAX,\n };\ndiff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h\nindex 07f6aa3c3f26..84d7cfb5e2c7 100644\n--- a/fs/xfs/xfs_mount.h\n+++ b/fs/xfs/xfs_mount.h\n@@ -583,6 +583,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)\n #define XFS_OPSTATE_WARNED_ZONED\t19\n /* (Zoned) GC is in progress */\n #define XFS_OPSTATE_ZONEGC_RUNNING\t20\n+/* Kernel has logged a warning about fsverity support */\n+#define XFS_OPSTATE_WARNED_FSVERITY\t21\n \n #define __XFS_IS_OPSTATE(name, NAME) \\\n static inline bool xfs_is_ ## name (struct xfs_mount *mp) \\\ndiff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c\nindex f8de44443e81..d9d442009610 100644\n--- a/fs/xfs/xfs_super.c\n+++ b/fs/xfs/xfs_super.c\n@@ -30,6 +30,7 @@\n #include \"xfs_filestream.h\"\n #include \"xfs_quota.h\"\n #include \"xfs_sysfs.h\"\n+#include \"xfs_fsverity.h\"\n #include \"xfs_ondisk.h\"\n #include \"xfs_rmap_item.h\"\n #include \"xfs_refcount_item.h\"\n@@ -1686,6 +1687,9 @@ xfs_fs_fill_super(\n \tsb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;\n #endif\n \tsb->s_op = &xfs_super_operations;\n+#ifdef CONFIG_FS_VERITY\n+\tsb->s_vop = &xfs_fsverity_ops;\n+#endif\n \n \t/*\n \t * Delay mount work if the debug hook is set. This is debug\n@@ -1939,6 +1943,9 @@ xfs_fs_fill_super(\n \tif (error)\n \t\tgoto out_filestream_unmount;\n \n+\tif (xfs_has_verity(mp))\n+\t\txfs_warn_experimental(mp, XFS_EXPERIMENTAL_FSVERITY);\n+\n \troot = igrab(VFS_I(mp->m_rootip));\n \tif (!root) {\n \t\terror = -ENOENT;\n", "prefixes": [ "v6", "15/22" ] }