Skip to content

Commit d45e0db

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(). Signed-off-by: loli10K <[email protected]> Co-authored-by: Brian Behlendorf <[email protected]>
1 parent 2c47bd5 commit d45e0db

File tree

6 files changed

+148
-20
lines changed

6 files changed

+148
-20
lines changed

include/sys/dmu_objset.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ void dmu_objset_evict(objset_t *os);
244244
void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx);
245245
void dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx);
246246
boolean_t dmu_objset_userused_enabled(objset_t *os);
247-
int dmu_objset_userspace_upgrade(objset_t *os);
247+
void dmu_objset_userspace_upgrade(objset_t *os);
248248
boolean_t dmu_objset_userspace_present(objset_t *os);
249249
boolean_t dmu_objset_userobjused_enabled(objset_t *os);
250250
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
@@ -783,11 +783,15 @@ dmu_objset_own(const char *name, dmu_objset_type_t type,
783783
* speed up pool import times and to keep this txg reserved
784784
* completely for recovery work.
785785
*/
786-
if ((dmu_objset_userobjspace_upgradable(*osp) ||
787-
dmu_objset_projectquota_upgradable(*osp)) &&
788-
!readonly && !dp->dp_spa->spa_claiming &&
789-
(ds->ds_dir->dd_crypto_obj == 0 || decrypt))
790-
dmu_objset_id_quota_upgrade(*osp);
786+
if (!readonly && !dp->dp_spa->spa_claiming &&
787+
(ds->ds_dir->dd_crypto_obj == 0 || decrypt)) {
788+
if (dmu_objset_userobjspace_upgradable(*osp) ||
789+
dmu_objset_projectquota_upgradable(*osp)) {
790+
dmu_objset_id_quota_upgrade(*osp);
791+
} else if (dmu_objset_userused_enabled(*osp)) {
792+
dmu_objset_userspace_upgrade(*osp);
793+
}
794+
}
791795

792796
dsl_pool_rele(dp, FTAG);
793797
return (0);
@@ -2274,8 +2278,8 @@ dmu_objset_space_upgrade(objset_t *os)
22742278
return (0);
22752279
}
22762280

2277-
int
2278-
dmu_objset_userspace_upgrade(objset_t *os)
2281+
static int
2282+
dmu_objset_userspace_upgrade_cb(objset_t *os)
22792283
{
22802284
int err = 0;
22812285

@@ -2295,6 +2299,12 @@ dmu_objset_userspace_upgrade(objset_t *os)
22952299
return (0);
22962300
}
22972301

2302+
void
2303+
dmu_objset_userspace_upgrade(objset_t *os)
2304+
{
2305+
dmu_objset_upgrade(os, dmu_objset_userspace_upgrade_cb);
2306+
}
2307+
22982308
static int
22992309
dmu_objset_id_quota_upgrade_cb(objset_t *os)
23002310
{
@@ -2305,14 +2315,15 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
23052315
return (0);
23062316
if (dmu_objset_is_snapshot(os))
23072317
return (SET_ERROR(EINVAL));
2308-
if (!dmu_objset_userobjused_enabled(os))
2318+
if (!dmu_objset_userused_enabled(os))
23092319
return (SET_ERROR(ENOTSUP));
23102320
if (!dmu_objset_projectquota_enabled(os) &&
23112321
dmu_objset_userobjspace_present(os))
23122322
return (SET_ERROR(ENOTSUP));
23132323

2314-
dmu_objset_ds(os)->ds_feature_activation[
2315-
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
2324+
if (dmu_objset_userobjused_enabled(os))
2325+
dmu_objset_ds(os)->ds_feature_activation[
2326+
SPA_FEATURE_USEROBJ_ACCOUNTING] = (void *)B_TRUE;
23162327
if (dmu_objset_projectquota_enabled(os))
23172328
dmu_objset_ds(os)->ds_feature_activation[
23182329
SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
@@ -2321,7 +2332,9 @@ dmu_objset_id_quota_upgrade_cb(objset_t *os)
23212332
if (err)
23222333
return (err);
23232334

2324-
os->os_flags |= OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
2335+
os->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
2336+
if (dmu_objset_userobjused_enabled(os))
2337+
os->os_flags |= OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
23252338
if (dmu_objset_projectquota_enabled(os))
23262339
os->os_flags |= OBJSET_FLAG_PROJECTQUOTA_COMPLETE;
23272340

module/zfs/zfs_ioctl.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5762,7 +5762,6 @@ zfs_ioc_userspace_many(zfs_cmd_t *zc)
57625762
static int
57635763
zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
57645764
{
5765-
objset_t *os;
57665765
int error = 0;
57675766
zfsvfs_t *zfsvfs;
57685767

@@ -5783,19 +5782,54 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
57835782
error = zfs_resume_fs(zfsvfs, newds);
57845783
}
57855784
}
5786-
if (error == 0)
5787-
error = dmu_objset_userspace_upgrade(zfsvfs->z_os);
5785+
if (error == 0) {
5786+
mutex_enter(&zfsvfs->z_os->os_upgrade_lock);
5787+
if (zfsvfs->z_os->os_upgrade_id == 0) {
5788+
/* clear potential error code and retry */
5789+
zfsvfs->z_os->os_upgrade_status = 0;
5790+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
5791+
5792+
dsl_pool_config_enter(
5793+
dmu_objset_pool(zfsvfs->z_os), FTAG);
5794+
dmu_objset_userspace_upgrade(zfsvfs->z_os);
5795+
dsl_pool_config_exit(
5796+
dmu_objset_pool(zfsvfs->z_os), FTAG);
5797+
} else {
5798+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
5799+
}
5800+
5801+
taskq_wait_id(zfsvfs->z_os->os_spa->spa_upgrade_taskq,
5802+
zfsvfs->z_os->os_upgrade_id);
5803+
error = zfsvfs->z_os->os_upgrade_status;
5804+
}
57885805
zfs_vfs_rele(zfsvfs);
57895806
} else {
5807+
objset_t *os;
5808+
57905809
/* XXX kind of reading contents without owning */
57915810
error = dmu_objset_hold_flags(zc->zc_name, B_TRUE, FTAG, &os);
57925811
if (error != 0)
57935812
return (error);
57945813

5795-
error = dmu_objset_userspace_upgrade(os);
5796-
dmu_objset_rele_flags(os, B_TRUE, FTAG);
5797-
}
5814+
mutex_enter(&os->os_upgrade_lock);
5815+
if (os->os_upgrade_id == 0) {
5816+
/* clear potential error code and retry */
5817+
os->os_upgrade_status = 0;
5818+
mutex_exit(&os->os_upgrade_lock);
5819+
5820+
dmu_objset_userspace_upgrade(os);
5821+
} else {
5822+
mutex_exit(&os->os_upgrade_lock);
5823+
}
57985824

5825+
dsl_pool_rele(dmu_objset_pool(os), FTAG);
5826+
5827+
taskq_wait_id(os->os_spa->spa_upgrade_taskq, os->os_upgrade_id);
5828+
error = os->os_upgrade_status;
5829+
5830+
dsl_dataset_rele_flags(dmu_objset_ds(os), DS_HOLD_FLAG_DECRYPT,
5831+
FTAG);
5832+
}
57995833
return (error);
58005834
}
58015835

tests/runfiles/common.run

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ tests = [
857857
'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos',
858858
'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos',
859859
'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg',
860-
'userspace_001_pos', 'userspace_002_pos']
860+
'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted']
861861
tags = ['functional', 'userquota']
862862

863863
[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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
log_onexit cleanup
38+
39+
FILEDEV="$TEST_BASE_DIR/userspace_encrypted"
40+
POOLNAME="testpool$$"
41+
typeset -a POOL_OPTS=('' # all pool features enabled
42+
'-d' # all pool features disabled
43+
'-d -o feature@userobj_accounting=enabled' # only userobj_accounting enabled
44+
'-d -o feature@project_quota=enabled') # only project_quota enabled
45+
DATASET_ENCROOT="$POOLNAME/encroot"
46+
DATASET_SENDFS="$POOLNAME/sendfs"
47+
48+
log_assert "'zfs user/groupspace' should work on encrypted datasets"
49+
50+
for opts in "${POOL_OPTS[@]}"; do
51+
# Setup
52+
truncate -s $SPA_MINDEVSIZE $FILEDEV
53+
log_must zpool create $opts -o feature@encryption=enabled $POOLNAME \
54+
$FILEDEV
55+
56+
# 1. Create both un-encrypted and encrypted datasets
57+
log_must zfs create $DATASET_SENDFS
58+
log_must eval "echo 'password' | zfs create -o encryption=on" \
59+
"-o keyformat=passphrase -o keylocation=prompt " \
60+
"$DATASET_ENCROOT"
61+
log_must zfs create $DATASET_ENCROOT/fs
62+
63+
# 2. Receive un-encrypted dataset in encrypted hierarchy
64+
log_must zfs snap $DATASET_SENDFS@snap
65+
log_must eval "zfs send $DATASET_SENDFS@snap | zfs recv " \
66+
"$DATASET_ENCROOT/recvfs"
67+
68+
# 3. Verify encrypted datasets support 'zfs userspace' and 'zfs groupspace'
69+
log_must eval "zfs userspace $DATASET_ENCROOT/fs > /dev/null"
70+
log_must eval "zfs groupspace $DATASET_ENCROOT/fs > /dev/null"
71+
log_must_retry "unsupported" 3 \
72+
eval "zfs userspace $DATASET_ENCROOT/recvfs > /dev/null"
73+
log_must_retry "unsupported" 3 \
74+
eval "zfs groupspace $DATASET_ENCROOT/recvfs > /dev/null"
75+
76+
# Cleanup
77+
cleanup
78+
done
79+
80+
log_pass "'zfs user/groupspace' works on encrypted datasets"

0 commit comments

Comments
 (0)