Skip to content

Commit e257bd4

Browse files
gamanakistonyhutter
authored andcommitted
Introduce a flag to skip comparing the local mac when raw sending
Raw receiving a snapshot back to the originating dataset is currently impossible because of user accounting being present in the originating dataset. One solution would be resetting user accounting when raw receiving on the receiving dataset. However, to recalculate it we would have to dirty all dnodes, which may not be preferable on big datasets. Instead, we rely on the os_phys flag OBJSET_FLAG_USERACCOUNTING_COMPLETE to indicate that user accounting is incomplete when raw receiving. Thus, on the next mount of the receiving dataset the local mac protecting user accounting is zeroed out. The flag is then cleared when user accounting of the raw received snapshot is calculated. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: George Amanakis <[email protected]> Closes openzfs#12981 Closes openzfs#10523 Closes openzfs#11221 Closes openzfs#11294 Closes openzfs#12594 Issue openzfs#11300
1 parent 1009e60 commit e257bd4

File tree

7 files changed

+163
-14
lines changed

7 files changed

+163
-14
lines changed

module/os/freebsd/zfs/zio_crypt.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,11 +1076,26 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
10761076

10771077
bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);
10781078

1079+
/*
1080+
* This is necessary here as we check next whether
1081+
* OBJSET_FLAG_USERACCOUNTING_COMPLETE is set in order to
1082+
* decide if the local_mac should be zeroed out. That flag will always
1083+
* be set by dmu_objset_id_quota_upgrade_cb() and
1084+
* dmu_objset_userspace_upgrade_cb() if useraccounting has been
1085+
* completed.
1086+
*/
1087+
intval = osp->os_flags;
1088+
if (should_bswap)
1089+
intval = BSWAP_64(intval);
1090+
boolean_t uacct_incomplete =
1091+
!(intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE);
1092+
10791093
/*
10801094
* The local MAC protects the user, group and project accounting.
10811095
* If these objects are not present, the local MAC is zeroed out.
10821096
*/
1083-
if ((datalen >= OBJSET_PHYS_SIZE_V3 &&
1097+
if (uacct_incomplete ||
1098+
(datalen >= OBJSET_PHYS_SIZE_V3 &&
10841099
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
10851100
osp->os_groupused_dnode.dn_type == DMU_OT_NONE &&
10861101
osp->os_projectused_dnode.dn_type == DMU_OT_NONE) ||

module/os/linux/zfs/zio_crypt.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,11 +1203,26 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
12031203

12041204
bcopy(raw_portable_mac, portable_mac, ZIO_OBJSET_MAC_LEN);
12051205

1206+
/*
1207+
* This is necessary here as we check next whether
1208+
* OBJSET_FLAG_USERACCOUNTING_COMPLETE is set in order to
1209+
* decide if the local_mac should be zeroed out. That flag will always
1210+
* be set by dmu_objset_id_quota_upgrade_cb() and
1211+
* dmu_objset_userspace_upgrade_cb() if useraccounting has been
1212+
* completed.
1213+
*/
1214+
intval = osp->os_flags;
1215+
if (should_bswap)
1216+
intval = BSWAP_64(intval);
1217+
boolean_t uacct_incomplete =
1218+
!(intval & OBJSET_FLAG_USERACCOUNTING_COMPLETE);
1219+
12061220
/*
12071221
* The local MAC protects the user, group and project accounting.
12081222
* If these objects are not present, the local MAC is zeroed out.
12091223
*/
1210-
if ((datalen >= OBJSET_PHYS_SIZE_V3 &&
1224+
if (uacct_incomplete ||
1225+
(datalen >= OBJSET_PHYS_SIZE_V3 &&
12111226
osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
12121227
osp->os_groupused_dnode.dn_type == DMU_OT_NONE &&
12131228
osp->os_projectused_dnode.dn_type == DMU_OT_NONE) ||

module/zfs/dnode_sync.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,13 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
655655
DNODE_FLAG_USEROBJUSED_ACCOUNTED;
656656
mutex_exit(&dn->dn_mtx);
657657
dmu_objset_userquota_get_ids(dn, B_FALSE, tx);
658-
} else {
659-
/* Once we account for it, we should always account for it */
658+
} else if (!(os->os_encrypted && dmu_objset_is_receiving(os))) {
659+
/*
660+
* Once we account for it, we should always account for it,
661+
* except for the case of a raw receive. We will not be able
662+
* to account for it until the receiving dataset has been
663+
* mounted.
664+
*/
660665
ASSERT(!(dn->dn_phys->dn_flags &
661666
DNODE_FLAG_USERUSED_ACCOUNTED));
662667
ASSERT(!(dn->dn_phys->dn_flags &

module/zfs/dsl_crypt.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,14 +2007,6 @@ dsl_crypto_recv_raw_objset_check(dsl_dataset_t *ds, dsl_dataset_t *fromds,
20072007
if (ret != 0)
20082008
return (ret);
20092009

2010-
/*
2011-
* Useraccounting is not portable and must be done with the keys loaded.
2012-
* Therefore, whenever we do any kind of receive the useraccounting
2013-
* must not be present.
2014-
*/
2015-
ASSERT0(os->os_flags & OBJSET_FLAG_USERACCOUNTING_COMPLETE);
2016-
ASSERT0(os->os_flags & OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE);
2017-
20182010
mdn = DMU_META_DNODE(os);
20192011

20202012
/*
@@ -2106,6 +2098,7 @@ dsl_crypto_recv_raw_objset_sync(dsl_dataset_t *ds, dmu_objset_type_t ostype,
21062098
arc_release(os->os_phys_buf, &os->os_phys_buf);
21072099
bcopy(portable_mac, os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN);
21082100
bzero(os->os_phys->os_local_mac, ZIO_OBJSET_MAC_LEN);
2101+
os->os_flags &= ~OBJSET_FLAG_USERACCOUNTING_COMPLETE;
21092102
os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE;
21102103

21112104
/* set metadnode compression and checksum */

tests/runfiles/common.run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,8 @@ tests = [
889889
'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos',
890890
'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos',
891891
'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg',
892-
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted']
892+
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted',
893+
'userspace_send_encrypted']
893894
tags = ['functional', 'userquota']
894895

895896
[tests/functional/vdev_zaps]

tests/zfs-tests/tests/functional/userquota/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ dist_pkgdata_SCRIPTS = \
2121
userspace_001_pos.ksh \
2222
userspace_002_pos.ksh \
2323
userspace_003_pos.ksh \
24-
userspace_encrypted.ksh
24+
userspace_encrypted.ksh \
25+
userspace_send_encrypted.ksh
2526

2627
dist_pkgdata_DATA = \
2728
userquota.cfg \
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/bin/ksh -p
2+
#
3+
# This file and its contents are supplied under the terms of the
4+
# Common Development and Distribution License ("CDDL"), version 1.0.
5+
# You may only use this file in accordance with the terms of version
6+
# 1.0 of the CDDL.
7+
#
8+
# A full copy of the text of the CDDL should have accompanied this
9+
# source. A copy of the CDDL is also available via the Internet at
10+
# http://www.illumos.org/license/CDDL.
11+
#
12+
13+
#
14+
# Copyright 2021, George Amanakis <[email protected]>. All rights reserved.
15+
#
16+
17+
. $STF_SUITE/include/libtest.shlib
18+
. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
19+
20+
#
21+
# DESCRIPTION:
22+
# Sending raw encrypted datasets back to the source dataset succeeds.
23+
#
24+
#
25+
# STRATEGY:
26+
# 1. Create encrypted source dataset, set userquota and write a file
27+
# 2. Create base snapshot
28+
# 3. Write new file, snapshot, get userspace
29+
# 4. Raw send both snapshots
30+
# 5. Destroy latest snapshot at source and rollback
31+
# 6. Unmount, unload key from source
32+
# 7. Raw send latest snapshot back to source
33+
# 8. Mount both source and target datasets
34+
# 9. Verify encrypted datasets support 'zfs userspace' and 'zfs groupspace'
35+
# and the accounting is done correctly
36+
#
37+
38+
function cleanup
39+
{
40+
destroy_pool $POOLNAME
41+
rm -f $FILEDEV
42+
}
43+
44+
log_onexit cleanup
45+
46+
FILEDEV="$TEST_BASE_DIR/userspace_encrypted"
47+
POOLNAME="testpool$$"
48+
ENC_SOURCE="$POOLNAME/source"
49+
ENC_TARGET="$POOLNAME/target"
50+
51+
log_assert "Sending raw encrypted datasets back to the source dataset succeeds."
52+
53+
# Setup pool and create source
54+
truncate -s 200m $FILEDEV
55+
log_must zpool create -o feature@encryption=enabled $POOLNAME \
56+
$FILEDEV
57+
log_must eval "echo 'password' | zfs create -o encryption=on" \
58+
"-o keyformat=passphrase -o keylocation=prompt " \
59+
"$ENC_SOURCE"
60+
61+
# Set user quota and write file
62+
log_must zfs set userquota@$QUSER1=50m $ENC_SOURCE
63+
mkmount_writable $ENC_SOURCE
64+
mntpnt=$(get_prop mountpoint $ENC_SOURCE)
65+
log_must user_run $QUSER1 mkfile 10m /$mntpnt/file1
66+
sync
67+
68+
# Snapshot
69+
log_must zfs snap $ENC_SOURCE@base
70+
71+
# Write new file, snapshot, get userspace
72+
log_must user_run $QUSER1 mkfile 20m /$mntpnt/file2
73+
log_must zfs snap $ENC_SOURCE@s1
74+
75+
# Raw send both snapshots
76+
log_must eval "zfs send -w $ENC_SOURCE@base | zfs recv " \
77+
"$ENC_TARGET"
78+
log_must eval "zfs send -w -i @base $ENC_SOURCE@s1 | zfs recv " \
79+
"$ENC_TARGET"
80+
81+
# Destroy latest snapshot at source and rollback
82+
log_must zfs destroy $ENC_SOURCE@s1
83+
log_must zfs rollback $ENC_SOURCE@base
84+
rollback_uspace=$(zfs userspace -Hp $ENC_SOURCE | \
85+
awk "/$QUSER1/"' {printf "%d\n", $4 / 1024 / 1024}')
86+
87+
# Unmount, unload key
88+
log_must zfs umount $ENC_SOURCE
89+
log_must zfs unload-key -a
90+
91+
# Raw send latest snapshot back to source
92+
log_must eval "zfs send -w -i @base $ENC_TARGET@s1 | zfs recv " \
93+
"$ENC_SOURCE"
94+
95+
# Mount encrypted datasets and verify they support 'zfs userspace' and
96+
# 'zfs groupspace' and the accounting is done correctly
97+
log_must eval "echo 'password' | zfs load-key $ENC_SOURCE"
98+
log_must eval "echo 'password' | zfs load-key $ENC_TARGET"
99+
log_must zfs mount $ENC_SOURCE
100+
log_must zfs mount $ENC_TARGET
101+
sync
102+
103+
sleep 5
104+
105+
src_uspace=$(zfs userspace -Hp $ENC_SOURCE | \
106+
awk "/$QUSER1/"' {printf "%d\n", $4 / 1024 / 1024}')
107+
tgt_uspace=$(zfs userspace -Hp $ENC_TARGET | \
108+
awk "/$QUSER1/"' {printf "%d\n", $4 / 1024 / 1024}')
109+
log_must test "$src_uspace" -eq "$tgt_uspace"
110+
log_must test "$rollback_uspace" -ne "$src_uspace"
111+
112+
src_uquota=$(zfs userspace -Hp $ENC_SOURCE | awk "/$QUSER1/"' {print $5}')
113+
tgt_uquota=$(zfs userspace -Hp $ENC_TARGET | awk "/$QUSER1/"' {print $5}')
114+
log_must test "$src_uquota" -eq "$tgt_uquota"
115+
116+
# Cleanup
117+
cleanup
118+
119+
log_pass "Sending raw encrypted datasets back to the source dataset succeeds."

0 commit comments

Comments
 (0)