Skip to content

Commit

Permalink
Handle compressed buffers in __dbuf_hold_impl()
Browse files Browse the repository at this point in the history
In __dbuf_hold_impl(), if a buffer is currently syncing and is still
referenced from db_data, a copy is made in case it is dirtied again in
the txg.  Previously, the buffer for the copy was simply allocated with
arc_alloc_buf() which doesn't handle compressed or encrypted buffers
(which are a special case of a compressed buffer).  The result was
typically an invalid memory access because the newly-allocated buffer
was of the uncompressed size.

This commit fixes the problem by handling the 2 compressed cases,
encrypted and unencrypted, respectively, with arc_alloc_raw_buf() and
arc_alloc_compressed_buf().

Although using the proper allocation functions fixes the invalid memory
access by allocating a buffer of the compressed size, another unrelated
issue made it impossible to properly detect compressed buffers in the
first place.  The header's compression flag was set to ZIO_COMPRESS_OFF
in arc_write() when it was possible that an attached buffer was actually
compressed.  This commit adds logic to only set ZIO_COMPRESS_OFF in
the non-ZIO_RAW case which wil handle both cases of compressed buffers
(encrypted or unencrypted).

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
Closes openzfs#5742 
Closes openzfs#6797
  • Loading branch information
dweeezil authored and FransUrbo committed Apr 28, 2019
1 parent c6f344c commit 3b3200c
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
3 changes: 2 additions & 1 deletion module/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -6936,7 +6936,8 @@ arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
if (HDR_HAS_RABD(hdr))
arc_hdr_free_abd(hdr, B_TRUE);

arc_hdr_set_compress(hdr, ZIO_COMPRESS_OFF);
if (!(zio_flags & ZIO_FLAG_RAW))
arc_hdr_set_compress(hdr, ZIO_COMPRESS_OFF);

ASSERT(!arc_buf_is_shared(buf));
ASSERT3P(hdr->b_l1hdr.b_pabd, ==, NULL);
Expand Down
17 changes: 14 additions & 3 deletions module/zfs/dbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2700,8 +2700,8 @@ dbuf_prefetch(dnode_t *dn, int64_t level, uint64_t blkid, zio_priority_t prio,

/*
* Helper function for __dbuf_hold_impl() to copy a buffer. Handles
* the case of compressed and uncompressed buffers by allocating the
* new buffer, respectively, with arc_alloc_raw_buf(),
* the case of encrypted, compressed and uncompressed buffers by
* allocating the new buffer, respectively, with arc_alloc_raw_buf(),
* arc_alloc_compressed_buf() or arc_alloc_buf().*
*
* NOTE: Declared noinline to avoid stack bloat in __dbuf_hold_impl().
Expand All @@ -2716,7 +2716,18 @@ dbuf_hold_copy(struct dbuf_hold_impl_data *dh)

enum zio_compress compress_type = arc_get_compression(data);

if (compress_type != ZIO_COMPRESS_OFF) {
if (arc_is_encrypted(data)) {
boolean_t byteorder;
uint8_t salt[ZIO_DATA_SALT_LEN];
uint8_t iv[ZIO_DATA_IV_LEN];
uint8_t mac[ZIO_DATA_MAC_LEN];

arc_get_raw_params(data, &byteorder, salt, iv, mac);
dbuf_set_data(db, arc_alloc_raw_buf(dn->dn_objset->os_spa, db,
dmu_objset_id(dn->dn_objset), byteorder, salt, iv, mac,
dn->dn_type, arc_buf_size(data), arc_buf_lsize(data),
compress_type));
} else if (compress_type != ZIO_COMPRESS_OFF) {
dbuf_set_data(db, arc_alloc_compressed_buf(
dn->dn_objset->os_spa, db, arc_buf_size(data),
arc_buf_lsize(data), compress_type));
Expand Down

0 comments on commit 3b3200c

Please sign in to comment.