Print this page
NEX-6855 System fails to boot up after a large number of datasets created
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-9301 BAD Trap: Double Fault panic on zfs destroy snapshot
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7641 Impossible to remove special vdev from pool if WBC-ed dataset was removed before disabling WBC
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
2605 want to resume interrupted zfs send
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Xin Li <delphij@freebsd.org>
Reviewed by: Arne Jansen <sensille@gmx.net>
Approved by: Dan McDonald <danmcd@omniti.com>
6047 SPARC boot should support feature@embedded_data
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Approved by: Dan McDonald <danmcd@omniti.com>
5959 clean up per-dataset feature count code
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-4582 update wrc test cases for allow to use write back cache per tree of datasets
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
5960 zfs recv should prefetch indirect blocks
5925 zfs receive -o origin=
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Revert "NEX-4476 WRC: Allow to use write back cache per tree of datasets"
This reverts commit fe97b74444278a6f36fec93179133641296312da.
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-3964 It should not be allowed to rename a snapshot that its new name is matched to the prefix of in-kernel autosnapshots (lint)
NEX-3964 It should not be allowed to rename a snapshot that its new name is matched to the prefix of in-kernel autosnapshots
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3558 KRRP Integration
4370 avoid transmitting holes during zfs send
4371 DMU code clean up
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Approved by: Garrett D'Amore <garrett@damore.org>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dsl_destroy.c
          +++ new/usr/src/uts/common/fs/zfs/dsl_destroy.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  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      - * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
       23 + * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  24   24   * Copyright (c) 2013 Steven Hartland. All rights reserved.
  25   25   * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
  26   26   * Copyright (c) 2014 Integros [integros.com]
       27 + * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  27   28   */
  28   29  
       30 +#include <sys/autosnap.h>
  29   31  #include <sys/zfs_context.h>
  30   32  #include <sys/dsl_userhold.h>
  31   33  #include <sys/dsl_dataset.h>
  32   34  #include <sys/dsl_synctask.h>
  33   35  #include <sys/dsl_destroy.h>
  34   36  #include <sys/dmu_tx.h>
  35   37  #include <sys/dsl_pool.h>
  36   38  #include <sys/dsl_dir.h>
  37   39  #include <sys/dmu_traverse.h>
  38   40  #include <sys/dsl_scan.h>
  39   41  #include <sys/dmu_objset.h>
  40   42  #include <sys/zap.h>
  41   43  #include <sys/zfeature.h>
  42   44  #include <sys/zfs_ioctl.h>
  43   45  #include <sys/dsl_deleg.h>
  44   46  #include <sys/dmu_impl.h>
       47 +#include <sys/wbc.h>
  45   48  #include <sys/zcp.h>
  46   49  
  47   50  int
  48   51  dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
  49   52  {
  50   53          if (!ds->ds_is_snapshot)
  51   54                  return (SET_ERROR(EINVAL));
  52   55  
  53   56          if (dsl_dataset_long_held(ds))
  54   57                  return (SET_ERROR(EBUSY));
↓ open down ↓ 122 lines elided ↑ open up ↑
 177  180          dsl_deadlist_open(&ds->ds_deadlist, mos,
 178  181              dsl_dataset_phys(ds)->ds_deadlist_obj);
 179  182          dsl_deadlist_open(&ds_next->ds_deadlist, mos,
 180  183              dsl_dataset_phys(ds_next)->ds_deadlist_obj);
 181  184  }
 182  185  
 183  186  static void
 184  187  dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
 185  188  {
 186  189          objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 187      -        zap_cursor_t zc;
 188      -        zap_attribute_t za;
      190 +        zap_cursor_t *zc;
      191 +        zap_attribute_t *za;
 189  192  
 190  193          /*
 191  194           * If it is the old version, dd_clones doesn't exist so we can't
 192  195           * find the clones, but dsl_deadlist_remove_key() is a no-op so it
 193  196           * doesn't matter.
 194  197           */
 195  198          if (dsl_dir_phys(ds->ds_dir)->dd_clones == 0)
 196  199                  return;
      200 +        zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
      201 +        za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
 197  202  
 198      -        for (zap_cursor_init(&zc, mos, dsl_dir_phys(ds->ds_dir)->dd_clones);
 199      -            zap_cursor_retrieve(&zc, &za) == 0;
 200      -            zap_cursor_advance(&zc)) {
      203 +        for (zap_cursor_init(zc, mos, dsl_dir_phys(ds->ds_dir)->dd_clones);
      204 +            zap_cursor_retrieve(zc, za) == 0;
      205 +            zap_cursor_advance(zc)) {
 201  206                  dsl_dataset_t *clone;
 202  207  
 203  208                  VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
 204      -                    za.za_first_integer, FTAG, &clone));
      209 +                    za->za_first_integer, FTAG, &clone));
 205  210                  if (clone->ds_dir->dd_origin_txg > mintxg) {
 206  211                          dsl_deadlist_remove_key(&clone->ds_deadlist,
 207  212                              mintxg, tx);
 208      -                        if (dsl_dataset_remap_deadlist_exists(clone)) {
 209      -                                dsl_deadlist_remove_key(
 210      -                                    &clone->ds_remap_deadlist, mintxg, tx);
 211      -                        }
 212  213                          dsl_dataset_remove_clones_key(clone, mintxg, tx);
 213  214                  }
 214  215                  dsl_dataset_rele(clone, FTAG);
 215  216          }
 216      -        zap_cursor_fini(&zc);
      217 +        zap_cursor_fini(zc);
      218 +        kmem_free(zc, sizeof (zap_cursor_t));
      219 +        kmem_free(za, sizeof (zap_attribute_t));
 217  220  }
 218  221  
 219      -static void
 220      -dsl_destroy_snapshot_handle_remaps(dsl_dataset_t *ds, dsl_dataset_t *ds_next,
 221      -    dmu_tx_t *tx)
 222      -{
 223      -        dsl_pool_t *dp = ds->ds_dir->dd_pool;
 224      -
 225      -        /* Move blocks to be obsoleted to pool's obsolete list. */
 226      -        if (dsl_dataset_remap_deadlist_exists(ds_next)) {
 227      -                if (!bpobj_is_open(&dp->dp_obsolete_bpobj))
 228      -                        dsl_pool_create_obsolete_bpobj(dp, tx);
 229      -
 230      -                dsl_deadlist_move_bpobj(&ds_next->ds_remap_deadlist,
 231      -                    &dp->dp_obsolete_bpobj,
 232      -                    dsl_dataset_phys(ds)->ds_prev_snap_txg, tx);
 233      -        }
 234      -
 235      -        /* Merge our deadlist into next's and free it. */
 236      -        if (dsl_dataset_remap_deadlist_exists(ds)) {
 237      -                uint64_t remap_deadlist_object =
 238      -                    dsl_dataset_get_remap_deadlist_object(ds);
 239      -                ASSERT(remap_deadlist_object != 0);
 240      -
 241      -                mutex_enter(&ds_next->ds_remap_deadlist_lock);
 242      -                if (!dsl_dataset_remap_deadlist_exists(ds_next))
 243      -                        dsl_dataset_create_remap_deadlist(ds_next, tx);
 244      -                mutex_exit(&ds_next->ds_remap_deadlist_lock);
 245      -
 246      -                dsl_deadlist_merge(&ds_next->ds_remap_deadlist,
 247      -                    remap_deadlist_object, tx);
 248      -                dsl_dataset_destroy_remap_deadlist(ds, tx);
 249      -        }
 250      -}
 251      -
 252  222  void
 253  223  dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 254  224  {
 255  225          int err;
 256  226          int after_branch_point = FALSE;
 257  227          dsl_pool_t *dp = ds->ds_dir->dd_pool;
      228 +        spa_t *spa = dp->dp_spa;
      229 +        wbc_data_t *wbc_data = spa_get_wbc_data(spa);
 258  230          objset_t *mos = dp->dp_meta_objset;
 259  231          dsl_dataset_t *ds_prev = NULL;
 260  232          uint64_t obj;
 261  233  
 262  234          ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 263  235          rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG);
 264  236          ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg);
 265  237          rrw_exit(&ds->ds_bp_rwlock, FTAG);
 266  238          ASSERT(refcount_is_zero(&ds->ds_longholds));
 267  239  
      240 +        /*
      241 +         * if an edge snapshot of WBC window is destroyed, the window must be
      242 +         * aborted
      243 +         */
      244 +        mutex_enter(&wbc_data->wbc_lock);
      245 +        if (dsl_dataset_phys(ds)->ds_creation_txg == wbc_data->wbc_finish_txg)
      246 +                wbc_purge_window(spa, tx);
      247 +        mutex_exit(&wbc_data->wbc_lock);
      248 +
 268  249          if (defer &&
 269  250              (ds->ds_userrefs > 0 ||
 270  251              dsl_dataset_phys(ds)->ds_num_children > 1)) {
 271  252                  ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
 272  253                  dmu_buf_will_dirty(ds->ds_dbuf, tx);
 273  254                  dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY;
 274  255                  spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
 275  256                  return;
 276  257          }
 277  258  
