]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Illumos 4951 - ZFS administrative commands should use reserved space
authorMatthew Ahrens <mahrens@delphix.com>
Mon, 3 Nov 2014 20:28:43 +0000 (12:28 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 4 May 2015 16:41:10 +0000 (09:41 -0700)
4951 ZFS administrative commands should use reserved space, not 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>

References:
  https://www.illumos.org/issues/4373
  https://github.com/illumos/illumos-gate/commit/7d46dc6

Ported by: Brian Behlendorf <behlendorf1@llnl.gov>

18 files changed:
cmd/zfs/zfs_main.c
cmd/zhack/zhack.c
include/sys/dsl_synctask.h
module/zfs/dmu_objset.c
module/zfs/dmu_send.c
module/zfs/dsl_bookmark.c
module/zfs/dsl_dataset.c
module/zfs/dsl_deleg.c
module/zfs/dsl_destroy.c
module/zfs/dsl_dir.c
module/zfs/dsl_prop.c
module/zfs/dsl_scan.c
module/zfs/dsl_synctask.c
module/zfs/dsl_userhold.c
module/zfs/spa.c
module/zfs/spa_history.c
module/zfs/spa_misc.c
module/zfs/zfs_ioctl.c

index c361e18b9faad5b4561f7013edee4790d9d8ec46..50ac59fba74766034aa5def8ae29c9efafd75ae1 100644 (file)
@@ -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 (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
@@ -6636,6 +6636,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;
@@ -6644,7 +6647,7 @@ zfs_do_bookmark(int argc, char **argv)
                    dgettext(TEXT_DOMAIN, err_msg));
        }
 
-       return (ret);
+       return (ret != 0);
 
 usage:
        usage(B_FALSE);
index 19493bd094102d950049abf92821b99e7c2cfbbc..3f86714fe31da34b523bd33bd28b5ae5addb352c 100644 (file)
@@ -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);
 }
index ef86fb64cf0c58d62fcef3a17491f4903ddf4220..6139303c1564847cbff4526325b9eb19063775e1 100644 (file)
@@ -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
 }
index 6399a0a75254425330876240547587a7703d7418..6d42bf8a28b74493ac7f1c9cd9ab298a1b6ddf4f 100644 (file)
@@ -865,7 +865,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 {
@@ -964,7 +965,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
index 108fa098b9854271b005c25a7d8921c57eaef04f..c1cac2e6762be2f8fe0f5fc82b7226e464080c56 100644 (file)
@@ -1191,7 +1191,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 {
@@ -2108,7 +2108,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);
@@ -2122,7 +2122,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);
index a4cb361d4e7a596c69c40922db0eedfe64d704c2..447a3a2dc3a2de6df39c4061b78772cf11ab0b4a 100644 (file)
@@ -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>
@@ -249,7 +249,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
@@ -454,7 +455,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);
 }
index de2703868e440149688648546463d8778a81817f..b444fca64a684e602e4d68fca111af122f750a49 100644 (file)
@@ -1406,7 +1406,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) {
@@ -1518,7 +1518,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);
@@ -1874,7 +1874,8 @@ dsl_dataset_rename_snapshot(const char *fsname,
        ddrsa.ddrsa_recursive = recursive;
 
        error = 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);
 
        if (error)
            return (SET_ERROR(error));
@@ -2064,7 +2065,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 {
@@ -2595,7 +2597,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
@@ -2949,7 +2952,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
@@ -3064,7 +3067,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));
 }
 
 /*
index 23bbe5b946928fec9d69babdf74ac817a9fd9e0e..952422be23813914dbb8efcf654d54c71e997aad 100644 (file)
@@ -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));
 }
 
 /*
index 6a52ed22f003bda69a43ed607d11702be399bf22..4623f5dd5b9dad47b91a92bfccd4e585a2eb481c 100644 (file)
@@ -520,7 +520,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);
@@ -918,7 +918,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);
 
@@ -944,7 +945,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));
 }
 
 /*
index 186b332033969dfe33cb1c300a83fdcf77aac93a..ba6c24486463cb3819b1678d5b33738de3375875 100644 (file)
@@ -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.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -665,7 +665,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;
@@ -1529,7 +1530,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
@@ -1650,7 +1651,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 *
@@ -1932,7 +1933,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
index 69bcd190f2e0965e8014f028d83fe79b76a8b8fa..28b101eee5475b11563266f3d6342cacda82023a 100644 (file)
@@ -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.
  */
 
@@ -865,7 +865,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 {
index 5f70b18719c8195a9e25c03aa9dd7b11b161075e..31e693149f6808c3691560cd229e9cd9889c852f 100644 (file)
@@ -388,7 +388,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, const zbookmark_phys_t *zb,
@@ -1848,7 +1848,7 @@ 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));
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
index 8b11cd957154a776d8bcef42357e610a1b925c5e..28130d25711a8dfca04059963a247a107d02d139 100644 (file)
@@ -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 = dsl_dir_phys(dp->dp_root_dir)->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 = dsl_dir_phys(dp->dp_root_dir)->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;
+               }
        }
 
        /*
index 4007d4c5ea351d1b4a18724c312844f24a778f30..1b234ed480f92bd4f2bf765acb6e06444a833cd8 100644 (file)
@@ -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.
  */
 
@@ -319,7 +319,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);
@@ -609,7 +610,7 @@ dsl_dataset_user_release_impl(nvlist_t *holds, nvlist_t *errlist,
            KM_SLEEP));
 
        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);
 
index 376f5ae13db3433aa5a5b5ddf4eac265207308d3..53aa05d01fb1d08fffb8c55f06a8d4562118a818 100644 (file)
@@ -666,7 +666,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;
@@ -678,7 +679,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);
@@ -759,7 +760,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);
index 8e0033d949da9fc84154449c4924b3e29344093b..1041c8f572f23f72f9bafeb48a54990718da190f 100644 (file)
@@ -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>
@@ -323,7 +323,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 */
 }
index c17043657497a75ce293e0d8893a4cf8a176601f..8e5fa683ef424402249938b4fcf99a9f6b484879 100644 (file)
@@ -311,6 +311,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
@@ -1564,6 +1590,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)
 {
index 121f99919c6174c58f5effc4db9d629963427c5f..caaa3a21c71c8840420cf58146675c17ac5d8b55 100644 (file)
@@ -26,7 +26,7 @@
  * Copyright (c) 2012, Joyent, Inc. 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.