diff options
author | Rich Ercolani <[email protected]> | 2022-05-04 14:59:30 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2022-05-04 11:59:30 -0700 |
commit | 7bf06f7262b52b6d8ac5725e072f46ad450485be (patch) | |
tree | df8625c282008e9c9d2d4ca1380dfb7325c2aa5f | |
parent | 81b8b2d004442c3e7f196d61c2ae8eed02712b6c (diff) |
Corrected edge case in uncompressed ARC->L2ARC handling
I genuinely don't know why this didn't come up before,
but adding the LZ4 early abort pointed out this flaw,
in which we're allocating a buffer of one size, and
then telling the compressor that we're handing it buffers
of a different size, which may be Very Different - say,
allocating 512b and then telling it the inputs are 128k.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: George Amanakis <[email protected]>
Signed-off-by: Rich Ercolani <[email protected]>
Closes #13375
-rw-r--r-- | module/zfs/arc.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c index c7568d8c2..af42670cc 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -9337,26 +9337,37 @@ l2arc_apply_transforms(spa_t *spa, arc_buf_hdr_t *hdr, uint64_t asize, } if (compress != ZIO_COMPRESS_OFF && !HDR_COMPRESSION_ENABLED(hdr)) { - cabd = abd_alloc_for_io(asize, ismd); - tmp = abd_borrow_buf(cabd, asize); + /* + * In some cases, we can wind up with size > asize, so + * we need to opt for the larger allocation option here. + * + * (We also need abd_return_buf_copy in all cases because + * it's an ASSERT() to modify the buffer before returning it + * with arc_return_buf(), and all the compressors + * write things before deciding to fail compression in nearly + * every case.) + */ + cabd = abd_alloc_for_io(size, ismd); + tmp = abd_borrow_buf(cabd, size); psize = zio_compress_data(compress, to_write, tmp, size, hdr->b_complevel); - if (psize >= size) { - abd_return_buf(cabd, tmp, asize); + if (psize >= asize) { + psize = HDR_GET_PSIZE(hdr); + abd_return_buf_copy(cabd, tmp, size); HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF); to_write = cabd; - abd_copy(to_write, hdr->b_l1hdr.b_pabd, size); - if (size != asize) - abd_zero_off(to_write, size, asize - size); + abd_copy(to_write, hdr->b_l1hdr.b_pabd, psize); + if (psize != asize) + abd_zero_off(to_write, psize, asize - psize); goto encrypt; } ASSERT3U(psize, <=, HDR_GET_PSIZE(hdr)); if (psize < asize) memset((char *)tmp + psize, 0, asize - psize); psize = HDR_GET_PSIZE(hdr); - abd_return_buf_copy(cabd, tmp, asize); + abd_return_buf_copy(cabd, tmp, size); to_write = cabd; } |