↓ open down ↓ 79 lines elided ↑ open up ↑
 357  338                  dsl_deadlist_move_bpobj(&ds_next->ds_deadlist,
 358  339                      &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg,
 359  340                      tx);
 360  341                  dsl_dir_diduse_space(tx->tx_pool->dp_free_dir,
 361  342                      DD_USED_HEAD, used, comp, uncomp, tx);
 362  343  
 363  344                  /* Merge our deadlist into next's and free it. */
 364  345                  dsl_deadlist_merge(&ds_next->ds_deadlist,
 365  346                      dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
 366  347          }
 367      -
 368  348          dsl_deadlist_close(&ds->ds_deadlist);
 369  349          dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
 370  350          dmu_buf_will_dirty(ds->ds_dbuf, tx);
 371  351          dsl_dataset_phys(ds)->ds_deadlist_obj = 0;
 372  352  
 373      -        dsl_destroy_snapshot_handle_remaps(ds, ds_next, tx);
 374      -
 375  353          /* Collapse range in clone heads */
 376  354          dsl_dataset_remove_clones_key(ds,
 377  355              dsl_dataset_phys(ds)->ds_creation_txg, tx);
 378  356  
 379  357          if (ds_next->ds_is_snapshot) {
 380  358                  dsl_dataset_t *ds_nextnext;
 381  359  
 382  360                  /*
 383  361                   * Update next's unique to include blocks which
 384  362                   * were previously shared by only this snapshot
↓ open down ↓ 13 lines elided ↑ open up ↑
 398  376                  dsl_dataset_phys(ds_next)->ds_unique_bytes += used;
 399  377                  dsl_dataset_rele(ds_nextnext, FTAG);
 400  378                  ASSERT3P(ds_next->ds_prev, ==, NULL);
 401  379  
 402  380                  /* Collapse range in this head. */
 403  381                  dsl_dataset_t *hds;
 404  382                  VERIFY0(dsl_dataset_hold_obj(dp,
 405  383                      dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &hds));
 406  384                  dsl_deadlist_remove_key(&hds->ds_deadlist,
 407  385                      dsl_dataset_phys(ds)->ds_creation_txg, tx);
 408      -                if (dsl_dataset_remap_deadlist_exists(hds)) {
 409      -                        dsl_deadlist_remove_key(&hds->ds_remap_deadlist,
 410      -                            dsl_dataset_phys(ds)->ds_creation_txg, tx);
 411      -                }
 412  386                  dsl_dataset_rele(hds, FTAG);
 413  387  
 414  388          } else {
 415  389                  ASSERT3P(ds_next->ds_prev, ==, ds);
 416  390                  dsl_dataset_rele(ds_next->ds_prev, ds_next);
 417  391                  ds_next->ds_prev = NULL;
 418  392                  if (ds_prev) {
 419  393                          VERIFY0(dsl_dataset_hold_obj(dp,
 420  394                              dsl_dataset_phys(ds)->ds_prev_snap_obj,
 421  395                              ds_next, &ds_next->ds_prev));
↓ open down ↓ 79 lines elided ↑ open up ↑
 501  475          const char *dsname = ddsa->ddsa_name;
 502  476          boolean_t defer = ddsa->ddsa_defer;
 503  477  
 504  478          dsl_pool_t *dp = dmu_tx_pool(tx);
 505  479          dsl_dataset_t *ds;
 506  480  
 507  481          int error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
 508  482          if (error == ENOENT)
 509  483                  return;
 510  484          ASSERT0(error);
      485 +
      486 +        if (autosnap_check_name(strchr(dsname, '@')))
      487 +                autosnap_exempt_snapshot(dp->dp_spa, dsname);
      488 +
 511  489          dsl_destroy_snapshot_sync_impl(ds, defer, tx);
 512  490          dsl_dataset_rele(ds, FTAG);
 513  491  }
 514  492  
 515  493  /*
 516  494   * The semantics of this function are described in the comment above
 517  495   * lzc_destroy_snaps().  To summarize:
 518  496   *
 519  497   * The snapshots must all be in the same pool.
 520  498   *
↓ open down ↓ 329 lines elided ↑ open up ↑
 850  828                          dsl_dataset_remove_from_next_clones(ds->ds_prev,
 851  829                              obj, tx);
 852  830                  }
 853  831  
 854  832                  ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1);
 855  833                  dsl_dataset_phys(ds->ds_prev)->ds_num_children--;
 856  834          }
 857  835  
 858  836          /*
 859  837           * Destroy the deadlist.  Unless it's a clone, the
 860      -         * deadlist should be empty since the dataset has no snapshots.
 861      -         * (If it's a clone, it's safe to ignore the deadlist contents
 862      -         * since they are still referenced by the origin snapshot.)
      838 +         * deadlist should be empty.  (If it's a clone, it's
      839 +         * safe to ignore the deadlist contents.)
 863  840           */
 864  841          dsl_deadlist_close(&ds->ds_deadlist);
 865  842          dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
 866  843          dmu_buf_will_dirty(ds->ds_dbuf, tx);
 867  844          dsl_dataset_phys(ds)->ds_deadlist_obj = 0;
 868  845  
 869      -        if (dsl_dataset_remap_deadlist_exists(ds))
 870      -                dsl_dataset_destroy_remap_deadlist(ds, tx);
 871      -
 872  846          objset_t *os;
 873  847          VERIFY0(dmu_objset_from_ds(ds, &os));
 874  848  
      849 +        if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_WBC)) {
      850 +                wbc_process_objset(spa_get_wbc_data(dp->dp_spa), os, B_TRUE);
      851 +
      852 +                /*
      853 +                 * If WBC was activated for this dataset and it is a root
      854 +                 * of WBC-ed tree of datasets then need to decrement WBC
      855 +                 * feature flag refcounter, to be sure that 'feature@wbc'
      856 +                 * shows correct information about the status of WBC
      857 +                 */
      858 +                if (os->os_wbc_root_ds_obj != 0 &&
      859 +                    ds->ds_object == os->os_wbc_root_ds_obj)
      860 +                        spa_feature_decr(os->os_spa, SPA_FEATURE_WBC, tx);
      861 +        }
      862 +
 875  863          if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
 876  864                  old_synchronous_dataset_destroy(ds, tx);
 877  865          } else {
 878  866                  /*
 879  867                   * Move the bptree into the pool's list of trees to
 880  868                   * clean up and update space accounting information.
 881  869                   */
 882  870                  uint64_t used, comp, uncomp;
 883  871  
 884  872                  zil_destroy_sync(dmu_objset_zil(os), tx);
↓ open down ↓ 121 lines elided ↑ open up ↑
1006  994          boolean_t isenabled;
1007  995  
1008  996  #ifdef _KERNEL
1009  997          zfs_destroy_unmount_origin(name);
1010  998  #endif
1011  999  
1012 1000          error = spa_open(name, &spa, FTAG);
1013 1001          if (error != 0)
1014 1002                  return (error);
1015 1003          isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY);
     1004 +
