xref: /illumos-gate/usr/src/uts/common/fs/zfs/vdev_indirect_mapping.c (revision 555d674d5d4b8191dc83723188349d28278b2431)
15cabbc6bSPrashanth Sreenivasa /*
25cabbc6bSPrashanth Sreenivasa  * CDDL HEADER START
35cabbc6bSPrashanth Sreenivasa  *
45cabbc6bSPrashanth Sreenivasa  * This file and its contents are supplied under the terms of the
55cabbc6bSPrashanth Sreenivasa  * Common Development and Distribution License ("CDDL"), version 1.0.
65cabbc6bSPrashanth Sreenivasa  * You may only use this file in accordance with the terms of version
75cabbc6bSPrashanth Sreenivasa  * 1.0 of the CDDL.
85cabbc6bSPrashanth Sreenivasa  *
95cabbc6bSPrashanth Sreenivasa  * A full copy of the text of the CDDL should have accompanied this
105cabbc6bSPrashanth Sreenivasa  * source.  A copy of the CDDL is also available via the Internet at
115cabbc6bSPrashanth Sreenivasa  * http://www.illumos.org/license/CDDL.
125cabbc6bSPrashanth Sreenivasa  *
135cabbc6bSPrashanth Sreenivasa  * CDDL HEADER END
145cabbc6bSPrashanth Sreenivasa  */
155cabbc6bSPrashanth Sreenivasa 
165cabbc6bSPrashanth Sreenivasa /*
1717f11284SSerapheim Dimitropoulos  * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
185cabbc6bSPrashanth Sreenivasa  */
195cabbc6bSPrashanth Sreenivasa 
205cabbc6bSPrashanth Sreenivasa #include <sys/dmu_tx.h>
215cabbc6bSPrashanth Sreenivasa #include <sys/dsl_pool.h>
225cabbc6bSPrashanth Sreenivasa #include <sys/spa.h>
235cabbc6bSPrashanth Sreenivasa #include <sys/vdev_impl.h>
245cabbc6bSPrashanth Sreenivasa #include <sys/vdev_indirect_mapping.h>
255cabbc6bSPrashanth Sreenivasa #include <sys/zfeature.h>
265cabbc6bSPrashanth Sreenivasa #include <sys/dmu_objset.h>
275cabbc6bSPrashanth Sreenivasa 
285cabbc6bSPrashanth Sreenivasa static boolean_t
295cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_verify(vdev_indirect_mapping_t *vim)
305cabbc6bSPrashanth Sreenivasa {
315cabbc6bSPrashanth Sreenivasa 	ASSERT(vim != NULL);
325cabbc6bSPrashanth Sreenivasa 
335cabbc6bSPrashanth Sreenivasa 	ASSERT(vim->vim_object != 0);
345cabbc6bSPrashanth Sreenivasa 	ASSERT(vim->vim_objset != NULL);
355cabbc6bSPrashanth Sreenivasa 	ASSERT(vim->vim_phys != NULL);
365cabbc6bSPrashanth Sreenivasa 	ASSERT(vim->vim_dbuf != NULL);
375cabbc6bSPrashanth Sreenivasa 
385cabbc6bSPrashanth Sreenivasa 	EQUIV(vim->vim_phys->vimp_num_entries > 0,
395cabbc6bSPrashanth Sreenivasa 	    vim->vim_entries != NULL);
405cabbc6bSPrashanth Sreenivasa 	if (vim->vim_phys->vimp_num_entries > 0) {
415cabbc6bSPrashanth Sreenivasa 		vdev_indirect_mapping_entry_phys_t *last_entry =
425cabbc6bSPrashanth Sreenivasa 		    &vim->vim_entries[vim->vim_phys->vimp_num_entries - 1];
435cabbc6bSPrashanth Sreenivasa 		uint64_t offset = DVA_MAPPING_GET_SRC_OFFSET(last_entry);
445cabbc6bSPrashanth Sreenivasa 		uint64_t size = DVA_GET_ASIZE(&last_entry->vimep_dst);
455cabbc6bSPrashanth Sreenivasa 
465cabbc6bSPrashanth Sreenivasa 		ASSERT3U(vim->vim_phys->vimp_max_offset, >=, offset + size);
475cabbc6bSPrashanth Sreenivasa 	}
485cabbc6bSPrashanth Sreenivasa 	if (vim->vim_havecounts) {
495cabbc6bSPrashanth Sreenivasa 		ASSERT(vim->vim_phys->vimp_counts_object != 0);
505cabbc6bSPrashanth Sreenivasa 	}
515cabbc6bSPrashanth Sreenivasa 
525cabbc6bSPrashanth Sreenivasa 	return (B_TRUE);
535cabbc6bSPrashanth Sreenivasa }
545cabbc6bSPrashanth Sreenivasa 
555cabbc6bSPrashanth Sreenivasa uint64_t
565cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_num_entries(vdev_indirect_mapping_t *vim)
575cabbc6bSPrashanth Sreenivasa {
585cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
595cabbc6bSPrashanth Sreenivasa 
605cabbc6bSPrashanth Sreenivasa 	return (vim->vim_phys->vimp_num_entries);
615cabbc6bSPrashanth Sreenivasa }
625cabbc6bSPrashanth Sreenivasa 
635cabbc6bSPrashanth Sreenivasa uint64_t
645cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_max_offset(vdev_indirect_mapping_t *vim)
655cabbc6bSPrashanth Sreenivasa {
665cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
675cabbc6bSPrashanth Sreenivasa 
685cabbc6bSPrashanth Sreenivasa 	return (vim->vim_phys->vimp_max_offset);
695cabbc6bSPrashanth Sreenivasa }
705cabbc6bSPrashanth Sreenivasa 
715cabbc6bSPrashanth Sreenivasa uint64_t
725cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_object(vdev_indirect_mapping_t *vim)
735cabbc6bSPrashanth Sreenivasa {
745cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
755cabbc6bSPrashanth Sreenivasa 
765cabbc6bSPrashanth Sreenivasa 	return (vim->vim_object);
775cabbc6bSPrashanth Sreenivasa }
785cabbc6bSPrashanth Sreenivasa 
795cabbc6bSPrashanth Sreenivasa uint64_t
805cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_bytes_mapped(vdev_indirect_mapping_t *vim)
815cabbc6bSPrashanth Sreenivasa {
825cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
835cabbc6bSPrashanth Sreenivasa 
845cabbc6bSPrashanth Sreenivasa 	return (vim->vim_phys->vimp_bytes_mapped);
855cabbc6bSPrashanth Sreenivasa }
865cabbc6bSPrashanth Sreenivasa 
875cabbc6bSPrashanth Sreenivasa /*
885cabbc6bSPrashanth Sreenivasa  * The length (in bytes) of the mapping object array in memory and
895cabbc6bSPrashanth Sreenivasa  * (logically) on disk.
905cabbc6bSPrashanth Sreenivasa  *
915cabbc6bSPrashanth Sreenivasa  * Note that unlike most of our accessor functions,
925cabbc6bSPrashanth Sreenivasa  * we don't assert that the struct is consistent; therefore it can be
935cabbc6bSPrashanth Sreenivasa  * called while there may be concurrent changes, if we don't care about
945cabbc6bSPrashanth Sreenivasa  * the value being immediately stale (e.g. from spa_removal_get_stats()).
955cabbc6bSPrashanth Sreenivasa  */
965cabbc6bSPrashanth Sreenivasa uint64_t
975cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_size(vdev_indirect_mapping_t *vim)
985cabbc6bSPrashanth Sreenivasa {
995cabbc6bSPrashanth Sreenivasa 	return (vim->vim_phys->vimp_num_entries * sizeof (*vim->vim_entries));
1005cabbc6bSPrashanth Sreenivasa }
1015cabbc6bSPrashanth Sreenivasa 
1025cabbc6bSPrashanth Sreenivasa /*
1035cabbc6bSPrashanth Sreenivasa  * Compare an offset with an indirect mapping entry; there are three
1045cabbc6bSPrashanth Sreenivasa  * possible scenarios:
1055cabbc6bSPrashanth Sreenivasa  *
1065cabbc6bSPrashanth Sreenivasa  *     1. The offset is "less than" the mapping entry; meaning the
1075cabbc6bSPrashanth Sreenivasa  *        offset is less than the source offset of the mapping entry. In
1085cabbc6bSPrashanth Sreenivasa  *        this case, there is no overlap between the offset and the
1095cabbc6bSPrashanth Sreenivasa  *        mapping entry and -1 will be returned.
1105cabbc6bSPrashanth Sreenivasa  *
1115cabbc6bSPrashanth Sreenivasa  *     2. The offset is "greater than" the mapping entry; meaning the
1125cabbc6bSPrashanth Sreenivasa  *        offset is greater than the mapping entry's source offset plus
1135cabbc6bSPrashanth Sreenivasa  *        the entry's size. In this case, there is no overlap between
1145cabbc6bSPrashanth Sreenivasa  *        the offset and the mapping entry and 1 will be returned.
1155cabbc6bSPrashanth Sreenivasa  *
1165cabbc6bSPrashanth Sreenivasa  *        NOTE: If the offset is actually equal to the entry's offset
1175cabbc6bSPrashanth Sreenivasa  *        plus size, this is considered to be "greater" than the entry,
1185cabbc6bSPrashanth Sreenivasa  *        and this case applies (i.e. 1 will be returned). Thus, the
1195cabbc6bSPrashanth Sreenivasa  *        entry's "range" can be considered to be inclusive at its
1205cabbc6bSPrashanth Sreenivasa  *        start, but exclusive at its end: e.g. [src, src + size).
1215cabbc6bSPrashanth Sreenivasa  *
1225cabbc6bSPrashanth Sreenivasa  *     3. The last case to consider is if the offset actually falls
1235cabbc6bSPrashanth Sreenivasa  *        within the mapping entry's range. If this is the case, the
1245cabbc6bSPrashanth Sreenivasa  *        offset is considered to be "equal to" the mapping entry and
1255cabbc6bSPrashanth Sreenivasa  *        0 will be returned.
1265cabbc6bSPrashanth Sreenivasa  *
1275cabbc6bSPrashanth Sreenivasa  *        NOTE: If the offset is equal to the entry's source offset,
1285cabbc6bSPrashanth Sreenivasa  *        this case applies and 0 will be returned. If the offset is
1295cabbc6bSPrashanth Sreenivasa  *        equal to the entry's source plus its size, this case does
1305cabbc6bSPrashanth Sreenivasa  *        *not* apply (see "NOTE" above for scenario 2), and 1 will be
1315cabbc6bSPrashanth Sreenivasa  *        returned.
1325cabbc6bSPrashanth Sreenivasa  */
1335cabbc6bSPrashanth Sreenivasa static int
1345cabbc6bSPrashanth Sreenivasa dva_mapping_overlap_compare(const void *v_key, const void *v_array_elem)
1355cabbc6bSPrashanth Sreenivasa {
136f02c28e4SToomas Soome 	const uint64_t *key = v_key;
137f02c28e4SToomas Soome 	const vdev_indirect_mapping_entry_phys_t *array_elem =
1385cabbc6bSPrashanth Sreenivasa 	    v_array_elem;
1395cabbc6bSPrashanth Sreenivasa 	uint64_t src_offset = DVA_MAPPING_GET_SRC_OFFSET(array_elem);
1405cabbc6bSPrashanth Sreenivasa 
1415cabbc6bSPrashanth Sreenivasa 	if (*key < src_offset) {
1425cabbc6bSPrashanth Sreenivasa 		return (-1);
1435cabbc6bSPrashanth Sreenivasa 	} else if (*key < src_offset + DVA_GET_ASIZE(&array_elem->vimep_dst)) {
1445cabbc6bSPrashanth Sreenivasa 		return (0);
1455cabbc6bSPrashanth Sreenivasa 	} else {
1465cabbc6bSPrashanth Sreenivasa 		return (1);
1475cabbc6bSPrashanth Sreenivasa 	}
1485cabbc6bSPrashanth Sreenivasa }
1495cabbc6bSPrashanth Sreenivasa 
1505cabbc6bSPrashanth Sreenivasa /*
1515cabbc6bSPrashanth Sreenivasa  * Returns the mapping entry for the given offset.
1525cabbc6bSPrashanth Sreenivasa  *
1535cabbc6bSPrashanth Sreenivasa  * It's possible that the given offset will not be in the mapping table
1545cabbc6bSPrashanth Sreenivasa  * (i.e. no mapping entries contain this offset), in which case, the
1555cabbc6bSPrashanth Sreenivasa  * return value value depends on the "next_if_missing" parameter.
1565cabbc6bSPrashanth Sreenivasa  *
1575cabbc6bSPrashanth Sreenivasa  * If the offset is not found in the table and "next_if_missing" is
1585cabbc6bSPrashanth Sreenivasa  * B_FALSE, then NULL will always be returned. The behavior is intended
1595cabbc6bSPrashanth Sreenivasa  * to allow consumers to get the entry corresponding to the offset
1605cabbc6bSPrashanth Sreenivasa  * parameter, iff the offset overlaps with an entry in the table.
1615cabbc6bSPrashanth Sreenivasa  *
1625cabbc6bSPrashanth Sreenivasa  * If the offset is not found in the table and "next_if_missing" is
1635cabbc6bSPrashanth Sreenivasa  * B_TRUE, then the entry nearest to the given offset will be returned,
1645cabbc6bSPrashanth Sreenivasa  * such that the entry's source offset is greater than the offset
1655cabbc6bSPrashanth Sreenivasa  * passed in (i.e. the "next" mapping entry in the table is returned, if
1665cabbc6bSPrashanth Sreenivasa  * the offset is missing from the table). If there are no entries whose
1675cabbc6bSPrashanth Sreenivasa  * source offset is greater than the passed in offset, NULL is returned.
1685cabbc6bSPrashanth Sreenivasa  */
1695cabbc6bSPrashanth Sreenivasa static vdev_indirect_mapping_entry_phys_t *
1705cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_entry_for_offset_impl(vdev_indirect_mapping_t *vim,
1715cabbc6bSPrashanth Sreenivasa     uint64_t offset, boolean_t next_if_missing)
1725cabbc6bSPrashanth Sreenivasa {
1735cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
1745cabbc6bSPrashanth Sreenivasa 	ASSERT(vim->vim_phys->vimp_num_entries > 0);
1755cabbc6bSPrashanth Sreenivasa 
1765cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_entry_phys_t *entry = NULL;
1775cabbc6bSPrashanth Sreenivasa 
1785cabbc6bSPrashanth Sreenivasa 	uint64_t last = vim->vim_phys->vimp_num_entries - 1;
1795cabbc6bSPrashanth Sreenivasa 	uint64_t base = 0;
1805cabbc6bSPrashanth Sreenivasa 
1815cabbc6bSPrashanth Sreenivasa 	/*
1825cabbc6bSPrashanth Sreenivasa 	 * We don't define these inside of the while loop because we use
1835cabbc6bSPrashanth Sreenivasa 	 * their value in the case that offset isn't in the mapping.
1845cabbc6bSPrashanth Sreenivasa 	 */
1855cabbc6bSPrashanth Sreenivasa 	uint64_t mid;
1865cabbc6bSPrashanth Sreenivasa 	int result;
1875cabbc6bSPrashanth Sreenivasa 
1885cabbc6bSPrashanth Sreenivasa 	while (last >= base) {
1895cabbc6bSPrashanth Sreenivasa 		mid = base + ((last - base) >> 1);
1905cabbc6bSPrashanth Sreenivasa 
1915cabbc6bSPrashanth Sreenivasa 		result = dva_mapping_overlap_compare(&offset,
1925cabbc6bSPrashanth Sreenivasa 		    &vim->vim_entries[mid]);
1935cabbc6bSPrashanth Sreenivasa 
1945cabbc6bSPrashanth Sreenivasa 		if (result == 0) {
1955cabbc6bSPrashanth Sreenivasa 			entry = &vim->vim_entries[mid];
1965cabbc6bSPrashanth Sreenivasa 			break;
1975cabbc6bSPrashanth Sreenivasa 		} else if (result < 0) {
1985cabbc6bSPrashanth Sreenivasa 			last = mid - 1;
1995cabbc6bSPrashanth Sreenivasa 		} else {
2005cabbc6bSPrashanth Sreenivasa 			base = mid + 1;
2015cabbc6bSPrashanth Sreenivasa 		}
2025cabbc6bSPrashanth Sreenivasa 	}
2035cabbc6bSPrashanth Sreenivasa 
2045cabbc6bSPrashanth Sreenivasa 	if (entry == NULL && next_if_missing) {
2055cabbc6bSPrashanth Sreenivasa 		ASSERT3U(base, ==, last + 1);
2065cabbc6bSPrashanth Sreenivasa 		ASSERT(mid == base || mid == last);
2075cabbc6bSPrashanth Sreenivasa 		ASSERT3S(result, !=, 0);
2085cabbc6bSPrashanth Sreenivasa 
2095cabbc6bSPrashanth Sreenivasa 		/*
2105cabbc6bSPrashanth Sreenivasa 		 * The offset we're looking for isn't actually contained
2115cabbc6bSPrashanth Sreenivasa 		 * in the mapping table, thus we need to return the
2125cabbc6bSPrashanth Sreenivasa 		 * closest mapping entry that is greater than the
2135cabbc6bSPrashanth Sreenivasa 		 * offset. We reuse the result of the last comparison,
2145cabbc6bSPrashanth Sreenivasa 		 * comparing the mapping entry at index "mid" and the
2155cabbc6bSPrashanth Sreenivasa 		 * offset. The offset is guaranteed to lie between
2165cabbc6bSPrashanth Sreenivasa 		 * indices one less than "mid", and one greater than
2175cabbc6bSPrashanth Sreenivasa 		 * "mid"; we just need to determine if offset is greater
2185cabbc6bSPrashanth Sreenivasa 		 * than, or less than the mapping entry contained at
2195cabbc6bSPrashanth Sreenivasa 		 * index "mid".
2205cabbc6bSPrashanth Sreenivasa 		 */
2215cabbc6bSPrashanth Sreenivasa 
2225cabbc6bSPrashanth Sreenivasa 		uint64_t index;
2235cabbc6bSPrashanth Sreenivasa 		if (result < 0)
2245cabbc6bSPrashanth Sreenivasa 			index = mid;
2255cabbc6bSPrashanth Sreenivasa 		else
2265cabbc6bSPrashanth Sreenivasa 			index = mid + 1;
2275cabbc6bSPrashanth Sreenivasa 
2285cabbc6bSPrashanth Sreenivasa 		ASSERT3U(index, <=, vim->vim_phys->vimp_num_entries);
2295cabbc6bSPrashanth Sreenivasa 
2305cabbc6bSPrashanth Sreenivasa 		if (index == vim->vim_phys->vimp_num_entries) {
2315cabbc6bSPrashanth Sreenivasa 			/*
2325cabbc6bSPrashanth Sreenivasa 			 * If "index" is past the end of the entries
2335cabbc6bSPrashanth Sreenivasa 			 * array, then not only is the offset not in the
2345cabbc6bSPrashanth Sreenivasa 			 * mapping table, but it's actually greater than
2355cabbc6bSPrashanth Sreenivasa 			 * all entries in the table. In this case, we
2365cabbc6bSPrashanth Sreenivasa 			 * can't return a mapping entry greater than the
2375cabbc6bSPrashanth Sreenivasa 			 * offset (since none exist), so we return NULL.
2385cabbc6bSPrashanth Sreenivasa 			 */
2395cabbc6bSPrashanth Sreenivasa 
2405cabbc6bSPrashanth Sreenivasa 			ASSERT3S(dva_mapping_overlap_compare(&offset,
2415cabbc6bSPrashanth Sreenivasa 			    &vim->vim_entries[index - 1]), >, 0);
2425cabbc6bSPrashanth Sreenivasa 
2435cabbc6bSPrashanth Sreenivasa 			return (NULL);
2445cabbc6bSPrashanth Sreenivasa 		} else {
2455cabbc6bSPrashanth Sreenivasa 			/*
2465cabbc6bSPrashanth Sreenivasa 			 * Just to be safe, we verify the offset falls
2475cabbc6bSPrashanth Sreenivasa 			 * in between the mapping entries at index and
2485cabbc6bSPrashanth Sreenivasa 			 * one less than index. Since we know the offset
2495cabbc6bSPrashanth Sreenivasa 			 * doesn't overlap an entry, and we're supposed
2505cabbc6bSPrashanth Sreenivasa 			 * to return the entry just greater than the
2515cabbc6bSPrashanth Sreenivasa 			 * offset, both of the following tests must be
2525cabbc6bSPrashanth Sreenivasa 			 * true.
2535cabbc6bSPrashanth Sreenivasa 			 */
2545cabbc6bSPrashanth Sreenivasa 			ASSERT3S(dva_mapping_overlap_compare(&offset,
2555cabbc6bSPrashanth Sreenivasa 			    &vim->vim_entries[index]), <, 0);
2565cabbc6bSPrashanth Sreenivasa 			IMPLY(index >= 1, dva_mapping_overlap_compare(&offset,
2575cabbc6bSPrashanth Sreenivasa 			    &vim->vim_entries[index - 1]) > 0);
2585cabbc6bSPrashanth Sreenivasa 
2595cabbc6bSPrashanth Sreenivasa 			return (&vim->vim_entries[index]);
2605cabbc6bSPrashanth Sreenivasa 		}
2615cabbc6bSPrashanth Sreenivasa 	} else {
2625cabbc6bSPrashanth Sreenivasa 		return (entry);
2635cabbc6bSPrashanth Sreenivasa 	}
2645cabbc6bSPrashanth Sreenivasa }
2655cabbc6bSPrashanth Sreenivasa 
2665cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_entry_phys_t *
2675cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim,
2685cabbc6bSPrashanth Sreenivasa     uint64_t offset)
2695cabbc6bSPrashanth Sreenivasa {
2705cabbc6bSPrashanth Sreenivasa 	return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
2715cabbc6bSPrashanth Sreenivasa 	    B_FALSE));
2725cabbc6bSPrashanth Sreenivasa }
2735cabbc6bSPrashanth Sreenivasa 
2745cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_entry_phys_t *
2755cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_entry_for_offset_or_next(vdev_indirect_mapping_t *vim,
2765cabbc6bSPrashanth Sreenivasa     uint64_t offset)
2775cabbc6bSPrashanth Sreenivasa {
2785cabbc6bSPrashanth Sreenivasa 	return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
2795cabbc6bSPrashanth Sreenivasa 	    B_TRUE));
2805cabbc6bSPrashanth Sreenivasa }
2815cabbc6bSPrashanth Sreenivasa 
2825cabbc6bSPrashanth Sreenivasa void
2835cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim)
2845cabbc6bSPrashanth Sreenivasa {
2855cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
2865cabbc6bSPrashanth Sreenivasa 
2875cabbc6bSPrashanth Sreenivasa 	if (vim->vim_phys->vimp_num_entries > 0) {
2885cabbc6bSPrashanth Sreenivasa 		uint64_t map_size = vdev_indirect_mapping_size(vim);
2895cabbc6bSPrashanth Sreenivasa 		kmem_free(vim->vim_entries, map_size);
2905cabbc6bSPrashanth Sreenivasa 		vim->vim_entries = NULL;
2915cabbc6bSPrashanth Sreenivasa 	}
2925cabbc6bSPrashanth Sreenivasa 
2935cabbc6bSPrashanth Sreenivasa 	dmu_buf_rele(vim->vim_dbuf, vim);
2945cabbc6bSPrashanth Sreenivasa 
2955cabbc6bSPrashanth Sreenivasa 	vim->vim_objset = NULL;
2965cabbc6bSPrashanth Sreenivasa 	vim->vim_object = 0;
2975cabbc6bSPrashanth Sreenivasa 	vim->vim_dbuf = NULL;
2985cabbc6bSPrashanth Sreenivasa 	vim->vim_phys = NULL;
2995cabbc6bSPrashanth Sreenivasa 
3005cabbc6bSPrashanth Sreenivasa 	kmem_free(vim, sizeof (*vim));
3015cabbc6bSPrashanth Sreenivasa }
3025cabbc6bSPrashanth Sreenivasa 
3035cabbc6bSPrashanth Sreenivasa uint64_t
3045cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_alloc(objset_t *os, dmu_tx_t *tx)
3055cabbc6bSPrashanth Sreenivasa {
3065cabbc6bSPrashanth Sreenivasa 	uint64_t object;
3075cabbc6bSPrashanth Sreenivasa 	ASSERT(dmu_tx_is_syncing(tx));
3085cabbc6bSPrashanth Sreenivasa 	uint64_t bonus_size = VDEV_INDIRECT_MAPPING_SIZE_V0;
3095cabbc6bSPrashanth Sreenivasa 
3105cabbc6bSPrashanth Sreenivasa 	if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
3115cabbc6bSPrashanth Sreenivasa 		bonus_size = sizeof (vdev_indirect_mapping_phys_t);
3125cabbc6bSPrashanth Sreenivasa 	}
3135cabbc6bSPrashanth Sreenivasa 
3145cabbc6bSPrashanth Sreenivasa 	object = dmu_object_alloc(os,
3155cabbc6bSPrashanth Sreenivasa 	    DMU_OTN_UINT64_METADATA, SPA_OLD_MAXBLOCKSIZE,
3165cabbc6bSPrashanth Sreenivasa 	    DMU_OTN_UINT64_METADATA, bonus_size,
3175cabbc6bSPrashanth Sreenivasa 	    tx);
3185cabbc6bSPrashanth Sreenivasa 
3195cabbc6bSPrashanth Sreenivasa 	if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
3205cabbc6bSPrashanth Sreenivasa 		dmu_buf_t *dbuf;
3215cabbc6bSPrashanth Sreenivasa 		vdev_indirect_mapping_phys_t *vimp;
3225cabbc6bSPrashanth Sreenivasa 
3235cabbc6bSPrashanth Sreenivasa 		VERIFY0(dmu_bonus_hold(os, object, FTAG, &dbuf));
3245cabbc6bSPrashanth Sreenivasa 		dmu_buf_will_dirty(dbuf, tx);
3255cabbc6bSPrashanth Sreenivasa 		vimp = dbuf->db_data;
3265cabbc6bSPrashanth Sreenivasa 		vimp->vimp_counts_object = dmu_object_alloc(os,
3275cabbc6bSPrashanth Sreenivasa 		    DMU_OTN_UINT32_METADATA, SPA_OLD_MAXBLOCKSIZE,
3285cabbc6bSPrashanth Sreenivasa 		    DMU_OT_NONE, 0, tx);
3295cabbc6bSPrashanth Sreenivasa 		spa_feature_incr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
3305cabbc6bSPrashanth Sreenivasa 		dmu_buf_rele(dbuf, FTAG);
3315cabbc6bSPrashanth Sreenivasa 	}
3325cabbc6bSPrashanth Sreenivasa 
3335cabbc6bSPrashanth Sreenivasa 	return (object);
3345cabbc6bSPrashanth Sreenivasa }
3355cabbc6bSPrashanth Sreenivasa 
3365cabbc6bSPrashanth Sreenivasa 
3375cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_t *
3385cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_open(objset_t *os, uint64_t mapping_object)
3395cabbc6bSPrashanth Sreenivasa {
3405cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_t *vim = kmem_zalloc(sizeof (*vim), KM_SLEEP);
3415cabbc6bSPrashanth Sreenivasa 	dmu_object_info_t doi;
3425cabbc6bSPrashanth Sreenivasa 	VERIFY0(dmu_object_info(os, mapping_object, &doi));
3435cabbc6bSPrashanth Sreenivasa 
3445cabbc6bSPrashanth Sreenivasa 	vim->vim_objset = os;
3455cabbc6bSPrashanth Sreenivasa 	vim->vim_object = mapping_object;
3465cabbc6bSPrashanth Sreenivasa 
3475cabbc6bSPrashanth Sreenivasa 	VERIFY0(dmu_bonus_hold(os, vim->vim_object, vim,
3485cabbc6bSPrashanth Sreenivasa 	    &vim->vim_dbuf));
3495cabbc6bSPrashanth Sreenivasa 	vim->vim_phys = vim->vim_dbuf->db_data;
3505cabbc6bSPrashanth Sreenivasa 
3515cabbc6bSPrashanth Sreenivasa 	vim->vim_havecounts =
3525cabbc6bSPrashanth Sreenivasa 	    (doi.doi_bonus_size > VDEV_INDIRECT_MAPPING_SIZE_V0);
3535cabbc6bSPrashanth Sreenivasa 
3545cabbc6bSPrashanth Sreenivasa 	if (vim->vim_phys->vimp_num_entries > 0) {
3555cabbc6bSPrashanth Sreenivasa 		uint64_t map_size = vdev_indirect_mapping_size(vim);
3565cabbc6bSPrashanth Sreenivasa 		vim->vim_entries = kmem_alloc(map_size, KM_SLEEP);
3575cabbc6bSPrashanth Sreenivasa 		VERIFY0(dmu_read(os, vim->vim_object, 0, map_size,
3585cabbc6bSPrashanth Sreenivasa 		    vim->vim_entries, DMU_READ_PREFETCH));
3595cabbc6bSPrashanth Sreenivasa 	}
3605cabbc6bSPrashanth Sreenivasa 
3615cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
3625cabbc6bSPrashanth Sreenivasa 
3635cabbc6bSPrashanth Sreenivasa 	return (vim);
3645cabbc6bSPrashanth Sreenivasa }
3655cabbc6bSPrashanth Sreenivasa 
3665cabbc6bSPrashanth Sreenivasa void
3675cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
3685cabbc6bSPrashanth Sreenivasa {
3695cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_t *vim = vdev_indirect_mapping_open(os, object);
3705cabbc6bSPrashanth Sreenivasa 	if (vim->vim_havecounts) {
3715cabbc6bSPrashanth Sreenivasa 		VERIFY0(dmu_object_free(os, vim->vim_phys->vimp_counts_object,
3725cabbc6bSPrashanth Sreenivasa 		    tx));
3735cabbc6bSPrashanth Sreenivasa 		spa_feature_decr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
3745cabbc6bSPrashanth Sreenivasa 	}
3755cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_close(vim);
3765cabbc6bSPrashanth Sreenivasa 
3775cabbc6bSPrashanth Sreenivasa 	VERIFY0(dmu_object_free(os, object, tx));
3785cabbc6bSPrashanth Sreenivasa }
3795cabbc6bSPrashanth Sreenivasa 
3805cabbc6bSPrashanth Sreenivasa /*
3815cabbc6bSPrashanth Sreenivasa  * Append the list of vdev_indirect_mapping_entry_t's to the on-disk
3825cabbc6bSPrashanth Sreenivasa  * mapping object.  Also remove the entries from the list and free them.
3835cabbc6bSPrashanth Sreenivasa  * This also implicitly extends the max_offset of the mapping (to the end
3845cabbc6bSPrashanth Sreenivasa  * of the last entry).
3855cabbc6bSPrashanth Sreenivasa  */
3865cabbc6bSPrashanth Sreenivasa void
3875cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim,
3885cabbc6bSPrashanth Sreenivasa     list_t *list, dmu_tx_t *tx)
3895cabbc6bSPrashanth Sreenivasa {
3905cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_entry_phys_t *mapbuf;
3915cabbc6bSPrashanth Sreenivasa 	uint64_t old_size;
3925cabbc6bSPrashanth Sreenivasa 	uint32_t *countbuf = NULL;
3935cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_entry_phys_t *old_entries;
3945cabbc6bSPrashanth Sreenivasa 	uint64_t old_count;
3955cabbc6bSPrashanth Sreenivasa 	uint64_t entries_written = 0;
3965cabbc6bSPrashanth Sreenivasa 
3975cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
3985cabbc6bSPrashanth Sreenivasa 	ASSERT(dmu_tx_is_syncing(tx));
3995cabbc6bSPrashanth Sreenivasa 	ASSERT(dsl_pool_sync_context(dmu_tx_pool(tx)));
4005cabbc6bSPrashanth Sreenivasa 	ASSERT(!list_is_empty(list));
4015cabbc6bSPrashanth Sreenivasa 
4025cabbc6bSPrashanth Sreenivasa 	old_size = vdev_indirect_mapping_size(vim);
4035cabbc6bSPrashanth Sreenivasa 	old_entries = vim->vim_entries;
4045cabbc6bSPrashanth Sreenivasa 	old_count = vim->vim_phys->vimp_num_entries;
4055cabbc6bSPrashanth Sreenivasa 
4065cabbc6bSPrashanth Sreenivasa 	dmu_buf_will_dirty(vim->vim_dbuf, tx);
4075cabbc6bSPrashanth Sreenivasa 
4085cabbc6bSPrashanth Sreenivasa 	mapbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
4095cabbc6bSPrashanth Sreenivasa 	if (vim->vim_havecounts) {
4105cabbc6bSPrashanth Sreenivasa 		countbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
4115cabbc6bSPrashanth Sreenivasa 		ASSERT(spa_feature_is_active(vim->vim_objset->os_spa,
4125cabbc6bSPrashanth Sreenivasa 		    SPA_FEATURE_OBSOLETE_COUNTS));
4135cabbc6bSPrashanth Sreenivasa 	}
4145cabbc6bSPrashanth Sreenivasa 	while (!list_is_empty(list)) {
4155cabbc6bSPrashanth Sreenivasa 		uint64_t i;
4165cabbc6bSPrashanth Sreenivasa 		/*
4175cabbc6bSPrashanth Sreenivasa 		 * Write entries from the list to the
4185cabbc6bSPrashanth Sreenivasa 		 * vdev_im_object in batches of size SPA_OLD_MAXBLOCKSIZE.
4195cabbc6bSPrashanth Sreenivasa 		 */
4205cabbc6bSPrashanth Sreenivasa 		for (i = 0; i < SPA_OLD_MAXBLOCKSIZE / sizeof (*mapbuf); i++) {
4215cabbc6bSPrashanth Sreenivasa 			vdev_indirect_mapping_entry_t *entry =
4225cabbc6bSPrashanth Sreenivasa 			    list_remove_head(list);
4235cabbc6bSPrashanth Sreenivasa 			if (entry == NULL)
4245cabbc6bSPrashanth Sreenivasa 				break;
4255cabbc6bSPrashanth Sreenivasa 
4265cabbc6bSPrashanth Sreenivasa 			uint64_t size =
4275cabbc6bSPrashanth Sreenivasa 			    DVA_GET_ASIZE(&entry->vime_mapping.vimep_dst);
4285cabbc6bSPrashanth Sreenivasa 			uint64_t src_offset =
4295cabbc6bSPrashanth Sreenivasa 			    DVA_MAPPING_GET_SRC_OFFSET(&entry->vime_mapping);
4305cabbc6bSPrashanth Sreenivasa 
4315cabbc6bSPrashanth Sreenivasa 			/*
4325cabbc6bSPrashanth Sreenivasa 			 * We shouldn't be adding an entry which is fully
4335cabbc6bSPrashanth Sreenivasa 			 * obsolete.
4345cabbc6bSPrashanth Sreenivasa 			 */
4355cabbc6bSPrashanth Sreenivasa 			ASSERT3U(entry->vime_obsolete_count, <, size);
4365cabbc6bSPrashanth Sreenivasa 			IMPLY(entry->vime_obsolete_count != 0,
4375cabbc6bSPrashanth Sreenivasa 			    vim->vim_havecounts);
4385cabbc6bSPrashanth Sreenivasa 
4395cabbc6bSPrashanth Sreenivasa 			mapbuf[i] = entry->vime_mapping;
4405cabbc6bSPrashanth Sreenivasa 			if (vim->vim_havecounts)
4415cabbc6bSPrashanth Sreenivasa 				countbuf[i] = entry->vime_obsolete_count;
4425cabbc6bSPrashanth Sreenivasa 
4435cabbc6bSPrashanth Sreenivasa 			vim->vim_phys->vimp_bytes_mapped += size;
4445cabbc6bSPrashanth Sreenivasa 			ASSERT3U(src_offset, >=,
4455cabbc6bSPrashanth Sreenivasa 			    vim->vim_phys->vimp_max_offset);
4465cabbc6bSPrashanth Sreenivasa 			vim->vim_phys->vimp_max_offset = src_offset + size;
4475cabbc6bSPrashanth Sreenivasa 
4485cabbc6bSPrashanth Sreenivasa 			entries_written++;
4495cabbc6bSPrashanth Sreenivasa 
4505cabbc6bSPrashanth Sreenivasa 			kmem_free(entry, sizeof (*entry));
4515cabbc6bSPrashanth Sreenivasa 		}
4525cabbc6bSPrashanth Sreenivasa 		dmu_write(vim->vim_objset, vim->vim_object,
4535cabbc6bSPrashanth Sreenivasa 		    vim->vim_phys->vimp_num_entries * sizeof (*mapbuf),
4545cabbc6bSPrashanth Sreenivasa 		    i * sizeof (*mapbuf),
4555cabbc6bSPrashanth Sreenivasa 		    mapbuf, tx);
4565cabbc6bSPrashanth Sreenivasa 		if (vim->vim_havecounts) {
4575cabbc6bSPrashanth Sreenivasa 			dmu_write(vim->vim_objset,
4585cabbc6bSPrashanth Sreenivasa 			    vim->vim_phys->vimp_counts_object,
4595cabbc6bSPrashanth Sreenivasa 			    vim->vim_phys->vimp_num_entries *
4605cabbc6bSPrashanth Sreenivasa 			    sizeof (*countbuf),
4615cabbc6bSPrashanth Sreenivasa 			    i * sizeof (*countbuf), countbuf, tx);
4625cabbc6bSPrashanth Sreenivasa 		}
4635cabbc6bSPrashanth Sreenivasa 		vim->vim_phys->vimp_num_entries += i;
4645cabbc6bSPrashanth Sreenivasa 	}
4655cabbc6bSPrashanth Sreenivasa 	zio_buf_free(mapbuf, SPA_OLD_MAXBLOCKSIZE);
4665cabbc6bSPrashanth Sreenivasa 	if (vim->vim_havecounts)
4675cabbc6bSPrashanth Sreenivasa 		zio_buf_free(countbuf, SPA_OLD_MAXBLOCKSIZE);
4685cabbc6bSPrashanth Sreenivasa 
4695cabbc6bSPrashanth Sreenivasa 	/*
4705cabbc6bSPrashanth Sreenivasa 	 * Update the entry array to reflect the new entries. First, copy
4715cabbc6bSPrashanth Sreenivasa 	 * over any old entries then read back the new entries we just wrote.
4725cabbc6bSPrashanth Sreenivasa 	 */
4735cabbc6bSPrashanth Sreenivasa 	uint64_t new_size = vdev_indirect_mapping_size(vim);
4745cabbc6bSPrashanth Sreenivasa 	ASSERT3U(new_size, >, old_size);
4755cabbc6bSPrashanth Sreenivasa 	ASSERT3U(new_size - old_size, ==,
4765cabbc6bSPrashanth Sreenivasa 	    entries_written * sizeof (vdev_indirect_mapping_entry_phys_t));
4775cabbc6bSPrashanth Sreenivasa 	vim->vim_entries = kmem_alloc(new_size, KM_SLEEP);
4785cabbc6bSPrashanth Sreenivasa 	if (old_size > 0) {
4795cabbc6bSPrashanth Sreenivasa 		bcopy(old_entries, vim->vim_entries, old_size);
4805cabbc6bSPrashanth Sreenivasa 		kmem_free(old_entries, old_size);
4815cabbc6bSPrashanth Sreenivasa 	}
4825cabbc6bSPrashanth Sreenivasa 	VERIFY0(dmu_read(vim->vim_objset, vim->vim_object, old_size,
4835cabbc6bSPrashanth Sreenivasa 	    new_size - old_size, &vim->vim_entries[old_count],
4845cabbc6bSPrashanth Sreenivasa 	    DMU_READ_PREFETCH));
4855cabbc6bSPrashanth Sreenivasa 
4865cabbc6bSPrashanth Sreenivasa 	zfs_dbgmsg("txg %llu: wrote %llu entries to "
4875cabbc6bSPrashanth Sreenivasa 	    "indirect mapping obj %llu; max offset=0x%llx",
4885cabbc6bSPrashanth Sreenivasa 	    (u_longlong_t)dmu_tx_get_txg(tx),
4895cabbc6bSPrashanth Sreenivasa 	    (u_longlong_t)entries_written,
4905cabbc6bSPrashanth Sreenivasa 	    (u_longlong_t)vim->vim_object,
4915cabbc6bSPrashanth Sreenivasa 	    (u_longlong_t)vim->vim_phys->vimp_max_offset);
4925cabbc6bSPrashanth Sreenivasa }
4935cabbc6bSPrashanth Sreenivasa 
4945cabbc6bSPrashanth Sreenivasa /*
4955cabbc6bSPrashanth Sreenivasa  * Increment the relevant counts for the specified offset and length.
4965cabbc6bSPrashanth Sreenivasa  * The counts array must be obtained from
4975cabbc6bSPrashanth Sreenivasa  * vdev_indirect_mapping_load_obsolete_counts().
4985cabbc6bSPrashanth Sreenivasa  */
4995cabbc6bSPrashanth Sreenivasa void
5005cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_increment_obsolete_count(vdev_indirect_mapping_t *vim,
5015cabbc6bSPrashanth Sreenivasa     uint64_t offset, uint64_t length, uint32_t *counts)
5025cabbc6bSPrashanth Sreenivasa {
5035cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_entry_phys_t *mapping;
5045cabbc6bSPrashanth Sreenivasa 	uint64_t index;
5055cabbc6bSPrashanth Sreenivasa 
5065cabbc6bSPrashanth Sreenivasa 	mapping = vdev_indirect_mapping_entry_for_offset(vim,  offset);
5075cabbc6bSPrashanth Sreenivasa 
5085cabbc6bSPrashanth Sreenivasa 	ASSERT(length > 0);
5095cabbc6bSPrashanth Sreenivasa 	ASSERT3P(mapping, !=, NULL);
5105cabbc6bSPrashanth Sreenivasa 
5115cabbc6bSPrashanth Sreenivasa 	index = mapping - vim->vim_entries;
5125cabbc6bSPrashanth Sreenivasa 
5135cabbc6bSPrashanth Sreenivasa 	while (length > 0) {
5145cabbc6bSPrashanth Sreenivasa 		ASSERT3U(index, <, vdev_indirect_mapping_num_entries(vim));
5155cabbc6bSPrashanth Sreenivasa 
5165cabbc6bSPrashanth Sreenivasa 		uint64_t size = DVA_GET_ASIZE(&mapping->vimep_dst);
5175cabbc6bSPrashanth Sreenivasa 		uint64_t inner_offset = offset -
5185cabbc6bSPrashanth Sreenivasa 		    DVA_MAPPING_GET_SRC_OFFSET(mapping);
5195cabbc6bSPrashanth Sreenivasa 		VERIFY3U(inner_offset, <, size);
5205cabbc6bSPrashanth Sreenivasa 		uint64_t inner_size = MIN(length, size - inner_offset);
5215cabbc6bSPrashanth Sreenivasa 
5225cabbc6bSPrashanth Sreenivasa 		VERIFY3U(counts[index] + inner_size, <=, size);
5235cabbc6bSPrashanth Sreenivasa 		counts[index] += inner_size;
5245cabbc6bSPrashanth Sreenivasa 
5255cabbc6bSPrashanth Sreenivasa 		offset += inner_size;
5265cabbc6bSPrashanth Sreenivasa 		length -= inner_size;
5275cabbc6bSPrashanth Sreenivasa 		mapping++;
5285cabbc6bSPrashanth Sreenivasa 		index++;
5295cabbc6bSPrashanth Sreenivasa 	}
5305cabbc6bSPrashanth Sreenivasa }
5315cabbc6bSPrashanth Sreenivasa 
5325cabbc6bSPrashanth Sreenivasa typedef struct load_obsolete_space_map_arg {
5335cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_t	*losma_vim;
5345cabbc6bSPrashanth Sreenivasa 	uint32_t		*losma_counts;
5355cabbc6bSPrashanth Sreenivasa } load_obsolete_space_map_arg_t;
5365cabbc6bSPrashanth Sreenivasa 
5375cabbc6bSPrashanth Sreenivasa static int
53817f11284SSerapheim Dimitropoulos load_obsolete_sm_callback(space_map_entry_t *sme, void *arg)
5395cabbc6bSPrashanth Sreenivasa {
5405cabbc6bSPrashanth Sreenivasa 	load_obsolete_space_map_arg_t *losma = arg;
54117f11284SSerapheim Dimitropoulos 	ASSERT3S(sme->sme_type, ==, SM_ALLOC);
5425cabbc6bSPrashanth Sreenivasa 
5435cabbc6bSPrashanth Sreenivasa 	vdev_indirect_mapping_increment_obsolete_count(losma->losma_vim,
54417f11284SSerapheim Dimitropoulos 	    sme->sme_offset, sme->sme_run, losma->losma_counts);
5455cabbc6bSPrashanth Sreenivasa 
5465cabbc6bSPrashanth Sreenivasa 	return (0);
5475cabbc6bSPrashanth Sreenivasa }
5485cabbc6bSPrashanth Sreenivasa 
5495cabbc6bSPrashanth Sreenivasa /*
5505cabbc6bSPrashanth Sreenivasa  * Modify the counts (increment them) based on the spacemap.
5515cabbc6bSPrashanth Sreenivasa  */
5525cabbc6bSPrashanth Sreenivasa void
5535cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_load_obsolete_spacemap(vdev_indirect_mapping_t *vim,
5545cabbc6bSPrashanth Sreenivasa     uint32_t *counts, space_map_t *obsolete_space_sm)
5555cabbc6bSPrashanth Sreenivasa {
5565cabbc6bSPrashanth Sreenivasa 	load_obsolete_space_map_arg_t losma;
5575cabbc6bSPrashanth Sreenivasa 	losma.losma_counts = counts;
5585cabbc6bSPrashanth Sreenivasa 	losma.losma_vim = vim;
5595cabbc6bSPrashanth Sreenivasa 	VERIFY0(space_map_iterate(obsolete_space_sm,
560*555d674dSSerapheim Dimitropoulos 	    space_map_length(obsolete_space_sm),
5615cabbc6bSPrashanth Sreenivasa 	    load_obsolete_sm_callback, &losma));
5625cabbc6bSPrashanth Sreenivasa }
5635cabbc6bSPrashanth Sreenivasa 
5645cabbc6bSPrashanth Sreenivasa /*
5655cabbc6bSPrashanth Sreenivasa  * Read the obsolete counts from disk, returning them in an array.
5665cabbc6bSPrashanth Sreenivasa  */
5675cabbc6bSPrashanth Sreenivasa uint32_t *
5685cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_load_obsolete_counts(vdev_indirect_mapping_t *vim)
5695cabbc6bSPrashanth Sreenivasa {
5705cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
5715cabbc6bSPrashanth Sreenivasa 
5725cabbc6bSPrashanth Sreenivasa 	uint64_t counts_size =
5735cabbc6bSPrashanth Sreenivasa 	    vim->vim_phys->vimp_num_entries * sizeof (uint32_t);
5745cabbc6bSPrashanth Sreenivasa 	uint32_t *counts = kmem_alloc(counts_size, KM_SLEEP);
5755cabbc6bSPrashanth Sreenivasa 	if (vim->vim_havecounts) {
5765cabbc6bSPrashanth Sreenivasa 		VERIFY0(dmu_read(vim->vim_objset,
5775cabbc6bSPrashanth Sreenivasa 		    vim->vim_phys->vimp_counts_object,
5785cabbc6bSPrashanth Sreenivasa 		    0, counts_size,
5795cabbc6bSPrashanth Sreenivasa 		    counts, DMU_READ_PREFETCH));
5805cabbc6bSPrashanth Sreenivasa 	} else {
5815cabbc6bSPrashanth Sreenivasa 		bzero(counts, counts_size);
5825cabbc6bSPrashanth Sreenivasa 	}
5835cabbc6bSPrashanth Sreenivasa 	return (counts);
5845cabbc6bSPrashanth Sreenivasa }
5855cabbc6bSPrashanth Sreenivasa 
5865cabbc6bSPrashanth Sreenivasa extern void
5875cabbc6bSPrashanth Sreenivasa vdev_indirect_mapping_free_obsolete_counts(vdev_indirect_mapping_t *vim,
5885cabbc6bSPrashanth Sreenivasa     uint32_t *counts)
5895cabbc6bSPrashanth Sreenivasa {
5905cabbc6bSPrashanth Sreenivasa 	ASSERT(vdev_indirect_mapping_verify(vim));
5915cabbc6bSPrashanth Sreenivasa 
5925cabbc6bSPrashanth Sreenivasa 	kmem_free(counts, vim->vim_phys->vimp_num_entries * sizeof (uint32_t));
5935cabbc6bSPrashanth Sreenivasa }
594