Skip to content

Commit f6f3089

Browse files
loli10Kbehlendorf
andcommitted
Fix 'zfs userspace' for received datasets in encrypted root
For encrypted receives, where user accounting is initially disabled on creation, both 'zfs userspace' and 'zfs groupspace' fails with EOPNOTSUPP: this is because dmu_objset_id_quota_upgrade_cb() forgets to set OBJSET_FLAG_USERACCOUNTING_COMPLETE on the objset flags after a successful dmu_objset_space_upgrade(). Reviewed-by: Brian Behlendorf <[email protected]> Co-authored-by: Brian Behlendorf <[email protected]> Signed-off-by: loli10K <[email protected]> Closes #9501 Closes #9596
1 parent a09aeb9 commit f6f3089

File tree

6 files changed

+153
-20
lines changed

6 files changed

+153
-20
lines changed

include/sys/dmu_objset.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ void dmu_objset_evict(objset_t *os);
245245
void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx);
246246
void dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx);
247247
boolean_t dmu_objset_userused_enabled(objset_t *os);
248-
int dmu_objset_userspace_upgrade(objset_t *os);
248+
void dmu_objset_userspace_upgrade(objset_t *os);
249249
boolean_t dmu_objset_userspace_present(objset_t *os);
250250
boolean_t dmu_objset_userobjused_enabled(objset_t *os);
251251
boolean_t dmu_objset_userobjspace_upgradable(objset_t *os);

module/zfs/dmu_objset.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -778,11 +778,15 @@ dmu_objset_own(const char *name, dmu_objset_type_t type,
778778
* speed up pool import times and to keep this txg reserved
779779
* completely for recovery work.
780780
*/
781-
if ((dmu_objset_userobjspace_upgradable(*osp) ||
782-
dmu_objset_projectquota_upgradable(*osp)) &&
783-
!readonly && !dp->dp_spa->spa_claiming &&
784-
(ds->ds_dir->dd_crypto_obj == 0 || decrypt))
785-
dmu_objset_id_quota_upgrade(*osp);
781+
if (!readonly && !dp->dp_spa->spa_claiming &&
782+
(ds->ds_dir->dd_crypto_obj == 0 || decrypt)) {
783+
if (dmu_objset_userobjspace_upgradable(*osp) ||
784+
dmu_objset_projectquota_upgradable(*osp)) {
785+
dmu_objset_id_quota_upgrade(*osp);
786+
} else if (dmu_objset_userused_enabled(*osp)) {
787+
dmu_objset_userspace_upgrade(*osp);
788+
}
789+
}
786790

787791
dsl_pool_rele(dp, FTAG);
788792
return (0);
@@ -2285,8 +2289,8 @@ dmu_objset_space_upgrade(objset_t *os)
22852289
return (0);
22862290
}
22872291

2288-
int
2289-
dmu_objset_userspace_upgrade(objset_t *os)
2292+
static int
2293+
dmu_objset_userspace_upgrade_cb(objset_t *os)
22902294
{
22912295
int err = 0;
22922296

@@ -2306,6 +2310,12 @@ dmu_objset_userspace_upgrade(objset_t *os)
23062310
return (0);
23072311
}
23082312

2313+
void
2314+
dmu_objset_userspace_upgrade(objset_t *os)
2315+
{
2316+
dmu_objset_upgrade(os, dmu_objset_userspace_upgrade_cb);
2317+
}
2318+
23092319
static int
23102320
dmu_objset_id_quota_upgrade_cb(objset_t *os)
23112321
{
@@ -2316,14 +2326,15 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
23162326
return (0);
23172327
if (dmu_objset_is_snapshot(os))
23182328
return (SET_ERROR(EINVAL));
2319-
if (!dmu_objset_userobjused_enabled(os))
2329+
if (!dmu_objset_userused_enabled(os))
23202330
return (SET_ERROR(ENOTSUP));
23212331
if (!dmu_objset_projectquota_enabled(os) &&
23222332
dmu_objset_userobjspace_present(os))
23232333
return (SET_ERROR(ENOTSUP));
23242334

2325-
dmu_objset_ds(os)->ds_feature_activation[
2326-
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
2335+
if (dmu_objset_userobjused_enabled(os))
2336+
dmu_objset_ds(os)->ds_feature_activation[
2337+
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
23272338
if (dmu_objset_projectquota_enabled(os))
23282339
dmu_objset_ds(os)->ds_feature_activation[
23292340
SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
@@ -2332,7 +2343,9 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
23322343
if (err)
23332344
return (err);
23342345

2335-
os->os_flags |= OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
2346+
os->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
2347+
if (dmu_objset_userobjused_enabled(os))
2348+
os->os_flags |= OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
23362349
if (dmu_objset_projectquota_enabled(os))
23372350
os->os_flags |= OBJSET_FLAG_PROJECTQUOTA_COMPLETE;
23382351

module/zfs/zfs_ioctl.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5856,7 +5856,6 @@ zfs_ioc_userspace_many(zfs_cmd_t *zc)
58565856
static int
58575857
zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
58585858
{
5859-
objset_t *os;
58605859
int error = 0;
58615860
zfsvfs_t *zfsvfs;
58625861

@@ -5877,19 +5876,54 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
58775876
error = zfs_resume_fs(zfsvfs, newds);
58785877
}
58795878
}
5880-
if (error == 0)
5881-
error = dmu_objset_userspace_upgrade(zfsvfs->z_os);
5879+
if (error == 0) {
5880+
mutex_enter(&zfsvfs->z_os->os_upgrade_lock);
5881+
if (zfsvfs->z_os->os_upgrade_id == 0) {
5882+
/* clear potential error code and retry */
5883+
zfsvfs->z_os->os_upgrade_status = 0;
5884+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
5885+
5886+
dsl_pool_config_enter(
5887+
dmu_objset_pool(zfsvfs->z_os), FTAG);
5888+
dmu_objset_userspace_upgrade(zfsvfs->z_os);
5889+
dsl_pool_config_exit(
5890+
dmu_objset_pool(zfsvfs->z_os), FTAG);
5891+
} else {
5892+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
5893+
}
5894+
5895+
taskq_wait_id(zfsvfs->z_os->os_spa->spa_upgrade_taskq,
5896+
zfsvfs->z_os->os_upgrade_id);
5897+
error = zfsvfs->z_os->os_upgrade_status;
5898+
}
58825899
zfs_vfs_rele(zfsvfs);
58835900
} else {
5901+
objset_t *os;
5902+
58845903
/* XXX kind of reading contents without owning */
58855904
error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os);
58865905
if (error != 0)
58875906
return (error);
58885907

5889-
error = dmu_objset_userspace_upgrade(os);
5890-
dmu_objset_rele_flags(os, B_TRUE, FTAG);
5891-
}
5908+
mutex_enter(&os->os_upgrade_lock);
5909+
if (os->os_upgrade_id == 0) {
5910+
/* clear potential error code and retry */
5911+
os->os_upgrade_status = 0;
5912+
mutex_exit(&os->os_upgrade_lock);
5913+
5914+
dmu_objset_userspace_upgrade(os);
5915+
} else {
5916+
mutex_exit(&os->os_upgrade_lock);
5917+
}
58925918

5919+
dsl_pool_rele(dmu_objset_pool(os), FTAG);
5920+
5921+
taskq_wait_id(os->os_spa->spa_upgrade_taskq, os->os_upgrade_id);
5922+
error = os->os_upgrade_status;
5923+
5924+
dsl_dataset_rele_flags(dmu_objset_ds(os), DS_HOLD_FLAG_DECRYPT,
5925+
FTAG);
5926+
}
58935927
return (error);
58945928
}
58955929

