Data from severity region is not mapped as file data but as a set of extended attributes. Add mapping function which removes region offset and map n-th page to attribute with name n. Signed-off-by: Andrey Albershteyn <aalbersh@xxxxxxxxxx> --- fs/xfs/xfs_aops.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index bcc51628dbdd..976d77277e95 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -20,6 +20,7 @@ #include "xfs_errortag.h" #include "xfs_error.h" #include "xfs_fsverity.h" +#include "xfs_attr.h" #include <linux/fsverity.h> struct xfs_writepage_ctx { @@ -132,7 +133,8 @@ xfs_end_ioend( else if (ioend->io_type == IOMAP_UNWRITTEN) error = xfs_iomap_write_unwritten(ip, offset, size, false); - if (!error && xfs_ioend_is_append(ioend)) + if (!error && !xfs_fsverity_in_region(ioend->io_offset) && + xfs_ioend_is_append(ioend)) error = xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); /* This IO was to the Merkle tree region */ @@ -472,14 +474,87 @@ static const struct iomap_writeback_ops xfs_writeback_ops = { .discard_folio = xfs_discard_folio, }; +static int +xfs_fsverity_map_blocks( + struct iomap_writepage_ctx *wpc, + struct inode *inode, + loff_t offset, + unsigned int len) +{ + struct xfs_inode *ip = XFS_I(inode); + struct xfs_mount *mp = ip->i_mount; + int error = 0; + int nmap = 1; + loff_t pos; + int seq; + struct xfs_bmbt_irec imap; + struct xfs_da_args args; + struct xfs_merkle_key name; + loff_t xattr_name; + + if (xfs_is_shutdown(mp)) + return -EIO; + + pos = (offset & XFS_FSVERITY_MTREE_MASK); + /* We always write one attribute block, but each block can have multiple + * Merkle tree blocks */ + ASSERT(!is_power_of_2(len)); + xattr_name = pos & ~(len - 1); + + xfs_fsverity_init_merkle_args(ip, &name, xattr_name, &args); + + error = xfs_attr_get(&args); + if (error) + return error; + + ASSERT(args->dp->i_af.if_format != XFS_DINODE_FMT_LOCAL); + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_bmapi_read(ip, (xfs_fileoff_t)args.rmtblkno, + args.rmtblkcnt, &imap, &nmap, + XFS_BMAPI_ATTRFORK); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + if (error) + return error; + + /* Instead of xattr extent offset, which will be over data, we need + * merkle tree offset in page cache */ + imap.br_startoff = + XFS_B_TO_FSBT(mp, xattr_name | XFS_FSVERITY_MTREE_OFFSET); + + seq = xfs_iomap_inode_sequence(ip, IOMAP_F_XATTR); + xfs_bmbt_to_iomap(ip, &wpc->iomap, &imap, 0, IOMAP_F_XATTR, seq); + + trace_xfs_map_blocks_found(ip, offset, len, XFS_ATTR_FORK, &imap); + + /* We want this to be separate from other IO as we will do + * CRC update on IO completion */ + wpc->iomap.flags |= IOMAP_F_NO_MERGE; + + return 0; +} + +static const struct iomap_writeback_ops xfs_writeback_verity_ops = { + .map_blocks = xfs_fsverity_map_blocks, + .prepare_ioend = xfs_prepare_ioend, + .discard_folio = xfs_discard_folio, +}; + STATIC int xfs_vm_writepages( - struct address_space *mapping, - struct writeback_control *wbc) + struct address_space *mapping, + struct writeback_control *wbc) { - struct xfs_writepage_ctx wpc = { }; + struct xfs_writepage_ctx wpc = { }; + struct xfs_inode *ip = XFS_I(mapping->host); - xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); + xfs_iflags_clear(ip, XFS_ITRUNCATED); + + if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION)) { + wbc->range_start = XFS_FSVERITY_MTREE_OFFSET; + wbc->range_end = LLONG_MAX; + return iomap_writepages_unbound(mapping, wbc, &wpc.ctx, + &xfs_writeback_verity_ops); + } return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops); } -- 2.47.0