From: "Darrick J. Wong" <djwong@kernel.org>
To: Eric Biggers <ebiggers@kernel.org>
Cc: aalbersh@redhat.com, linux-xfs@vger.kernel.org,
linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev
Subject: Re: [PATCH 03/13] fsverity: support block-based Merkle tree caching
Date: Wed, 24 Apr 2024 14:25:23 -0700 [thread overview]
Message-ID: <20240424212523.GO360919@frogsfrogsfrogs> (raw)
In-Reply-To: <20240405023145.GB1958@quark.localdomain>
On Thu, Apr 04, 2024 at 10:31:45PM -0400, Eric Biggers wrote:
> On Fri, Mar 29, 2024 at 05:33:27PM -0700, Darrick J. Wong wrote:
> > diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
> > index b3506f56e180b..c9d97c2bebd84 100644
> > --- a/fs/verity/fsverity_private.h
> > +++ b/fs/verity/fsverity_private.h
> > @@ -154,4 +154,41 @@ static inline void fsverity_init_signature(void)
> >
> > void __init fsverity_init_workqueue(void);
> >
> > +static inline bool fsverity_caches_blocks(const struct inode *inode)
> > +{
> > + const struct fsverity_operations *vops = inode->i_sb->s_vop;
> > +
> > + WARN_ON_ONCE(vops->read_merkle_tree_block &&
> > + !vops->drop_merkle_tree_block);
> > +
> > + return vops->read_merkle_tree_block != NULL;
> > +}
> > +
> > +static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi,
> > + const struct inode *inode)
> > +{
> > + if (fsverity_caches_blocks(inode))
> > + return false;
> > +
> > + /*
> > + * If fs uses block-based Merkle tree caching, then fs-verity must use
> > + * hash_block_verified bitmap as there's no page to mark it with
> > + * PG_checked.
> > + */
> > + return vi->tree_params.block_size != PAGE_SIZE;
> > +}
>
> For checking whether the bitmap is in use, it's simpler and more efficient to
> just directly check whether vi->hash_block_verified is NULL, as the existing
> code does. Only the code that allocates the bitmap actually needs to be aware
> of the details of when the bitmap gets enabled.
>
> fsverity_caches_blocks() has a similar issue, where it could just be replaced
> with checking vops->read_merkle_tree_block != NULL directly (or equivalently
> vops->drop_merkle_tree_block, which works well in
> fsverity_drop_merkle_tree_block() since that's the function pointer it's
> calling). The WARN_ON_ONCE() should be done in fsverity_create_info(), not
> inlined multiple times into the verification code.
Ok, I'll move the WARN_ON_ONCE there:
/*
* If the filesystem implementation supplies Merkle tree content on a
* per-block basis, it must implement both the read and drop functions.
* If it supplies content on a per-page basis, neither should be
* provided.
*/
if (vops->read_merkle_tree_block)
WARN_ON_ONCE(vops->drop_merkle_tree_block == NULL);
else
WARN_ON_ONCE(vops->drop_merkle_tree_block != NULL);
> (I think the name "fsverity_caches_blocks()" is also confusing because the
> fsverity support layer does not cache blocks, but all the filesystems do. What
> it's actually trying to convey is a difference in how the filesystem caches the
> blocks, which I don't think it does a good job at.)
Ok, I'll drop both and open-code them with nicer comments.
> > +int fsverity_read_merkle_tree_block(struct inode *inode,
> > + const struct merkle_tree_params *params,
> > + u64 pos, unsigned long ra_bytes,
> > + struct fsverity_blockbuf *block);
> > +
> > +/*
> > + * Drop 'block' obtained with ->read_merkle_tree_block(). Calls out back to
> > + * filesystem if ->drop_merkle_tree_block() is set, otherwise, drop the
> > + * reference in the block->context.
>
> "drop the reference" => "drops the reference"
Fixed.
> > + /*
> > + * If fs uses block-based Merkle tree cachin, then fs-verity must use
> > + * hash_block_verified bitmap as there's no page to mark it with
> > + * PG_checked.
> > + */
> > + if (fsverity_uses_bitmap(vi, inode)) {
>
> The comment contradicts the code.
Urrrk, yes, it does. Sorry about that.
/*
* If the fs supplies Merkle tree blocks on a per-page basis and the
* page size doesn't match the block size, fs-verity must use the
* hash_block_verified bitmap instead of PG_checked.
*/
if (vops->read_merkle_tree_block == NULL &&
vi->tree_params.block_size != PAGE_SIZE) {
...allocate bitmap...
}
>
> > diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c
> > index f58432772d9ea..94fffa060f829 100644
> > --- a/fs/verity/read_metadata.c
> > +++ b/fs/verity/read_metadata.c
> > @@ -14,65 +14,60 @@
> >
> > static int fsverity_read_merkle_tree(struct inode *inode,
> > const struct fsverity_info *vi,
> > - void __user *buf, u64 offset, int length)
> > + void __user *buf, u64 pos, int length)
> > {
> > - const struct fsverity_operations *vops = inode->i_sb->s_vop;
> > - u64 end_offset;
> > - unsigned int offs_in_page;
> > - pgoff_t index, last_index;
> > + const u64 end_pos = min(pos + length, vi->tree_params.tree_size);
> > + const struct merkle_tree_params *params = &vi->tree_params;
> > + unsigned int offs_in_block = pos & (params->block_size - 1);
> > int retval = 0;
> > int err = 0;
> >
> > - end_offset = min(offset + length, vi->tree_params.tree_size);
> > - if (offset >= end_offset)
> > + if (pos >= end_pos)
> > return 0;
>
> The above 'pos >= end_pos' check is no longer necessary.
Aha, good catch.
> > /*
> > - * Iterate through each Merkle tree page in the requested range and copy
> > - * the requested portion to userspace. Note that the Merkle tree block
> > - * size isn't important here, as we are returning a byte stream; i.e.,
> > - * we can just work with pages even if the tree block size != PAGE_SIZE.
> > + * Iterate through each Merkle tree block in the requested range and
> > + * copy the requested portion to userspace. Note that we are returning
> > + * a byte stream.
> > */
> > - for (index = offset >> PAGE_SHIFT; index <= last_index; index++) {
> > - unsigned long num_ra_pages =
> > - min_t(unsigned long, last_index - index + 1,
> > - inode->i_sb->s_bdi->io_pages);
> > - unsigned int bytes_to_copy = min_t(u64, end_offset - offset,
> > - PAGE_SIZE - offs_in_page);
> > - struct page *page;
> > - const void *virt;
> > + while (pos < end_pos) {
> > + unsigned long ra_bytes;
> > + unsigned int bytes_to_copy;
> > + struct fsverity_blockbuf block = {
> > + .size = params->block_size,
> > + };
> >
> > - page = vops->read_merkle_tree_page(inode, index, num_ra_pages);
> > - if (IS_ERR(page)) {
> > - err = PTR_ERR(page);
> > + ra_bytes = min_t(unsigned long, end_pos - pos + 1,
> > + inode->i_sb->s_bdi->io_pages << PAGE_SHIFT);
>
> This introduces an off-by-one error in the calculation of ra_bytes. end_pos
> is exclusive, but the calculation of ra_bytes assumes it is inclusive.
>
> Also, might io_pages << PAGE_SHIFT overflow an unsigned long?
I hope not -- max io and readahead should never be 4GB. I'm a little
surprised this isn't s_bdi->ra_pages.
struct backing_dev_info *bdi = inode->i_sb->s_bdi;
const u64 max_ra_bytes = min((u64)bdi->io_pages << PAGE_SHIFT,
ULONG_MAX);
while (pos < end_pos) {
ra_bytes = min_t(unsigned long, end_pos - pos, max_ra_bytes);
> > + bytes_to_copy = min_t(u64, end_pos - pos,
> > + params->block_size - offs_in_block);
> > +
> > + err = fsverity_read_merkle_tree_block(inode, &vi->tree_params,
> > + pos - offs_in_block, ra_bytes, &block);
> > + if (err) {
> > fsverity_err(inode,
> > - "Error %d reading Merkle tree page %lu",
> > - err, index);
> > + "Error %d reading Merkle tree block %llu",
> > + err, pos);
> > break;
>
> The error message should go into fsverity_read_merkle_tree_block() so that it
> does not need to be duplicated in its two callers. This would, additionally,
> eliminate the need to introduce the 'err' variable in verify_data_block().
Do you want that to be a separate cleanup patch?
> > diff --git a/fs/verity/verify.c b/fs/verity/verify.c
> > index 4fcad0825a120..0b5e11073e883 100644
> > --- a/fs/verity/verify.c
> > +++ b/fs/verity/verify.c
> > @@ -13,14 +13,27 @@
> > static struct workqueue_struct *fsverity_read_workqueue;
> >
> > /*
> > - * Returns true if the hash block with index @hblock_idx in the tree, located in
> > - * @hpage, has already been verified.
> > + * Returns true if the hash block with index @hblock_idx in the tree has
> > + * already been verified.
> > */
> > -static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage,
> > +static bool is_hash_block_verified(struct inode *inode,
> > + struct fsverity_blockbuf *block,
> > unsigned long hblock_idx)
>
> The comment should be updated to mention @block.
I'll mention @inode too:
/*
* Returns true if the hash @block with index @hblock_idx in the merkle tree
* for @inode has already been verified.
*/
> > @@ -143,11 +156,9 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
> > for (level = 0; level < params->num_levels; level++) {
> > unsigned long next_hidx;
> > unsigned long hblock_idx;
> > - pgoff_t hpage_idx;
> > - unsigned int hblock_offset_in_page;
> > + u64 hblock_pos;
> > unsigned int hoffset;
> > - struct page *hpage;
> > - const void *haddr;
> > + struct fsverity_blockbuf *block = &hblocks[level].block;
> >
> > /*
> > * The index of the block in the current level; also the index
> > @@ -158,36 +169,34 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi,
> > /* Index of the hash block in the tree overall */
> > hblock_idx = params->level_start[level] + next_hidx;
> >
> > - /* Index of the hash page in the tree overall */
> > - hpage_idx = hblock_idx >> params->log_blocks_per_page;
> > -
> > - /* Byte offset of the hash block within the page */
> > - hblock_offset_in_page =
> > - (hblock_idx << params->log_blocksize) & ~PAGE_MASK;
> > + /* Byte offset of the hash block in the tree overall */
> > + hblock_pos = hblock_idx << params->log_blocksize;
>
> 'hblock_idx << params->log_blocksize' may overflow an unsigned long, so
> 'hblock_idx' needs to be cast to u64 before doing the shift.
Fixed.
> > + if (level == 0)
> > + ra_bytes = min(max_ra_bytes,
> > + params->tree_size - hblock_pos);
> > + else
> > + ra_bytes = 0;
>
> The first argument to min() has type unsigned long, and the second has type u64.
> Doesn't this generate a warning on 32-bit systems?
Probably. I'll turn it into a min_t(u64...).
> > @@ -325,7 +333,7 @@ void fsverity_verify_bio(struct bio *bio)
> >
> > bio_for_each_folio_all(fi, bio) {
> > if (!verify_data_blocks(fi.folio, fi.length, fi.offset,
> > - max_ra_pages)) {
> > + max_ra_pages << PAGE_SHIFT)) {
> > bio->bi_status = BLK_STS_IOERR;
> > break;
>
> This function should calculate max_ra_bytes as bio->bi_iter.bi_size >> 2. It's
> not necessary to convert to pages, then back to bytes again.
Aha, Andrey and I missed that. Fixed.
> > +/**
> > + * fsverity_read_merkle_tree_block() - read Merkle tree block
> > + * @inode: inode to which this Merkle tree blocks belong
>
> "this Merkle tree blocks belong" => "this Merkle tree block belongs"
>
> > + * @params: merkle tree parameters
> > + * @pos: byte position within merkle tree
> > + * @ra_bytes: try to read ahead this many btes
>
> "btes" => "bytes"
Both fixed.
> > +int fsverity_read_merkle_tree_block(struct inode *inode,
> > + const struct merkle_tree_params *params,
> > + u64 pos, unsigned long ra_bytes,
> > + struct fsverity_blockbuf *block)
> > +{
> > + const struct fsverity_operations *vops = inode->i_sb->s_vop;
> > + unsigned long page_idx;
> > + struct page *page;
> > + unsigned long index;
> > + unsigned int offset_in_page;
> > +
> > + if (fsverity_caches_blocks(inode)) {
> > + block->verified = false;
> > + return vops->read_merkle_tree_block(inode, pos, ra_bytes,
> > + params->log_blocksize, block);
> > + }
> > +
> > + index = pos >> params->log_blocksize;
>
> Should the fourth parameter to ->read_merkle_tree_block be the block index
> (which is computed above) instead of log_blocksize? XFS only uses
> params->log_blocksize to compute the block index anyway.
I don't know. XFS is infamous for everyone having a different opinion
and developers being unable to drive a consensus and being able to get a
patchset to completion. So:
Andrey wrote an implementation that used the buffer cache and used block
indexes to load/store from the xattr structure. I didn't like that
because layering violation.
willy suggested hanging an xarray off struct xfs_inode and using that to
cache merkle tree blocks. For that design, we want the xarray indexes
in units of blocks to conserve space, which means passing in (pos,
log_blocksize) or a direct block index.
Christoph then suggested using a per-AG rhashtable to reduce per-inode
memory overhead, in which case the lookup key can be either (inumber,
pos) or (inumber, block index). This is a better design if there aren't
really going to be that many xfs inodes with verity enabled, though we
lose per-inode sharding of the merkle blocks.
Dave thinks that verity inodes could constitute the majority of xfs
inodes some day and it should be in the inode instead.
Andrey and I do not have crystal balls, we have no idea how this
dchinner/hch disagreement will play out. Earlier I got the sense that
you wanted to move towards expressing all the merkle tree info in units
of bytes.
In a lot of ways it would be preferable to move to block indexes
instead, since there's never going to be a meaningful access to merkle
position 1337. But you're the maintainer, so it's up to you. :)
> > +/**
> > + * struct fsverity_blockbuf - Merkle Tree block buffer
> > + * @kaddr: virtual address of the block's data
> > + * @offset: block's offset into Merkle tree
> > + * @size: the Merkle tree block size
> > + * @context: filesystem private context
> > + * @verified: has this buffer been validated?
> > + *
> > + * Buffer containing single Merkle Tree block. These buffers are passed
> > + * - to filesystem, when fs-verity is building merkel tree,
> > + * - from filesystem, when fs-verity is reading merkle tree from a disk.
> > + * Filesystems sets kaddr together with size to point to a memory which contains
> > + * Merkle tree block. Same is done by fs-verity when Merkle tree is need to be
> > + * written down to disk.
>
> This comment still incorrectly claims that fsverity_blockbuf is being used for
> writes.
Oops, I forgot to delete that.
--D
>
> - Eric
>
next prev parent reply other threads:[~2024-04-24 21:25 UTC|newest]
Thread overview: 111+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-30 0:30 [PATCHBOMB v5.5] fs-verity support for XFS Darrick J. Wong
2024-03-30 0:32 ` [PATCHSET v5.5 1/2] fs-verity: support merkle tree access by blocks Darrick J. Wong
2024-03-30 0:32 ` [PATCH 01/13] fs: add FS_XFLAG_VERITY for verity files Darrick J. Wong
2024-03-30 0:33 ` [PATCH 02/13] fsverity: pass tree_blocksize to end_enable_verity() Darrick J. Wong
2024-03-30 0:33 ` [PATCH 03/13] fsverity: support block-based Merkle tree caching Darrick J. Wong
2024-04-05 2:31 ` Eric Biggers
2024-04-24 21:25 ` Darrick J. Wong [this message]
2024-04-24 22:08 ` Eric Biggers
2024-04-25 0:27 ` Darrick J. Wong
2024-04-25 0:46 ` Eric Biggers
2024-04-25 0:53 ` Darrick J. Wong
2024-03-30 0:33 ` [PATCH 04/13] fsverity: add per-sb workqueue for post read processing Darrick J. Wong
2024-04-05 2:39 ` Eric Biggers
2024-04-24 21:33 ` Darrick J. Wong
2024-03-30 0:33 ` [PATCH 05/13] fsverity: add tracepoints Darrick J. Wong
2024-03-30 0:34 ` [PATCH 06/13] fsverity: send the level of the merkle tree block to ->read_merkle_tree_block Darrick J. Wong
2024-04-05 2:42 ` Eric Biggers
2024-04-25 0:30 ` Darrick J. Wong
2024-03-30 0:34 ` [PATCH 07/13] fsverity: pass the new tree size and block size to ->begin_enable_verity Darrick J. Wong
2024-04-05 2:46 ` Eric Biggers
2024-04-24 21:36 ` Darrick J. Wong
2024-03-30 0:34 ` [PATCH 08/13] fsverity: expose merkle tree geometry to callers Darrick J. Wong
2024-04-05 2:50 ` Eric Biggers
2024-04-25 0:45 ` Darrick J. Wong
2024-04-25 0:49 ` Eric Biggers
2024-04-25 1:01 ` Darrick J. Wong
2024-04-25 1:04 ` Eric Biggers
2024-03-30 0:35 ` [PATCH 09/13] fsverity: box up the write_merkle_tree_block parameters too Darrick J. Wong
2024-04-05 2:52 ` Eric Biggers
2024-04-25 0:46 ` Darrick J. Wong
2024-03-30 0:35 ` [PATCH 10/13] fsverity: pass the zero-hash value to the implementation Darrick J. Wong
2024-04-05 2:57 ` Eric Biggers
2024-04-24 19:02 ` Darrick J. Wong
2024-04-24 19:19 ` Eric Biggers
2024-04-24 20:23 ` Darrick J. Wong
2024-04-24 20:59 ` Eric Biggers
2024-04-24 21:43 ` Darrick J. Wong
2024-03-30 0:35 ` [PATCH 11/13] fsverity: report validation errors back to the filesystem Darrick J. Wong
2024-04-05 3:09 ` Eric Biggers
2024-04-24 18:18 ` Darrick J. Wong
2024-04-24 18:52 ` Eric Biggers
2024-04-24 19:03 ` Darrick J. Wong
2024-03-30 0:35 ` [PATCH 12/13] fsverity: remove system-wide workqueue Darrick J. Wong
2024-04-05 3:14 ` Eric Biggers
2024-04-24 18:05 ` Darrick J. Wong
2024-04-24 18:41 ` Eric Biggers
2024-04-29 10:15 ` Andrey Albershteyn
2024-04-29 16:35 ` Darrick J. Wong
2024-03-30 0:36 ` [PATCH 13/13] iomap: integrate fs-verity verification into iomap's read path Darrick J. Wong
2024-03-30 0:32 ` [PATCHSET v5.5 2/2] xfs: fs-verity support Darrick J. Wong
2024-03-30 0:36 ` [PATCH 01/29] xfs: use unsigned ints for non-negative quantities in xfs_attr_remote.c Darrick J. Wong
2024-04-02 9:51 ` Andrey Albershteyn
2024-04-02 16:25 ` Darrick J. Wong
2024-03-30 0:36 ` [PATCH 02/29] xfs: turn XFS_ATTR3_RMT_BUF_SPACE into a function Darrick J. Wong
2024-04-02 10:09 ` Andrey Albershteyn
2024-03-30 0:36 ` [PATCH 03/29] xfs: create a helper to compute the blockcount of a max sized remote value Darrick J. Wong
2024-04-02 10:09 ` Andrey Albershteyn
2024-03-30 0:37 ` [PATCH 04/29] xfs: minor cleanups of xfs_attr3_rmt_blocks Darrick J. Wong
2024-04-02 10:11 ` Andrey Albershteyn
2024-03-30 0:37 ` [PATCH 05/29] xfs: add attribute type for fs-verity Darrick J. Wong
2024-03-30 0:37 ` [PATCH 06/29] xfs: do not use xfs_attr3_rmt_hdr for remote verity value blocks Darrick J. Wong
2024-03-30 0:37 ` [PATCH 07/29] xfs: add fs-verity ro-compat flag Darrick J. Wong
2024-03-30 0:38 ` [PATCH 08/29] xfs: add inode on-disk VERITY flag Darrick J. Wong
2024-03-30 0:38 ` [PATCH 09/29] xfs: initialize fs-verity on file open and cleanup on inode destruction Darrick J. Wong
2024-03-30 0:38 ` [PATCH 10/29] xfs: don't allow to enable DAX on fs-verity sealed inode Darrick J. Wong
2024-03-30 0:38 ` [PATCH 11/29] xfs: disable direct read path for fs-verity files Darrick J. Wong
2024-03-30 0:39 ` [PATCH 12/29] xfs: widen flags argument to the xfs_iflags_* helpers Darrick J. Wong
2024-04-02 12:37 ` Andrey Albershteyn
2024-04-02 16:27 ` Darrick J. Wong
2024-03-30 0:39 ` [PATCH 13/29] xfs: add fs-verity support Darrick J. Wong
2024-04-02 8:42 ` Andrey Albershteyn
2024-04-02 16:34 ` Darrick J. Wong
2024-04-25 1:14 ` Darrick J. Wong
2024-03-30 0:39 ` [PATCH 14/29] xfs: create a per-mount shrinker for verity inodes merkle tree blocks Darrick J. Wong
2024-04-05 3:16 ` Eric Biggers
2024-04-24 17:39 ` Darrick J. Wong
2024-03-30 0:39 ` [PATCH 15/29] xfs: create an icache tag for files with cached " Darrick J. Wong
2024-03-30 0:40 ` [PATCH 16/29] xfs: shrink verity blob cache Darrick J. Wong
2024-03-30 0:40 ` [PATCH 17/29] xfs: only allow the verity iflag for regular files Darrick J. Wong
2024-04-02 12:52 ` Andrey Albershteyn
2024-03-30 0:40 ` [PATCH 18/29] xfs: don't store trailing zeroes of merkle tree blocks Darrick J. Wong
2024-03-30 0:41 ` [PATCH 19/29] xfs: use merkle tree offset as attr hash Darrick J. Wong
2024-03-30 0:41 ` [PATCH 20/29] xfs: don't bother storing merkle tree blocks for zeroed data blocks Darrick J. Wong
2024-03-30 0:41 ` [PATCH 21/29] xfs: add fs-verity ioctls Darrick J. Wong
2024-03-30 0:41 ` [PATCH 22/29] xfs: advertise fs-verity being available on filesystem Darrick J. Wong
2024-04-02 13:44 ` Andrey Albershteyn
2024-03-30 0:42 ` [PATCH 23/29] xfs: make scrub aware of verity dinode flag Darrick J. Wong
2024-03-30 0:42 ` [PATCH 24/29] xfs: teach online repair to evaluate fsverity xattrs Darrick J. Wong
2024-04-02 15:42 ` Andrey Albershteyn
2024-04-02 16:42 ` Darrick J. Wong
2024-03-30 0:42 ` [PATCH 25/29] xfs: report verity failures through the health system Darrick J. Wong
2024-04-02 16:16 ` Andrey Albershteyn
2024-03-30 0:42 ` [PATCH 26/29] xfs: clear the verity iflag when not appropriate Darrick J. Wong
2024-04-02 16:26 ` Andrey Albershteyn
2024-03-30 0:43 ` [PATCH 27/29] xfs: make it possible to disable fsverity Darrick J. Wong
2024-04-02 17:15 ` Andrey Albershteyn
2024-04-02 23:25 ` Eric Biggers
2024-04-03 1:26 ` Darrick J. Wong
2024-03-30 0:43 ` [PATCH 28/29] xfs: allow verity files to be opened even if the fsverity metadata is damaged Darrick J. Wong
2024-04-02 18:04 ` Andrey Albershteyn
2024-04-02 20:00 ` Colin Walters
2024-04-02 22:52 ` Darrick J. Wong
2024-04-02 23:45 ` Eric Biggers
2024-04-03 1:34 ` Darrick J. Wong
2024-04-03 0:10 ` Colin Walters
2024-04-03 1:39 ` Darrick J. Wong
2024-04-03 1:59 ` Dave Chinner
2024-04-03 3:19 ` Darrick J. Wong
2024-04-03 22:22 ` Dave Chinner
2024-04-03 8:35 ` Alexander Larsson
2024-03-30 0:43 ` [PATCH 29/29] xfs: enable ro-compat fs-verity flag 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=20240424212523.GO360919@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=aalbersh@redhat.com \
--cc=ebiggers@kernel.org \
--cc=fsverity@lists.linux.dev \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.