1016 1005          spa_close(spa, FTAG);
1017 1006  
1018 1007          ddha.ddha_name = name;
1019 1008  
1020 1009          if (!isenabled) {
1021 1010                  objset_t *os;
1022 1011  
1023 1012                  error = dsl_sync_task(name, dsl_destroy_head_check,
1024 1013                      dsl_destroy_head_begin_sync, &ddha,
1025 1014                      0, ZFS_SPACE_CHECK_NONE);
↓ open down ↓ 17 lines elided ↑ open up ↑
1043 1032                          /* sync out all frees */
1044 1033                          txg_wait_synced(dmu_objset_pool(os), 0);
1045 1034                          dmu_objset_disown(os, FTAG);
1046 1035                  }
1047 1036          }
1048 1037  
1049 1038          return (dsl_sync_task(name, dsl_destroy_head_check,
1050 1039              dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_NONE));
1051 1040  }
1052 1041  
     1042 +typedef struct {
     1043 +        kmutex_t        lock;
     1044 +        list_t list;
     1045 +} dsl_inconsistent_walker_cb_t;
     1046 +
     1047 +typedef struct {
     1048 +        char name[ZFS_MAX_DATASET_NAME_LEN];
     1049 +        list_node_t node;
     1050 +} dsl_inconsistent_node_t;
     1051 +
     1052 +/* ARGSUSED */
     1053 +static int
     1054 +dsl_collect_inconsistent_datasets_cb(dsl_pool_t *dp,
     1055 +    dsl_dataset_t *ds, void *arg)
     1056 +{
     1057 +        dsl_inconsistent_node_t *ds_node;
     1058 +        dsl_inconsistent_walker_cb_t *walker =
     1059 +            (dsl_inconsistent_walker_cb_t *)arg;
     1060 +
     1061 +        if (!DS_IS_INCONSISTENT(ds))
     1062 +                return (0);
     1063 +
     1064 +        /*
     1065 +         * If the dataset is inconsistent because a resumable receive
     1066 +         * has failed, then do not destroy it.
     1067 +         */
     1068 +        if (dsl_dataset_has_resume_receive_state(ds))
     1069 +                return (0);
     1070 +
     1071 +        ds_node = kmem_alloc(sizeof (dsl_inconsistent_node_t), KM_SLEEP);
     1072 +        dsl_dataset_name(ds, ds_node->name);
     1073 +
     1074 +        mutex_enter(&walker->lock);
     1075 +        list_insert_tail(&walker->list, ds_node);
     1076 +        mutex_exit(&walker->lock);
     1077 +
     1078 +        return (0);
     1079 +}
     1080 +
