]> git.proxmox.com Git - mirror_zfs-debian.git/blobdiff - module/zfs/dsl_dataset.c
Imported Upstream version 0.6.4.2
[mirror_zfs-debian.git] / module / zfs / dsl_dataset.c
index 7c4819bbcdadedf4f752035ac6f6853f72b51278..79cb6a3a25e591b97bf5171352e969b1fbeae975 100644 (file)
@@ -22,6 +22,7 @@
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014 RackTop Systems.
  */
 
 #include <sys/dmu_objset.h>
@@ -47,6 +48,7 @@
 #include <sys/dsl_deadlist.h>
 #include <sys/dsl_destroy.h>
 #include <sys/dsl_userhold.h>
+#include <sys/dsl_bookmark.h>
 
 #define        SWITCH64(x, y) \
        { \
@@ -121,7 +123,9 @@ int
 dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
     boolean_t async)
 {
-       int used, compressed, uncompressed;
+       int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
+       int compressed = BP_GET_PSIZE(bp);
+       int uncompressed = BP_GET_UCSIZE(bp);
 
        if (BP_IS_HOLE(bp))
                return (0);
@@ -129,11 +133,6 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
        ASSERT(dmu_tx_is_syncing(tx));
        ASSERT(bp->blk_birth <= tx->tx_txg);
 
-       used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
-       compressed = BP_GET_PSIZE(bp);
-       uncompressed = BP_GET_UCSIZE(bp);
-
-       ASSERT(used > 0);
        if (ds == NULL) {
                dsl_free(tx->tx_pool, tx->tx_txg, bp);
                dsl_pool_mos_diduse_space(tx->tx_pool,
@@ -231,7 +230,8 @@ boolean_t
 dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp,
     uint64_t blk_birth)
 {
-       if (blk_birth <= dsl_dataset_prev_snap_txg(ds))
+       if (blk_birth <= dsl_dataset_prev_snap_txg(ds) ||
+           (bp != NULL && BP_IS_HOLE(bp)))
                return (B_FALSE);
 
        ddt_prefetch(dsl_dataset_get_spa(ds), bp);
@@ -356,7 +356,7 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
 
        /* Make sure dsobj has the correct object type. */
        dmu_object_info_from_db(dbuf, &doi);
-       if (doi.doi_type != DMU_OT_DSL_DATASET) {
+       if (doi.doi_bonus_type != DMU_OT_DSL_DATASET) {
                dmu_buf_rele(dbuf, tag);
                return (SET_ERROR(EINVAL));
        }
@@ -365,7 +365,7 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
        if (ds == NULL) {
                dsl_dataset_t *winner = NULL;
 
-               ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_PUSHPAGE);
+               ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
                ds->ds_dbuf = dbuf;
                ds->ds_object = dsobj;
                ds->ds_phys = dbuf->db_data;
@@ -405,6 +405,14 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
                                    ds->ds_phys->ds_prev_snap_obj,
                                    ds, &ds->ds_prev);
                        }
+                       if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
+                               int zaperr = zap_lookup(mos, ds->ds_object,
+                                   DS_FIELD_BOOKMARK_NAMES,
+                                   sizeof (ds->ds_bookmarks), 1,
+                                   &ds->ds_bookmarks);
+                               if (zaperr != ENOENT)
+                                       VERIFY0(zaperr);
+                       }
                } else {
                        if (zfs_flags & ZFS_DEBUG_SNAPNAMES)
                                err = dsl_dataset_get_snapname(ds);
@@ -678,7 +686,13 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
                dsphys->ds_uncompressed_bytes =
                    origin->ds_phys->ds_uncompressed_bytes;
                dsphys->ds_bp = origin->ds_phys->ds_bp;
-               dsphys->ds_flags |= origin->ds_phys->ds_flags;
+
+               /*
+                * Inherit flags that describe the dataset's contents
+                * (INCONSISTENT) or properties (Case Insensitive).
+                */
+               dsphys->ds_flags |= origin->ds_phys->ds_flags &
+                   (DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
 
                dmu_buf_will_dirty(origin->ds_dbuf, tx);
                origin->ds_phys->ds_num_children++;
@@ -1371,7 +1385,7 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
         * Only trust it if it has the right number of entries.
         */
        if (ds->ds_phys->ds_next_clones_obj != 0) {
-               ASSERT0(zap_count(mos, ds->ds_phys->ds_next_clones_obj,
+               VERIFY0(zap_count(mos, ds->ds_phys->ds_next_clones_obj,
                    &count));
        }
        if (count != ds->ds_phys->ds_num_children - 1)
@@ -1517,7 +1531,7 @@ dsl_dataset_space(dsl_dataset_t *ds,
                else
                        *availbytesp = 0;
        }
-       *usedobjsp = ds->ds_phys->ds_bp.blk_fill;
+       *usedobjsp = BP_GET_FILL(&ds->ds_phys->ds_bp);
        *availobjsp = DN_MAX_OBJECT - *usedobjsp;
 }
 
@@ -1611,9 +1625,6 @@ static int
 dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
     dsl_dataset_t *hds, void *arg)
 {
-#ifdef _KERNEL
-       char *oldname, *newname;
-#endif
        dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
        dsl_dataset_t *ds;
        uint64_t val;
@@ -1640,18 +1651,6 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
        VERIFY0(zap_add(dp->dp_meta_objset, hds->ds_phys->ds_snapnames_zapobj,
            ds->ds_snapname, 8, 1, &ds->ds_object, tx));
 
-#ifdef _KERNEL
-       oldname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
-       newname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
-       snprintf(oldname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname,
-           ddrsa->ddrsa_oldsnapname);
-       snprintf(newname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname,
-           ddrsa->ddrsa_newsnapname);
-       zvol_rename_minors(oldname, newname);
-       kmem_free(newname, MAXPATHLEN);
-       kmem_free(oldname, MAXPATHLEN);
-#endif
-
        dsl_dataset_rele(ds, FTAG);
        return (0);
 }
@@ -1679,6 +1678,11 @@ int
 dsl_dataset_rename_snapshot(const char *fsname,
     const char *oldsnapname, const char *newsnapname, boolean_t recursive)
 {
+#ifdef _KERNEL
+       char *oldname, *newname;
+#endif
+       int error;
+
        dsl_dataset_rename_snapshot_arg_t ddrsa;
 
        ddrsa.ddrsa_fsname = fsname;
@@ -1686,8 +1690,21 @@ dsl_dataset_rename_snapshot(const char *fsname,
        ddrsa.ddrsa_newsnapname = newsnapname;
        ddrsa.ddrsa_recursive = recursive;
 
-       return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
-           dsl_dataset_rename_snapshot_sync, &ddrsa, 1));
+       error = dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
+           dsl_dataset_rename_snapshot_sync, &ddrsa, 1);
+
+       if (error)
+           return (SET_ERROR(error));
+
+#ifdef _KERNEL
+       oldname = kmem_asprintf("%s@%s", fsname, oldsnapname);
+       newname = kmem_asprintf("%s@%s", fsname, newsnapname);
+       zvol_rename_minors(oldname, newname);
+       strfree(newname);
+       strfree(oldname);
+#endif
+
+       return (0);
 }
 
 /*
@@ -1735,6 +1752,8 @@ dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
        dsl_dataset_t *ds;
        int64_t unused_refres_delta;
        int error;
+       nvpair_t *pair;
+       nvlist_t *proprequest, *bookmarks;
 
        error = dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds);
        if (error != 0)
@@ -1752,6 +1771,28 @@ dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
                return (SET_ERROR(EINVAL));
        }
 
+       /* must not have any bookmarks after the most recent snapshot */
+       proprequest = fnvlist_alloc();
+       fnvlist_add_boolean(proprequest, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+       bookmarks = fnvlist_alloc();
+       error = dsl_get_bookmarks_impl(ds, proprequest, bookmarks);
+       fnvlist_free(proprequest);
+       if (error != 0)
+               return (error);
+       for (pair = nvlist_next_nvpair(bookmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(bookmarks, pair)) {
+               nvlist_t *valuenv =
+                   fnvlist_lookup_nvlist(fnvpair_value_nvlist(pair),
+                   zfs_prop_to_name(ZFS_PROP_CREATETXG));
+               uint64_t createtxg = fnvlist_lookup_uint64(valuenv, "value");
+               if (createtxg > ds->ds_phys->ds_prev_snap_txg) {
+                       fnvlist_free(bookmarks);
+                       dsl_dataset_rele(ds, FTAG);
+                       return (SET_ERROR(EEXIST));
+               }
+       }
+       fnvlist_free(bookmarks);
+
        error = dsl_dataset_handoff_check(ds, ddra->ddra_owner, tx);
        if (error != 0) {
                dsl_dataset_rele(ds, FTAG);
@@ -2221,7 +2262,7 @@ snaplist_make(dsl_pool_t *dp,
                if (first_obj == 0)
                        first_obj = ds->ds_dir->dd_phys->dd_origin_obj;
 
-               snap = kmem_alloc(sizeof (*snap), KM_PUSHPAGE);
+               snap = kmem_alloc(sizeof (*snap), KM_SLEEP);
                snap->ds = ds;
                list_insert_tail(l, snap);
                obj = ds->ds_phys->ds_prev_snap_obj;
@@ -2973,9 +3014,12 @@ dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
  * 'earlier' is before 'later'.  Or 'earlier' could be the origin of
  * 'later's filesystem.  Or 'earlier' could be an older snapshot in the origin's
  * filesystem.  Or 'earlier' could be the origin's origin.
+ *
+ * If non-zero, earlier_txg is used instead of earlier's ds_creation_txg.
  */
 boolean_t
-dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
+dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
+       uint64_t earlier_txg)
 {
        dsl_pool_t *dp = later->ds_dir->dd_pool;
        int error;
@@ -2983,9 +3027,13 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
        dsl_dataset_t *origin;
 
        ASSERT(dsl_pool_config_held(dp));
+       ASSERT(dsl_dataset_is_snapshot(earlier) || earlier_txg != 0);
 
-       if (earlier->ds_phys->ds_creation_txg >=
-           later->ds_phys->ds_creation_txg)
+       if (earlier_txg == 0)
+               earlier_txg = earlier->ds_phys->ds_creation_txg;
+
+       if (dsl_dataset_is_snapshot(later) &&
+           earlier_txg >= later->ds_phys->ds_creation_txg)
                return (B_FALSE);
 
        if (later->ds_dir == earlier->ds_dir)
@@ -2999,11 +3047,19 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
            later->ds_dir->dd_phys->dd_origin_obj, FTAG, &origin);
        if (error != 0)
                return (B_FALSE);
-       ret = dsl_dataset_is_before(origin, earlier);
+       ret = dsl_dataset_is_before(origin, earlier, earlier_txg);
        dsl_dataset_rele(origin, FTAG);
        return (ret);
 }
 
+
+void
+dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(dsl_dataset_hold);
 EXPORT_SYMBOL(dsl_dataset_hold_obj);