From 369aa501d11f4d21d4732b58d749259ad811a10a Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Wed, 13 Mar 2019 13:52:01 -0400 Subject: Fix handling of maxblkid for raw sends Currently, the receive code can create an unreadable dataset from a correct raw send stream. This is because it is currently impossible to set maxblkid to a lower value without freeing the associated object. This means truncating files on the send side to a non-0 size could result in corruption. This patch solves this issue by adding a new 'force' flag to dnode_new_blkid() which will allow the raw receive code to force the DMU to accept the provided maxblkid even if it is a lower value than the existing one. For testing purposes the send_encrypted_files.ksh test has been extended to include a variety of truncated files and multiple snapshots. It also now leverages the xattrtest command to help ensure raw receives correctly handle xattrs. Reviewed-by: Paul Dagnelie Reviewed-by: Brian Behlendorf Reviewed-by: Matt Ahrens Signed-off-by: Tom Caputi Closes #8168 Closes #8487 --- include/sys/dmu.h | 3 ++- include/sys/dnode.h | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sys/dmu.h b/include/sys/dmu.h index e4c2ebc2f..93d05aac4 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -477,7 +477,8 @@ int dmu_object_set_blocksize(objset_t *os, uint64_t object, uint64_t size, /* * Manually set the maxblkid on a dnode. This will adjust nlevels accordingly - * to accommodate the change. + * to accommodate the change. When calling this function, the caller must + * ensure that the object's nlevels can sufficiently support the new maxblkid. */ int dmu_object_set_maxblkid(objset_t *os, uint64_t object, uint64_t maxblkid, dmu_tx_t *tx); diff --git a/include/sys/dnode.h b/include/sys/dnode.h index 48ef927d4..6355aaa50 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -371,6 +371,12 @@ struct dnode { struct zfetch dn_zfetch; }; +/* + * We use this (otherwise unused) bit to indicate if the value of + * dn_next_maxblkid[txgoff] is valid to use in dnode_sync(). + */ +#define DMU_NEXT_MAXBLKID_SET (1ULL << 63) + /* * Adds a level of indirection between the dbuf and the dnode to avoid * iterating descendent dbufs in dnode_move(). Handles are not allocated @@ -423,7 +429,8 @@ int dnode_set_nlevels(dnode_t *dn, int nlevels, dmu_tx_t *tx); int dnode_set_blksz(dnode_t *dn, uint64_t size, int ibs, dmu_tx_t *tx); void dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx); void dnode_diduse_space(dnode_t *dn, int64_t space); -void dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t); +void dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, + boolean_t have_read, boolean_t force); uint64_t dnode_block_freed(dnode_t *dn, uint64_t blkid); void dnode_init(void); void dnode_fini(void); -- cgit v1.2.3