* Writes one or more entries given a segment. * * Note: The function may release the dbuf from the pointer initially * passed to it, and return a different dbuf. Also, the space map's * dbuf must be dirty for the changes in sm_phys to take effect. */
| 546 | * dbuf must be dirty for the changes in sm_phys to take effect. |
| 547 | */ |
| 548 | static void |
| 549 | space_map_write_seg(space_map_t *sm, uint64_t rstart, uint64_t rend, |
| 550 | maptype_t maptype, uint64_t vdev_id, uint8_t words, dmu_buf_t **dbp, |
| 551 | void *tag, dmu_tx_t *tx) |
| 552 | { |
| 553 | ASSERT3U(words, !=, 0); |
| 554 | ASSERT3U(words, <=, 2); |
| 555 | |
| 556 | /* ensure the vdev_id can be represented by the space map */ |
| 557 | ASSERT3U(vdev_id, <=, SM_NO_VDEVID); |
| 558 | |
| 559 | /* |
| 560 | * if this is a single word entry, ensure that no vdev was |
| 561 | * specified. |
| 562 | */ |
| 563 | IMPLY(words == 1, vdev_id == SM_NO_VDEVID); |
| 564 | |
| 565 | dmu_buf_t *db = *dbp; |
| 566 | ASSERT3U(db->db_size, ==, sm->sm_blksz); |
| 567 | |
| 568 | uint64_t *block_base = db->db_data; |
| 569 | uint64_t *block_end = block_base + (sm->sm_blksz / sizeof (uint64_t)); |
| 570 | uint64_t *block_cursor = block_base + |
| 571 | (sm->sm_phys->smp_length - db->db_offset) / sizeof (uint64_t); |
| 572 | |
| 573 | ASSERT3P(block_cursor, <=, block_end); |
| 574 | |
| 575 | uint64_t size = (rend - rstart) >> sm->sm_shift; |
| 576 | uint64_t start = (rstart - sm->sm_start) >> sm->sm_shift; |
| 577 | uint64_t run_max = (words == 2) ? SM2_RUN_MAX : SM_RUN_MAX; |
| 578 | |
| 579 | ASSERT3U(rstart, >=, sm->sm_start); |
| 580 | ASSERT3U(rstart, <, sm->sm_start + sm->sm_size); |
| 581 | ASSERT3U(rend - rstart, <=, sm->sm_size); |
| 582 | ASSERT3U(rend, <=, sm->sm_start + sm->sm_size); |
| 583 | |
| 584 | while (size != 0) { |
| 585 | ASSERT3P(block_cursor, <=, block_end); |
| 586 | |
| 587 | /* |
| 588 | * If we are at the end of this block, flush it and start |
| 589 | * writing again from the beginning. |
| 590 | */ |
| 591 | if (block_cursor == block_end) { |
| 592 | dmu_buf_rele(db, tag); |
| 593 | |
| 594 | uint64_t next_word_offset = sm->sm_phys->smp_length; |
| 595 | VERIFY0(dmu_buf_hold(sm->sm_os, |
| 596 | space_map_object(sm), next_word_offset, |
| 597 | tag, &db, DMU_READ_PREFETCH)); |
| 598 | dmu_buf_will_dirty(db, tx); |
| 599 | |
| 600 | /* update caller's dbuf */ |
| 601 | *dbp = db; |
| 602 | |
| 603 | ASSERT3U(db->db_size, ==, sm->sm_blksz); |
| 604 | |
| 605 | block_base = db->db_data; |
no test coverage detected