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 <behlendorf1@llnl.gov>
Reviewed-by: George Amanakis <gamanakis@gmail.com>
Signed-off-by: Rich Ercolani <rincebrain@gmail.com>
Closes #13375
This commit is contained in:
Rich Ercolani 2022-05-04 14:59:30 -04:00 committed by Tony Hutter
parent 338188562b
commit cc565f557b
1 changed files with 19 additions and 8 deletions

View File

@ -9307,26 +9307,37 @@ l2arc_apply_transforms(spa_t *spa, arc_buf_hdr_t *hdr, uint64_t asize,
} }
if (compress != ZIO_COMPRESS_OFF && !HDR_COMPRESSION_ENABLED(hdr)) { 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, psize = zio_compress_data(compress, to_write, tmp, size,
hdr->b_complevel); hdr->b_complevel);
if (psize >= size) { if (psize >= asize) {
abd_return_buf(cabd, tmp, asize); psize = HDR_GET_PSIZE(hdr);
abd_return_buf_copy(cabd, tmp, size);
HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF); HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF);
to_write = cabd; to_write = cabd;
abd_copy(to_write, hdr->b_l1hdr.b_pabd, size); abd_copy(to_write, hdr->b_l1hdr.b_pabd, psize);
if (size != asize) if (psize != asize)
abd_zero_off(to_write, size, asize - size); abd_zero_off(to_write, psize, asize - psize);
goto encrypt; goto encrypt;
} }
ASSERT3U(psize, <=, HDR_GET_PSIZE(hdr)); ASSERT3U(psize, <=, HDR_GET_PSIZE(hdr));
if (psize < asize) if (psize < asize)
bzero((char *)tmp + psize, asize - psize); bzero((char *)tmp + psize, asize - psize);
psize = HDR_GET_PSIZE(hdr); psize = HDR_GET_PSIZE(hdr);
abd_return_buf_copy(cabd, tmp, asize); abd_return_buf_copy(cabd, tmp, size);
to_write = cabd; to_write = cabd;
} }