1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * This file and its contents are supplied under the terms of the 6 * Common Development and Distribution License ("CDDL"), version 1.0. 7 * You may only use this file in accordance with the terms of version 8 * 1.0 of the CDDL. 9 * 10 * A full copy of the text of the CDDL should have accompanied this 11 * source. A copy of the CDDL is also available via the Internet at 12 * http://www.illumos.org/license/CDDL. 13 * 14 * CDDL HEADER END 15 */ 16 17 /* 18 * Copyright (c) 2015 by Delphix. All rights reserved. 19 */ 20 21 #include <sys/dmu_tx.h> 22 #include <sys/spa.h> 23 #include <sys/dmu.h> 24 #include <sys/dsl_pool.h> 25 #include <sys/vdev_indirect_births.h> 26 27 #ifdef ZFS_DEBUG 28 static boolean_t 29 vdev_indirect_births_verify(vdev_indirect_births_t *vib) 30 { 31 ASSERT(vib != NULL); 32 33 ASSERT(vib->vib_object != 0); 34 ASSERT(vib->vib_objset != NULL); 35 ASSERT(vib->vib_phys != NULL); 36 ASSERT(vib->vib_dbuf != NULL); 37 38 EQUIV(vib->vib_phys->vib_count > 0, vib->vib_entries != NULL); 39 40 return (B_TRUE); 41 } 42 #else 43 #define vdev_indirect_births_verify(vib) ((void) sizeof (vib), B_TRUE) 44 #endif 45 46 uint64_t 47 vdev_indirect_births_count(vdev_indirect_births_t *vib) 48 { 49 ASSERT(vdev_indirect_births_verify(vib)); 50 51 return (vib->vib_phys->vib_count); 52 } 53 54 uint64_t 55 vdev_indirect_births_object(vdev_indirect_births_t *vib) 56 { 57 ASSERT(vdev_indirect_births_verify(vib)); 58 59 return (vib->vib_object); 60 } 61 62 static uint64_t 63 vdev_indirect_births_size_impl(vdev_indirect_births_t *vib) 64 { 65 return (vib->vib_phys->vib_count * sizeof (*vib->vib_entries)); 66 } 67 68 void 69 vdev_indirect_births_close(vdev_indirect_births_t *vib) 70 { 71 ASSERT(vdev_indirect_births_verify(vib)); 72 73 if (vib->vib_phys->vib_count > 0) { 74 uint64_t births_size = vdev_indirect_births_size_impl(vib); 75 76 vmem_free(vib->vib_entries, births_size); 77 vib->vib_entries = NULL; 78 } 79 80 dmu_buf_rele(vib->vib_dbuf, vib); 81 82 vib->vib_objset = NULL; 83 vib->vib_object = 0; 84 vib->vib_dbuf = NULL; 85 vib->vib_phys = NULL; 86 87 kmem_free(vib, sizeof (*vib)); 88 } 89 90 uint64_t 91 vdev_indirect_births_alloc(objset_t *os, dmu_tx_t *tx) 92 { 93 ASSERT(dmu_tx_is_syncing(tx)); 94 95 return (dmu_object_alloc(os, 96 DMU_OTN_UINT64_METADATA, SPA_OLD_MAXBLOCKSIZE, 97 DMU_OTN_UINT64_METADATA, sizeof (vdev_indirect_birth_phys_t), 98 tx)); 99 } 100 101 vdev_indirect_births_t * 102 vdev_indirect_births_open(objset_t *os, uint64_t births_object) 103 { 104 vdev_indirect_births_t *vib = kmem_zalloc(sizeof (*vib), KM_SLEEP); 105 106 vib->vib_objset = os; 107 vib->vib_object = births_object; 108 109 VERIFY0(dmu_bonus_hold(os, vib->vib_object, vib, &vib->vib_dbuf)); 110 vib->vib_phys = vib->vib_dbuf->db_data; 111 112 if (vib->vib_phys->vib_count > 0) { 113 uint64_t births_size = vdev_indirect_births_size_impl(vib); 114 vib->vib_entries = vmem_alloc(births_size, KM_SLEEP); 115 VERIFY0(dmu_read(vib->vib_objset, vib->vib_object, 0, 116 births_size, vib->vib_entries, DMU_READ_PREFETCH)); 117 } 118 119 ASSERT(vdev_indirect_births_verify(vib)); 120 121 return (vib); 122 } 123 124 void 125 vdev_indirect_births_free(objset_t *os, uint64_t object, dmu_tx_t *tx) 126 { 127 VERIFY0(dmu_object_free(os, object, tx)); 128 } 129 130 void 131 vdev_indirect_births_add_entry(vdev_indirect_births_t *vib, 132 uint64_t max_offset, uint64_t txg, dmu_tx_t *tx) 133 { 134 vdev_indirect_birth_entry_phys_t vibe; 135 uint64_t old_size; 136 uint64_t new_size; 137 vdev_indirect_birth_entry_phys_t *new_entries; 138 139 ASSERT(dmu_tx_is_syncing(tx)); 140 ASSERT(dsl_pool_sync_context(dmu_tx_pool(tx))); 141 ASSERT(vdev_indirect_births_verify(vib)); 142 143 dmu_buf_will_dirty(vib->vib_dbuf, tx); 144 145 vibe.vibe_offset = max_offset; 146 vibe.vibe_phys_birth_txg = txg; 147 148 old_size = vdev_indirect_births_size_impl(vib); 149 dmu_write(vib->vib_objset, vib->vib_object, old_size, sizeof (vibe), 150 &vibe, tx); 151 vib->vib_phys->vib_count++; 152 new_size = vdev_indirect_births_size_impl(vib); 153 154 new_entries = vmem_alloc(new_size, KM_SLEEP); 155 if (old_size > 0) { 156 memcpy(new_entries, vib->vib_entries, old_size); 157 vmem_free(vib->vib_entries, old_size); 158 } 159 new_entries[vib->vib_phys->vib_count - 1] = vibe; 160 vib->vib_entries = new_entries; 161 } 162 163 uint64_t 164 vdev_indirect_births_last_entry_txg(vdev_indirect_births_t *vib) 165 { 166 ASSERT(vdev_indirect_births_verify(vib)); 167 ASSERT(vib->vib_phys->vib_count > 0); 168 169 vdev_indirect_birth_entry_phys_t *last = 170 &vib->vib_entries[vib->vib_phys->vib_count - 1]; 171 return (last->vibe_phys_birth_txg); 172 } 173 174 /* 175 * Return the txg in which the given range was copied (i.e. its physical 176 * birth txg). The specified offset+asize must be contiguously mapped 177 * (i.e. not a split block). 178 * 179 * The entries are sorted by increasing phys_birth, and also by increasing 180 * offset. We find the specified offset by binary search. Note that we 181 * can not use bsearch() because looking at each entry independently is 182 * insufficient to find the correct entry. Each entry implicitly relies 183 * on the previous entry: an entry indicates that the offsets from the 184 * end of the previous entry to the end of this entry were written in the 185 * specified txg. 186 */ 187 uint64_t 188 vdev_indirect_births_physbirth(vdev_indirect_births_t *vib, uint64_t offset, 189 uint64_t asize) 190 { 191 vdev_indirect_birth_entry_phys_t *base; 192 vdev_indirect_birth_entry_phys_t *last; 193 194 ASSERT(vdev_indirect_births_verify(vib)); 195 ASSERT(vib->vib_phys->vib_count > 0); 196 197 base = vib->vib_entries; 198 last = base + vib->vib_phys->vib_count - 1; 199 200 ASSERT3U(offset, <, last->vibe_offset); 201 202 while (last >= base) { 203 vdev_indirect_birth_entry_phys_t *p = 204 base + ((last - base) / 2); 205 if (offset >= p->vibe_offset) { 206 base = p + 1; 207 } else if (p == vib->vib_entries || 208 offset >= (p - 1)->vibe_offset) { 209 ASSERT3U(offset + asize, <=, p->vibe_offset); 210 return (p->vibe_phys_birth_txg); 211 } else { 212 last = p - 1; 213 } 214 } 215 ASSERT(!"offset not found"); 216 return (-1); 217 } 218 219 #if defined(_KERNEL) 220 EXPORT_SYMBOL(vdev_indirect_births_add_entry); 221 EXPORT_SYMBOL(vdev_indirect_births_alloc); 222 EXPORT_SYMBOL(vdev_indirect_births_close); 223 EXPORT_SYMBOL(vdev_indirect_births_count); 224 EXPORT_SYMBOL(vdev_indirect_births_free); 225 EXPORT_SYMBOL(vdev_indirect_births_last_entry_txg); 226 EXPORT_SYMBOL(vdev_indirect_births_object); 227 EXPORT_SYMBOL(vdev_indirect_births_open); 228 EXPORT_SYMBOL(vdev_indirect_births_physbirth); 229 #endif 230