Skip to content

Commit 6c302ac

Browse files
Re-initialize objsets when feature@project_quota is enabled
Addresses the issue of project quotas not being usable after pool upgrade coming from an older version which does not support project quotas to the one that does, similarly to how it was solved for user quotas back in the day with `zfs set version=current` -- when feature@project_quota is first enabled, re-initialize the pool's objsets. Signed-off-by: Dušan Gvozdenović <dusan.gvozdenovic.99@gmail.com> Closes #17955
1 parent 7f7d493 commit 6c302ac

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

include/sys/dmu_objset.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ boolean_t dmu_objset_projectquota_enabled(objset_t *os);
261261
boolean_t dmu_objset_projectquota_present(objset_t *os);
262262
boolean_t dmu_objset_projectquota_upgradable(objset_t *os);
263263
void dmu_objset_id_quota_upgrade(objset_t *os);
264+
void dmu_objset_id_projectquota_upgrade(objset_t *os);
264265
int dmu_get_file_info(objset_t *os, dmu_object_type_t bonustype,
265266
const void *data, zfs_file_info_t *zfi);
266267

module/zfs/dmu_objset.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,30 @@ dmu_objset_id_quota_upgrade(objset_t *os)
24392439
dmu_objset_upgrade(os, dmu_objset_id_quota_upgrade_cb);
24402440
}
24412441

2442+
static int
2443+
dmu_objset_id_projectquota_upgrade_cb(objset_t *os)
2444+
{
2445+
if (dmu_objset_projectquota_present(os))
2446+
return (0);
2447+
if (!dmu_objset_projectquota_enabled(os))
2448+
return (SET_ERROR(ENOTSUP));
2449+
2450+
dmu_objset_ds(os)->ds_feature_activation[
2451+
SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE;
2452+
2453+
if (dmu_objset_projectquota_enabled(os))
2454+
os->os_flags |= OBJSET_FLAG_PROJECTQUOTA_COMPLETE;
2455+
2456+
txg_wait_synced(dmu_objset_pool(os), 0);
2457+
return (0);
2458+
}
2459+
2460+
void
2461+
dmu_objset_id_projectquota_upgrade(objset_t *os)
2462+
{
2463+
dmu_objset_upgrade(os, dmu_objset_id_projectquota_upgrade_cb);
2464+
}
2465+
24422466
boolean_t
24432467
dmu_objset_userobjspace_upgradable(objset_t *os)
24442468
{

module/zfs/zfs_ioctl.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,6 +3104,67 @@ zfs_ioc_inherit_prop(zfs_cmd_t *zc)
31043104
return (err);
31053105
}
31063106

3107+
static int
3108+
zfs_projectquota_upgrade_cb(const char *dataset, void *arg)
3109+
{
3110+
zfsvfs_t *zfsvfs;
3111+
int error;
3112+
3113+
(void) arg;
3114+
3115+
error = getzfsvfs(dataset, &zfsvfs);
3116+
3117+
if (error != 0)
3118+
return (0);
3119+
3120+
if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) {
3121+
/*
3122+
* If projectquota is not enabled, it may be because the objset
3123+
* needs to be closed & reopened (to grow the objset_phys_t).
3124+
* Suspend/resume the fs will do that.
3125+
*/
3126+
dsl_dataset_t *ds, *newds;
3127+
3128+
ds = dmu_objset_ds(zfsvfs->z_os);
3129+
error = zfs_suspend_fs(zfsvfs);
3130+
if (error == 0) {
3131+
dmu_objset_refresh_ownership(ds, &newds,
3132+
B_TRUE, zfsvfs);
3133+
error = zfs_resume_fs(zfsvfs, newds);
3134+
}
3135+
}
3136+
3137+
if (error == 0) {
3138+
mutex_enter(&zfsvfs->z_os->os_upgrade_lock);
3139+
if (zfsvfs->z_os->os_upgrade_id == 0) {
3140+
/* clear potential error code and retry */
3141+
zfsvfs->z_os->os_upgrade_status = 0;
3142+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
3143+
3144+
dsl_pool_config_enter(
3145+
dmu_objset_pool(zfsvfs->z_os), FTAG);
3146+
dmu_objset_id_projectquota_upgrade(zfsvfs->z_os);
3147+
dsl_pool_config_exit(
3148+
dmu_objset_pool(zfsvfs->z_os), FTAG);
3149+
} else {
3150+
mutex_exit(&zfsvfs->z_os->os_upgrade_lock);
3151+
}
3152+
3153+
taskq_wait_id(zfsvfs->z_os->os_spa->spa_upgrade_taskq,
3154+
zfsvfs->z_os->os_upgrade_id);
3155+
error = zfsvfs->z_os->os_upgrade_status;
3156+
}
3157+
3158+
zfs_vfs_rele(zfsvfs);
3159+
3160+
if (error != 0)
3161+
cmn_err(CE_WARN,
3162+
"Failed to activate the project quota feature on dataset "
3163+
"%s (%d).", dataset, error);
3164+
3165+
return (0);
3166+
}
3167+
31073168
static int
31083169
zfs_ioc_pool_set_props(zfs_cmd_t *zc)
31093170
{
@@ -3143,6 +3204,16 @@ zfs_ioc_pool_set_props(zfs_cmd_t *zc)
31433204

31443205
error = spa_prop_set(spa, props);
31453206

3207+
/*
3208+
* If we are enabling the project quota feature, try to re-initialize
3209+
* the active file systems on that pool and activate the feature -- all
3210+
* in best effort.
3211+
*/
3212+
if ((error == 0) && nvlist_exists(props, "feature@project_quota"))
3213+
(void) dmu_objset_find(spa_name(spa),
3214+
zfs_projectquota_upgrade_cb,
3215+
NULL, DS_FIND_CHILDREN);
3216+
31463217
nvlist_free(props);
31473218
spa_close(spa, FTAG);
31483219

0 commit comments

Comments
 (0)