Handle new dnode size in incremental backup stream

When receiving an incremental backup stream, call
dmu_object_reclaim_dnsize() if an object's dnode size differs between
the incremental source and target. Otherwise it may appear that a
dnode which has shrunk is still occupying slots which are in fact
free. This will cause a failure to receive new objects that should
occupy the now-free slots.

Add a test case to verify that an incremental stream containing
objects with changed dnode sizes can be received without error. This
test case fails without this change.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes #6366 
Closes #6576
This commit is contained in:
Ned Bass 2017-09-05 16:09:15 -07:00 committed by Brian Behlendorf
parent c8811dec70
commit 65dcb0f67a
4 changed files with 73 additions and 4 deletions

View File

@ -2482,11 +2482,13 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
} else if (drro->drr_type != doi.doi_type ||
drro->drr_blksz != doi.doi_data_block_size ||
drro->drr_bonustype != doi.doi_bonus_type ||
drro->drr_bonuslen != doi.doi_bonus_size) {
drro->drr_bonuslen != doi.doi_bonus_size ||
drro->drr_dn_slots != (doi.doi_dnodesize >> DNODE_SHIFT)) {
/* currently allocated, but with different properties */
err = dmu_object_reclaim(rwa->os, drro->drr_object,
err = dmu_object_reclaim_dnsize(rwa->os, drro->drr_object,
drro->drr_type, drro->drr_blksz,
drro->drr_bonustype, drro->drr_bonuslen, tx);
drro->drr_bonustype, drro->drr_bonuslen,
drro->drr_dn_slots << DNODE_SHIFT, tx);
}
if (err != 0) {
dmu_tx_commit(tx);

View File

@ -520,7 +520,7 @@ tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
'send-c_lz4_disabled', 'send-c_recv_lz4_disabled',
'send-c_mixed_compression', 'send-c_stream_size_estimate', 'send-cD',
'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize',
'send-c_recv_dedup', 'send_encrypted_heirarchy']
'send-c_recv_dedup', 'send_encrypted_heirarchy', 'send_changed_dnodesize']
[tests/functional/scrub_mirror]
tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos',

View File

@ -23,6 +23,7 @@ dist_pkgdata_SCRIPTS = \
rsend_021_pos.ksh \
rsend_022_pos.ksh \
rsend_024_pos.ksh \
send_changed_dnodesize.ksh \
send_encrypted_heirarchy.ksh \
send-cD.ksh \
send-c_embedded_blocks.ksh \

View File

@ -0,0 +1,66 @@
#!/bin/ksh
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/rsend/rsend.kshlib
#
# Description:
# Verify incremental receive properly handles objects with changed
# dnode size.
#
# Strategy:
# 1. Populate a dataset with dnodesize=auto with objects
# 2. Take a snapshot
# 3. Remove objects and set dnodesize=legacy
# 4. Remount dataset so object numbers get recycled and formerly
# "interior" dnode slots get assigned to new objects
# 5. Repopulate dataset
# 6. Send first snapshot to new dataset
# 7. Send incremental snapshot from second snapshot to new dataset
#
verify_runnable "both"
log_assert "Verify incremental receive handles objects with changed dnode size"
function cleanup
{
rm -f $BACKDIR/fs-dn-auto
rm -f $BACKDIR/fs-dn-legacy
}
log_onexit cleanup
log_must zfs create -o dnodesize=auto $POOL/fs
mk_files 200 262144 0 $POOL/fs
log_must zfs unmount $POOL/fs
log_must zfs snapshot $POOL/fs@a
log_must zfs mount $POOL/fs
log_must rm /$POOL/fs/*
log_must zfs unmount $POOL/fs
log_must zfs set dnodesize=legacy $POOL/fs
log_must zfs mount $POOL/fs
mk_files 200 262144 0 $POOL/fs
log_must zfs unmount $POOL/fs
log_must zfs snapshot $POOL/fs@b
log_must eval "zfs send $POOL/fs@a > $BACKDIR/fs-dn-auto"
log_must eval "zfs send -i $POOL/fs@a $POOL/fs@b > $BACKDIR/fs-dn-legacy"
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-auto"
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-legacy"
log_pass "Verify incremental receive handles objects with changed dnode size"