]> granicus.if.org Git - zfs/commitdiff
OpenZFS 6562 - Refquota on receive doesn't account for overage
authorDan McDonald <danmcd@omniti.com>
Thu, 9 Jun 2016 19:29:09 +0000 (12:29 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 28 Jun 2016 20:47:03 +0000 (13:47 -0700)
Authored by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Gordon Ross <gwr@nexenta.com>
Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
OpenZFS-issue: https://www.illumos.org/issues/6562
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/5f7a8e6

module/zfs/dsl_dataset.c
tests/runfiles/linux.run

index e86e6cc731eceb7683f2ce4c2080bef90279d598..3d1115e31c7f4a5fd593203306992956f0943307 100644 (file)
@@ -25,6 +25,7 @@
  * Copyright (c) 2014 RackTop Systems.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ * Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <sys/dmu_objset.h>
@@ -78,6 +79,8 @@ int zfs_max_recordsize = 1 * 1024 * 1024;
 
 extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
 
+extern int spa_asize_inflation;
+
 /*
  * Figure out how much of this delta should be propogated to the dsl_dir
  * layer.  If there's a refreservation, that space has already been
@@ -2810,6 +2813,11 @@ int
 dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
     dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
 {
+       /*
+        * "slack" factor for received datasets with refquota set on them.
+        * See the bottom of this function for details on its use.
+        */
+       uint64_t refquota_slack = DMU_MAX_ACCESS * spa_asize_inflation;
        int64_t unused_refres_delta;
 
        /* they should both be heads */
@@ -2852,10 +2860,22 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
            dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
                return (SET_ERROR(ENOSPC));
 
-       /* clone can't be over the head's refquota */
+       /*
+        * The clone can't be too much over the head's refquota.
+        *
+        * To ensure that the entire refquota can be used, we allow one
+        * transaction to exceed the the refquota.  Therefore, this check
+        * needs to also allow for the space referenced to be more than the
+        * refquota.  The maximum amount of space that one transaction can use
+        * on disk is DMU_MAX_ACCESS * spa_asize_inflation.  Allowing this
+        * overage ensures that we are able to receive a filesystem that
+        * exceeds the refquota on the source system.
+        *
+        * So that overage is the refquota_slack we use below.
+        */
        if (origin_head->ds_quota != 0 &&
            dsl_dataset_phys(clone)->ds_referenced_bytes >
-           origin_head->ds_quota)
+           origin_head->ds_quota + refquota_slack)
                return (SET_ERROR(EDQUOT));
 
        return (0);
@@ -2870,8 +2890,13 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
        int64_t unused_refres_delta;
 
        ASSERT(clone->ds_reserved == 0);
+       /*
+        * NOTE: On DEBUG kernels there could be a race between this and
+        * the check function if spa_asize_inflation is adjusted...
+        */
        ASSERT(origin_head->ds_quota == 0 ||
-           dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
+           dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota +
+           DMU_MAX_ACCESS * spa_asize_inflation);
        ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
 
        /*
index b393368f08c4ecd0068d819a969bb0db440830cd..b2f35ee240a0eaa324dfe6559407b3ecc52b70c4 100644 (file)
@@ -148,12 +148,11 @@ tests = []
 # DISABLED:
 # zfs_receive_004_neg - Fails for OpenZFS on illumos
 # zfs_receive_011_pos - Requires port of OpenZFS 6562
-# zfs_receive_012_pos - Requires port of OpenZFS 6562
 [tests/functional/cli_root/zfs_receive]
 tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
     'zfs_receive_005_neg', 'zfs_receive_006_pos',
     'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg',
-    'zfs_receive_010_pos']
+    'zfs_receive_010_pos', 'zfs_receive_012_pos']
 
 # DISABLED:
 # zfs_rename_002_pos - needs investigation