summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Ahrens <mahrens@delphix.com>2014-07-08 20:49:56 -0800
committerChristopher Siden <chris@delphix.com>2014-07-08 21:49:57 -0700
commit7d46dc6ca63a6f3f0d51aa655bfcf10cf2405a9e (patch)
treeba560108487312f24294332156f10015c91b775d
parentcd67d23d32df7b247d00e5b82257a2220b1e0c13 (diff)
downloadillumos-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>
-rw-r--r--usr/src/cmd/zfs/zfs_main.c7
-rw-r--r--usr/src/cmd/zhack/zhack.c7
-rw-r--r--usr/src/pkg/manifests/system-test-zfstest.mf3
-rw-r--r--usr/src/test/zfs-tests/runfiles/delphix.run4
-rw-r--r--usr/src/test/zfs-tests/runfiles/omnios.run2
-rw-r--r--usr/src/test/zfs-tests/runfiles/openindiana.run2
-rw-r--r--usr/src/test/zfs-tests/tests/functional/no_space/Makefile3
-rw-r--r--usr/src/test/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh10
-rw-r--r--usr/src/test/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh74
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_objset.c6
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_send.c6
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_bookmark.c8
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c18
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deleg.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_destroy.c7
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dir.c12
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_prop.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_scan.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_synctask.c46
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_userhold.c7
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c7
-rw-r--r--usr/src/uts/common/fs/zfs/spa_history.c6
-rw-r--r--usr/src/uts/common/fs/zfs/spa_misc.c38
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_synctask.h42
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c3
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);