Print this page
OS-1566 dataset quota for ZFS datasets

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dmu_objset.c
          +++ new/usr/src/uts/common/fs/zfs/dmu_objset.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  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) 2012 by Delphix. All rights reserved.
       24 + * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /* Portions Copyright 2010 Robert Milkowski */
  27   28  
  28   29  #include <sys/cred.h>
  29   30  #include <sys/zfs_context.h>
  30   31  #include <sys/dmu_objset.h>
  31   32  #include <sys/dsl_dir.h>
  32   33  #include <sys/dsl_dataset.h>
  33   34  #include <sys/dsl_prop.h>
↓ open down ↓ 649 lines elided ↑ open up ↑
 683  684          if (oa->clone_origin != NULL) {
 684  685                  /* You can't clone across pools. */
 685  686                  if (oa->clone_origin->ds_dir->dd_pool != dd->dd_pool)
 686  687                          return (EXDEV);
 687  688  
 688  689                  /* You can only clone snapshots, not the head datasets. */
 689  690                  if (!dsl_dataset_is_snapshot(oa->clone_origin))
 690  691                          return (EINVAL);
 691  692          }
 692  693  
 693      -        return (0);
      694 +        return (dsl_dir_dscount_check(dd, tx, 1, NULL));
 694  695  }
 695  696  
 696  697  static void
 697  698  dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 698  699  {
 699  700          dsl_dir_t *dd = arg1;
 700  701          spa_t *spa = dd->dd_pool->dp_spa;
 701  702          struct oscarg *oa = arg2;
 702  703          uint64_t obj;
 703  704          dsl_dataset_t *ds;
 704  705          blkptr_t *bp;
 705  706  
 706  707          ASSERT(dmu_tx_is_syncing(tx));
 707  708  
      709 +        dsl_dir_dscount_adjust(dd, tx, 1, B_TRUE, B_TRUE);
      710 +
 708  711          obj = dsl_dataset_create_sync(dd, oa->lastname,
 709  712              oa->clone_origin, oa->flags, oa->cr, tx);
 710  713  
 711  714          VERIFY3U(0, ==, dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds));
 712  715          bp = dsl_dataset_get_blkptr(ds);
 713  716          if (BP_IS_HOLE(bp)) {
 714  717                  objset_t *os =
 715  718                      dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
 716  719  
 717  720                  if (oa->userfunc)
↓ open down ↓ 82 lines elided ↑ open up ↑
 800  803                  /* dsl_dataset_destroy() closes the ds. */
 801  804          }
 802  805  
 803  806          return (error);
 804  807  }
 805  808  
 806  809  typedef struct snapallarg {
 807  810          dsl_sync_task_group_t *saa_dstg;
 808  811          boolean_t saa_needsuspend;
 809  812          nvlist_t *saa_props;
      813 +        uint64_t saa_tot_cnt;
 810  814  
 811  815          /* the following are used only if 'temporary' is set: */
 812  816          boolean_t saa_temporary;
 813  817          const char *saa_htag;
 814  818          struct dsl_ds_holdarg *saa_ha;
 815  819          dsl_dataset_t *saa_newds;
 816  820  } snapallarg_t;
 817  821  
 818  822  typedef struct snaponearg {
 819  823          const char *soa_longname; /* long snap name */
↓ open down ↓ 4 lines elided ↑ open up ↑
 824  828  static int
 825  829  snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
 826  830  {
 827  831          objset_t *os = arg1;
 828  832          snaponearg_t *soa = arg2;
 829  833          snapallarg_t *saa = soa->soa_saa;
 830  834          int error;
 831  835  
 832  836          /* The props have already been checked by zfs_check_userprops(). */
 833  837  
      838 +        /*
      839 +         * The saa_tot_cnt is used to track how many snapshots there are going
      840 +         * to be at the highest level of the snapshot tree. This is necessary
      841 +         * because the counts are not actually adjusted when we are checking,
      842 +         * only when we finally sync. For a single snapshot, this is easy, the
      843 +         * count is 1, but it gets more complicated for recursive snapshots.
      844 +         *
      845 +         * We only enforce the snapshot quota at the level where the snapshot
      846 +         * is being taken. This is to prevent datasets with a full snapshot
      847 +         * count at a lower level from blocking recursive snapshots being taken
      848 +         * at a higher level. For example, the quota is only enforced on 'a'
      849 +         * and 'b' when taking a recursive snapshot of a/b@x with the following
      850 +         * existing state:
      851 +         *      a/b     (0 snaps, snap quota is 5)
      852 +         *      a/b/c   (0 snaps, snap quota is none)
      853 +         *      a/b/d   (1 snaps, snap quota is 1)
      854 +         * A recursive snapshot of a/b will be allowed since it results in
      855 +         * 3 new snapshots (a/b@x, a/b/c@x, a/b/d@x), even though a/b/d already
      856 +         * has 1 snapshot and has hit its quota (note that the existing
      857 +         * snapshot on a/b/d is being counted against the quota on a/b). When
      858 +         * the snapshot completes, a/b will have a snapshot count of 4 and
      859 +         * a/b/d will have a count of 2. As can be seen, this means that
      860 +         * datasets can have a snapshot count > their quota.
      861 +         *
      862 +         * In order to properly handle recursive snapshots, we increment the
      863 +         * total count in open context, but this count is not validated in open
      864 +         * context. This gives us the maximum count to validate at the
      865 +         * top-level dataset when we're in syncing context. We then use a count
      866 +         * of 0 in syncing conext as we descend the tree past the top-level
      867 +         * snapshot so that lower levels are not being validated against their
      868 +         * quota.
      869 +         */
      870 +        if (!dmu_tx_is_syncing(tx))
      871 +                saa->saa_tot_cnt++;
 834  872          error = dsl_dataset_snapshot_check(os->os_dsl_dataset,
 835      -            soa->soa_snapname, tx);
      873 +            soa->soa_snapname, saa->saa_tot_cnt, tx);
      874 +        if (dmu_tx_is_syncing(tx))
      875 +                saa->saa_tot_cnt = 0;
 836  876          if (error)
 837  877                  return (error);
 838  878  
 839  879          if (saa->saa_temporary) {
 840  880                  /*
 841  881                   * Ideally we would just call
 842  882                   * dsl_dataset_user_hold_check() and
 843  883                   * dsl_dataset_destroy_check() here.  However the
 844  884                   * dataset we want to hold and destroy is the snapshot
 845  885                   * that we just confirmed we can create, but it won't
↓ open down ↓ 996 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX