diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index 492be29200e4..ef186fd2d32f 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -261,6 +261,7 @@ boolean_t dmu_objset_projectquota_enabled(objset_t *os); boolean_t dmu_objset_projectquota_present(objset_t *os); boolean_t dmu_objset_projectquota_upgradable(objset_t *os); void dmu_objset_id_quota_upgrade(objset_t *os); +void dmu_objset_id_projectquota_upgrade(objset_t *os); int dmu_get_file_info(objset_t *os, dmu_object_type_t bonustype, const void *data, zfs_file_info_t *zfi); diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 8e6b569c2100..513d432eb1ac 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -2439,6 +2439,30 @@ dmu_objset_id_quota_upgrade(objset_t *os) dmu_objset_upgrade(os, dmu_objset_id_quota_upgrade_cb); } +static int +dmu_objset_id_projectquota_upgrade_cb(objset_t *os) +{ + if (dmu_objset_projectquota_present(os)) + return (0); + if (!dmu_objset_projectquota_enabled(os)) + return (SET_ERROR(ENOTSUP)); + + dmu_objset_ds(os)->ds_feature_activation[ + SPA_FEATURE_PROJECT_QUOTA] = (void *)B_TRUE; + + if (dmu_objset_projectquota_enabled(os)) + os->os_flags |= OBJSET_FLAG_PROJECTQUOTA_COMPLETE; + + txg_wait_synced(dmu_objset_pool(os), 0); + return (0); +} + +void +dmu_objset_id_projectquota_upgrade(objset_t *os) +{ + dmu_objset_upgrade(os, dmu_objset_id_projectquota_upgrade_cb); +} + boolean_t dmu_objset_userobjspace_upgradable(objset_t *os) { diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 1b2392aeaa85..2cfe4c24dc0b 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3104,6 +3104,67 @@ zfs_ioc_inherit_prop(zfs_cmd_t *zc) return (err); } +static int +zfs_projectquota_upgrade_cb(const char *dataset, void *arg) +{ + zfsvfs_t *zfsvfs; + int error; + + (void) arg; + + error = getzfsvfs(dataset, &zfsvfs); + + if (error != 0) + return (0); + + if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) { + /* + * If projectquota is not enabled, it may be because the objset + * needs to be closed & reopened (to grow the objset_phys_t). + * Suspend/resume the fs will do that. + */ + dsl_dataset_t *ds, *newds; + + ds = dmu_objset_ds(zfsvfs->z_os); + error = zfs_suspend_fs(zfsvfs); + if (error == 0) { + dmu_objset_refresh_ownership(ds, &newds, + B_TRUE, zfsvfs); + error = zfs_resume_fs(zfsvfs, newds); + } + } + + if (error == 0) { + mutex_enter(&zfsvfs->z_os->os_upgrade_lock); + if (zfsvfs->z_os->os_upgrade_id == 0) { + /* clear potential error code and retry */ + zfsvfs->z_os->os_upgrade_status = 0; + mutex_exit(&zfsvfs->z_os->os_upgrade_lock); + + dsl_pool_config_enter( + dmu_objset_pool(zfsvfs->z_os), FTAG); + dmu_objset_id_projectquota_upgrade(zfsvfs->z_os); + dsl_pool_config_exit( + dmu_objset_pool(zfsvfs->z_os), FTAG); + } else { + mutex_exit(&zfsvfs->z_os->os_upgrade_lock); + } + + taskq_wait_id(zfsvfs->z_os->os_spa->spa_upgrade_taskq, + zfsvfs->z_os->os_upgrade_id); + error = zfsvfs->z_os->os_upgrade_status; + } + + zfs_vfs_rele(zfsvfs); + + if (error != 0) + cmn_err(CE_WARN, + "Failed to activate the project quota feature on dataset " + "%s (%d).", dataset, error); + + return (0); +} + static int zfs_ioc_pool_set_props(zfs_cmd_t *zc) { @@ -3143,6 +3204,16 @@ zfs_ioc_pool_set_props(zfs_cmd_t *zc) error = spa_prop_set(spa, props); + /* + * If we are enabling the project quota feature, try to re-initialize + * the active file systems on that pool and activate the feature -- all + * in best effort. + */ + if ((error == 0) && nvlist_exists(props, "feature@project_quota")) + (void) dmu_objset_find(spa_name(spa), + zfs_projectquota_upgrade_cb, + NULL, DS_FIND_CHILDREN); + nvlist_free(props); spa_close(spa, FTAG);