Print this page
10592 misc. metaslab and vdev related ZoL bug fixes
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed by: George Melikov <mail@gmelikov.ru>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: Pavel Zakharov <pavel.zakharov@delphix.com>
Reviewed by: Tony Hutter <hutter2@llnl.gov>
Reviewed by: Kody Kantor <kody.kantor@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/zfs/vdev_indirect_mapping.c
+++ new/usr/src/uts/common/fs/zfs/vdev_indirect_mapping.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * This file and its contents are supplied under the terms of the
5 5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 6 * You may only use this file in accordance with the terms of version
7 7 * 1.0 of the CDDL.
8 8 *
9 9 * A full copy of the text of the CDDL should have accompanied this
10 10 * source. A copy of the CDDL is also available via the Internet at
11 11 * http://www.illumos.org/license/CDDL.
12 12 *
13 13 * CDDL HEADER END
14 14 */
15 15
16 16 /*
17 17 * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
18 18 */
19 19
20 20 #include <sys/dmu_tx.h>
21 21 #include <sys/dsl_pool.h>
22 22 #include <sys/spa.h>
23 23 #include <sys/vdev_impl.h>
24 24 #include <sys/vdev_indirect_mapping.h>
25 25 #include <sys/zfeature.h>
26 26 #include <sys/dmu_objset.h>
27 27
28 28 static boolean_t
29 29 vdev_indirect_mapping_verify(vdev_indirect_mapping_t *vim)
30 30 {
31 31 ASSERT(vim != NULL);
32 32
33 33 ASSERT(vim->vim_object != 0);
34 34 ASSERT(vim->vim_objset != NULL);
35 35 ASSERT(vim->vim_phys != NULL);
36 36 ASSERT(vim->vim_dbuf != NULL);
37 37
38 38 EQUIV(vim->vim_phys->vimp_num_entries > 0,
39 39 vim->vim_entries != NULL);
40 40 if (vim->vim_phys->vimp_num_entries > 0) {
41 41 vdev_indirect_mapping_entry_phys_t *last_entry =
42 42 &vim->vim_entries[vim->vim_phys->vimp_num_entries - 1];
43 43 uint64_t offset = DVA_MAPPING_GET_SRC_OFFSET(last_entry);
44 44 uint64_t size = DVA_GET_ASIZE(&last_entry->vimep_dst);
45 45
46 46 ASSERT3U(vim->vim_phys->vimp_max_offset, >=, offset + size);
47 47 }
48 48 if (vim->vim_havecounts) {
49 49 ASSERT(vim->vim_phys->vimp_counts_object != 0);
50 50 }
51 51
52 52 return (B_TRUE);
53 53 }
54 54
55 55 uint64_t
56 56 vdev_indirect_mapping_num_entries(vdev_indirect_mapping_t *vim)
57 57 {
58 58 ASSERT(vdev_indirect_mapping_verify(vim));
59 59
60 60 return (vim->vim_phys->vimp_num_entries);
61 61 }
62 62
63 63 uint64_t
64 64 vdev_indirect_mapping_max_offset(vdev_indirect_mapping_t *vim)
65 65 {
66 66 ASSERT(vdev_indirect_mapping_verify(vim));
67 67
68 68 return (vim->vim_phys->vimp_max_offset);
69 69 }
70 70
71 71 uint64_t
72 72 vdev_indirect_mapping_object(vdev_indirect_mapping_t *vim)
73 73 {
74 74 ASSERT(vdev_indirect_mapping_verify(vim));
75 75
76 76 return (vim->vim_object);
77 77 }
78 78
79 79 uint64_t
80 80 vdev_indirect_mapping_bytes_mapped(vdev_indirect_mapping_t *vim)
81 81 {
82 82 ASSERT(vdev_indirect_mapping_verify(vim));
83 83
84 84 return (vim->vim_phys->vimp_bytes_mapped);
85 85 }
86 86
87 87 /*
88 88 * The length (in bytes) of the mapping object array in memory and
89 89 * (logically) on disk.
90 90 *
91 91 * Note that unlike most of our accessor functions,
92 92 * we don't assert that the struct is consistent; therefore it can be
93 93 * called while there may be concurrent changes, if we don't care about
94 94 * the value being immediately stale (e.g. from spa_removal_get_stats()).
95 95 */
96 96 uint64_t
97 97 vdev_indirect_mapping_size(vdev_indirect_mapping_t *vim)
98 98 {
99 99 return (vim->vim_phys->vimp_num_entries * sizeof (*vim->vim_entries));
100 100 }
101 101
102 102 /*
103 103 * Compare an offset with an indirect mapping entry; there are three
104 104 * possible scenarios:
105 105 *
106 106 * 1. The offset is "less than" the mapping entry; meaning the
107 107 * offset is less than the source offset of the mapping entry. In
108 108 * this case, there is no overlap between the offset and the
109 109 * mapping entry and -1 will be returned.
110 110 *
111 111 * 2. The offset is "greater than" the mapping entry; meaning the
112 112 * offset is greater than the mapping entry's source offset plus
113 113 * the entry's size. In this case, there is no overlap between
114 114 * the offset and the mapping entry and 1 will be returned.
115 115 *
116 116 * NOTE: If the offset is actually equal to the entry's offset
117 117 * plus size, this is considered to be "greater" than the entry,
118 118 * and this case applies (i.e. 1 will be returned). Thus, the
119 119 * entry's "range" can be considered to be inclusive at its
120 120 * start, but exclusive at its end: e.g. [src, src + size).
121 121 *
122 122 * 3. The last case to consider is if the offset actually falls
123 123 * within the mapping entry's range. If this is the case, the
124 124 * offset is considered to be "equal to" the mapping entry and
125 125 * 0 will be returned.
126 126 *
127 127 * NOTE: If the offset is equal to the entry's source offset,
128 128 * this case applies and 0 will be returned. If the offset is
129 129 * equal to the entry's source plus its size, this case does
130 130 * *not* apply (see "NOTE" above for scenario 2), and 1 will be
131 131 * returned.
132 132 */
133 133 static int
134 134 dva_mapping_overlap_compare(const void *v_key, const void *v_array_elem)
135 135 {
136 136 const uint64_t *key = v_key;
137 137 const vdev_indirect_mapping_entry_phys_t *array_elem =
138 138 v_array_elem;
139 139 uint64_t src_offset = DVA_MAPPING_GET_SRC_OFFSET(array_elem);
140 140
141 141 if (*key < src_offset) {
142 142 return (-1);
143 143 } else if (*key < src_offset + DVA_GET_ASIZE(&array_elem->vimep_dst)) {
144 144 return (0);
145 145 } else {
146 146 return (1);
147 147 }
148 148 }
149 149
150 150 /*
151 151 * Returns the mapping entry for the given offset.
152 152 *
153 153 * It's possible that the given offset will not be in the mapping table
154 154 * (i.e. no mapping entries contain this offset), in which case, the
155 155 * return value value depends on the "next_if_missing" parameter.
156 156 *
157 157 * If the offset is not found in the table and "next_if_missing" is
158 158 * B_FALSE, then NULL will always be returned. The behavior is intended
159 159 * to allow consumers to get the entry corresponding to the offset
160 160 * parameter, iff the offset overlaps with an entry in the table.
161 161 *
162 162 * If the offset is not found in the table and "next_if_missing" is
163 163 * B_TRUE, then the entry nearest to the given offset will be returned,
164 164 * such that the entry's source offset is greater than the offset
165 165 * passed in (i.e. the "next" mapping entry in the table is returned, if
166 166 * the offset is missing from the table). If there are no entries whose
167 167 * source offset is greater than the passed in offset, NULL is returned.
168 168 */
169 169 static vdev_indirect_mapping_entry_phys_t *
170 170 vdev_indirect_mapping_entry_for_offset_impl(vdev_indirect_mapping_t *vim,
171 171 uint64_t offset, boolean_t next_if_missing)
172 172 {
173 173 ASSERT(vdev_indirect_mapping_verify(vim));
174 174 ASSERT(vim->vim_phys->vimp_num_entries > 0);
175 175
176 176 vdev_indirect_mapping_entry_phys_t *entry = NULL;
177 177
178 178 uint64_t last = vim->vim_phys->vimp_num_entries - 1;
179 179 uint64_t base = 0;
180 180
181 181 /*
182 182 * We don't define these inside of the while loop because we use
183 183 * their value in the case that offset isn't in the mapping.
184 184 */
185 185 uint64_t mid;
186 186 int result;
187 187
188 188 while (last >= base) {
189 189 mid = base + ((last - base) >> 1);
190 190
191 191 result = dva_mapping_overlap_compare(&offset,
192 192 &vim->vim_entries[mid]);
193 193
194 194 if (result == 0) {
195 195 entry = &vim->vim_entries[mid];
196 196 break;
197 197 } else if (result < 0) {
198 198 last = mid - 1;
199 199 } else {
200 200 base = mid + 1;
201 201 }
202 202 }
203 203
204 204 if (entry == NULL && next_if_missing) {
205 205 ASSERT3U(base, ==, last + 1);
206 206 ASSERT(mid == base || mid == last);
207 207 ASSERT3S(result, !=, 0);
208 208
209 209 /*
210 210 * The offset we're looking for isn't actually contained
211 211 * in the mapping table, thus we need to return the
212 212 * closest mapping entry that is greater than the
213 213 * offset. We reuse the result of the last comparison,
214 214 * comparing the mapping entry at index "mid" and the
215 215 * offset. The offset is guaranteed to lie between
216 216 * indices one less than "mid", and one greater than
217 217 * "mid"; we just need to determine if offset is greater
218 218 * than, or less than the mapping entry contained at
219 219 * index "mid".
220 220 */
221 221
222 222 uint64_t index;
223 223 if (result < 0)
224 224 index = mid;
225 225 else
226 226 index = mid + 1;
227 227
228 228 ASSERT3U(index, <=, vim->vim_phys->vimp_num_entries);
229 229
230 230 if (index == vim->vim_phys->vimp_num_entries) {
231 231 /*
232 232 * If "index" is past the end of the entries
233 233 * array, then not only is the offset not in the
234 234 * mapping table, but it's actually greater than
235 235 * all entries in the table. In this case, we
236 236 * can't return a mapping entry greater than the
237 237 * offset (since none exist), so we return NULL.
238 238 */
239 239
240 240 ASSERT3S(dva_mapping_overlap_compare(&offset,
241 241 &vim->vim_entries[index - 1]), >, 0);
242 242
243 243 return (NULL);
244 244 } else {
245 245 /*
246 246 * Just to be safe, we verify the offset falls
247 247 * in between the mapping entries at index and
248 248 * one less than index. Since we know the offset
249 249 * doesn't overlap an entry, and we're supposed
250 250 * to return the entry just greater than the
251 251 * offset, both of the following tests must be
252 252 * true.
253 253 */
254 254 ASSERT3S(dva_mapping_overlap_compare(&offset,
255 255 &vim->vim_entries[index]), <, 0);
256 256 IMPLY(index >= 1, dva_mapping_overlap_compare(&offset,
257 257 &vim->vim_entries[index - 1]) > 0);
258 258
259 259 return (&vim->vim_entries[index]);
260 260 }
261 261 } else {
262 262 return (entry);
263 263 }
264 264 }
265 265
266 266 vdev_indirect_mapping_entry_phys_t *
267 267 vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim,
268 268 uint64_t offset)
269 269 {
270 270 return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
271 271 B_FALSE));
272 272 }
273 273
274 274 vdev_indirect_mapping_entry_phys_t *
275 275 vdev_indirect_mapping_entry_for_offset_or_next(vdev_indirect_mapping_t *vim,
276 276 uint64_t offset)
277 277 {
278 278 return (vdev_indirect_mapping_entry_for_offset_impl(vim, offset,
279 279 B_TRUE));
280 280 }
281 281
282 282 void
283 283 vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim)
284 284 {
285 285 ASSERT(vdev_indirect_mapping_verify(vim));
286 286
287 287 if (vim->vim_phys->vimp_num_entries > 0) {
288 288 uint64_t map_size = vdev_indirect_mapping_size(vim);
289 289 kmem_free(vim->vim_entries, map_size);
290 290 vim->vim_entries = NULL;
291 291 }
292 292
293 293 dmu_buf_rele(vim->vim_dbuf, vim);
294 294
295 295 vim->vim_objset = NULL;
296 296 vim->vim_object = 0;
297 297 vim->vim_dbuf = NULL;
298 298 vim->vim_phys = NULL;
299 299
300 300 kmem_free(vim, sizeof (*vim));
301 301 }
302 302
303 303 uint64_t
304 304 vdev_indirect_mapping_alloc(objset_t *os, dmu_tx_t *tx)
305 305 {
306 306 uint64_t object;
307 307 ASSERT(dmu_tx_is_syncing(tx));
308 308 uint64_t bonus_size = VDEV_INDIRECT_MAPPING_SIZE_V0;
309 309
310 310 if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
311 311 bonus_size = sizeof (vdev_indirect_mapping_phys_t);
312 312 }
313 313
314 314 object = dmu_object_alloc(os,
315 315 DMU_OTN_UINT64_METADATA, SPA_OLD_MAXBLOCKSIZE,
316 316 DMU_OTN_UINT64_METADATA, bonus_size,
317 317 tx);
318 318
319 319 if (spa_feature_is_enabled(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
320 320 dmu_buf_t *dbuf;
321 321 vdev_indirect_mapping_phys_t *vimp;
322 322
323 323 VERIFY0(dmu_bonus_hold(os, object, FTAG, &dbuf));
324 324 dmu_buf_will_dirty(dbuf, tx);
325 325 vimp = dbuf->db_data;
326 326 vimp->vimp_counts_object = dmu_object_alloc(os,
327 327 DMU_OTN_UINT32_METADATA, SPA_OLD_MAXBLOCKSIZE,
328 328 DMU_OT_NONE, 0, tx);
329 329 spa_feature_incr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
330 330 dmu_buf_rele(dbuf, FTAG);
331 331 }
332 332
333 333 return (object);
334 334 }
335 335
336 336
337 337 vdev_indirect_mapping_t *
338 338 vdev_indirect_mapping_open(objset_t *os, uint64_t mapping_object)
339 339 {
340 340 vdev_indirect_mapping_t *vim = kmem_zalloc(sizeof (*vim), KM_SLEEP);
341 341 dmu_object_info_t doi;
342 342 VERIFY0(dmu_object_info(os, mapping_object, &doi));
343 343
344 344 vim->vim_objset = os;
345 345 vim->vim_object = mapping_object;
346 346
347 347 VERIFY0(dmu_bonus_hold(os, vim->vim_object, vim,
348 348 &vim->vim_dbuf));
349 349 vim->vim_phys = vim->vim_dbuf->db_data;
350 350
351 351 vim->vim_havecounts =
352 352 (doi.doi_bonus_size > VDEV_INDIRECT_MAPPING_SIZE_V0);
353 353
354 354 if (vim->vim_phys->vimp_num_entries > 0) {
355 355 uint64_t map_size = vdev_indirect_mapping_size(vim);
356 356 vim->vim_entries = kmem_alloc(map_size, KM_SLEEP);
357 357 VERIFY0(dmu_read(os, vim->vim_object, 0, map_size,
358 358 vim->vim_entries, DMU_READ_PREFETCH));
359 359 }
360 360
361 361 ASSERT(vdev_indirect_mapping_verify(vim));
362 362
363 363 return (vim);
364 364 }
365 365
366 366 void
367 367 vdev_indirect_mapping_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
368 368 {
369 369 vdev_indirect_mapping_t *vim = vdev_indirect_mapping_open(os, object);
370 370 if (vim->vim_havecounts) {
371 371 VERIFY0(dmu_object_free(os, vim->vim_phys->vimp_counts_object,
372 372 tx));
373 373 spa_feature_decr(os->os_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
374 374 }
375 375 vdev_indirect_mapping_close(vim);
376 376
377 377 VERIFY0(dmu_object_free(os, object, tx));
378 378 }
379 379
380 380 /*
381 381 * Append the list of vdev_indirect_mapping_entry_t's to the on-disk
382 382 * mapping object. Also remove the entries from the list and free them.
383 383 * This also implicitly extends the max_offset of the mapping (to the end
384 384 * of the last entry).
385 385 */
386 386 void
387 387 vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim,
388 388 list_t *list, dmu_tx_t *tx)
389 389 {
390 390 vdev_indirect_mapping_entry_phys_t *mapbuf;
391 391 uint64_t old_size;
392 392 uint32_t *countbuf = NULL;
393 393 vdev_indirect_mapping_entry_phys_t *old_entries;
394 394 uint64_t old_count;
395 395 uint64_t entries_written = 0;
396 396
397 397 ASSERT(vdev_indirect_mapping_verify(vim));
398 398 ASSERT(dmu_tx_is_syncing(tx));
399 399 ASSERT(dsl_pool_sync_context(dmu_tx_pool(tx)));
400 400 ASSERT(!list_is_empty(list));
401 401
402 402 old_size = vdev_indirect_mapping_size(vim);
403 403 old_entries = vim->vim_entries;
404 404 old_count = vim->vim_phys->vimp_num_entries;
405 405
406 406 dmu_buf_will_dirty(vim->vim_dbuf, tx);
407 407
408 408 mapbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
409 409 if (vim->vim_havecounts) {
410 410 countbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
411 411 ASSERT(spa_feature_is_active(vim->vim_objset->os_spa,
412 412 SPA_FEATURE_OBSOLETE_COUNTS));
413 413 }
414 414 while (!list_is_empty(list)) {
415 415 uint64_t i;
416 416 /*
417 417 * Write entries from the list to the
418 418 * vdev_im_object in batches of size SPA_OLD_MAXBLOCKSIZE.
419 419 */
420 420 for (i = 0; i < SPA_OLD_MAXBLOCKSIZE / sizeof (*mapbuf); i++) {
421 421 vdev_indirect_mapping_entry_t *entry =
422 422 list_remove_head(list);
423 423 if (entry == NULL)
424 424 break;
425 425
426 426 uint64_t size =
427 427 DVA_GET_ASIZE(&entry->vime_mapping.vimep_dst);
428 428 uint64_t src_offset =
429 429 DVA_MAPPING_GET_SRC_OFFSET(&entry->vime_mapping);
430 430
431 431 /*
432 432 * We shouldn't be adding an entry which is fully
433 433 * obsolete.
434 434 */
435 435 ASSERT3U(entry->vime_obsolete_count, <, size);
436 436 IMPLY(entry->vime_obsolete_count != 0,
437 437 vim->vim_havecounts);
438 438
439 439 mapbuf[i] = entry->vime_mapping;
440 440 if (vim->vim_havecounts)
441 441 countbuf[i] = entry->vime_obsolete_count;
442 442
443 443 vim->vim_phys->vimp_bytes_mapped += size;
444 444 ASSERT3U(src_offset, >=,
445 445 vim->vim_phys->vimp_max_offset);
446 446 vim->vim_phys->vimp_max_offset = src_offset + size;
447 447
448 448 entries_written++;
449 449
450 450 kmem_free(entry, sizeof (*entry));
451 451 }
452 452 dmu_write(vim->vim_objset, vim->vim_object,
453 453 vim->vim_phys->vimp_num_entries * sizeof (*mapbuf),
454 454 i * sizeof (*mapbuf),
455 455 mapbuf, tx);
456 456 if (vim->vim_havecounts) {
457 457 dmu_write(vim->vim_objset,
458 458 vim->vim_phys->vimp_counts_object,
459 459 vim->vim_phys->vimp_num_entries *
460 460 sizeof (*countbuf),
461 461 i * sizeof (*countbuf), countbuf, tx);
462 462 }
463 463 vim->vim_phys->vimp_num_entries += i;
464 464 }
465 465 zio_buf_free(mapbuf, SPA_OLD_MAXBLOCKSIZE);
466 466 if (vim->vim_havecounts)
467 467 zio_buf_free(countbuf, SPA_OLD_MAXBLOCKSIZE);
468 468
469 469 /*
470 470 * Update the entry array to reflect the new entries. First, copy
471 471 * over any old entries then read back the new entries we just wrote.
472 472 */
473 473 uint64_t new_size = vdev_indirect_mapping_size(vim);
474 474 ASSERT3U(new_size, >, old_size);
475 475 ASSERT3U(new_size - old_size, ==,
476 476 entries_written * sizeof (vdev_indirect_mapping_entry_phys_t));
477 477 vim->vim_entries = kmem_alloc(new_size, KM_SLEEP);
478 478 if (old_size > 0) {
479 479 bcopy(old_entries, vim->vim_entries, old_size);
480 480 kmem_free(old_entries, old_size);
481 481 }
482 482 VERIFY0(dmu_read(vim->vim_objset, vim->vim_object, old_size,
483 483 new_size - old_size, &vim->vim_entries[old_count],
484 484 DMU_READ_PREFETCH));
485 485
486 486 zfs_dbgmsg("txg %llu: wrote %llu entries to "
487 487 "indirect mapping obj %llu; max offset=0x%llx",
488 488 (u_longlong_t)dmu_tx_get_txg(tx),
489 489 (u_longlong_t)entries_written,
490 490 (u_longlong_t)vim->vim_object,
491 491 (u_longlong_t)vim->vim_phys->vimp_max_offset);
492 492 }
493 493
494 494 /*
495 495 * Increment the relevant counts for the specified offset and length.
496 496 * The counts array must be obtained from
497 497 * vdev_indirect_mapping_load_obsolete_counts().
498 498 */
499 499 void
500 500 vdev_indirect_mapping_increment_obsolete_count(vdev_indirect_mapping_t *vim,
501 501 uint64_t offset, uint64_t length, uint32_t *counts)
502 502 {
503 503 vdev_indirect_mapping_entry_phys_t *mapping;
504 504 uint64_t index;
505 505
506 506 mapping = vdev_indirect_mapping_entry_for_offset(vim, offset);
507 507
508 508 ASSERT(length > 0);
509 509 ASSERT3P(mapping, !=, NULL);
510 510
511 511 index = mapping - vim->vim_entries;
512 512
513 513 while (length > 0) {
514 514 ASSERT3U(index, <, vdev_indirect_mapping_num_entries(vim));
515 515
516 516 uint64_t size = DVA_GET_ASIZE(&mapping->vimep_dst);
517 517 uint64_t inner_offset = offset -
518 518 DVA_MAPPING_GET_SRC_OFFSET(mapping);
519 519 VERIFY3U(inner_offset, <, size);
520 520 uint64_t inner_size = MIN(length, size - inner_offset);
521 521
522 522 VERIFY3U(counts[index] + inner_size, <=, size);
523 523 counts[index] += inner_size;
524 524
525 525 offset += inner_size;
526 526 length -= inner_size;
527 527 mapping++;
528 528 index++;
529 529 }
530 530 }
531 531
532 532 typedef struct load_obsolete_space_map_arg {
533 533 vdev_indirect_mapping_t *losma_vim;
534 534 uint32_t *losma_counts;
535 535 } load_obsolete_space_map_arg_t;
536 536
537 537 static int
538 538 load_obsolete_sm_callback(space_map_entry_t *sme, void *arg)
539 539 {
540 540 load_obsolete_space_map_arg_t *losma = arg;
541 541 ASSERT3S(sme->sme_type, ==, SM_ALLOC);
542 542
543 543 vdev_indirect_mapping_increment_obsolete_count(losma->losma_vim,
544 544 sme->sme_offset, sme->sme_run, losma->losma_counts);
545 545
546 546 return (0);
547 547 }
548 548
549 549 /*
|
↓ open down ↓ |
549 lines elided |
↑ open up ↑ |
550 550 * Modify the counts (increment them) based on the spacemap.
551 551 */
552 552 void
553 553 vdev_indirect_mapping_load_obsolete_spacemap(vdev_indirect_mapping_t *vim,
554 554 uint32_t *counts, space_map_t *obsolete_space_sm)
555 555 {
556 556 load_obsolete_space_map_arg_t losma;
557 557 losma.losma_counts = counts;
558 558 losma.losma_vim = vim;
559 559 VERIFY0(space_map_iterate(obsolete_space_sm,
560 + space_map_length(obsolete_space_sm),
560 561 load_obsolete_sm_callback, &losma));
561 562 }
562 563
563 564 /*
564 565 * Read the obsolete counts from disk, returning them in an array.
565 566 */
566 567 uint32_t *
567 568 vdev_indirect_mapping_load_obsolete_counts(vdev_indirect_mapping_t *vim)
568 569 {
569 570 ASSERT(vdev_indirect_mapping_verify(vim));
570 571
571 572 uint64_t counts_size =
572 573 vim->vim_phys->vimp_num_entries * sizeof (uint32_t);
573 574 uint32_t *counts = kmem_alloc(counts_size, KM_SLEEP);
574 575 if (vim->vim_havecounts) {
575 576 VERIFY0(dmu_read(vim->vim_objset,
576 577 vim->vim_phys->vimp_counts_object,
577 578 0, counts_size,
578 579 counts, DMU_READ_PREFETCH));
579 580 } else {
580 581 bzero(counts, counts_size);
581 582 }
582 583 return (counts);
583 584 }
584 585
585 586 extern void
586 587 vdev_indirect_mapping_free_obsolete_counts(vdev_indirect_mapping_t *vim,
587 588 uint32_t *counts)
588 589 {
589 590 ASSERT(vdev_indirect_mapping_verify(vim));
590 591
591 592 kmem_free(counts, vim->vim_phys->vimp_num_entries * sizeof (uint32_t));
592 593 }
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX