153089ab7Seschrock /* 253089ab7Seschrock * CDDL HEADER START 353089ab7Seschrock * 453089ab7Seschrock * The contents of this file are subject to the terms of the 553089ab7Seschrock * Common Development and Distribution License (the "License"). 653089ab7Seschrock * You may not use this file except in compliance with the License. 753089ab7Seschrock * 853089ab7Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 953089ab7Seschrock * or http://www.opensolaris.org/os/licensing. 1053089ab7Seschrock * See the License for the specific language governing permissions 1153089ab7Seschrock * and limitations under the License. 1253089ab7Seschrock * 1353089ab7Seschrock * When distributing Covered Code, include this CDDL HEADER in each 1453089ab7Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1553089ab7Seschrock * If applicable, add the following below this CDDL HEADER, with the 1653089ab7Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 1753089ab7Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 1853089ab7Seschrock * 1953089ab7Seschrock * CDDL HEADER END 2053089ab7Seschrock */ 2153089ab7Seschrock 2253089ab7Seschrock /* 2343466aaeSMax Grossman * Copyright (c) 2013 by Delphix. All rights reserved. 2453089ab7Seschrock */ 2553089ab7Seschrock 2653089ab7Seschrock #include <sys/arc.h> 2753089ab7Seschrock #include <sys/bptree.h> 2853089ab7Seschrock #include <sys/dmu.h> 2953089ab7Seschrock #include <sys/dmu_objset.h> 3053089ab7Seschrock #include <sys/dmu_tx.h> 3153089ab7Seschrock #include <sys/dmu_traverse.h> 3253089ab7Seschrock #include <sys/dsl_dataset.h> 3353089ab7Seschrock #include <sys/dsl_dir.h> 3453089ab7Seschrock #include <sys/dsl_pool.h> 3553089ab7Seschrock #include <sys/dnode.h> 3653089ab7Seschrock #include <sys/refcount.h> 3753089ab7Seschrock #include <sys/spa.h> 3853089ab7Seschrock 3953089ab7Seschrock /* 4053089ab7Seschrock * A bptree is a queue of root block pointers from destroyed datasets. When a 4153089ab7Seschrock * dataset is destroyed its root block pointer is put on the end of the pool's 4253089ab7Seschrock * bptree queue so the dataset's blocks can be freed asynchronously by 4353089ab7Seschrock * dsl_scan_sync. This allows the delete operation to finish without traversing 4453089ab7Seschrock * all the dataset's blocks. 4553089ab7Seschrock * 46f7170741SWill Andrews * Note that while bt_begin and bt_end are only ever incremented in this code, 4753089ab7Seschrock * they are effectively reset to 0 every time the entire bptree is freed because 4853089ab7Seschrock * the bptree's object is destroyed and re-created. 4953089ab7Seschrock */ 5053089ab7Seschrock 5153089ab7Seschrock struct bptree_args { 5253089ab7Seschrock bptree_phys_t *ba_phys; /* data in bonus buffer, dirtied if freeing */ 5353089ab7Seschrock boolean_t ba_free; /* true if freeing during traversal */ 5453089ab7Seschrock 5553089ab7Seschrock bptree_itor_t *ba_func; /* function to call for each blockpointer */ 5653089ab7Seschrock void *ba_arg; /* caller supplied argument to ba_func */ 5753089ab7Seschrock dmu_tx_t *ba_tx; /* caller supplied tx, NULL if not freeing */ 5853089ab7Seschrock } bptree_args_t; 5953089ab7Seschrock 6053089ab7Seschrock uint64_t 6153089ab7Seschrock bptree_alloc(objset_t *os, dmu_tx_t *tx) 6253089ab7Seschrock { 6353089ab7Seschrock uint64_t obj; 6453089ab7Seschrock dmu_buf_t *db; 6553089ab7Seschrock bptree_phys_t *bt; 6653089ab7Seschrock 6753089ab7Seschrock obj = dmu_object_alloc(os, DMU_OTN_UINT64_METADATA, 6853089ab7Seschrock SPA_MAXBLOCKSIZE, DMU_OTN_UINT64_METADATA, 6953089ab7Seschrock sizeof (bptree_phys_t), tx); 7053089ab7Seschrock 7153089ab7Seschrock /* 7253089ab7Seschrock * Bonus buffer contents are already initialized to 0, but for 7353089ab7Seschrock * readability we make it explicit. 7453089ab7Seschrock */ 75b420f3adSRichard Lowe VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db)); 7653089ab7Seschrock dmu_buf_will_dirty(db, tx); 7753089ab7Seschrock bt = db->db_data; 7853089ab7Seschrock bt->bt_begin = 0; 7953089ab7Seschrock bt->bt_end = 0; 8053089ab7Seschrock bt->bt_bytes = 0; 8153089ab7Seschrock bt->bt_comp = 0; 8253089ab7Seschrock bt->bt_uncomp = 0; 8353089ab7Seschrock dmu_buf_rele(db, FTAG); 8453089ab7Seschrock 8553089ab7Seschrock return (obj); 8653089ab7Seschrock } 8753089ab7Seschrock 8853089ab7Seschrock int 8953089ab7Seschrock bptree_free(objset_t *os, uint64_t obj, dmu_tx_t *tx) 9053089ab7Seschrock { 9153089ab7Seschrock dmu_buf_t *db; 9253089ab7Seschrock bptree_phys_t *bt; 9353089ab7Seschrock 94b420f3adSRichard Lowe VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db)); 9553089ab7Seschrock bt = db->db_data; 9653089ab7Seschrock ASSERT3U(bt->bt_begin, ==, bt->bt_end); 97fb09f5aaSMadhav Suresh ASSERT0(bt->bt_bytes); 98fb09f5aaSMadhav Suresh ASSERT0(bt->bt_comp); 99fb09f5aaSMadhav Suresh ASSERT0(bt->bt_uncomp); 10053089ab7Seschrock dmu_buf_rele(db, FTAG); 10153089ab7Seschrock 10253089ab7Seschrock return (dmu_object_free(os, obj, tx)); 10353089ab7Seschrock } 10453089ab7Seschrock 10553089ab7Seschrock void 10653089ab7Seschrock bptree_add(objset_t *os, uint64_t obj, blkptr_t *bp, uint64_t birth_txg, 10753089ab7Seschrock uint64_t bytes, uint64_t comp, uint64_t uncomp, dmu_tx_t *tx) 10853089ab7Seschrock { 10953089ab7Seschrock dmu_buf_t *db; 11053089ab7Seschrock bptree_phys_t *bt; 11153089ab7Seschrock bptree_entry_phys_t bte; 11253089ab7Seschrock 11353089ab7Seschrock /* 11453089ab7Seschrock * bptree objects are in the pool mos, therefore they can only be 11553089ab7Seschrock * modified in syncing context. Furthermore, this is only modified 11653089ab7Seschrock * by the sync thread, so no locking is necessary. 11753089ab7Seschrock */ 11853089ab7Seschrock ASSERT(dmu_tx_is_syncing(tx)); 11953089ab7Seschrock 120b420f3adSRichard Lowe VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db)); 12153089ab7Seschrock bt = db->db_data; 12253089ab7Seschrock 12353089ab7Seschrock bte.be_birth_txg = birth_txg; 12453089ab7Seschrock bte.be_bp = *bp; 12553089ab7Seschrock bzero(&bte.be_zb, sizeof (bte.be_zb)); 12653089ab7Seschrock dmu_write(os, obj, bt->bt_end * sizeof (bte), sizeof (bte), &bte, tx); 12753089ab7Seschrock 12853089ab7Seschrock dmu_buf_will_dirty(db, tx); 12953089ab7Seschrock bt->bt_end++; 13053089ab7Seschrock bt->bt_bytes += bytes; 13153089ab7Seschrock bt->bt_comp += comp; 13253089ab7Seschrock bt->bt_uncomp += uncomp; 13353089ab7Seschrock dmu_buf_rele(db, FTAG); 13453089ab7Seschrock } 13553089ab7Seschrock 13653089ab7Seschrock /* ARGSUSED */ 13753089ab7Seschrock static int 1381b912ec7SGeorge Wilson bptree_visit_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 13953089ab7Seschrock const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 14053089ab7Seschrock { 14153089ab7Seschrock int err; 14253089ab7Seschrock struct bptree_args *ba = arg; 14353089ab7Seschrock 14443466aaeSMax Grossman if (BP_IS_HOLE(bp)) 14553089ab7Seschrock return (0); 14653089ab7Seschrock 14753089ab7Seschrock err = ba->ba_func(ba->ba_arg, bp, ba->ba_tx); 14853089ab7Seschrock if (err == 0 && ba->ba_free) { 14953089ab7Seschrock ba->ba_phys->bt_bytes -= bp_get_dsize_sync(spa, bp); 15053089ab7Seschrock ba->ba_phys->bt_comp -= BP_GET_PSIZE(bp); 15153089ab7Seschrock ba->ba_phys->bt_uncomp -= BP_GET_UCSIZE(bp); 15253089ab7Seschrock } 15353089ab7Seschrock return (err); 15453089ab7Seschrock } 15553089ab7Seschrock 15653089ab7Seschrock int 15753089ab7Seschrock bptree_iterate(objset_t *os, uint64_t obj, boolean_t free, bptree_itor_t func, 15853089ab7Seschrock void *arg, dmu_tx_t *tx) 15953089ab7Seschrock { 16053089ab7Seschrock int err; 16153089ab7Seschrock uint64_t i; 16253089ab7Seschrock dmu_buf_t *db; 16353089ab7Seschrock struct bptree_args ba; 16453089ab7Seschrock 16553089ab7Seschrock ASSERT(!free || dmu_tx_is_syncing(tx)); 16653089ab7Seschrock 16753089ab7Seschrock err = dmu_bonus_hold(os, obj, FTAG, &db); 16853089ab7Seschrock if (err != 0) 16953089ab7Seschrock return (err); 17053089ab7Seschrock 17153089ab7Seschrock if (free) 17253089ab7Seschrock dmu_buf_will_dirty(db, tx); 17353089ab7Seschrock 17453089ab7Seschrock ba.ba_phys = db->db_data; 17553089ab7Seschrock ba.ba_free = free; 17653089ab7Seschrock ba.ba_func = func; 17753089ab7Seschrock ba.ba_arg = arg; 17853089ab7Seschrock ba.ba_tx = tx; 17953089ab7Seschrock 18053089ab7Seschrock err = 0; 18153089ab7Seschrock for (i = ba.ba_phys->bt_begin; i < ba.ba_phys->bt_end; i++) { 18253089ab7Seschrock bptree_entry_phys_t bte; 183*8b36997aSMatthew Ahrens int flags = TRAVERSE_PREFETCH_METADATA | TRAVERSE_POST; 18453089ab7Seschrock 18553089ab7Seschrock ASSERT(!free || i == ba.ba_phys->bt_begin); 18653089ab7Seschrock 18753089ab7Seschrock err = dmu_read(os, obj, i * sizeof (bte), sizeof (bte), 18853089ab7Seschrock &bte, DMU_READ_NO_PREFETCH); 18953089ab7Seschrock if (err != 0) 19053089ab7Seschrock break; 19153089ab7Seschrock 192*8b36997aSMatthew Ahrens if (zfs_recover) 193*8b36997aSMatthew Ahrens flags |= TRAVERSE_HARD; 19453089ab7Seschrock err = traverse_dataset_destroyed(os->os_spa, &bte.be_bp, 195*8b36997aSMatthew Ahrens bte.be_birth_txg, &bte.be_zb, flags, 19653089ab7Seschrock bptree_visit_cb, &ba); 19753089ab7Seschrock if (free) { 198*8b36997aSMatthew Ahrens if (err == ERESTART) { 19953089ab7Seschrock /* save bookmark for future resume */ 20053089ab7Seschrock ASSERT3U(bte.be_zb.zb_objset, ==, 20153089ab7Seschrock ZB_DESTROYED_OBJSET); 202fb09f5aaSMadhav Suresh ASSERT0(bte.be_zb.zb_level); 20353089ab7Seschrock dmu_write(os, obj, i * sizeof (bte), 20453089ab7Seschrock sizeof (bte), &bte, tx); 20553089ab7Seschrock break; 20653089ab7Seschrock } 207*8b36997aSMatthew Ahrens if (err != 0) { 208*8b36997aSMatthew Ahrens /* 209*8b36997aSMatthew Ahrens * We can not properly handle an i/o 210*8b36997aSMatthew Ahrens * error, because the traversal code 211*8b36997aSMatthew Ahrens * does not know how to resume from an 212*8b36997aSMatthew Ahrens * arbitrary bookmark. 213*8b36997aSMatthew Ahrens */ 214*8b36997aSMatthew Ahrens zfs_panic_recover("error %u from " 215*8b36997aSMatthew Ahrens "traverse_dataset_destroyed()", err); 216*8b36997aSMatthew Ahrens } 217*8b36997aSMatthew Ahrens 218*8b36997aSMatthew Ahrens ba.ba_phys->bt_begin++; 219*8b36997aSMatthew Ahrens (void) dmu_free_range(os, obj, 220*8b36997aSMatthew Ahrens i * sizeof (bte), sizeof (bte), tx); 22153089ab7Seschrock } 22253089ab7Seschrock } 22353089ab7Seschrock 22453089ab7Seschrock ASSERT(!free || err != 0 || ba.ba_phys->bt_begin == ba.ba_phys->bt_end); 22553089ab7Seschrock 22653089ab7Seschrock /* if all blocks are free there should be no used space */ 22753089ab7Seschrock if (ba.ba_phys->bt_begin == ba.ba_phys->bt_end) { 228fb09f5aaSMadhav Suresh ASSERT0(ba.ba_phys->bt_bytes); 229fb09f5aaSMadhav Suresh ASSERT0(ba.ba_phys->bt_comp); 230fb09f5aaSMadhav Suresh ASSERT0(ba.ba_phys->bt_uncomp); 23153089ab7Seschrock } 23253089ab7Seschrock 23353089ab7Seschrock dmu_buf_rele(db, FTAG); 23453089ab7Seschrock 23553089ab7Seschrock return (err); 23653089ab7Seschrock } 237