Fix problems receiving reallocated dnodes

This is a port of 047116ac - Raw sends must be able to decrease nlevels,
to the zfs-0.7-stable branch.  It includes the various fixes to the
problem of receiving incremental streams which include reallocated dnodes
in which the number of dnode slots has changed but excludes the parts
which are related to raw streams.

From 047116ac:

    Currently, when a raw zfs send file includes a
    DRR_OBJECT record that would decrease the number of
    levels of an existing object, the object is reallocated
    with dmu_object_reclaim() which creates the new dnode
    using the old object's nlevels. For non-raw sends this
    doesn't really matter, but raw sends require that
    nlevels on the receive side match that of the send
    side so that the checksum-of-MAC tree can be properly
    maintained. This patch corrects the issue by freeing
    the object completely before allocating it again in
    this case.

    This patch also corrects several issues with
    dnode_hold_impl() and related functions that prevented
    dnodes (particularly multi-slot dnodes) from being
    reallocated properly due to the fact that existing
    dnodes were not being fully cleaned up when they
    were freed.

    This patch adds a test to make sure that zfs recv
    functions properly with incremental streams containing
    dnodes of different sizes.

This also includes a one-liner fix from loli10K to fix a test failure:
https://github.com/zfsonlinux/zfs/pull/7792#discussion_r212769264

Authored-by: Tom Caputi <tcaputi@datto.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Jorgen Lundman <lundman@lundman.net>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tim Chase <tim@chase2k.com>
Ported-by: Tim Chase <tim@chase2k.com>

Closes #6821
Closes #6864

NOTE: This is the first of the port of 3 related patches patches to the
zfs-0.7-release branch of ZoL.  The other two patches should immediately
follow this one.
This commit is contained in:
Tim Chase
2018-08-27 10:28:32 -04:00
committed by Tony Hutter
parent 3ea1f7f193
commit d2c8103a68
10 changed files with 258 additions and 15 deletions
+1 -1
View File
@@ -605,7 +605,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_freeobjects']
'send-c_recv_dedup', 'send_freeobjects', 'send_realloc_dnode_size']
tags = ['functional', 'rsend']
[tests/functional/scrub_mirror]
@@ -36,7 +36,8 @@ dist_pkgdata_SCRIPTS = \
send-c_volume.ksh \
send-c_zstreamdump.ksh \
send-cpL_varied_recsize.ksh \
send_freeobjects.ksh
send_freeobjects.ksh \
send_realloc_dnode_size.ksh
dist_pkgdata_DATA = \
rsend.cfg \
@@ -0,0 +1,98 @@
#!/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 slot count.
#
# Strategy:
# 1. Populate a dataset with 1k byte dnodes and snapshot
# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects
# get recycled numbers and formerly "interior" dnode slots get assigned
# to new objects
# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects
# overlap with recently recycled and formerly "normal" dnode slots get
# assigned to new objects
# 4. Generate initial and incremental streams
# 5. Verify initial and incremental streams can be received
#
verify_runnable "both"
log_assert "Verify incremental receive handles objects with changed dnode size"
function cleanup
{
rm -f $BACKDIR/fs-dn-legacy
rm -f $BACKDIR/fs-dn-1k
rm -f $BACKDIR/fs-dn-2k
if datasetexists $POOL/fs ; then
log_must zfs destroy -rR $POOL/fs
fi
if datasetexists $POOL/newfs ; then
log_must zfs destroy -rR $POOL/newfs
fi
}
log_onexit cleanup
# 1. Populate a dataset with 1k byte dnodes and snapshot
log_must zfs create -o dnodesize=1k $POOL/fs
log_must mk_files 200 262144 0 $POOL/fs
log_must zfs snapshot $POOL/fs@a
# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects
# get recycled numbers and formerly "interior" dnode slots get assigned
# to new objects
rm /$POOL/fs/*
log_must zfs unmount $POOL/fs
log_must zfs set dnodesize=legacy $POOL/fs
log_must zfs mount $POOL/fs
log_must mk_files 200 262144 0 $POOL/fs
log_must zfs snapshot $POOL/fs@b
# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects
# overlap with recently recycled and formerly "normal" dnode slots get
# assigned to new objects
rm /$POOL/fs/*
log_must zfs unmount $POOL/fs
log_must zfs set dnodesize=2k $POOL/fs
log_must zfs mount $POOL/fs
mk_files 200 262144 0 $POOL/fs
log_must zfs snapshot $POOL/fs@c
# 4. Generate initial and incremental streams
log_must eval "zfs send $POOL/fs@a > $BACKDIR/fs-dn-1k"
log_must eval "zfs send -i $POOL/fs@a $POOL/fs@b > $BACKDIR/fs-dn-legacy"
log_must eval "zfs send -i $POOL/fs@b $POOL/fs@c > $BACKDIR/fs-dn-2k"
# 5. Verify initial and incremental streams can be received
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-1k"
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-legacy"
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-2k"
log_pass "Verify incremental receive handles objects with changed dnode size"