MFV r268455:
Use reserved space for ZFS administrative commands. We reserve 1/2^spa_slop_shift = 1/32 or 3.125% of pool space (or 32MB at least) for system use. Most ZPL operations, e.g. write(2), creat(2), will fail with ENOSPC if we fall below this. Certain operations, e.g. file removal and most administrative actions, still permitted until half of the slop space is used. This would allow users to use these operations to free up space in the pool when pool is close to full but half of slop space is still free. A very restricted set of operations that frees up space or change quota are always permitted, regardless of the amount of free space. MFC after: 2 weeks
This commit is contained in:
commit
1b174fa1eb
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright 2012 Milan Jurik. All rights reserved.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
@ -6856,6 +6856,9 @@ zfs_do_bookmark(int argc, char **argv)
|
||||
case ENOTSUP:
|
||||
err_msg = "bookmark feature not enabled";
|
||||
break;
|
||||
case ENOSPC:
|
||||
err_msg = "out of space";
|
||||
break;
|
||||
default:
|
||||
err_msg = "unknown error";
|
||||
break;
|
||||
@ -6864,7 +6867,7 @@ zfs_do_bookmark(int argc, char **argv)
|
||||
dgettext(TEXT_DOMAIN, err_msg));
|
||||
}
|
||||
|
||||
return (ret);
|
||||
return (ret != 0);
|
||||
|
||||
usage:
|
||||
usage(B_FALSE);
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -362,7 +362,7 @@ zhack_do_feature_enable(int argc, char **argv)
|
||||
feature.fi_guid);
|
||||
|
||||
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
|
||||
zhack_feature_enable_sync, &feature, 5));
|
||||
zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
|
||||
|
||||
spa_close(spa, FTAG);
|
||||
|
||||
@ -473,7 +473,8 @@ zhack_do_feature_ref(int argc, char **argv)
|
||||
}
|
||||
|
||||
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
|
||||
decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
|
||||
decr ? feature_decr_sync : feature_incr_sync, &feature,
|
||||
5, ZFS_SPACE_CHECK_NORMAL));
|
||||
|
||||
spa_close(spa, FTAG);
|
||||
}
|
||||
|
@ -832,7 +832,8 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
|
||||
doca.doca_type = type;
|
||||
|
||||
return (dsl_sync_task(name,
|
||||
dmu_objset_create_check, dmu_objset_create_sync, &doca, 5));
|
||||
dmu_objset_create_check, dmu_objset_create_sync, &doca,
|
||||
5, ZFS_SPACE_CHECK_NORMAL));
|
||||
}
|
||||
|
||||
typedef struct dmu_objset_clone_arg {
|
||||
@ -931,7 +932,8 @@ dmu_objset_clone(const char *clone, const char *origin)
|
||||
doca.doca_cred = CRED();
|
||||
|
||||
return (dsl_sync_task(clone,
|
||||
dmu_objset_clone_check, dmu_objset_clone_sync, &doca, 5));
|
||||
dmu_objset_clone_check, dmu_objset_clone_sync, &doca,
|
||||
5, ZFS_SPACE_CHECK_NORMAL));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1196,7 +1196,7 @@ dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
|
||||
drba.drba_cred = CRED();
|
||||
|
||||
return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync,
|
||||
&drba, 5));
|
||||
&drba, 5, ZFS_SPACE_CHECK_NORMAL));
|
||||
}
|
||||
|
||||
struct restorearg {
|
||||
@ -2081,7 +2081,7 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc)
|
||||
|
||||
error = dsl_sync_task(drc->drc_tofs,
|
||||
dmu_recv_end_check, dmu_recv_end_sync, drc,
|
||||
dmu_recv_end_modified_blocks);
|
||||
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
|
||||
|
||||
if (error != 0)
|
||||
dmu_recv_cleanup_ds(drc);
|
||||
@ -2095,7 +2095,7 @@ dmu_recv_new_end(dmu_recv_cookie_t *drc)
|
||||
|
||||
error = dsl_sync_task(drc->drc_tofs,
|
||||
dmu_recv_end_check, dmu_recv_end_sync, drc,
|
||||
dmu_recv_end_modified_blocks);
|
||||
dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
|
||||
|
||||
if (error != 0) {
|
||||
dmu_recv_cleanup_ds(drc);
|
||||
|
@ -13,7 +13,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@ -246,7 +246,8 @@ dsl_bookmark_create(nvlist_t *bmarks, nvlist_t *errors)
|
||||
dbca.dbca_errors = errors;
|
||||
|
||||
return (dsl_sync_task(nvpair_name(pair), dsl_bookmark_create_check,
|
||||
dsl_bookmark_create_sync, &dbca, fnvlist_num_pairs(bmarks)));
|
||||
dsl_bookmark_create_sync, &dbca,
|
||||
fnvlist_num_pairs(bmarks), ZFS_SPACE_CHECK_NORMAL));
|
||||
}
|
||||
|
||||
int
|
||||
@ -448,7 +449,8 @@ dsl_bookmark_destroy(nvlist_t *bmarks, nvlist_t *errors)
|
||||
dbda.dbda_success = fnvlist_alloc();
|
||||
|
||||
rv = dsl_sync_task(nvpair_name(pair), dsl_bookmark_destroy_check,
|
||||
dsl_bookmark_destroy_sync, &dbda, fnvlist_num_pairs(bmarks));
|
||||
dsl_bookmark_destroy_sync, &dbda, fnvlist_num_pairs(bmarks),
|
||||
ZFS_SPACE_CHECK_RESERVED);
|
||||
fnvlist_free(dbda.dbda_success);
|
||||
return (rv);
|
||||
}
|
||||
|
@ -1401,7 +1401,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
|
||||
if (error == 0) {
|
||||
error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
|
||||
dsl_dataset_snapshot_sync, &ddsa,
|
||||
fnvlist_num_pairs(snaps) * 3);
|
||||
fnvlist_num_pairs(snaps) * 3, ZFS_SPACE_CHECK_NORMAL);
|
||||
}
|
||||
|
||||
if (suspended != NULL) {
|
||||
@ -1514,7 +1514,7 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
|
||||
}
|
||||
|
||||
error = dsl_sync_task(fsname, dsl_dataset_snapshot_tmp_check,
|
||||
dsl_dataset_snapshot_tmp_sync, &ddsta, 3);
|
||||
dsl_dataset_snapshot_tmp_sync, &ddsta, 3, ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
if (needsuspend)
|
||||
zil_resume(cookie);
|
||||
@ -1885,7 +1885,8 @@ dsl_dataset_rename_snapshot(const char *fsname,
|
||||
ddrsa.ddrsa_recursive = recursive;
|
||||
|
||||
return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
|
||||
dsl_dataset_rename_snapshot_sync, &ddrsa, 1));
|
||||
dsl_dataset_rename_snapshot_sync, &ddrsa,
|
||||
1, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2060,7 +2061,8 @@ dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result)
|
||||
ddra.ddra_result = result;
|
||||
|
||||
return (dsl_sync_task(fsname, dsl_dataset_rollback_check,
|
||||
dsl_dataset_rollback_sync, &ddra, 1));
|
||||
dsl_dataset_rollback_sync, &ddra,
|
||||
1, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
struct promotenode {
|
||||
@ -2581,7 +2583,8 @@ dsl_dataset_promote(const char *name, char *conflsnap)
|
||||
ddpa.cr = CRED();
|
||||
|
||||
return (dsl_sync_task(name, dsl_dataset_promote_check,
|
||||
dsl_dataset_promote_sync, &ddpa, 2 + numsnaps));
|
||||
dsl_dataset_promote_sync, &ddpa,
|
||||
2 + numsnaps, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
int
|
||||
@ -2926,7 +2929,7 @@ dsl_dataset_set_refquota(const char *dsname, zprop_source_t source,
|
||||
ddsqra.ddsqra_value = refquota;
|
||||
|
||||
return (dsl_sync_task(dsname, dsl_dataset_set_refquota_check,
|
||||
dsl_dataset_set_refquota_sync, &ddsqra, 0));
|
||||
dsl_dataset_set_refquota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -3041,7 +3044,8 @@ dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source,
|
||||
ddsqra.ddsqra_value = refreservation;
|
||||
|
||||
return (dsl_sync_task(dsname, dsl_dataset_set_refreservation_check,
|
||||
dsl_dataset_set_refreservation_sync, &ddsqra, 0));
|
||||
dsl_dataset_set_refreservation_sync, &ddsqra,
|
||||
0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -282,7 +282,7 @@ dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
|
||||
|
||||
return (dsl_sync_task(ddname, dsl_deleg_check,
|
||||
unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
|
||||
&dda, fnvlist_num_pairs(nvp)));
|
||||
&dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -506,7 +506,7 @@ dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer,
|
||||
|
||||
error = dsl_sync_task(nvpair_name(pair),
|
||||
dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync,
|
||||
&dsda, 0);
|
||||
&dsda, 0, ZFS_SPACE_CHECK_NONE);
|
||||
fnvlist_free(dsda.dsda_successful_snaps);
|
||||
|
||||
return (error);
|
||||
@ -899,7 +899,8 @@ dsl_destroy_head(const char *name)
|
||||
objset_t *os;
|
||||
|
||||
error = dsl_sync_task(name, dsl_destroy_head_check,
|
||||
dsl_destroy_head_begin_sync, &ddha, 0);
|
||||
dsl_destroy_head_begin_sync, &ddha,
|
||||
0, ZFS_SPACE_CHECK_NONE);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
@ -923,7 +924,7 @@ dsl_destroy_head(const char *name)
|
||||
}
|
||||
|
||||
return (dsl_sync_task(name, dsl_destroy_head_check,
|
||||
dsl_destroy_head_sync, &ddha, 0));
|
||||
dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -22,7 +22,7 @@
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014 Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -642,7 +642,8 @@ dsl_dir_activate_fs_ss_limit(const char *ddname)
|
||||
int error;
|
||||
|
||||
error = dsl_sync_task(ddname, dsl_dir_actv_fs_ss_limit_check,
|
||||
dsl_dir_actv_fs_ss_limit_sync, (void *)ddname, 0);
|
||||
dsl_dir_actv_fs_ss_limit_sync, (void *)ddname, 0,
|
||||
ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
if (error == EALREADY)
|
||||
error = 0;
|
||||
@ -1496,7 +1497,7 @@ dsl_dir_set_quota(const char *ddname, zprop_source_t source, uint64_t quota)
|
||||
ddsqra.ddsqra_value = quota;
|
||||
|
||||
return (dsl_sync_task(ddname, dsl_dir_set_quota_check,
|
||||
dsl_dir_set_quota_sync, &ddsqra, 0));
|
||||
dsl_dir_set_quota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
||||
int
|
||||
@ -1617,7 +1618,7 @@ dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
|
||||
ddsqra.ddsqra_value = reservation;
|
||||
|
||||
return (dsl_sync_task(ddname, dsl_dir_set_reservation_check,
|
||||
dsl_dir_set_reservation_sync, &ddsqra, 0));
|
||||
dsl_dir_set_reservation_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
||||
static dsl_dir_t *
|
||||
@ -1899,7 +1900,8 @@ dsl_dir_rename(const char *oldname, const char *newname)
|
||||
ddra.ddra_cred = CRED();
|
||||
|
||||
return (dsl_sync_task(oldname,
|
||||
dsl_dir_rename_check, dsl_dir_rename_sync, &ddra, 3));
|
||||
dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
|
||||
3, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -691,17 +691,12 @@ dsl_pool_adjustedsize(dsl_pool_t *dp, boolean_t netfree)
|
||||
uint64_t space, resv;
|
||||
|
||||
/*
|
||||
* Reserve about 1.6% (1/64), or at least 32MB, for allocation
|
||||
* efficiency.
|
||||
* XXX The intent log is not accounted for, so it must fit
|
||||
* within this slop.
|
||||
*
|
||||
* If we're trying to assess whether it's OK to do a free,
|
||||
* cut the reservation in half to allow forward progress
|
||||
* (e.g. make it possible to rm(1) files from a full pool).
|
||||
*/
|
||||
space = spa_get_dspace(dp->dp_spa);
|
||||
resv = MAX(space >> 6, SPA_MINDEVSIZE >> 1);
|
||||
resv = spa_get_slop_space(dp->dp_spa);
|
||||
if (netfree)
|
||||
resv >>= 1;
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@ -834,7 +834,7 @@ dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
|
||||
nblks = 2 * fnvlist_num_pairs(props);
|
||||
|
||||
return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
|
||||
&dpsa, nblks));
|
||||
&dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
typedef enum dsl_prop_getflags {
|
||||
|
@ -367,7 +367,7 @@ int
|
||||
dsl_scan_cancel(dsl_pool_t *dp)
|
||||
{
|
||||
return (dsl_sync_task(spa_name(dp->dp_spa), dsl_scan_cancel_check,
|
||||
dsl_scan_cancel_sync, NULL, 3));
|
||||
dsl_scan_cancel_sync, NULL, 3, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
static void dsl_scan_visitbp(blkptr_t *bp,
|
||||
@ -1807,5 +1807,5 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func)
|
||||
(void) spa_vdev_state_exit(spa, NULL, 0);
|
||||
|
||||
return (dsl_sync_task(spa_name(spa), dsl_scan_setup_check,
|
||||
dsl_scan_setup_sync, &func, 0));
|
||||
dsl_scan_setup_sync, &func, 0, ZFS_SPACE_CHECK_NONE));
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/dmu.h>
|
||||
@ -64,7 +64,8 @@ dsl_null_checkfunc(void *arg, dmu_tx_t *tx)
|
||||
*/
|
||||
int
|
||||
dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
|
||||
dsl_syncfunc_t *syncfunc, void *arg, int blocks_modified)
|
||||
dsl_syncfunc_t *syncfunc, void *arg,
|
||||
int blocks_modified, zfs_space_check_t space_check)
|
||||
{
|
||||
spa_t *spa;
|
||||
dmu_tx_t *tx;
|
||||
@ -84,6 +85,7 @@ dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
|
||||
dst.dst_pool = dp;
|
||||
dst.dst_txg = dmu_tx_get_txg(tx);
|
||||
dst.dst_space = blocks_modified << DST_AVG_BLKSHIFT;
|
||||
dst.dst_space_check = space_check;
|
||||
dst.dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc;
|
||||
dst.dst_syncfunc = syncfunc;
|
||||
dst.dst_arg = arg;
|
||||
@ -117,13 +119,14 @@ dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
|
||||
|
||||
void
|
||||
dsl_sync_task_nowait(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg,
|
||||
int blocks_modified, dmu_tx_t *tx)
|
||||
int blocks_modified, zfs_space_check_t space_check, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_sync_task_t *dst = kmem_zalloc(sizeof (*dst), KM_SLEEP);
|
||||
|
||||
dst->dst_pool = dp;
|
||||
dst->dst_txg = dmu_tx_get_txg(tx);
|
||||
dst->dst_space = blocks_modified << DST_AVG_BLKSHIFT;
|
||||
dst->dst_space_check = space_check;
|
||||
dst->dst_checkfunc = dsl_null_checkfunc;
|
||||
dst->dst_syncfunc = syncfunc;
|
||||
dst->dst_arg = arg;
|
||||
@ -140,25 +143,34 @@ void
|
||||
dsl_sync_task_sync(dsl_sync_task_t *dst, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_pool_t *dp = dst->dst_pool;
|
||||
uint64_t quota, used;
|
||||
|
||||
ASSERT0(dst->dst_error);
|
||||
|
||||
/*
|
||||
* Check for sufficient space. We just check against what's
|
||||
* on-disk; we don't want any in-flight accounting to get in our
|
||||
* way, because open context may have already used up various
|
||||
* in-core limits (arc_tempreserve, dsl_pool_tempreserve).
|
||||
* Check for sufficient space.
|
||||
*
|
||||
* When the sync task was created, the caller specified the
|
||||
* type of space checking required. See the comment in
|
||||
* zfs_space_check_t for details on the semantics of each
|
||||
* type of space checking.
|
||||
*
|
||||
* We just check against what's on-disk; we don't want any
|
||||
* in-flight accounting to get in our way, because open context
|
||||
* may have already used up various in-core limits
|
||||
* (arc_tempreserve, dsl_pool_tempreserve).
|
||||
*/
|
||||
quota = dsl_pool_adjustedsize(dp, B_FALSE) -
|
||||
metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
|
||||
used = dp->dp_root_dir->dd_phys->dd_used_bytes;
|
||||
/* MOS space is triple-dittoed, so we multiply by 3. */
|
||||
if (dst->dst_space > 0 && used + dst->dst_space * 3 > quota) {
|
||||
dst->dst_error = SET_ERROR(ENOSPC);
|
||||
if (dst->dst_nowaiter)
|
||||
kmem_free(dst, sizeof (*dst));
|
||||
return;
|
||||
if (dst->dst_space_check != ZFS_SPACE_CHECK_NONE) {
|
||||
uint64_t quota = dsl_pool_adjustedsize(dp,
|
||||
dst->dst_space_check == ZFS_SPACE_CHECK_RESERVED) -
|
||||
metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
|
||||
uint64_t used = dp->dp_root_dir->dd_phys->dd_used_bytes;
|
||||
/* MOS space is triple-dittoed, so we multiply by 3. */
|
||||
if (dst->dst_space > 0 && used + dst->dst_space * 3 > quota) {
|
||||
dst->dst_error = SET_ERROR(ENOSPC);
|
||||
if (dst->dst_nowaiter)
|
||||
kmem_free(dst, sizeof (*dst));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -317,7 +317,8 @@ dsl_dataset_user_hold(nvlist_t *holds, minor_t cleanup_minor, nvlist_t *errlist)
|
||||
dduha.dduha_minor = cleanup_minor;
|
||||
|
||||
ret = dsl_sync_task(nvpair_name(pair), dsl_dataset_user_hold_check,
|
||||
dsl_dataset_user_hold_sync, &dduha, fnvlist_num_pairs(holds));
|
||||
dsl_dataset_user_hold_sync, &dduha,
|
||||
fnvlist_num_pairs(holds), ZFS_SPACE_CHECK_RESERVED);
|
||||
fnvlist_free(dduha.dduha_chkholds);
|
||||
|
||||
return (ret);
|
||||
@ -600,7 +601,7 @@ dsl_dataset_user_release_impl(nvlist_t *holds, nvlist_t *errlist,
|
||||
ddura.ddura_chkholds = fnvlist_alloc();
|
||||
|
||||
error = dsl_sync_task(pool, dsl_dataset_user_release_check,
|
||||
dsl_dataset_user_release_sync, &ddura, 0);
|
||||
dsl_dataset_user_release_sync, &ddura, 0, ZFS_SPACE_CHECK_NONE);
|
||||
fnvlist_free(ddura.ddura_todelete);
|
||||
fnvlist_free(ddura.ddura_chkholds);
|
||||
|
||||
|
@ -689,7 +689,8 @@ spa_prop_set(spa_t *spa, nvlist_t *nvp)
|
||||
* feature descriptions object.
|
||||
*/
|
||||
error = dsl_sync_task(spa->spa_name, NULL,
|
||||
spa_sync_version, &ver, 6);
|
||||
spa_sync_version, &ver,
|
||||
6, ZFS_SPACE_CHECK_RESERVED);
|
||||
if (error)
|
||||
return (error);
|
||||
continue;
|
||||
@ -701,7 +702,7 @@ spa_prop_set(spa_t *spa, nvlist_t *nvp)
|
||||
|
||||
if (need_sync) {
|
||||
return (dsl_sync_task(spa->spa_name, NULL, spa_sync_props,
|
||||
nvp, 6));
|
||||
nvp, 6, ZFS_SPACE_CHECK_RESERVED));
|
||||
}
|
||||
|
||||
return (0);
|
||||
@ -782,7 +783,7 @@ spa_change_guid(spa_t *spa)
|
||||
guid = spa_generate_guid(NULL);
|
||||
|
||||
error = dsl_sync_task(spa->spa_name, spa_change_guid_check,
|
||||
spa_change_guid_sync, &guid, 5);
|
||||
spa_change_guid_sync, &guid, 5, ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
if (error == 0) {
|
||||
spa_config_sync(spa, B_FALSE, B_TRUE);
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/spa.h>
|
||||
@ -324,7 +324,7 @@ spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
|
||||
|
||||
/* Kick this off asynchronously; errors are ignored. */
|
||||
dsl_sync_task_nowait(spa_get_dsl(spa), spa_history_log_sync,
|
||||
nvarg, 0, tx);
|
||||
nvarg, 0, ZFS_SPACE_CHECK_NONE, tx);
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
/* spa_history_log_sync will free nvl */
|
||||
@ -465,7 +465,7 @@ log_internal(nvlist_t *nvl, const char *operation, spa_t *spa,
|
||||
spa_history_log_sync(nvl, tx);
|
||||
} else {
|
||||
dsl_sync_task_nowait(spa_get_dsl(spa),
|
||||
spa_history_log_sync, nvl, 0, tx);
|
||||
spa_history_log_sync, nvl, 0, ZFS_SPACE_CHECK_NONE, tx);
|
||||
}
|
||||
/* spa_history_log_sync() will free nvl */
|
||||
}
|
||||
|
@ -353,6 +353,32 @@ zfs_deadman_init()
|
||||
#endif /* _KERNEL */
|
||||
#endif /* !illumos */
|
||||
|
||||
/*
|
||||
* Normally, we don't allow the last 3.2% (1/(2^spa_slop_shift)) of space in
|
||||
* the pool to be consumed. This ensures that we don't run the pool
|
||||
* completely out of space, due to unaccounted changes (e.g. to the MOS).
|
||||
* It also limits the worst-case time to allocate space. If we have
|
||||
* less than this amount of free space, most ZPL operations (e.g. write,
|
||||
* create) will return ENOSPC.
|
||||
*
|
||||
* Certain operations (e.g. file removal, most administrative actions) can
|
||||
* use half the slop space. They will only return ENOSPC if less than half
|
||||
* the slop space is free. Typically, once the pool has less than the slop
|
||||
* space free, the user will use these operations to free up space in the pool.
|
||||
* These are the operations that call dsl_pool_adjustedsize() with the netfree
|
||||
* argument set to TRUE.
|
||||
*
|
||||
* A very restricted set of operations are always permitted, regardless of
|
||||
* the amount of free space. These are the operations that call
|
||||
* dsl_sync_task(ZFS_SPACE_CHECK_NONE), e.g. "zfs destroy". If these
|
||||
* operations result in a net increase in the amount of space used,
|
||||
* it is possible to run the pool completely out of space, causing it to
|
||||
* be permanently read-only.
|
||||
*
|
||||
* See also the comments in zfs_space_check_t.
|
||||
*/
|
||||
int spa_slop_shift = 5;
|
||||
|
||||
/*
|
||||
* ==========================================================================
|
||||
* SPA config locking
|
||||
@ -1622,6 +1648,18 @@ spa_get_asize(spa_t *spa, uint64_t lsize)
|
||||
return (lsize * spa_asize_inflation);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the amount of slop space in bytes. It is 1/32 of the pool (3.2%),
|
||||
* or at least 32MB.
|
||||
*
|
||||
* See the comment above spa_slop_shift for details.
|
||||
*/
|
||||
uint64_t
|
||||
spa_get_slop_space(spa_t *spa) {
|
||||
uint64_t space = spa_get_dspace(spa);
|
||||
return (MAX(space >> spa_slop_shift, SPA_MINDEVSIZE >> 1));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
spa_get_dspace(spa_t *spa)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_DSL_SYNCTASK_H
|
||||
@ -38,11 +38,41 @@ struct dsl_pool;
|
||||
typedef int (dsl_checkfunc_t)(void *, dmu_tx_t *);
|
||||
typedef void (dsl_syncfunc_t)(void *, dmu_tx_t *);
|
||||
|
||||
typedef enum zfs_space_check {
|
||||
/*
|
||||
* Normal space check: if there is less than 3.2% free space,
|
||||
* the operation will fail. Operations which are logically
|
||||
* creating things should use this (e.g. "zfs create", "zfs snapshot").
|
||||
* User writes (via the ZPL / ZVOL) also fail at this point.
|
||||
*/
|
||||
ZFS_SPACE_CHECK_NORMAL,
|
||||
|
||||
/*
|
||||
* Space check allows use of half the slop space. If there
|
||||
* is less than 1.6% free space, the operation will fail. Most
|
||||
* operations should use this (e.g. "zfs set", "zfs rename"),
|
||||
* because we want them to succeed even after user writes are failing,
|
||||
* so that they can be used as part of the space recovery process.
|
||||
*/
|
||||
ZFS_SPACE_CHECK_RESERVED,
|
||||
|
||||
/*
|
||||
* No space check is performed. Only operations which we expect to
|
||||
* result in a net reduction in space should use this
|
||||
* (e.g. "zfs destroy". Setting quotas & reservations also uses
|
||||
* this because it needs to circumvent the quota/reservation checks).
|
||||
*
|
||||
* See also the comments above spa_slop_shift.
|
||||
*/
|
||||
ZFS_SPACE_CHECK_NONE,
|
||||
} zfs_space_check_t;
|
||||
|
||||
typedef struct dsl_sync_task {
|
||||
txg_node_t dst_node;
|
||||
struct dsl_pool *dst_pool;
|
||||
uint64_t dst_txg;
|
||||
int dst_space;
|
||||
zfs_space_check_t dst_space_check;
|
||||
dsl_checkfunc_t *dst_checkfunc;
|
||||
dsl_syncfunc_t *dst_syncfunc;
|
||||
void *dst_arg;
|
||||
@ -50,11 +80,11 @@ typedef struct dsl_sync_task {
|
||||
boolean_t dst_nowaiter;
|
||||
} dsl_sync_task_t;
|
||||
|
||||
void dsl_sync_task_sync(dsl_sync_task_t *dst, dmu_tx_t *tx);
|
||||
int dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
|
||||
dsl_syncfunc_t *syncfunc, void *arg, int blocks_modified);
|
||||
void dsl_sync_task_nowait(struct dsl_pool *dp, dsl_syncfunc_t *syncfunc,
|
||||
void *arg, int blocks_modified, dmu_tx_t *tx);
|
||||
void dsl_sync_task_sync(dsl_sync_task_t *, dmu_tx_t *);
|
||||
int dsl_sync_task(const char *, dsl_checkfunc_t *,
|
||||
dsl_syncfunc_t *, void *, int, zfs_space_check_t);
|
||||
void dsl_sync_task_nowait(struct dsl_pool *, dsl_syncfunc_t *,
|
||||
void *, int, zfs_space_check_t, dmu_tx_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -759,6 +759,7 @@ extern spa_load_state_t spa_load_state(spa_t *spa);
|
||||
extern uint64_t spa_freeze_txg(spa_t *spa);
|
||||
extern uint64_t spa_get_asize(spa_t *spa, uint64_t lsize);
|
||||
extern uint64_t spa_get_dspace(spa_t *spa);
|
||||
extern uint64_t spa_get_slop_space(spa_t *spa);
|
||||
extern void spa_update_dspace(spa_t *spa);
|
||||
extern uint64_t spa_version(spa_t *spa);
|
||||
extern boolean_t spa_deflate(spa_t *spa);
|
||||
|
@ -27,7 +27,7 @@
|
||||
* Copyright 2014 Xin Li <delphij@FreeBSD.org>. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
|
||||
@ -3957,7 +3957,7 @@ zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature)
|
||||
/* EBUSY here indicates that the feature is already active */
|
||||
err = dsl_sync_task(spa_name(spa),
|
||||
zfs_prop_activate_feature_check, zfs_prop_activate_feature_sync,
|
||||
&feature, 2);
|
||||
&feature, 2, ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
if (err != 0 && err != EBUSY)
|
||||
return (err);
|
||||
|
@ -2113,7 +2113,8 @@ zvol_dump_init(zvol_state_t *zv, boolean_t resize)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
(void) dsl_sync_task(spa_name(spa),
|
||||
zfs_mvdev_dump_feature_check,
|
||||
zfs_mvdev_dump_activate_feature_sync, NULL, 2);
|
||||
zfs_mvdev_dump_activate_feature_sync, NULL,
|
||||
2, ZFS_SPACE_CHECK_RESERVED);
|
||||
}
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
Loading…
Reference in New Issue
Block a user