diff options
author | Matthew Ahrens <mahrens@delphix.com> | 2014-07-08 20:49:56 -0800 |
---|---|---|
committer | Christopher Siden <chris@delphix.com> | 2014-07-08 21:49:57 -0700 |
commit | 7d46dc6ca63a6f3f0d51aa655bfcf10cf2405a9e (patch) | |
tree | ba560108487312f24294332156f10015c91b775d | |
parent | cd67d23d32df7b247d00e5b82257a2220b1e0c13 (diff) | |
download | illumos-joyent-7d46dc6ca63a6f3f0d51aa655bfcf10cf2405a9e.tar.gz |
4951 ZFS administrative commands should use reserved space, not fail with ENOSPC
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Approved by: Garrett D'Amore <garrett@damore.org>
26 files changed, 258 insertions, 76 deletions
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index f89e2d45e9..1c642b5e3d 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -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) 2013 Steven Hartland. All rights reserved. @@ -6708,6 +6708,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; @@ -6716,7 +6719,7 @@ zfs_do_bookmark(int argc, char **argv) dgettext(TEXT_DOMAIN, err_msg)); } - return (ret); + return (ret != 0); usage: usage(B_FALSE); diff --git a/usr/src/cmd/zhack/zhack.c b/usr/src/cmd/zhack/zhack.c index c0ed974363..ece1fc0322 100644 --- a/usr/src/cmd/zhack/zhack.c +++ b/usr/src/cmd/zhack/zhack.c @@ -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); } diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf index b371419902..3a97a72f1b 100644 --- a/usr/src/pkg/manifests/system-test-zfstest.mf +++ b/usr/src/pkg/manifests/system-test-zfstest.mf @@ -10,7 +10,7 @@ # # -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2012, 2014 by Delphix. All rights reserved. # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. # @@ -1817,6 +1817,7 @@ file path=opt/zfs-tests/tests/functional/nestedfs/setup mode=0555 file path=opt/zfs-tests/tests/functional/no_space/cleanup mode=0555 file path=opt/zfs-tests/tests/functional/no_space/enospc.cfg mode=0555 file path=opt/zfs-tests/tests/functional/no_space/enospc_001_pos mode=0555 +file path=opt/zfs-tests/tests/functional/no_space/enospc_002_pos mode=0555 file path=opt/zfs-tests/tests/functional/no_space/setup mode=0555 file path=opt/zfs-tests/tests/functional/nopwrite/cleanup mode=0555 file path=opt/zfs-tests/tests/functional/nopwrite/nopwrite.shlib mode=0555 diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run index b4e0f42bad..6ba4b94cea 100644 --- a/usr/src/test/zfs-tests/runfiles/delphix.run +++ b/usr/src/test/zfs-tests/runfiles/delphix.run @@ -10,7 +10,7 @@ # # -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2012, 2014 by Delphix. All rights reserved. # [DEFAULT] @@ -397,7 +397,7 @@ tests = ['mv_files_001_pos', 'mv_files_002_pos'] tests = ['nestedfs_001_pos'] [/opt/zfs-tests/tests/functional/no_space] -tests = ['enospc_001_pos'] +tests = ['enospc_001_pos', 'enospc_002_pos'] [/opt/zfs-tests/tests/functional/nopwrite] tests = ['nopwrite_copies', 'nopwrite_mtime', 'nopwrite_negative', diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run index b4e0f42bad..ba9438b811 100644 --- a/usr/src/test/zfs-tests/runfiles/omnios.run +++ b/usr/src/test/zfs-tests/runfiles/omnios.run @@ -397,7 +397,7 @@ tests = ['mv_files_001_pos', 'mv_files_002_pos'] tests = ['nestedfs_001_pos'] [/opt/zfs-tests/tests/functional/no_space] -tests = ['enospc_001_pos'] +tests = ['enospc_001_pos', 'enospc_002_pos'] [/opt/zfs-tests/tests/functional/nopwrite] tests = ['nopwrite_copies', 'nopwrite_mtime', 'nopwrite_negative', diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run index b4e0f42bad..ba9438b811 100644 --- a/usr/src/test/zfs-tests/runfiles/openindiana.run +++ b/usr/src/test/zfs-tests/runfiles/openindiana.run @@ -397,7 +397,7 @@ tests = ['mv_files_001_pos', 'mv_files_002_pos'] tests = ['nestedfs_001_pos'] [/opt/zfs-tests/tests/functional/no_space] -tests = ['enospc_001_pos'] +tests = ['enospc_001_pos', 'enospc_002_pos'] [/opt/zfs-tests/tests/functional/nopwrite] tests = ['nopwrite_copies', 'nopwrite_mtime', 'nopwrite_negative', diff --git a/usr/src/test/zfs-tests/tests/functional/no_space/Makefile b/usr/src/test/zfs-tests/tests/functional/no_space/Makefile index 4edd55ecea..4340e24bcf 100644 --- a/usr/src/test/zfs-tests/tests/functional/no_space/Makefile +++ b/usr/src/test/zfs-tests/tests/functional/no_space/Makefile @@ -10,7 +10,7 @@ # # -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2013, 2014 by Delphix. All rights reserved. # include $(SRC)/Makefile.master @@ -20,6 +20,7 @@ TESTDIR = $(ROOTOPTPKG)/tests/functional/no_space PROGS = cleanup \ enospc_001_pos \ + enospc_002_pos \ setup FILES = enospc.cfg diff --git a/usr/src/test/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh index 482172c444..7b20eb7c5e 100644 --- a/usr/src/test/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh @@ -25,7 +25,7 @@ # Use is subject to license terms. # # -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2013, 2014 by Delphix. All rights reserved. # . $STF_SUITE/include/libtest.shlib @@ -46,6 +46,14 @@ verify_runnable "both" +function cleanup +{ + rm -f $TESTDIR/$TESTFILE0 + rm -f $TESTDIR/$TESTFILE1 +} + +log_onexit cleanup + log_assert "ENOSPC is returned when file system is full." log_must $ZFS set compression=off $TESTPOOL/$TESTFS diff --git a/usr/src/test/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh b/usr/src/test/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh new file mode 100644 index 0000000000..25d88d7c5a --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh @@ -0,0 +1,74 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2014 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/no_space/enospc.cfg + +# +# DESCRIPTION: +# After filling a filesystem, certain zfs commands are allowed. +# + +verify_runnable "both" + +log_assert "ENOSPC is returned when file system is full." +sync +log_must $ZFS set compression=off $TESTPOOL/$TESTFS +log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap + +log_note "Writing file: $TESTFILE0 until ENOSPC." +$FILE_WRITE -o create -f $TESTDIR/$TESTFILE0 -b $BLOCKSZ \ + -c $NUM_WRITES -d $DATA +ret=$? + +(( $ret != $ENOSPC )) && \ + log_fail "$TESTFILE0 returned: $ret rather than ENOSPC." + +log_mustnot_expect space $ZFS create $TESTPOOL/$TESTFS/subfs +log_mustnot_expect space $ZFS clone $TESTPOOL/$TESTFS@snap $TESTPOOL/clone +log_mustnot_expect space $ZFS snapshot $TESTPOOL/$TESTFS@snap2 +log_mustnot_expect space $ZFS bookmark \ + $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS#bookmark + +log_must $ZFS send $TESTPOOL/$TESTFS@snap >/tmp/stream.$$ +log_mustnot_expect space $ZFS receive $TESTPOOL/$TESTFS/recvd </tmp/stream.$$ +log_must rm /tmp/stream.$$ + +log_must $ZFS rename $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS@snap_newname +log_must $ZFS rename $TESTPOOL/$TESTFS@snap_newname $TESTPOOL/$TESTFS@snap +log_must $ZFS rename $TESTPOOL/$TESTFS $TESTPOOL/${TESTFS}_newname +log_must $ZFS rename $TESTPOOL/${TESTFS}_newname $TESTPOOL/$TESTFS +log_must $ZFS allow staff snapshot $TESTPOOL/$TESTFS +log_must $ZFS unallow staff snapshot $TESTPOOL/$TESTFS +log_must $ZFS set user:prop=value $TESTPOOL/$TESTFS +log_must $ZFS set quota=1EB $TESTPOOL/$TESTFS +log_must $ZFS set quota=none $TESTPOOL/$TESTFS +log_must $ZFS set reservation=1KB $TESTPOOL/$TESTFS +log_must $ZFS set reservation=none $TESTPOOL/$TESTFS +log_must $ZPOOL scrub $TESTPOOL +$ZPOOL scrub -s $TESTPOOL +log_must $ZPOOL set comment="Use the force, Luke." $TESTPOOL +log_must $ZPOOL set comment="" $TESTPOOL + +# destructive tests must come last +log_must $ZFS rollback $TESTPOOL/$TESTFS@snap +log_must $ZFS destroy $TESTPOOL/$TESTFS@snap + +log_pass "ENOSPC returned as expected." diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c index 9cfe42a323..73b8e056cc 100644 --- a/usr/src/uts/common/fs/zfs/dmu_objset.c +++ b/usr/src/uts/common/fs/zfs/dmu_objset.c @@ -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 diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c index 20d196a833..97c9926bd7 100644 --- a/usr/src/uts/common/fs/zfs/dmu_send.c +++ b/usr/src/uts/common/fs/zfs/dmu_send.c @@ -1162,7 +1162,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 { @@ -2022,7 +2022,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); @@ -2036,7 +2036,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); diff --git a/usr/src/uts/common/fs/zfs/dsl_bookmark.c b/usr/src/uts/common/fs/zfs/dsl_bookmark.c index 35e55ece4f..21784630da 100644 --- a/usr/src/uts/common/fs/zfs/dsl_bookmark.c +++ b/usr/src/uts/common/fs/zfs/dsl_bookmark.c @@ -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); } diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c index 425c0d4551..937a0eb59e 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c @@ -1352,7 +1352,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) { @@ -1454,7 +1454,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); @@ -1805,7 +1805,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)); } /* @@ -1980,7 +1981,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 { @@ -2501,7 +2503,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 @@ -2846,7 +2849,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 @@ -2961,7 +2964,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)); } /* diff --git a/usr/src/uts/common/fs/zfs/dsl_deleg.c b/usr/src/uts/common/fs/zfs/dsl_deleg.c index 4f98c843d3..9c6f38a6bd 100644 --- a/usr/src/uts/common/fs/zfs/dsl_deleg.c +++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c @@ -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)); } /* diff --git a/usr/src/uts/common/fs/zfs/dsl_destroy.c b/usr/src/uts/common/fs/zfs/dsl_destroy.c index 0813f3288d..f8a4546535 100644 --- a/usr/src/uts/common/fs/zfs/dsl_destroy.c +++ b/usr/src/uts/common/fs/zfs/dsl_destroy.c @@ -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)); } /* diff --git a/usr/src/uts/common/fs/zfs/dsl_dir.c b/usr/src/uts/common/fs/zfs/dsl_dir.c index 285634fa88..415bd91e90 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dir.c +++ b/usr/src/uts/common/fs/zfs/dsl_dir.c @@ -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 Martin Matuska. All rights reserved. * Copyright (c) 2014 Joyent, Inc. All rights reserved. */ @@ -637,7 +637,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; @@ -1487,7 +1488,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 @@ -1609,7 +1610,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 * @@ -1884,7 +1885,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 diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c index 2eada5cd16..7e62635176 100644 --- a/usr/src/uts/common/fs/zfs/dsl_prop.c +++ b/usr/src/uts/common/fs/zfs/dsl_prop.c @@ -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 Martin Matuska. All rights reserved. */ @@ -835,7 +835,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 { diff --git a/usr/src/uts/common/fs/zfs/dsl_scan.c b/usr/src/uts/common/fs/zfs/dsl_scan.c index 1f705580d0..d4e234937a 100644 --- a/usr/src/uts/common/fs/zfs/dsl_scan.c +++ b/usr/src/uts/common/fs/zfs/dsl_scan.c @@ -346,7 +346,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, @@ -1784,5 +1784,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)); } diff --git a/usr/src/uts/common/fs/zfs/dsl_synctask.c b/usr/src/uts/common/fs/zfs/dsl_synctask.c index 58f7d37952..8e09347678 100644 --- a/usr/src/uts/common/fs/zfs/dsl_synctask.c +++ b/usr/src/uts/common/fs/zfs/dsl_synctask.c @@ -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 @@ top: 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 @@ top: 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; + } } /* diff --git a/usr/src/uts/common/fs/zfs/dsl_userhold.c b/usr/src/uts/common/fs/zfs/dsl_userhold.c index be5b7102ca..b6878d7ecc 100644 --- a/usr/src/uts/common/fs/zfs/dsl_userhold.c +++ b/usr/src/uts/common/fs/zfs/dsl_userhold.c @@ -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); diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index c8cabb2c32..1f86482725 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -673,7 +673,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; @@ -685,7 +686,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); @@ -766,7 +767,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); diff --git a/usr/src/uts/common/fs/zfs/spa_history.c b/usr/src/uts/common/fs/zfs/spa_history.c index 9e172482fe..cf72c8ad88 100644 --- a/usr/src/uts/common/fs/zfs/spa_history.c +++ b/usr/src/uts/common/fs/zfs/spa_history.c @@ -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> @@ -322,7 +322,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 */ @@ -458,7 +458,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 */ } diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c index ea386591b2..14bd2a0176 100644 --- a/usr/src/uts/common/fs/zfs/spa_misc.c +++ b/usr/src/uts/common/fs/zfs/spa_misc.c @@ -317,6 +317,32 @@ int zfs_deadman_enabled = -1; int spa_asize_inflation = 24; /* + * 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 * ========================================================================== @@ -1578,6 +1604,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) { diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h b/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h index ef86fb64cf..6139303c15 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h @@ -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 } diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 83ec68854e..7f07ec61f6 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -24,7 +24,7 @@ * Portions Copyright 2011 Martin Matuska * 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. @@ -3885,7 +3885,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); diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c index 1564e0da68..5b511ffa02 100644 --- a/usr/src/uts/common/fs/zfs/zvol.c +++ b/usr/src/uts/common/fs/zfs/zvol.c @@ -1910,7 +1910,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); |