forked from openzfs/zfs
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When receiving an object in a send stream the receive_object() function must determine if it is an existing or new object. This is normally straight forward since that object number will usually not be allocated, and therefore it must be a new object. However, when the object exists there are two possible scenarios. 1) The object may have been freed and an entirely new object allocated. In which case it needs to be reallocated to free any attached spill block and to set the new attributes (i.e. block size, bonus size, etc). Or, 2) The object's attributes, like block size, we're modified at the source but it is the same original object. In which case only those attributes should be updated, and everything else preserved. The issue is that this determination is accomplished using a set of heuristics from the OBJECT record. Unfortunately, these fields aren't sufficient to always distinguish between these two cases. The result of which is that a change in the objects block size will result it in being reallocated. As part of this reallocation any spill block associated with the object will be freed. When performing a normal send/recv this issue will most likely manifest itself as a file with missing xattrs. This is because when the xattr=sa property is set the xattrs can be stored in this lost spill block. If this issue occurs when performing a raw send then the missing spill block will trigger an authentication error. This error will prevent the receiving side for accessing the damaged dnode block. Furthermore, if first dnode block is damaged in this way it will make it impossible to mount the received snapshot. This change resolves the issue by updating the sender to always include a SPILL record for each OBJECT record with a spill block. This allows the missing spill block to be recreated if it's freed during receive_object(). The major advantage of this approach is that it is backwards compatible with existing versions of 'zfs receive'. This means there's no need to add an incompatible feature flag which is only understood by the latest versions. Older versions of the software which already know how to handle spill blocks will do the right thing. The downside to this approach is that it can increases the size of the stream due to the additional spill blocks. Additionally, since new spill blocks will be written the received snapshot will consume more capacity. These drawbacks can be largely mitigated by using the large dnode feature which reduces the need for spill blocks. Both the send_realloc_files and send_realloc_encrypted_files ZTS test cases were updated to create xattrs in order to force spill blocks. As part of validating an incremental receive the contents of all received xattrs are verified against the source snapshot. OpenZFS-issue: https://www.illumos.org/issues/9952 FreeBSD-issue: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=233277 Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Issue openzfs#6224
- Loading branch information
1 parent
17cbc2e
commit a436e48
Showing
11 changed files
with
214 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
tests/zfs-tests/tests/functional/rsend/send_spill_block.ksh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
#!/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) 2019 by Lawrence Livermore National Security, LLC. | ||
# | ||
|
||
. $STF_SUITE/include/libtest.shlib | ||
. $STF_SUITE/tests/functional/rsend/rsend.kshlib | ||
|
||
# | ||
# Description: | ||
# Verify spill blocks are correctly preserved. | ||
# | ||
# Strategy: | ||
# 1) Create a set of files each containing some file data. | ||
# 2) Add enough xattrs to the file to require a spill block. | ||
# 3) Snapshot and send these files to a new dataset. | ||
# 4) Modify the files and spill blocks in a variety of ways. | ||
# 5) Send the changes using an incremental send stream. | ||
# 6) Verify that all the xattrs (and thus the spill block) were | ||
# preserved when receiving the incremental stream. | ||
# | ||
|
||
verify_runnable "both" | ||
|
||
log_assert "Verify spill blocks are correctly preserved" | ||
|
||
function cleanup | ||
{ | ||
rm -f $BACKDIR/fs@* | ||
destroy_dataset $POOL/fs "-rR" | ||
destroy_dataset $POOL/newfs "-rR" | ||
} | ||
|
||
attrvalue="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" | ||
|
||
log_onexit cleanup | ||
|
||
log_must zfs create $POOL/fs | ||
log_must zfs set xattr=sa $POOL/fs | ||
log_must zfs set dnodesize=legacy $POOL/fs | ||
log_must zfs set recordsize=128k $POOL/fs | ||
|
||
# Create 40 files each with a spill block containing xattrs. Each file | ||
# will be modified in a different way to validate the incremental receive. | ||
for i in {1..40}; do | ||
file="/$POOL/fs/file$i" | ||
|
||
log_must mkfile 16384 $file | ||
for j in {1..20}; do | ||
log_must attr -qs "testattr$j" -V "$attrvalue" $file | ||
done | ||
done | ||
|
||
# Snapshot the pool and send it to the new dataset. | ||
log_must zfs snapshot $POOL/fs@snap1 | ||
log_must eval "zfs send -e $POOL/fs@snap1 >$BACKDIR/fs@snap1" | ||
log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs@snap1" | ||
|
||
# | ||
# Modify file[1-6]'s contents but not the spill blocks. | ||
# | ||
# file1 - Increase record size; single block | ||
# file2 - Increase record size; multiple blocks | ||
# file3 - Truncate file to zero size; single block | ||
# file4 - Truncate file to smaller size; single block | ||
# file5 - Truncate file to much larger size; add holes | ||
# file6 - Truncate file to embedded size; embedded data | ||
# | ||
log_must mkfile 32768 /$POOL/fs/file1 | ||
log_must mkfile 1048576 /$POOL/fs/file2 | ||
log_must truncate -s 0 /$POOL/fs/file3 | ||
log_must truncate -s 8192 /$POOL/fs/file4 | ||
log_must truncate -s 1073741824 /$POOL/fs/file5 | ||
log_must truncate -s 50 /$POOL/fs/file6 | ||
|
||
# | ||
# Modify file[11-16]'s contents and their spill blocks. | ||
# | ||
# file11 - Increase record size; single block | ||
# file12 - Increase record size; multiple blocks | ||
# file13 - Truncate file to zero size; single block | ||
# file14 - Truncate file to smaller size; single block | ||
# file15 - Truncate file to much larger size; add holes | ||
# file16 - Truncate file to embedded size; embedded data | ||
# | ||
log_must mkfile 32768 /$POOL/fs/file11 | ||
log_must mkfile 1048576 /$POOL/fs/file12 | ||
log_must truncate -s 0 /$POOL/fs/file13 | ||
log_must truncate -s 8192 /$POOL/fs/file14 | ||
log_must truncate -s 1073741824 /$POOL/fs/file15 | ||
log_must truncate -s 50 /$POOL/fs/file16 | ||
|
||
for i in {11..20}; do | ||
log_must attr -qr testattr1 /$POOL/fs/file$i | ||
done | ||
|
||
# | ||
# Modify file[21-26]'s contents and remove their spill blocks. | ||
# | ||
# file21 - Increase record size; single block | ||
# file22 - Increase record size; multiple blocks | ||
# file23 - Truncate file to zero size; single block | ||
# file24 - Truncate file to smaller size; single block | ||
# file25 - Truncate file to much larger size; add holes | ||
# file26 - Truncate file to embedded size; embedded data | ||
# | ||
log_must mkfile 32768 /$POOL/fs/file21 | ||
log_must mkfile 1048576 /$POOL/fs/file22 | ||
log_must truncate -s 0 /$POOL/fs/file23 | ||
log_must truncate -s 8192 /$POOL/fs/file24 | ||
log_must truncate -s 1073741824 /$POOL/fs/file25 | ||
log_must truncate -s 50 /$POOL/fs/file26 | ||
|
||
for i in {21..30}; do | ||
for j in {1..20}; do | ||
log_must attr -qr testattr$j /$POOL/fs/file$i | ||
done | ||
done | ||
|
||
# | ||
# Modify file[31-40]'s spill blocks but not the file contents. | ||
# | ||
for i in {31..40}; do | ||
file="/$POOL/fs/file$i" | ||
log_must attr -qr testattr$(((RANDOM % 20) + 1)) $file | ||
log_must attr -qs testattr$(((RANDOM % 20) + 1)) -V "$attrvalue" $file | ||
done | ||
|
||
# Calculate the expected recursive checksum for the source. | ||
expected_cksum=$(recursive_cksum /$POOL/fs) | ||
|
||
# Snapshot the pool and send the incremental snapshot. | ||
log_must zfs snapshot $POOL/fs@snap2 | ||
log_must eval "zfs send -e -i $POOL/fs@snap1 $POOL/fs@snap2 >$BACKDIR/fs@snap2" | ||
log_must eval "zfs recv -F $POOL/newfs < $BACKDIR/fs@snap2" | ||
|
||
# Validate the received copy using the received recursive checksum. | ||
actual_cksum=$(recursive_cksum /$POOL/newfs) | ||
if [[ "$expected_cksum" != "$actual_cksum" ]]; then | ||
log_fail "Checksums differ ($expected_cksum != $actual_cksum)" | ||
fi | ||
|
||
log_pass "Verify spill blocks are correctly preserved" |