* Given an initial bpo, start by freeing the BPs that are directly referenced * by that bpo. If the bpo has subobjs, read in its last subobj and push the * subobj to our stack. By popping items off our stack, eventually we will * encounter a bpo that has no subobjs. We can free its bpobj_info_t, and if * requested also free the now-empty bpo from disk and decrement * its parent's subobj coun
| 349 | * visiting its last subobj until they too have no more subobjs, and so on. |
| 350 | */ |
| 351 | static int |
| 352 | bpobj_iterate_impl(bpobj_t *initial_bpo, bpobj_itor_t func, void *arg, |
| 353 | dmu_tx_t *tx, boolean_t free, uint64_t *bpobj_size) |
| 354 | { |
| 355 | list_t stack; |
| 356 | bpobj_info_t *bpi; |
| 357 | int err = 0; |
| 358 | |
| 359 | /* |
| 360 | * Create a "stack" for us to work with without worrying about |
| 361 | * stack overflows. Initialize it with the initial_bpo. |
| 362 | */ |
| 363 | list_create(&stack, sizeof (bpobj_info_t), |
| 364 | offsetof(bpobj_info_t, bpi_node)); |
| 365 | mutex_enter(&initial_bpo->bpo_lock); |
| 366 | |
| 367 | if (bpobj_size != NULL) |
| 368 | *bpobj_size = initial_bpo->bpo_phys->bpo_num_blkptrs; |
| 369 | |
| 370 | list_insert_head(&stack, bpi_alloc(initial_bpo, NULL, 0)); |
| 371 | |
| 372 | while ((bpi = list_head(&stack)) != NULL) { |
| 373 | bpobj_t *bpo = bpi->bpi_bpo; |
| 374 | |
| 375 | ASSERT3P(bpo, !=, NULL); |
| 376 | ASSERT(MUTEX_HELD(&bpo->bpo_lock)); |
| 377 | ASSERT(bpobj_is_open(bpo)); |
| 378 | |
| 379 | if (free) |
| 380 | dmu_buf_will_dirty(bpo->bpo_dbuf, tx); |
| 381 | |
| 382 | if (bpi->bpi_visited == B_FALSE) { |
| 383 | err = bpobj_iterate_blkptrs(bpi, func, arg, 0, tx, |
| 384 | free); |
| 385 | bpi->bpi_visited = B_TRUE; |
| 386 | if (err != 0) |
| 387 | break; |
| 388 | } |
| 389 | /* |
| 390 | * We've finished with this bpo's directly-referenced BP's and |
| 391 | * it has no more unprocessed subobjs. We can free its |
| 392 | * bpobj_info_t (unless it is the topmost, initial_bpo). |
| 393 | * If we are freeing from disk, we can also do that. |
| 394 | */ |
| 395 | if (bpi->bpi_unprocessed_subobjs == 0) { |
| 396 | /* |
| 397 | * If there are no entries, there should |
| 398 | * be no bytes. |
| 399 | */ |
| 400 | if (bpobj_is_empty_impl(bpo)) { |
| 401 | ASSERT0(bpo->bpo_phys->bpo_bytes); |
| 402 | ASSERT0(bpo->bpo_phys->bpo_comp); |
| 403 | ASSERT0(bpo->bpo_phys->bpo_uncomp); |
| 404 | } |
| 405 | |
| 406 | /* The initial_bpo has no parent and is not closed. */ |
| 407 | if (bpi->bpi_parent != NULL) { |
| 408 | if (free) { |
no test coverage detected