tests/runfiles/common.run

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ tests = [
859859
'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos',
860860
'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos',
861861
'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg',
862-
'userspace_001_pos', 'userspace_002_pos']
862+
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted']
863863
tags = ['functional', 'userquota']
864864

865865
[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
@@ -20,7 +20,8 @@ dist_pkgdata_SCRIPTS = \
2020
userquota_013_pos.ksh \
2121
userspace_001_pos.ksh \
2222
userspace_002_pos.ksh \
23-
userspace_003_pos.ksh
23+
userspace_003_pos.ksh \
24+
userspace_encrypted.ksh
2425

2526
dist_pkgdata_DATA = \
2627
userquota.cfg \
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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 2019, loli10K <[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+
# 'zfs userspace' and 'zfs groupspace' can be used on encrypted datasets
23+
#
24+
#
25+
# STRATEGY:
26+
# 1. Create both un-encrypted and encrypted datasets
27+
# 2. Receive un-encrypted dataset in encrypted hierarchy
28+
# 3. Verify encrypted datasets support 'zfs userspace' and 'zfs groupspace'
29+
#
30+
31+
function cleanup
32+
{
33+
destroy_pool $POOLNAME
34+
rm -f $FILEDEV
35+
}
36+
37+
function log_must_unsupported
38+
{
39+
log_must_retry "unsupported" 3 "$@"
40+
(( $? != 0 )) && log_fail
41+
}
42+
43+
log_onexit cleanup
44+
45+
FILEDEV="$TEST_BASE_DIR/userspace_encrypted"
46+
POOLNAME="testpool$$"
47+
typeset -a POOL_OPTS=('' # all pool features enabled
48+
'-d' # all pool features disabled
49+
'-d -o feature@userobj_accounting=enabled' # only userobj_accounting enabled
50+
'-d -o feature@project_quota=enabled') # only project_quota enabled
51+
DATASET_ENCROOT="$POOLNAME/encroot"
52+
DATASET_SENDFS="$POOLNAME/sendfs"
53+
54+
log_assert "'zfs user/groupspace' should work on encrypted datasets"
55+
56+
for opts in "${POOL_OPTS[@]}"; do
57+
# Setup
58+
truncate -s $SPA_MINDEVSIZE $FILEDEV
59+
log_must zpool create $opts -o feature@encryption=enabled $POOLNAME \
60+
$FILEDEV
61+
62+
# 1. Create both un-encrypted and encrypted datasets
63+
log_must zfs create $DATASET_SENDFS
64+
log_must eval "echo 'password' | zfs create -o encryption=on" \
65+
"-o keyformat=passphrase -o keylocation=prompt " \
66+
"$DATASET_ENCROOT"
67+
log_must zfs create $DATASET_ENCROOT/fs
68+
69+
# 2. Receive un-encrypted dataset in encrypted hierarchy
70+
log_must zfs snap $DATASET_SENDFS@snap
71+
log_must eval "zfs send $DATASET_SENDFS@snap | zfs recv " \
72+
"$DATASET_ENCROOT/recvfs"
73+
74+
# 3. Verify encrypted datasets support 'zfs userspace' and
75+
# 'zfs groupspace'
76+
log_must zfs userspace $DATASET_ENCROOT/fs
77+
log_must zfs groupspace $DATASET_ENCROOT/fs
78+
log_must_unsupported zfs userspace $DATASET_ENCROOT/recvfs
79+
log_must_unsupported zfs groupspace $DATASET_ENCROOT/recvfs
80+
81+
# Cleanup
82+
cleanup
83+
done
84+
85+
log_pass "'zfs user/groupspace' works on encrypted datasets"

0 commit comments

Comments
 (0)