Print this page
6562 Refquota on receive doesn't account for overage
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Toomas Soome <tsoome@me.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dsl_dataset.c
          +++ new/usr/src/uts/common/fs/zfs/dsl_dataset.c
↓ open down ↓ 17 lines elided ↑ open up ↑
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  24   24   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  25   25   * Copyright (c) 2014 RackTop Systems.
  26   26   * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  27   27   * Copyright (c) 2014 Integros [integros.com]
       28 + * Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
  28   29   */
  29   30  
  30   31  #include <sys/dmu_objset.h>
  31   32  #include <sys/dsl_dataset.h>
  32   33  #include <sys/dsl_dir.h>
  33   34  #include <sys/dsl_prop.h>
  34   35  #include <sys/dsl_synctask.h>
  35   36  #include <sys/dmu_traverse.h>
  36   37  #include <sys/dmu_impl.h>
  37   38  #include <sys/dmu_tx.h>
↓ open down ↓ 33 lines elided ↑ open up ↑
  71   72          { \
  72   73                  uint64_t __tmp = (x); \
  73   74                  (x) = (y); \
  74   75                  (y) = __tmp; \
  75   76          }
  76   77  
  77   78  #define DS_REF_MAX      (1ULL << 62)
  78   79  
  79   80  extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
  80   81  
       82 +extern int spa_asize_inflation;
       83 +
  81   84  /*
  82   85   * Figure out how much of this delta should be propogated to the dsl_dir
  83   86   * layer.  If there's a refreservation, that space has already been
  84   87   * partially accounted for in our ancestors.
  85   88   */
  86   89  static int64_t
  87   90  parent_delta(dsl_dataset_t *ds, int64_t delta)
  88   91  {
  89   92          dsl_dataset_phys_t *ds_phys;
  90   93          uint64_t old_bytes, new_bytes;
↓ open down ↓ 2690 lines elided ↑ open up ↑
2781 2784  
2782 2785          return (dsl_sync_task(name, dsl_dataset_promote_check,
2783 2786              dsl_dataset_promote_sync, &ddpa,
2784 2787              2 + numsnaps, ZFS_SPACE_CHECK_RESERVED));
2785 2788  }
2786 2789  
2787 2790  int
2788 2791  dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
2789 2792      dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
2790 2793  {
     2794 +        /*
     2795 +         * "slack" factor for received datasets with refquota set on them.
     2796 +         * See the bottom of this function for details on its use.
     2797 +         */
     2798 +        uint64_t refquota_slack = DMU_MAX_ACCESS * spa_asize_inflation;
2791 2799          int64_t unused_refres_delta;
2792 2800  
2793 2801          /* they should both be heads */
2794 2802          if (clone->ds_is_snapshot ||
2795 2803              origin_head->ds_is_snapshot)
2796 2804                  return (SET_ERROR(EINVAL));
2797 2805  
2798 2806          /* if we are not forcing, the branch point should be just before them */
2799 2807          if (!force && clone->ds_prev != origin_head->ds_prev)
2800 2808                  return (SET_ERROR(EINVAL));
↓ open down ↓ 22 lines elided ↑ open up ↑
2823 2831              (int64_t)MIN(origin_head->ds_reserved,
2824 2832              dsl_dataset_phys(origin_head)->ds_unique_bytes) -
2825 2833              (int64_t)MIN(origin_head->ds_reserved,
2826 2834              dsl_dataset_phys(clone)->ds_unique_bytes);
2827 2835  
2828 2836          if (unused_refres_delta > 0 &&
2829 2837              unused_refres_delta >
2830 2838              dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
2831 2839                  return (SET_ERROR(ENOSPC));
2832 2840  
2833      -        /* clone can't be over the head's refquota */
     2841 +        /*
     2842 +         * The clone can't be too much over the head's refquota.
     2843 +         *
     2844 +         * To ensure that the entire refquota can be used, we allow one
     2845 +         * transaction to exceed the the refquota.  Therefore, this check
     2846 +         * needs to also allow for the space referenced to be more than the
     2847 +         * refquota.  The maximum amount of space that one transaction can use
     2848 +         * on disk is DMU_MAX_ACCESS * spa_asize_inflation.  Allowing this
     2849 +         * overage ensures that we are able to receive a filesystem that
     2850 +         * exceeds the refquota on the source system.
     2851 +         *
     2852 +         * So that overage is the refquota_slack we use below.
     2853 +         */
2834 2854          if (origin_head->ds_quota != 0 &&
2835 2855              dsl_dataset_phys(clone)->ds_referenced_bytes >
2836      -            origin_head->ds_quota)
     2856 +            origin_head->ds_quota + refquota_slack)
2837 2857                  return (SET_ERROR(EDQUOT));
2838 2858  
2839 2859          return (0);
2840 2860  }
2841 2861  
2842 2862  void
2843 2863  dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
2844 2864      dsl_dataset_t *origin_head, dmu_tx_t *tx)
2845 2865  {
2846 2866          dsl_pool_t *dp = dmu_tx_pool(tx);
2847 2867          int64_t unused_refres_delta;
2848 2868  
2849 2869          ASSERT(clone->ds_reserved == 0);
     2870 +        /*
     2871 +         * NOTE: On DEBUG kernels there could be a race between this and
     2872 +         * the check function if spa_asize_inflation is adjusted...
     2873 +         */
2850 2874          ASSERT(origin_head->ds_quota == 0 ||
2851      -            dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
     2875 +            dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota +
     2876 +            DMU_MAX_ACCESS * spa_asize_inflation);
2852 2877          ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
2853 2878  
2854 2879          /*
2855 2880           * Swap per-dataset feature flags.
2856 2881           */
2857 2882          for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
2858 2883                  if (!(spa_feature_table[f].fi_flags &
2859 2884                      ZFEATURE_FLAG_PER_DATASET)) {
2860 2885                          ASSERT(!clone->ds_feature_inuse[f]);
2861 2886                          ASSERT(!origin_head->ds_feature_inuse[f]);
↓ open down ↓ 647 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX