Home | History | Annotate | Download | only in zfs
      1    789    ahrens /*
      2    789    ahrens  * CDDL HEADER START
      3    789    ahrens  *
      4    789    ahrens  * The contents of this file are subject to the terms of the
      5   1544  eschrock  * Common Development and Distribution License (the "License").
      6   1544  eschrock  * You may not use this file except in compliance with the License.
      7    789    ahrens  *
      8    789    ahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9    789    ahrens  * or http://www.opensolaris.org/os/licensing.
     10    789    ahrens  * See the License for the specific language governing permissions
     11    789    ahrens  * and limitations under the License.
     12    789    ahrens  *
     13    789    ahrens  * When distributing Covered Code, include this CDDL HEADER in each
     14    789    ahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15    789    ahrens  * If applicable, add the following below this CDDL HEADER, with the
     16    789    ahrens  * fields enclosed by brackets "[]" replaced with your own identifying
     17    789    ahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
     18    789    ahrens  *
     19    789    ahrens  * CDDL HEADER END
     20    789    ahrens  */
     21    789    ahrens /*
     22   9480    George  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23    789    ahrens  * Use is subject to license terms.
     24    789    ahrens  */
     25    789    ahrens 
     26    789    ahrens #include <sys/zfs_context.h>
     27    789    ahrens #include <sys/spa.h>
     28    789    ahrens #include <sys/dmu.h>
     29   1732   bonwick #include <sys/zio.h>
     30    789    ahrens #include <sys/space_map.h>
     31    789    ahrens 
     32    789    ahrens /*
     33    789    ahrens  * Space map routines.
     34    789    ahrens  * NOTE: caller is responsible for all locking.
     35    789    ahrens  */
     36    789    ahrens static int
     37    789    ahrens space_map_seg_compare(const void *x1, const void *x2)
     38    789    ahrens {
     39    789    ahrens 	const space_seg_t *s1 = x1;
     40    789    ahrens 	const space_seg_t *s2 = x2;
     41    789    ahrens 
     42    789    ahrens 	if (s1->ss_start < s2->ss_start) {
     43    789    ahrens 		if (s1->ss_end > s2->ss_start)
     44    789    ahrens 			return (0);
     45    789    ahrens 		return (-1);
     46    789    ahrens 	}
     47    789    ahrens 	if (s1->ss_start > s2->ss_start) {
     48    789    ahrens 		if (s1->ss_start < s2->ss_end)
     49    789    ahrens 			return (0);
     50    789    ahrens 		return (1);
     51    789    ahrens 	}
     52    789    ahrens 	return (0);
     53    789    ahrens }
     54    789    ahrens 
     55    789    ahrens void
     56   1732   bonwick space_map_create(space_map_t *sm, uint64_t start, uint64_t size, uint8_t shift,
     57    789    ahrens 	kmutex_t *lp)
     58    789    ahrens {
     59   1732   bonwick 	bzero(sm, sizeof (*sm));
     60   1732   bonwick 
     61   8214   Ricardo 	cv_init(&sm->sm_load_cv, NULL, CV_DEFAULT, NULL);
     62   8214   Ricardo 
     63    789    ahrens 	avl_create(&sm->sm_root, space_map_seg_compare,
     64    789    ahrens 	    sizeof (space_seg_t), offsetof(struct space_seg, ss_node));
     65   1732   bonwick 
     66    789    ahrens 	sm->sm_start = start;
     67    789    ahrens 	sm->sm_size = size;
     68    789    ahrens 	sm->sm_shift = shift;
     69    789    ahrens 	sm->sm_lock = lp;
     70    789    ahrens }
     71    789    ahrens 
     72    789    ahrens void
     73    789    ahrens space_map_destroy(space_map_t *sm)
     74    789    ahrens {
     75   1732   bonwick 	ASSERT(!sm->sm_loaded && !sm->sm_loading);
     76    789    ahrens 	VERIFY3U(sm->sm_space, ==, 0);
     77    789    ahrens 	avl_destroy(&sm->sm_root);
     78   8214   Ricardo 	cv_destroy(&sm->sm_load_cv);
     79    789    ahrens }
     80    789    ahrens 
     81    789    ahrens void
     82    789    ahrens space_map_add(space_map_t *sm, uint64_t start, uint64_t size)
     83    789    ahrens {
     84    789    ahrens 	avl_index_t where;
     85    789    ahrens 	space_seg_t ssearch, *ss_before, *ss_after, *ss;
     86    789    ahrens 	uint64_t end = start + size;
     87    789    ahrens 	int merge_before, merge_after;
     88    789    ahrens 
     89    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
     90    789    ahrens 	VERIFY(size != 0);
     91    789    ahrens 	VERIFY3U(start, >=, sm->sm_start);
     92   1732   bonwick 	VERIFY3U(end, <=, sm->sm_start + sm->sm_size);
     93    789    ahrens 	VERIFY(sm->sm_space + size <= sm->sm_size);
     94    789    ahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
     95    789    ahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
     96    789    ahrens 
     97    789    ahrens 	ssearch.ss_start = start;
     98    789    ahrens 	ssearch.ss_end = end;
     99    789    ahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
    100    789    ahrens 
    101   3713    ahrens 	if (ss != NULL && ss->ss_start <= start && ss->ss_end >= end) {
    102   3713    ahrens 		zfs_panic_recover("zfs: allocating allocated segment"
    103   3713    ahrens 		    "(offset=%llu size=%llu)\n",
    104   3713    ahrens 		    (longlong_t)start, (longlong_t)size);
    105   3713    ahrens 		return;
    106   3713    ahrens 	}
    107   3713    ahrens 
    108    789    ahrens 	/* Make sure we don't overlap with either of our neighbors */
    109    789    ahrens 	VERIFY(ss == NULL);
    110    789    ahrens 
    111    789    ahrens 	ss_before = avl_nearest(&sm->sm_root, where, AVL_BEFORE);
    112    789    ahrens 	ss_after = avl_nearest(&sm->sm_root, where, AVL_AFTER);
    113    789    ahrens 
    114    789    ahrens 	merge_before = (ss_before != NULL && ss_before->ss_end == start);
    115    789    ahrens 	merge_after = (ss_after != NULL && ss_after->ss_start == end);
    116    789    ahrens 
    117    789    ahrens 	if (merge_before && merge_after) {
    118    789    ahrens 		avl_remove(&sm->sm_root, ss_before);
    119   9480    George 		if (sm->sm_pp_root) {
    120   9480    George 			avl_remove(sm->sm_pp_root, ss_before);
    121   9480    George 			avl_remove(sm->sm_pp_root, ss_after);
    122   9480    George 		}
    123    789    ahrens 		ss_after->ss_start = ss_before->ss_start;
    124    789    ahrens 		kmem_free(ss_before, sizeof (*ss_before));
    125   9480    George 		ss = ss_after;
    126    789    ahrens 	} else if (merge_before) {
    127    789    ahrens 		ss_before->ss_end = end;
    128   9480    George 		if (sm->sm_pp_root)
    129   9480    George 			avl_remove(sm->sm_pp_root, ss_before);
    130   9480    George 		ss = ss_before;
    131    789    ahrens 	} else if (merge_after) {
    132    789    ahrens 		ss_after->ss_start = start;
    133   9480    George 		if (sm->sm_pp_root)
    134   9480    George 			avl_remove(sm->sm_pp_root, ss_after);
    135   9480    George 		ss = ss_after;
    136    789    ahrens 	} else {
    137    789    ahrens 		ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
    138    789    ahrens 		ss->ss_start = start;
    139    789    ahrens 		ss->ss_end = end;
    140    789    ahrens 		avl_insert(&sm->sm_root, ss, where);
    141    789    ahrens 	}
    142   9480    George 
    143   9480    George 	if (sm->sm_pp_root)
    144   9480    George 		avl_add(sm->sm_pp_root, ss);
    145    789    ahrens 
    146    789    ahrens 	sm->sm_space += size;
    147    789    ahrens }
    148    789    ahrens 
    149    789    ahrens void
    150    789    ahrens space_map_remove(space_map_t *sm, uint64_t start, uint64_t size)
    151    789    ahrens {
    152    789    ahrens 	avl_index_t where;
    153    789    ahrens 	space_seg_t ssearch, *ss, *newseg;
    154    789    ahrens 	uint64_t end = start + size;
    155    789    ahrens 	int left_over, right_over;
    156    789    ahrens 
    157    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
    158    789    ahrens 	VERIFY(size != 0);
    159    789    ahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
    160    789    ahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
    161    789    ahrens 
    162    789    ahrens 	ssearch.ss_start = start;
    163    789    ahrens 	ssearch.ss_end = end;
    164    789    ahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
    165    789    ahrens 
    166    789    ahrens 	/* Make sure we completely overlap with someone */
    167   3713    ahrens 	if (ss == NULL) {
    168   3713    ahrens 		zfs_panic_recover("zfs: freeing free segment "
    169   3713    ahrens 		    "(offset=%llu size=%llu)",
    170   3713    ahrens 		    (longlong_t)start, (longlong_t)size);
    171   3713    ahrens 		return;
    172   3713    ahrens 	}
    173    789    ahrens 	VERIFY3U(ss->ss_start, <=, start);
    174    789    ahrens 	VERIFY3U(ss->ss_end, >=, end);
    175    789    ahrens 	VERIFY(sm->sm_space - size <= sm->sm_size);
    176    789    ahrens 
    177    789    ahrens 	left_over = (ss->ss_start != start);
    178    789    ahrens 	right_over = (ss->ss_end != end);
    179    789    ahrens 
    180   9480    George 	if (sm->sm_pp_root)
    181   9480    George 		avl_remove(sm->sm_pp_root, ss);
    182   9480    George 
    183    789    ahrens 	if (left_over && right_over) {
    184    789    ahrens 		newseg = kmem_alloc(sizeof (*newseg), KM_SLEEP);
    185    789    ahrens 		newseg->ss_start = end;
    186    789    ahrens 		newseg->ss_end = ss->ss_end;
    187    789    ahrens 		ss->ss_end = start;
    188    789    ahrens 		avl_insert_here(&sm->sm_root, newseg, ss, AVL_AFTER);
    189   9480    George 		if (sm->sm_pp_root)
    190   9480    George 			avl_add(sm->sm_pp_root, newseg);
    191    789    ahrens 	} else if (left_over) {
    192    789    ahrens 		ss->ss_end = start;
    193    789    ahrens 	} else if (right_over) {
    194    789    ahrens 		ss->ss_start = end;
    195    789    ahrens 	} else {
    196    789    ahrens 		avl_remove(&sm->sm_root, ss);
    197    789    ahrens 		kmem_free(ss, sizeof (*ss));
    198   9480    George 		ss = NULL;
    199    789    ahrens 	}
    200   9480    George 
    201   9480    George 	if (sm->sm_pp_root && ss != NULL)
    202   9480    George 		avl_add(sm->sm_pp_root, ss);
    203    789    ahrens 
    204    789    ahrens 	sm->sm_space -= size;
    205    789    ahrens }
    206    789    ahrens 
    207   8241      Jeff boolean_t
    208    789    ahrens space_map_contains(space_map_t *sm, uint64_t start, uint64_t size)
    209    789    ahrens {
    210    789    ahrens 	avl_index_t where;
    211    789    ahrens 	space_seg_t ssearch, *ss;
    212    789    ahrens 	uint64_t end = start + size;
    213    789    ahrens 
    214    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
    215    789    ahrens 	VERIFY(size != 0);
    216    789    ahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
    217    789    ahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
    218    789    ahrens 
    219    789    ahrens 	ssearch.ss_start = start;
    220    789    ahrens 	ssearch.ss_end = end;
    221    789    ahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
    222    789    ahrens 
    223    789    ahrens 	return (ss != NULL && ss->ss_start <= start && ss->ss_end >= end);
    224    789    ahrens }
    225    789    ahrens 
    226    789    ahrens void
    227    789    ahrens space_map_vacate(space_map_t *sm, space_map_func_t *func, space_map_t *mdest)
    228    789    ahrens {
    229    789    ahrens 	space_seg_t *ss;
    230    789    ahrens 	void *cookie = NULL;
    231    789    ahrens 
    232    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
    233    789    ahrens 
    234    789    ahrens 	while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
    235    789    ahrens 		if (func != NULL)
    236    789    ahrens 			func(mdest, ss->ss_start, ss->ss_end - ss->ss_start);
    237    789    ahrens 		kmem_free(ss, sizeof (*ss));
    238    789    ahrens 	}
    239    789    ahrens 	sm->sm_space = 0;
    240    789    ahrens }
    241    789    ahrens 
    242    789    ahrens void
    243   1732   bonwick space_map_walk(space_map_t *sm, space_map_func_t *func, space_map_t *mdest)
    244    789    ahrens {
    245    789    ahrens 	space_seg_t *ss;
    246    789    ahrens 
    247   8241      Jeff 	ASSERT(MUTEX_HELD(sm->sm_lock));
    248   8241      Jeff 
    249    789    ahrens 	for (ss = avl_first(&sm->sm_root); ss; ss = AVL_NEXT(&sm->sm_root, ss))
    250    789    ahrens 		func(mdest, ss->ss_start, ss->ss_end - ss->ss_start);
    251    789    ahrens }
    252    789    ahrens 
    253   1732   bonwick /*
    254   1732   bonwick  * Wait for any in-progress space_map_load() to complete.
    255   1732   bonwick  */
    256   1732   bonwick void
    257   1732   bonwick space_map_load_wait(space_map_t *sm)
    258   1732   bonwick {
    259   1732   bonwick 	ASSERT(MUTEX_HELD(sm->sm_lock));
    260   1732   bonwick 
    261  10922      Jeff 	while (sm->sm_loading) {
    262  10922      Jeff 		ASSERT(!sm->sm_loaded);
    263   1732   bonwick 		cv_wait(&sm->sm_load_cv, sm->sm_lock);
    264  10922      Jeff 	}
    265   1732   bonwick }
    266   1732   bonwick 
    267   1732   bonwick /*
    268   1732   bonwick  * Note: space_map_load() will drop sm_lock across dmu_read() calls.
    269   1732   bonwick  * The caller must be OK with this.
    270   1732   bonwick  */
    271    789    ahrens int
    272   1732   bonwick space_map_load(space_map_t *sm, space_map_ops_t *ops, uint8_t maptype,
    273   1732   bonwick 	space_map_obj_t *smo, objset_t *os)
    274    789    ahrens {
    275    789    ahrens 	uint64_t *entry, *entry_map, *entry_map_end;
    276   3761     billm 	uint64_t bufsize, size, offset, end, space;
    277    789    ahrens 	uint64_t mapstart = sm->sm_start;
    278   5329   gw25295 	int error = 0;
    279    789    ahrens 
    280    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
    281  10921       Tim 	ASSERT(!sm->sm_loaded);
    282  10921       Tim 	ASSERT(!sm->sm_loading);
    283   1732   bonwick 
    284   1732   bonwick 	sm->sm_loading = B_TRUE;
    285   3761     billm 	end = smo->smo_objsize;
    286   3761     billm 	space = smo->smo_alloc;
    287   1732   bonwick 
    288   1732   bonwick 	ASSERT(sm->sm_ops == NULL);
    289    789    ahrens 	VERIFY3U(sm->sm_space, ==, 0);
    290    789    ahrens 
    291    789    ahrens 	if (maptype == SM_FREE) {
    292    789    ahrens 		space_map_add(sm, sm->sm_start, sm->sm_size);
    293    789    ahrens 		space = sm->sm_size - space;
    294    789    ahrens 	}
    295   1732   bonwick 
    296   1732   bonwick 	bufsize = 1ULL << SPACE_MAP_BLOCKSHIFT;
    297   1732   bonwick 	entry_map = zio_buf_alloc(bufsize);
    298   1732   bonwick 
    299   1732   bonwick 	mutex_exit(sm->sm_lock);
    300   1732   bonwick 	if (end > bufsize)
    301   1732   bonwick 		dmu_prefetch(os, smo->smo_object, bufsize, end - bufsize);
    302   1732   bonwick 	mutex_enter(sm->sm_lock);
    303    789    ahrens 
    304    789    ahrens 	for (offset = 0; offset < end; offset += bufsize) {
    305    789    ahrens 		size = MIN(end - offset, bufsize);
    306    789    ahrens 		VERIFY(P2PHASE(size, sizeof (uint64_t)) == 0);
    307    789    ahrens 		VERIFY(size != 0);
    308    789    ahrens 
    309    789    ahrens 		dprintf("object=%llu  offset=%llx  size=%llx\n",
    310    789    ahrens 		    smo->smo_object, offset, size);
    311   1732   bonwick 
    312   1732   bonwick 		mutex_exit(sm->sm_lock);
    313   9512      Neil 		error = dmu_read(os, smo->smo_object, offset, size, entry_map,
    314   9512      Neil 		    DMU_READ_PREFETCH);
    315   1732   bonwick 		mutex_enter(sm->sm_lock);
    316   5329   gw25295 		if (error != 0)
    317   6227  vl146290 			break;
    318    789    ahrens 
    319    789    ahrens 		entry_map_end = entry_map + (size / sizeof (uint64_t));
    320    789    ahrens 		for (entry = entry_map; entry < entry_map_end; entry++) {
    321    789    ahrens 			uint64_t e = *entry;
    322    789    ahrens 
    323    789    ahrens 			if (SM_DEBUG_DECODE(e))		/* Skip debug entries */
    324    789    ahrens 				continue;
    325    789    ahrens 
    326    789    ahrens 			(SM_TYPE_DECODE(e) == maptype ?
    327    789    ahrens 			    space_map_add : space_map_remove)(sm,
    328    789    ahrens 			    (SM_OFFSET_DECODE(e) << sm->sm_shift) + mapstart,
    329    789    ahrens 			    SM_RUN_DECODE(e) << sm->sm_shift);
    330    789    ahrens 		}
    331    789    ahrens 	}
    332    789    ahrens 
    333   6227  vl146290 	if (error == 0) {
    334   6227  vl146290 		VERIFY3U(sm->sm_space, ==, space);
    335   6227  vl146290 
    336   6227  vl146290 		sm->sm_loaded = B_TRUE;
    337   6227  vl146290 		sm->sm_ops = ops;
    338   6227  vl146290 		if (ops != NULL)
    339   6227  vl146290 			ops->smop_load(sm);
    340   6227  vl146290 	} else {
    341   6227  vl146290 		space_map_vacate(sm, NULL, NULL);
    342   6227  vl146290 	}
    343   6227  vl146290 
    344   1732   bonwick 	zio_buf_free(entry_map, bufsize);
    345   1732   bonwick 
    346   1732   bonwick 	sm->sm_loading = B_FALSE;
    347   1732   bonwick 
    348   1732   bonwick 	cv_broadcast(&sm->sm_load_cv);
    349    789    ahrens 
    350   5329   gw25295 	return (error);
    351    789    ahrens }
    352    789    ahrens 
    353    789    ahrens void
    354   1732   bonwick space_map_unload(space_map_t *sm)
    355   1732   bonwick {
    356   1732   bonwick 	ASSERT(MUTEX_HELD(sm->sm_lock));
    357   1732   bonwick 
    358   1732   bonwick 	if (sm->sm_loaded && sm->sm_ops != NULL)
    359   1732   bonwick 		sm->sm_ops->smop_unload(sm);
    360   1732   bonwick 
    361   1732   bonwick 	sm->sm_loaded = B_FALSE;
    362   1732   bonwick 	sm->sm_ops = NULL;
    363   1732   bonwick 
    364   1732   bonwick 	space_map_vacate(sm, NULL, NULL);
    365   9480    George }
    366   9480    George 
    367   9480    George uint64_t
    368   9480    George space_map_maxsize(space_map_t *sm)
    369   9480    George {
    370  11146    George 	ASSERT(sm->sm_ops != NULL);
    371  11146    George 	return (sm->sm_ops->smop_max(sm));
    372   1732   bonwick }
    373   1732   bonwick 
    374   1732   bonwick uint64_t
    375   1732   bonwick space_map_alloc(space_map_t *sm, uint64_t size)
    376   1732   bonwick {
    377   1732   bonwick 	uint64_t start;
    378   1732   bonwick 
    379   1732   bonwick 	start = sm->sm_ops->smop_alloc(sm, size);
    380   1732   bonwick 	if (start != -1ULL)
    381   1732   bonwick 		space_map_remove(sm, start, size);
    382   1732   bonwick 	return (start);
    383   1732   bonwick }
    384   1732   bonwick 
    385   1732   bonwick void
    386   1732   bonwick space_map_claim(space_map_t *sm, uint64_t start, uint64_t size)
    387   1732   bonwick {
    388   1732   bonwick 	sm->sm_ops->smop_claim(sm, start, size);
    389   1732   bonwick 	space_map_remove(sm, start, size);
    390   1732   bonwick }
    391   1732   bonwick 
    392   1732   bonwick void
    393   1732   bonwick space_map_free(space_map_t *sm, uint64_t start, uint64_t size)
    394   1732   bonwick {
    395   1732   bonwick 	space_map_add(sm, start, size);
    396   1732   bonwick 	sm->sm_ops->smop_free(sm, start, size);
    397   1732   bonwick }
    398   1732   bonwick 
    399   1732   bonwick /*
    400   1732   bonwick  * Note: space_map_sync() will drop sm_lock across dmu_write() calls.
    401   1732   bonwick  */
    402   1732   bonwick void
    403   1732   bonwick space_map_sync(space_map_t *sm, uint8_t maptype,
    404   1732   bonwick 	space_map_obj_t *smo, objset_t *os, dmu_tx_t *tx)
    405    789    ahrens {
    406    789    ahrens 	spa_t *spa = dmu_objset_spa(os);
    407    789    ahrens 	void *cookie = NULL;
    408    789    ahrens 	space_seg_t *ss;
    409    789    ahrens 	uint64_t bufsize, start, size, run_len;
    410    789    ahrens 	uint64_t *entry, *entry_map, *entry_map_end;
    411    789    ahrens 
    412    789    ahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
    413    789    ahrens 
    414    789    ahrens 	if (sm->sm_space == 0)
    415    789    ahrens 		return;
    416    789    ahrens 
    417    789    ahrens 	dprintf("object %4llu, txg %llu, pass %d, %c, count %lu, space %llx\n",
    418    789    ahrens 	    smo->smo_object, dmu_tx_get_txg(tx), spa_sync_pass(spa),
    419    789    ahrens 	    maptype == SM_ALLOC ? 'A' : 'F', avl_numnodes(&sm->sm_root),
    420    789    ahrens 	    sm->sm_space);
    421    789    ahrens 
    422   1732   bonwick 	if (maptype == SM_ALLOC)
    423   1732   bonwick 		smo->smo_alloc += sm->sm_space;
    424   1732   bonwick 	else
    425   1732   bonwick 		smo->smo_alloc -= sm->sm_space;
    426   1732   bonwick 
    427    789    ahrens 	bufsize = (8 + avl_numnodes(&sm->sm_root)) * sizeof (uint64_t);
    428   1732   bonwick 	bufsize = MIN(bufsize, 1ULL << SPACE_MAP_BLOCKSHIFT);
    429   1732   bonwick 	entry_map = zio_buf_alloc(bufsize);
    430    789    ahrens 	entry_map_end = entry_map + (bufsize / sizeof (uint64_t));
    431    789    ahrens 	entry = entry_map;
    432    789    ahrens 
    433    789    ahrens 	*entry++ = SM_DEBUG_ENCODE(1) |
    434    789    ahrens 	    SM_DEBUG_ACTION_ENCODE(maptype) |
    435    789    ahrens 	    SM_DEBUG_SYNCPASS_ENCODE(spa_sync_pass(spa)) |
    436    789    ahrens 	    SM_DEBUG_TXG_ENCODE(dmu_tx_get_txg(tx));
    437    789    ahrens 
    438    789    ahrens 	while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
    439    789    ahrens 		size = ss->ss_end - ss->ss_start;
    440    789    ahrens 		start = (ss->ss_start - sm->sm_start) >> sm->sm_shift;
    441    789    ahrens 
    442    789    ahrens 		sm->sm_space -= size;
    443    789    ahrens 		size >>= sm->sm_shift;
    444    789    ahrens 
    445    789    ahrens 		while (size) {
    446    789    ahrens 			run_len = MIN(size, SM_RUN_MAX);
    447    789    ahrens 
    448    789    ahrens 			if (entry == entry_map_end) {
    449   1732   bonwick 				mutex_exit(sm->sm_lock);
    450    789    ahrens 				dmu_write(os, smo->smo_object, smo->smo_objsize,
    451    789    ahrens 				    bufsize, entry_map, tx);
    452   1732   bonwick 				mutex_enter(sm->sm_lock);
    453    789    ahrens 				smo->smo_objsize += bufsize;
    454    789    ahrens 				entry = entry_map;
    455    789    ahrens 			}
    456    789    ahrens 
    457    789    ahrens 			*entry++ = SM_OFFSET_ENCODE(start) |
    458    789    ahrens 			    SM_TYPE_ENCODE(maptype) |
    459    789    ahrens 			    SM_RUN_ENCODE(run_len);
    460    789    ahrens 
    461    789    ahrens 			start += run_len;
    462    789    ahrens 			size -= run_len;
    463    789    ahrens 		}
    464    789    ahrens 		kmem_free(ss, sizeof (*ss));
    465    789    ahrens 	}
    466    789    ahrens 
    467    789    ahrens 	if (entry != entry_map) {
    468    789    ahrens 		size = (entry - entry_map) * sizeof (uint64_t);
    469   1732   bonwick 		mutex_exit(sm->sm_lock);
    470    789    ahrens 		dmu_write(os, smo->smo_object, smo->smo_objsize,
    471    789    ahrens 		    size, entry_map, tx);
    472   1732   bonwick 		mutex_enter(sm->sm_lock);
    473    789    ahrens 		smo->smo_objsize += size;
    474    789    ahrens 	}
    475    789    ahrens 
    476   1732   bonwick 	zio_buf_free(entry_map, bufsize);
    477    789    ahrens 
    478    789    ahrens 	VERIFY3U(sm->sm_space, ==, 0);
    479    789    ahrens }
    480    789    ahrens 
    481    789    ahrens void
    482   1732   bonwick space_map_truncate(space_map_obj_t *smo, objset_t *os, dmu_tx_t *tx)
    483    789    ahrens {
    484   1732   bonwick 	VERIFY(dmu_free_range(os, smo->smo_object, 0, -1ULL, tx) == 0);
    485    789    ahrens 
    486    789    ahrens 	smo->smo_objsize = 0;
    487   1732   bonwick 	smo->smo_alloc = 0;
    488    789    ahrens }
    489   8241      Jeff 
    490   8241      Jeff /*
    491   8241      Jeff  * Space map reference trees.
    492   8241      Jeff  *
    493   8241      Jeff  * A space map is a collection of integers.  Every integer is either
    494   8241      Jeff  * in the map, or it's not.  A space map reference tree generalizes
    495   8241      Jeff  * the idea: it allows its members to have arbitrary reference counts,
    496   8241      Jeff  * as opposed to the implicit reference count of 0 or 1 in a space map.
    497   8241      Jeff  * This representation comes in handy when computing the union or
    498   8241      Jeff  * intersection of multiple space maps.  For example, the union of
    499   8241      Jeff  * N space maps is the subset of the reference tree with refcnt >= 1.
    500   8241      Jeff  * The intersection of N space maps is the subset with refcnt >= N.
    501   8241      Jeff  *
    502   8241      Jeff  * [It's very much like a Fourier transform.  Unions and intersections
    503   8241      Jeff  * are hard to perform in the 'space map domain', so we convert the maps
    504   8241      Jeff  * into the 'reference count domain', where it's trivial, then invert.]
    505   8241      Jeff  *
    506   8241      Jeff  * vdev_dtl_reassess() uses computations of this form to determine
    507   8241      Jeff  * DTL_MISSING and DTL_OUTAGE for interior vdevs -- e.g. a RAID-Z vdev
    508   8241      Jeff  * has an outage wherever refcnt >= vdev_nparity + 1, and a mirror vdev
    509   8241      Jeff  * has an outage wherever refcnt >= vdev_children.
    510   8241      Jeff  */
    511   8241      Jeff static int
    512   8241      Jeff space_map_ref_compare(const void *x1, const void *x2)
    513   8241      Jeff {
    514   8241      Jeff 	const space_ref_t *sr1 = x1;
    515   8241      Jeff 	const space_ref_t *sr2 = x2;
    516   8241      Jeff 
    517   8241      Jeff 	if (sr1->sr_offset < sr2->sr_offset)
    518   8241      Jeff 		return (-1);
    519   8241      Jeff 	if (sr1->sr_offset > sr2->sr_offset)
    520   8241      Jeff 		return (1);
    521   8241      Jeff 
    522   8241      Jeff 	if (sr1 < sr2)
    523   8241      Jeff 		return (-1);
    524   8241      Jeff 	if (sr1 > sr2)
    525   8241      Jeff 		return (1);
    526   8241      Jeff 
    527   8241      Jeff 	return (0);
    528   8241      Jeff }
    529   8241      Jeff 
    530   8241      Jeff void
    531   8241      Jeff space_map_ref_create(avl_tree_t *t)
    532   8241      Jeff {
    533   8241      Jeff 	avl_create(t, space_map_ref_compare,
    534   8241      Jeff 	    sizeof (space_ref_t), offsetof(space_ref_t, sr_node));
    535   8241      Jeff }
    536   8241      Jeff 
    537   8241      Jeff void
    538   8241      Jeff space_map_ref_destroy(avl_tree_t *t)
    539   8241      Jeff {
    540   8241      Jeff 	space_ref_t *sr;
    541   8241      Jeff 	void *cookie = NULL;
    542   8241      Jeff 
    543   8241      Jeff 	while ((sr = avl_destroy_nodes(t, &cookie)) != NULL)
    544   8241      Jeff 		kmem_free(sr, sizeof (*sr));
    545   8241      Jeff 
    546   8241      Jeff 	avl_destroy(t);
    547   8241      Jeff }
    548   8241      Jeff 
    549   8241      Jeff static void
    550   8241      Jeff space_map_ref_add_node(avl_tree_t *t, uint64_t offset, int64_t refcnt)
    551   8241      Jeff {
    552   8241      Jeff 	space_ref_t *sr;
    553   8241      Jeff 
    554   8241      Jeff 	sr = kmem_alloc(sizeof (*sr), KM_SLEEP);
    555   8241      Jeff 	sr->sr_offset = offset;
    556   8241      Jeff 	sr->sr_refcnt = refcnt;
    557   8241      Jeff 
    558   8241      Jeff 	avl_add(t, sr);
    559   8241      Jeff }
    560   8241      Jeff 
    561   8241      Jeff void
    562   8241      Jeff space_map_ref_add_seg(avl_tree_t *t, uint64_t start, uint64_t end,
    563   8241      Jeff 	int64_t refcnt)
    564   8241      Jeff {
    565   8241      Jeff 	space_map_ref_add_node(t, start, refcnt);
    566   8241      Jeff 	space_map_ref_add_node(t, end, -refcnt);
    567   8241      Jeff }
    568   8241      Jeff 
    569   8241      Jeff /*
    570   8241      Jeff  * Convert (or add) a space map into a reference tree.
    571   8241      Jeff  */
    572   8241      Jeff void
    573   8241      Jeff space_map_ref_add_map(avl_tree_t *t, space_map_t *sm, int64_t refcnt)
    574   8241      Jeff {
    575   8241      Jeff 	space_seg_t *ss;
    576   8241      Jeff 
    577   8241      Jeff 	ASSERT(MUTEX_HELD(sm->sm_lock));
    578   8241      Jeff 
    579   8241      Jeff 	for (ss = avl_first(&sm->sm_root); ss; ss = AVL_NEXT(&sm->sm_root, ss))
    580   8241      Jeff 		space_map_ref_add_seg(t, ss->ss_start, ss->ss_end, refcnt);
    581   8241      Jeff }
    582   8241      Jeff 
    583   8241      Jeff /*
    584   8241      Jeff  * Convert a reference tree into a space map.  The space map will contain
    585   8241      Jeff  * all members of the reference tree for which refcnt >= minref.
    586   8241      Jeff  */
    587   8241      Jeff void
    588   8241      Jeff space_map_ref_generate_map(avl_tree_t *t, space_map_t *sm, int64_t minref)
    589   8241      Jeff {
    590   8241      Jeff 	uint64_t start = -1ULL;
    591   8241      Jeff 	int64_t refcnt = 0;
    592   8241      Jeff 	space_ref_t *sr;
    593   8241      Jeff 
    594   8241      Jeff 	ASSERT(MUTEX_HELD(sm->sm_lock));
    595   8241      Jeff 
    596   8241      Jeff 	space_map_vacate(sm, NULL, NULL);
    597   8241      Jeff 
    598   8241      Jeff 	for (sr = avl_first(t); sr != NULL; sr = AVL_NEXT(t, sr)) {
    599   8241      Jeff 		refcnt += sr->sr_refcnt;
    600   8241      Jeff 		if (refcnt >= minref) {
    601   8241      Jeff 			if (start == -1ULL) {
    602   8241      Jeff 				start = sr->sr_offset;
    603   8241      Jeff 			}
    604   8241      Jeff 		} else {
    605   8241      Jeff 			if (start != -1ULL) {
    606   8241      Jeff 				uint64_t end = sr->sr_offset;
    607   8241      Jeff 				ASSERT(start <= end);
    608   8241      Jeff 				if (end > start)
    609   8241      Jeff 					space_map_add(sm, start, end - start);
    610   8241      Jeff 				start = -1ULL;
    611   8241      Jeff 			}
    612   8241      Jeff 		}
    613   8241      Jeff 	}
    614   8241      Jeff 	ASSERT(refcnt == 0);
    615   8241      Jeff 	ASSERT(start == -1ULL);
    616   8241      Jeff }
    617