xref: /illumos-gate/usr/src/uts/common/fs/zfs/space_map.c (revision b8493d5dbb69dc46a036795418389fe3e011f3e1)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
22*b8493d5dSvl  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/zfs_context.h>
29fa9e4066Sahrens #include <sys/spa.h>
30fa9e4066Sahrens #include <sys/dmu.h>
31ecc2d604Sbonwick #include <sys/zio.h>
32fa9e4066Sahrens #include <sys/space_map.h>
33fa9e4066Sahrens 
34fa9e4066Sahrens /*
35fa9e4066Sahrens  * Space map routines.
36fa9e4066Sahrens  * NOTE: caller is responsible for all locking.
37fa9e4066Sahrens  */
38fa9e4066Sahrens static int
39fa9e4066Sahrens space_map_seg_compare(const void *x1, const void *x2)
40fa9e4066Sahrens {
41fa9e4066Sahrens 	const space_seg_t *s1 = x1;
42fa9e4066Sahrens 	const space_seg_t *s2 = x2;
43fa9e4066Sahrens 
44fa9e4066Sahrens 	if (s1->ss_start < s2->ss_start) {
45fa9e4066Sahrens 		if (s1->ss_end > s2->ss_start)
46fa9e4066Sahrens 			return (0);
47fa9e4066Sahrens 		return (-1);
48fa9e4066Sahrens 	}
49fa9e4066Sahrens 	if (s1->ss_start > s2->ss_start) {
50fa9e4066Sahrens 		if (s1->ss_start < s2->ss_end)
51fa9e4066Sahrens 			return (0);
52fa9e4066Sahrens 		return (1);
53fa9e4066Sahrens 	}
54fa9e4066Sahrens 	return (0);
55fa9e4066Sahrens }
56fa9e4066Sahrens 
57fa9e4066Sahrens void
58ecc2d604Sbonwick space_map_create(space_map_t *sm, uint64_t start, uint64_t size, uint8_t shift,
59fa9e4066Sahrens 	kmutex_t *lp)
60fa9e4066Sahrens {
61ecc2d604Sbonwick 	bzero(sm, sizeof (*sm));
62ecc2d604Sbonwick 
63fa9e4066Sahrens 	avl_create(&sm->sm_root, space_map_seg_compare,
64fa9e4066Sahrens 	    sizeof (space_seg_t), offsetof(struct space_seg, ss_node));
65ecc2d604Sbonwick 
66fa9e4066Sahrens 	sm->sm_start = start;
67fa9e4066Sahrens 	sm->sm_size = size;
68fa9e4066Sahrens 	sm->sm_shift = shift;
69fa9e4066Sahrens 	sm->sm_lock = lp;
70fa9e4066Sahrens }
71fa9e4066Sahrens 
72fa9e4066Sahrens void
73fa9e4066Sahrens space_map_destroy(space_map_t *sm)
74fa9e4066Sahrens {
75ecc2d604Sbonwick 	ASSERT(!sm->sm_loaded && !sm->sm_loading);
76fa9e4066Sahrens 	VERIFY3U(sm->sm_space, ==, 0);
77fa9e4066Sahrens 	avl_destroy(&sm->sm_root);
78fa9e4066Sahrens }
79fa9e4066Sahrens 
80fa9e4066Sahrens void
81fa9e4066Sahrens space_map_add(space_map_t *sm, uint64_t start, uint64_t size)
82fa9e4066Sahrens {
83fa9e4066Sahrens 	avl_index_t where;
84fa9e4066Sahrens 	space_seg_t ssearch, *ss_before, *ss_after, *ss;
85fa9e4066Sahrens 	uint64_t end = start + size;
86fa9e4066Sahrens 	int merge_before, merge_after;
87fa9e4066Sahrens 
88fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
89fa9e4066Sahrens 	VERIFY(size != 0);
90fa9e4066Sahrens 	VERIFY3U(start, >=, sm->sm_start);
91ecc2d604Sbonwick 	VERIFY3U(end, <=, sm->sm_start + sm->sm_size);
92fa9e4066Sahrens 	VERIFY(sm->sm_space + size <= sm->sm_size);
93fa9e4066Sahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
94fa9e4066Sahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
95fa9e4066Sahrens 
96fa9e4066Sahrens 	ssearch.ss_start = start;
97fa9e4066Sahrens 	ssearch.ss_end = end;
98fa9e4066Sahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
99fa9e4066Sahrens 
1000125049cSahrens 	if (ss != NULL && ss->ss_start <= start && ss->ss_end >= end) {
1010125049cSahrens 		zfs_panic_recover("zfs: allocating allocated segment"
1020125049cSahrens 		    "(offset=%llu size=%llu)\n",
1030125049cSahrens 		    (longlong_t)start, (longlong_t)size);
1040125049cSahrens 		return;
1050125049cSahrens 	}
1060125049cSahrens 
107fa9e4066Sahrens 	/* Make sure we don't overlap with either of our neighbors */
108fa9e4066Sahrens 	VERIFY(ss == NULL);
109fa9e4066Sahrens 
110fa9e4066Sahrens 	ss_before = avl_nearest(&sm->sm_root, where, AVL_BEFORE);
111fa9e4066Sahrens 	ss_after = avl_nearest(&sm->sm_root, where, AVL_AFTER);
112fa9e4066Sahrens 
113fa9e4066Sahrens 	merge_before = (ss_before != NULL && ss_before->ss_end == start);
114fa9e4066Sahrens 	merge_after = (ss_after != NULL && ss_after->ss_start == end);
115fa9e4066Sahrens 
116fa9e4066Sahrens 	if (merge_before && merge_after) {
117fa9e4066Sahrens 		avl_remove(&sm->sm_root, ss_before);
118fa9e4066Sahrens 		ss_after->ss_start = ss_before->ss_start;
119fa9e4066Sahrens 		kmem_free(ss_before, sizeof (*ss_before));
120fa9e4066Sahrens 	} else if (merge_before) {
121fa9e4066Sahrens 		ss_before->ss_end = end;
122fa9e4066Sahrens 	} else if (merge_after) {
123fa9e4066Sahrens 		ss_after->ss_start = start;
124fa9e4066Sahrens 	} else {
125fa9e4066Sahrens 		ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
126fa9e4066Sahrens 		ss->ss_start = start;
127fa9e4066Sahrens 		ss->ss_end = end;
128fa9e4066Sahrens 		avl_insert(&sm->sm_root, ss, where);
129fa9e4066Sahrens 	}
130fa9e4066Sahrens 
131fa9e4066Sahrens 	sm->sm_space += size;
132fa9e4066Sahrens }
133fa9e4066Sahrens 
134fa9e4066Sahrens void
135fa9e4066Sahrens space_map_remove(space_map_t *sm, uint64_t start, uint64_t size)
136fa9e4066Sahrens {
137fa9e4066Sahrens 	avl_index_t where;
138fa9e4066Sahrens 	space_seg_t ssearch, *ss, *newseg;
139fa9e4066Sahrens 	uint64_t end = start + size;
140fa9e4066Sahrens 	int left_over, right_over;
141fa9e4066Sahrens 
142fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
143fa9e4066Sahrens 	VERIFY(size != 0);
144fa9e4066Sahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
145fa9e4066Sahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
146fa9e4066Sahrens 
147fa9e4066Sahrens 	ssearch.ss_start = start;
148fa9e4066Sahrens 	ssearch.ss_end = end;
149fa9e4066Sahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
150fa9e4066Sahrens 
151fa9e4066Sahrens 	/* Make sure we completely overlap with someone */
1520125049cSahrens 	if (ss == NULL) {
1530125049cSahrens 		zfs_panic_recover("zfs: freeing free segment "
1540125049cSahrens 		    "(offset=%llu size=%llu)",
1550125049cSahrens 		    (longlong_t)start, (longlong_t)size);
1560125049cSahrens 		return;
1570125049cSahrens 	}
158fa9e4066Sahrens 	VERIFY3U(ss->ss_start, <=, start);
159fa9e4066Sahrens 	VERIFY3U(ss->ss_end, >=, end);
160fa9e4066Sahrens 	VERIFY(sm->sm_space - size <= sm->sm_size);
161fa9e4066Sahrens 
162fa9e4066Sahrens 	left_over = (ss->ss_start != start);
163fa9e4066Sahrens 	right_over = (ss->ss_end != end);
164fa9e4066Sahrens 
165fa9e4066Sahrens 	if (left_over && right_over) {
166fa9e4066Sahrens 		newseg = kmem_alloc(sizeof (*newseg), KM_SLEEP);
167fa9e4066Sahrens 		newseg->ss_start = end;
168fa9e4066Sahrens 		newseg->ss_end = ss->ss_end;
169fa9e4066Sahrens 		ss->ss_end = start;
170fa9e4066Sahrens 		avl_insert_here(&sm->sm_root, newseg, ss, AVL_AFTER);
171fa9e4066Sahrens 	} else if (left_over) {
172fa9e4066Sahrens 		ss->ss_end = start;
173fa9e4066Sahrens 	} else if (right_over) {
174fa9e4066Sahrens 		ss->ss_start = end;
175fa9e4066Sahrens 	} else {
176fa9e4066Sahrens 		avl_remove(&sm->sm_root, ss);
177fa9e4066Sahrens 		kmem_free(ss, sizeof (*ss));
178fa9e4066Sahrens 	}
179fa9e4066Sahrens 
180fa9e4066Sahrens 	sm->sm_space -= size;
181fa9e4066Sahrens }
182fa9e4066Sahrens 
183fa9e4066Sahrens int
184fa9e4066Sahrens space_map_contains(space_map_t *sm, uint64_t start, uint64_t size)
185fa9e4066Sahrens {
186fa9e4066Sahrens 	avl_index_t where;
187fa9e4066Sahrens 	space_seg_t ssearch, *ss;
188fa9e4066Sahrens 	uint64_t end = start + size;
189fa9e4066Sahrens 
190fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
191fa9e4066Sahrens 	VERIFY(size != 0);
192fa9e4066Sahrens 	VERIFY(P2PHASE(start, 1ULL << sm->sm_shift) == 0);
193fa9e4066Sahrens 	VERIFY(P2PHASE(size, 1ULL << sm->sm_shift) == 0);
194fa9e4066Sahrens 
195fa9e4066Sahrens 	ssearch.ss_start = start;
196fa9e4066Sahrens 	ssearch.ss_end = end;
197fa9e4066Sahrens 	ss = avl_find(&sm->sm_root, &ssearch, &where);
198fa9e4066Sahrens 
199fa9e4066Sahrens 	return (ss != NULL && ss->ss_start <= start && ss->ss_end >= end);
200fa9e4066Sahrens }
201fa9e4066Sahrens 
202fa9e4066Sahrens void
203fa9e4066Sahrens space_map_vacate(space_map_t *sm, space_map_func_t *func, space_map_t *mdest)
204fa9e4066Sahrens {
205fa9e4066Sahrens 	space_seg_t *ss;
206fa9e4066Sahrens 	void *cookie = NULL;
207fa9e4066Sahrens 
208fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
209fa9e4066Sahrens 
210fa9e4066Sahrens 	while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
211fa9e4066Sahrens 		if (func != NULL)
212fa9e4066Sahrens 			func(mdest, ss->ss_start, ss->ss_end - ss->ss_start);
213fa9e4066Sahrens 		kmem_free(ss, sizeof (*ss));
214fa9e4066Sahrens 	}
215fa9e4066Sahrens 	sm->sm_space = 0;
216fa9e4066Sahrens }
217fa9e4066Sahrens 
218fa9e4066Sahrens void
219ecc2d604Sbonwick space_map_walk(space_map_t *sm, space_map_func_t *func, space_map_t *mdest)
220fa9e4066Sahrens {
221fa9e4066Sahrens 	space_seg_t *ss;
222fa9e4066Sahrens 
223fa9e4066Sahrens 	for (ss = avl_first(&sm->sm_root); ss; ss = AVL_NEXT(&sm->sm_root, ss))
224fa9e4066Sahrens 		func(mdest, ss->ss_start, ss->ss_end - ss->ss_start);
225fa9e4066Sahrens }
226fa9e4066Sahrens 
227fa9e4066Sahrens void
228fa9e4066Sahrens space_map_excise(space_map_t *sm, uint64_t start, uint64_t size)
229fa9e4066Sahrens {
230fa9e4066Sahrens 	avl_tree_t *t = &sm->sm_root;
231fa9e4066Sahrens 	avl_index_t where;
232fa9e4066Sahrens 	space_seg_t *ss, search;
233fa9e4066Sahrens 	uint64_t end = start + size;
234fa9e4066Sahrens 	uint64_t rm_start, rm_end;
235fa9e4066Sahrens 
236fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
237fa9e4066Sahrens 
238fa9e4066Sahrens 	search.ss_start = start;
239fa9e4066Sahrens 	search.ss_end = start;
240fa9e4066Sahrens 
241fa9e4066Sahrens 	for (;;) {
242fa9e4066Sahrens 		ss = avl_find(t, &search, &where);
243fa9e4066Sahrens 
244fa9e4066Sahrens 		if (ss == NULL)
245fa9e4066Sahrens 			ss = avl_nearest(t, where, AVL_AFTER);
246fa9e4066Sahrens 
247fa9e4066Sahrens 		if (ss == NULL || ss->ss_start >= end)
248fa9e4066Sahrens 			break;
249fa9e4066Sahrens 
250fa9e4066Sahrens 		rm_start = MAX(ss->ss_start, start);
251fa9e4066Sahrens 		rm_end = MIN(ss->ss_end, end);
252fa9e4066Sahrens 
253fa9e4066Sahrens 		space_map_remove(sm, rm_start, rm_end - rm_start);
254fa9e4066Sahrens 	}
255fa9e4066Sahrens }
256fa9e4066Sahrens 
257fa9e4066Sahrens /*
258fa9e4066Sahrens  * Replace smd with the union of smd and sms.
259fa9e4066Sahrens  */
260fa9e4066Sahrens void
261fa9e4066Sahrens space_map_union(space_map_t *smd, space_map_t *sms)
262fa9e4066Sahrens {
263fa9e4066Sahrens 	avl_tree_t *t = &sms->sm_root;
264fa9e4066Sahrens 	space_seg_t *ss;
265fa9e4066Sahrens 
266fa9e4066Sahrens 	ASSERT(MUTEX_HELD(smd->sm_lock));
267fa9e4066Sahrens 
268fa9e4066Sahrens 	/*
269fa9e4066Sahrens 	 * For each source segment, remove any intersections with the
270fa9e4066Sahrens 	 * destination, then add the source segment to the destination.
271fa9e4066Sahrens 	 */
272fa9e4066Sahrens 	for (ss = avl_first(t); ss != NULL; ss = AVL_NEXT(t, ss)) {
273fa9e4066Sahrens 		space_map_excise(smd, ss->ss_start, ss->ss_end - ss->ss_start);
274fa9e4066Sahrens 		space_map_add(smd, ss->ss_start, ss->ss_end - ss->ss_start);
275fa9e4066Sahrens 	}
276fa9e4066Sahrens }
277fa9e4066Sahrens 
278ecc2d604Sbonwick /*
279ecc2d604Sbonwick  * Wait for any in-progress space_map_load() to complete.
280ecc2d604Sbonwick  */
281ecc2d604Sbonwick void
282ecc2d604Sbonwick space_map_load_wait(space_map_t *sm)
283ecc2d604Sbonwick {
284ecc2d604Sbonwick 	ASSERT(MUTEX_HELD(sm->sm_lock));
285ecc2d604Sbonwick 
286ecc2d604Sbonwick 	while (sm->sm_loading)
287ecc2d604Sbonwick 		cv_wait(&sm->sm_load_cv, sm->sm_lock);
288ecc2d604Sbonwick }
289ecc2d604Sbonwick 
290ecc2d604Sbonwick /*
291ecc2d604Sbonwick  * Note: space_map_load() will drop sm_lock across dmu_read() calls.
292ecc2d604Sbonwick  * The caller must be OK with this.
293ecc2d604Sbonwick  */
294fa9e4066Sahrens int
295ecc2d604Sbonwick space_map_load(space_map_t *sm, space_map_ops_t *ops, uint8_t maptype,
296ecc2d604Sbonwick 	space_map_obj_t *smo, objset_t *os)
297fa9e4066Sahrens {
298fa9e4066Sahrens 	uint64_t *entry, *entry_map, *entry_map_end;
2998365e7c9Sbillm 	uint64_t bufsize, size, offset, end, space;
300fa9e4066Sahrens 	uint64_t mapstart = sm->sm_start;
3010a4e9518Sgw 	int error = 0;
302fa9e4066Sahrens 
303fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
304fa9e4066Sahrens 
305ecc2d604Sbonwick 	space_map_load_wait(sm);
306ecc2d604Sbonwick 
307ecc2d604Sbonwick 	if (sm->sm_loaded)
308ecc2d604Sbonwick 		return (0);
309ecc2d604Sbonwick 
310ecc2d604Sbonwick 	sm->sm_loading = B_TRUE;
3118365e7c9Sbillm 	end = smo->smo_objsize;
3128365e7c9Sbillm 	space = smo->smo_alloc;
313ecc2d604Sbonwick 
314ecc2d604Sbonwick 	ASSERT(sm->sm_ops == NULL);
315ecc2d604Sbonwick 	VERIFY3U(sm->sm_space, ==, 0);
316fa9e4066Sahrens 
317fa9e4066Sahrens 	if (maptype == SM_FREE) {
318fa9e4066Sahrens 		space_map_add(sm, sm->sm_start, sm->sm_size);
319fa9e4066Sahrens 		space = sm->sm_size - space;
320fa9e4066Sahrens 	}
321fa9e4066Sahrens 
322ecc2d604Sbonwick 	bufsize = 1ULL << SPACE_MAP_BLOCKSHIFT;
323ecc2d604Sbonwick 	entry_map = zio_buf_alloc(bufsize);
324ecc2d604Sbonwick 
325ecc2d604Sbonwick 	mutex_exit(sm->sm_lock);
326ecc2d604Sbonwick 	if (end > bufsize)
327ecc2d604Sbonwick 		dmu_prefetch(os, smo->smo_object, bufsize, end - bufsize);
328ecc2d604Sbonwick 	mutex_enter(sm->sm_lock);
329ecc2d604Sbonwick 
330fa9e4066Sahrens 	for (offset = 0; offset < end; offset += bufsize) {
331fa9e4066Sahrens 		size = MIN(end - offset, bufsize);
332fa9e4066Sahrens 		VERIFY(P2PHASE(size, sizeof (uint64_t)) == 0);
333fa9e4066Sahrens 		VERIFY(size != 0);
334fa9e4066Sahrens 
335fa9e4066Sahrens 		dprintf("object=%llu  offset=%llx  size=%llx\n",
336fa9e4066Sahrens 		    smo->smo_object, offset, size);
337ecc2d604Sbonwick 
338ecc2d604Sbonwick 		mutex_exit(sm->sm_lock);
3390a4e9518Sgw 		error = dmu_read(os, smo->smo_object, offset, size, entry_map);
340ecc2d604Sbonwick 		mutex_enter(sm->sm_lock);
3410a4e9518Sgw 		if (error != 0)
342*b8493d5dSvl 			break;
343fa9e4066Sahrens 
344fa9e4066Sahrens 		entry_map_end = entry_map + (size / sizeof (uint64_t));
345fa9e4066Sahrens 		for (entry = entry_map; entry < entry_map_end; entry++) {
346fa9e4066Sahrens 			uint64_t e = *entry;
347fa9e4066Sahrens 
348fa9e4066Sahrens 			if (SM_DEBUG_DECODE(e))		/* Skip debug entries */
349fa9e4066Sahrens 				continue;
350fa9e4066Sahrens 
351fa9e4066Sahrens 			(SM_TYPE_DECODE(e) == maptype ?
352fa9e4066Sahrens 			    space_map_add : space_map_remove)(sm,
353fa9e4066Sahrens 			    (SM_OFFSET_DECODE(e) << sm->sm_shift) + mapstart,
354fa9e4066Sahrens 			    SM_RUN_DECODE(e) << sm->sm_shift);
355fa9e4066Sahrens 		}
356fa9e4066Sahrens 	}
357fa9e4066Sahrens 
358*b8493d5dSvl 	if (error == 0) {
359*b8493d5dSvl 		VERIFY3U(sm->sm_space, ==, space);
360*b8493d5dSvl 
361*b8493d5dSvl 		sm->sm_loaded = B_TRUE;
362*b8493d5dSvl 		sm->sm_ops = ops;
363*b8493d5dSvl 		if (ops != NULL)
364*b8493d5dSvl 			ops->smop_load(sm);
365*b8493d5dSvl 	} else {
366*b8493d5dSvl 		space_map_vacate(sm, NULL, NULL);
367*b8493d5dSvl 	}
368*b8493d5dSvl 
369ecc2d604Sbonwick 	zio_buf_free(entry_map, bufsize);
370ecc2d604Sbonwick 
371ecc2d604Sbonwick 	sm->sm_loading = B_FALSE;
372ecc2d604Sbonwick 
373ecc2d604Sbonwick 	cv_broadcast(&sm->sm_load_cv);
374ecc2d604Sbonwick 
3750a4e9518Sgw 	return (error);
376fa9e4066Sahrens }
377fa9e4066Sahrens 
378fa9e4066Sahrens void
379ecc2d604Sbonwick space_map_unload(space_map_t *sm)
380ecc2d604Sbonwick {
381ecc2d604Sbonwick 	ASSERT(MUTEX_HELD(sm->sm_lock));
382ecc2d604Sbonwick 
383ecc2d604Sbonwick 	if (sm->sm_loaded && sm->sm_ops != NULL)
384ecc2d604Sbonwick 		sm->sm_ops->smop_unload(sm);
385ecc2d604Sbonwick 
386ecc2d604Sbonwick 	sm->sm_loaded = B_FALSE;
387ecc2d604Sbonwick 	sm->sm_ops = NULL;
388ecc2d604Sbonwick 
389ecc2d604Sbonwick 	space_map_vacate(sm, NULL, NULL);
390ecc2d604Sbonwick }
391ecc2d604Sbonwick 
392ecc2d604Sbonwick uint64_t
393ecc2d604Sbonwick space_map_alloc(space_map_t *sm, uint64_t size)
394ecc2d604Sbonwick {
395ecc2d604Sbonwick 	uint64_t start;
396ecc2d604Sbonwick 
397ecc2d604Sbonwick 	start = sm->sm_ops->smop_alloc(sm, size);
398ecc2d604Sbonwick 	if (start != -1ULL)
399ecc2d604Sbonwick 		space_map_remove(sm, start, size);
400ecc2d604Sbonwick 	return (start);
401ecc2d604Sbonwick }
402ecc2d604Sbonwick 
403ecc2d604Sbonwick void
404ecc2d604Sbonwick space_map_claim(space_map_t *sm, uint64_t start, uint64_t size)
405ecc2d604Sbonwick {
406ecc2d604Sbonwick 	sm->sm_ops->smop_claim(sm, start, size);
407ecc2d604Sbonwick 	space_map_remove(sm, start, size);
408ecc2d604Sbonwick }
409ecc2d604Sbonwick 
410ecc2d604Sbonwick void
411ecc2d604Sbonwick space_map_free(space_map_t *sm, uint64_t start, uint64_t size)
412ecc2d604Sbonwick {
413ecc2d604Sbonwick 	space_map_add(sm, start, size);
414ecc2d604Sbonwick 	sm->sm_ops->smop_free(sm, start, size);
415ecc2d604Sbonwick }
416ecc2d604Sbonwick 
417ecc2d604Sbonwick /*
418ecc2d604Sbonwick  * Note: space_map_sync() will drop sm_lock across dmu_write() calls.
419ecc2d604Sbonwick  */
420ecc2d604Sbonwick void
421ecc2d604Sbonwick space_map_sync(space_map_t *sm, uint8_t maptype,
422ecc2d604Sbonwick 	space_map_obj_t *smo, objset_t *os, dmu_tx_t *tx)
423fa9e4066Sahrens {
424fa9e4066Sahrens 	spa_t *spa = dmu_objset_spa(os);
425fa9e4066Sahrens 	void *cookie = NULL;
426fa9e4066Sahrens 	space_seg_t *ss;
427fa9e4066Sahrens 	uint64_t bufsize, start, size, run_len;
428fa9e4066Sahrens 	uint64_t *entry, *entry_map, *entry_map_end;
429fa9e4066Sahrens 
430fa9e4066Sahrens 	ASSERT(MUTEX_HELD(sm->sm_lock));
431fa9e4066Sahrens 
432fa9e4066Sahrens 	if (sm->sm_space == 0)
433fa9e4066Sahrens 		return;
434fa9e4066Sahrens 
435fa9e4066Sahrens 	dprintf("object %4llu, txg %llu, pass %d, %c, count %lu, space %llx\n",
436fa9e4066Sahrens 	    smo->smo_object, dmu_tx_get_txg(tx), spa_sync_pass(spa),
437fa9e4066Sahrens 	    maptype == SM_ALLOC ? 'A' : 'F', avl_numnodes(&sm->sm_root),
438fa9e4066Sahrens 	    sm->sm_space);
439fa9e4066Sahrens 
440ecc2d604Sbonwick 	if (maptype == SM_ALLOC)
441ecc2d604Sbonwick 		smo->smo_alloc += sm->sm_space;
442ecc2d604Sbonwick 	else
443ecc2d604Sbonwick 		smo->smo_alloc -= sm->sm_space;
444ecc2d604Sbonwick 
445fa9e4066Sahrens 	bufsize = (8 + avl_numnodes(&sm->sm_root)) * sizeof (uint64_t);
446ecc2d604Sbonwick 	bufsize = MIN(bufsize, 1ULL << SPACE_MAP_BLOCKSHIFT);
447ecc2d604Sbonwick 	entry_map = zio_buf_alloc(bufsize);
448fa9e4066Sahrens 	entry_map_end = entry_map + (bufsize / sizeof (uint64_t));
449fa9e4066Sahrens 	entry = entry_map;
450fa9e4066Sahrens 
451fa9e4066Sahrens 	*entry++ = SM_DEBUG_ENCODE(1) |
452fa9e4066Sahrens 	    SM_DEBUG_ACTION_ENCODE(maptype) |
453fa9e4066Sahrens 	    SM_DEBUG_SYNCPASS_ENCODE(spa_sync_pass(spa)) |
454fa9e4066Sahrens 	    SM_DEBUG_TXG_ENCODE(dmu_tx_get_txg(tx));
455fa9e4066Sahrens 
456fa9e4066Sahrens 	while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
457fa9e4066Sahrens 		size = ss->ss_end - ss->ss_start;
458fa9e4066Sahrens 		start = (ss->ss_start - sm->sm_start) >> sm->sm_shift;
459fa9e4066Sahrens 
460fa9e4066Sahrens 		sm->sm_space -= size;
461fa9e4066Sahrens 		size >>= sm->sm_shift;
462fa9e4066Sahrens 
463fa9e4066Sahrens 		while (size) {
464fa9e4066Sahrens 			run_len = MIN(size, SM_RUN_MAX);
465fa9e4066Sahrens 
466fa9e4066Sahrens 			if (entry == entry_map_end) {
467ecc2d604Sbonwick 				mutex_exit(sm->sm_lock);
468fa9e4066Sahrens 				dmu_write(os, smo->smo_object, smo->smo_objsize,
469fa9e4066Sahrens 				    bufsize, entry_map, tx);
470ecc2d604Sbonwick 				mutex_enter(sm->sm_lock);
471fa9e4066Sahrens 				smo->smo_objsize += bufsize;
472fa9e4066Sahrens 				entry = entry_map;
473fa9e4066Sahrens 			}
474fa9e4066Sahrens 
475fa9e4066Sahrens 			*entry++ = SM_OFFSET_ENCODE(start) |
476fa9e4066Sahrens 			    SM_TYPE_ENCODE(maptype) |
477fa9e4066Sahrens 			    SM_RUN_ENCODE(run_len);
478fa9e4066Sahrens 
479fa9e4066Sahrens 			start += run_len;
480fa9e4066Sahrens 			size -= run_len;
481fa9e4066Sahrens 		}
482fa9e4066Sahrens 		kmem_free(ss, sizeof (*ss));
483fa9e4066Sahrens 	}
484fa9e4066Sahrens 
485fa9e4066Sahrens 	if (entry != entry_map) {
486fa9e4066Sahrens 		size = (entry - entry_map) * sizeof (uint64_t);
487ecc2d604Sbonwick 		mutex_exit(sm->sm_lock);
488fa9e4066Sahrens 		dmu_write(os, smo->smo_object, smo->smo_objsize,
489fa9e4066Sahrens 		    size, entry_map, tx);
490ecc2d604Sbonwick 		mutex_enter(sm->sm_lock);
491fa9e4066Sahrens 		smo->smo_objsize += size;
492fa9e4066Sahrens 	}
493fa9e4066Sahrens 
494ecc2d604Sbonwick 	zio_buf_free(entry_map, bufsize);
495fa9e4066Sahrens 
496fa9e4066Sahrens 	VERIFY3U(sm->sm_space, ==, 0);
497fa9e4066Sahrens }
498fa9e4066Sahrens 
499fa9e4066Sahrens void
500ecc2d604Sbonwick space_map_truncate(space_map_obj_t *smo, objset_t *os, dmu_tx_t *tx)
501fa9e4066Sahrens {
502ecc2d604Sbonwick 	VERIFY(dmu_free_range(os, smo->smo_object, 0, -1ULL, tx) == 0);
503fa9e4066Sahrens 
504fa9e4066Sahrens 	smo->smo_objsize = 0;
505ecc2d604Sbonwick 	smo->smo_alloc = 0;
506fa9e4066Sahrens }
507