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