1053 1081  /*
1054      - * Note, this function is used as the callback for dmu_objset_find().  We
1055      - * always return 0 so that we will continue to find and process
1056      - * inconsistent datasets, even if we encounter an error trying to
1057      - * process one of them.
     1082 + * Walk in parallel over the entire pool and gather inconsistent
     1083 + * datasets namely, those that don't have resume token and destroy them.
1058 1084   */
1059      -/* ARGSUSED */
1060      -int
1061      -dsl_destroy_inconsistent(const char *dsname, void *arg)
     1085 +void
     1086 +dsl_destroy_inconsistent(dsl_pool_t *dp)
1062 1087  {
1063      -        objset_t *os;
     1088 +        dsl_inconsistent_walker_cb_t walker;
     1089 +        dsl_inconsistent_node_t *ds_node;
1064 1090  
1065      -        if (dmu_objset_hold(dsname, FTAG, &os) == 0) {
1066      -                boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os));
     1091 +        mutex_init(&walker.lock, NULL, MUTEX_DEFAULT, NULL);
     1092 +        list_create(&walker.list, sizeof (dsl_inconsistent_node_t),
     1093 +            offsetof(dsl_inconsistent_node_t, node));
1067 1094  
     1095 +        VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
     1096 +                dsl_collect_inconsistent_datasets_cb,
     1097 +            &walker, DS_FIND_CHILDREN));
     1098 +
     1099 +        while ((ds_node = list_remove_head(&walker.list)) != NULL) {
     1100 +                (void) dsl_destroy_head(ds_node->name);
     1101 +                kmem_free(ds_node, sizeof (dsl_inconsistent_node_t));
     1102 +        }
     1103 +
     1104 +        list_destroy(&walker.list);
     1105 +        mutex_destroy(&walker.lock);
     1106 +}
     1107 +
     1108 +typedef struct {
     1109 +        const char *from_ds;
     1110 +        boolean_t defer;
     1111 +} dmu_destroy_atomically_arg_t;
     1112 +
     1113 +static int
     1114 +dsl_destroy_atomically_sync(void *arg, dmu_tx_t *tx)
     1115 +{
     1116 +        dmu_destroy_atomically_arg_t *ddaa = arg;
     1117 +        boolean_t defer = ddaa->defer;
     1118 +        dsl_pool_t *dp = dmu_tx_pool(tx);
     1119 +        zfs_ds_collector_entry_t *tail;
     1120 +        list_t namestack;
     1121 +        int err = 0;
     1122 +
     1123 +        /* do not perfrom checks in ioctl */
     1124 +        if (!dmu_tx_is_syncing(tx))
     1125 +                return (0);
     1126 +
     1127 +        ASSERT(dsl_pool_config_held(dp));
     1128 +
     1129 +        if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY))
     1130 +                return (SET_ERROR(ENOTSUP));
     1131 +
     1132 +        /* It is possible than autosnap watches the DS */
     1133 +        if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_WBC)) {
     1134 +                objset_t *os = NULL;
     1135 +                dsl_dataset_t *ds = NULL;
     1136 +
     1137 +                err = dsl_dataset_hold(dp, ddaa->from_ds, FTAG, &ds);
     1138 +                if (err != 0)
     1139 +                        return (err);
     1140 +
     1141 +                err = dmu_objset_from_ds(ds, &os);
     1142 +                if (err != 0) {
     1143 +                        dsl_dataset_rele(ds, FTAG);
     1144 +                        return (err);
     1145 +                }
     1146 +
     1147 +                if (!dmu_objset_is_snapshot(os)) {
     1148 +                        wbc_process_objset(spa_get_wbc_data(dp->dp_spa),
     1149 +                            os, B_TRUE);
     1150 +                }
     1151 +
     1152 +                dsl_dataset_rele(ds, FTAG);
     1153 +        }
     1154 +
     1155 +        /* initialize the stack of datasets */
     1156 +        list_create(&namestack, sizeof (zfs_ds_collector_entry_t),
     1157 +            offsetof(zfs_ds_collector_entry_t, node));
     1158 +        tail = dsl_dataset_collector_cache_alloc();
     1159 +
     1160 +        /* push the head */
     1161 +        tail->cookie = 0;
     1162 +        tail->cookie_is_snap = B_FALSE;
     1163 +        (void) strcpy(tail->name, ddaa->from_ds);
     1164 +        list_insert_tail(&namestack, tail);
     1165 +
     1166 +        /* the head is processed at the very end and after all is done */
     1167 +        while (err == 0 && ((tail = list_tail(&namestack)) != NULL)) {
     1168 +                zfs_ds_collector_entry_t *el;
     1169 +                objset_t *os;
     1170 +                dsl_dataset_t *ds;
     1171 +                char *p;
     1172 +
     1173 +                /* init new entry */
     1174 +                el = dsl_dataset_collector_cache_alloc();
     1175 +                el->cookie = 0;
     1176 +                el->cookie_is_snap = B_FALSE;
     1177 +                (void) strcpy(el->name, tail->name);
     1178 +                p = el->name + strlen(el->name);
     1179 +
     1180 +                /* hold the current dataset to traverse its children */
     1181 +                err = dsl_dataset_hold(dp, tail->name, FTAG, &ds);
     1182 +                if (err != 0) {
     1183 +                        dsl_dataset_collector_cache_free(el);
     1184 +                        break;
     1185 +                }
     1186 +
     1187 +                err  = dmu_objset_from_ds(ds, &os);
     1188 +                if (err != 0) {
     1189 +                        dsl_dataset_rele(ds, FTAG);
     1190 +                        dsl_dataset_collector_cache_free(el);
     1191 +                        break;
     1192 +                }
     1193 +
     1194 +                if (dmu_objset_is_snapshot(os)) {
     1195 +                        /* traverse clones for snapshots */
     1196 +                        err = dmu_clone_list_next(os, MAXNAMELEN,
     1197 +                            el->name, NULL, &tail->cookie);
     1198 +                } else {
     1199 +                        /* for filesystems traverse fs first, then snaps */
     1200 +                        if (!tail->cookie_is_snap) {
     1201 +                                *p++ = '/';
     1202 +                                do {
     1203 +                                        *p = '\0';
     1204 +                                        err = dmu_dir_list_next(os,
     1205 +                                            MAXNAMELEN - (p - el->name),
     1206 +                                            p, NULL, &tail->cookie);
     1207 +                                } while (err == 0 &&
     1208 +                                    dataset_name_hidden(el->name));
     1209 +
     1210 +                                /* no more fs, move to snapshots */
     1211 +                                if (err == ENOENT) {
     1212 +                                        *(--p) = '\0';
     1213 +                                        tail->cookie_is_snap = 1;
     1214 +                                        tail->cookie = 0;
     1215 +                                        err = 0;
     1216 +                                }
     1217 +                        }
     1218 +
     1219 +                        if (err == 0 && tail->cookie_is_snap) {
     1220 +                                *p++ = '@';
     1221 +                                *p = '\0';
     1222 +                                err = dmu_snapshot_list_next(os,
     1223 +                                    MAXNAMELEN - (p - el->name),
     1224 +                                    p, NULL, &tail->cookie, NULL);
     1225 +                        }
     1226 +                }
     1227 +
     1228 +                if (err == 0) {
     1229 +                        /* a children found, add it and continue */
     1230 +                        list_insert_tail(&namestack, el);
     1231 +                        dsl_dataset_rele(ds, FTAG);
     1232 +                        continue;
     1233 +                }
     1234 +
     1235 +                dsl_dataset_collector_cache_free(el);
     1236 +
     1237 +                if (err != ENOENT) {
     1238 +                        dsl_dataset_rele(ds, FTAG);
     1239 +                        break;
     1240 +                }
     1241 +
1068 1242                  /*
1069      -                 * If the dataset is inconsistent because a resumable receive
1070      -                 * has failed, then do not destroy it.
     1243 +                 * There are no more children of the dataset, pop it from stack
     1244 +                 * and destroy it
1071 1245                   */
1072      -                if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os)))
1073      -                        need_destroy = B_FALSE;
1074 1246  
1075      -                dmu_objset_rele(os, FTAG);
1076      -                if (need_destroy)
1077      -                        (void) dsl_destroy_head(dsname);
     1247 +                err = 0;
     1248 +
     1249 +                list_remove(&namestack, tail);
     1250 +
     1251 +                if (dmu_objset_is_snapshot(os)) {
     1252 +                        err = dsl_destroy_snapshot_check_impl(ds, defer);
     1253 +                        if (err == 0)
     1254 +                                dsl_destroy_snapshot_sync_impl(ds, defer, tx);
     1255 +                } else if (strchr(tail->name, '/') != NULL) {
     1256 +                        err = dsl_destroy_head_check_impl(ds, 0);
     1257 +                        if (err == 0)
     1258 +                                dsl_destroy_head_sync_impl(ds, tx);
     1259 +                }
     1260 +
     1261 +                dsl_dataset_rele(ds, FTAG);
     1262 +                dsl_dataset_collector_cache_free(tail);
1078 1263          }
1079      -        return (0);
     1264 +
     1265 +        if (err != 0) {
     1266 +                while ((tail = list_remove_tail(&namestack)) != NULL)
     1267 +                        dsl_dataset_collector_cache_free(tail);
     1268 +        }
     1269 +
     1270 +        ASSERT(list_head(&namestack) == NULL);
     1271 +
     1272 +        list_destroy(&namestack);
     1273 +
     1274 +        return (err);
     1275 +}
     1276 +
     1277 +/*ARGSUSED*/
     1278 +void
     1279 +dsl_destroy_atomically_sync_dummy(void *arg, dmu_tx_t *tx)
     1280 +{
     1281 +}
     1282 +
     1283 +int
     1284 +dsl_destroy_atomically(const char *name, boolean_t defer)
     1285 +{
     1286 +        dmu_destroy_atomically_arg_t ddaa;
     1287 +
     1288 +        ddaa.from_ds = name;
     1289 +        ddaa.defer = defer;
     1290 +
     1291 +        return (dsl_sync_task(name, dsl_destroy_atomically_sync,
     1292 +            dsl_destroy_atomically_sync_dummy, &ddaa, 0, ZFS_SPACE_CHECK_NONE));
1080 1293  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX