362 rw_exit(&dn->dn_struct_rwlock); |
362 rw_exit(&dn->dn_struct_rwlock); |
363 |
363 |
364 dnode_rele(dn, FTAG); |
364 dnode_rele(dn, FTAG); |
365 } |
365 } |
366 |
366 |
|
367 static int |
|
368 get_next_chunk(dnode_t *dn, uint64_t *offset, uint64_t limit) |
|
369 { |
|
370 uint64_t len = limit - *offset; |
|
371 uint64_t chunk_len = dn->dn_datablksz * DMU_MAX_DELETEBLKCNT; |
|
372 uint64_t dn_used; |
|
373 int err; |
|
374 |
|
375 ASSERT(limit <= *offset); |
|
376 |
|
377 dn_used = dn->dn_phys->dn_used << |
|
378 (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES ? 0 : DEV_BSHIFT); |
|
379 if (len <= chunk_len || dn_used <= chunk_len) { |
|
380 *offset = limit; |
|
381 return (0); |
|
382 } |
|
383 |
|
384 while (*offset > limit) { |
|
385 uint64_t initial_offset = *offset; |
|
386 uint64_t delta; |
|
387 |
|
388 /* skip over allocated data */ |
|
389 err = dnode_next_offset(dn, |
|
390 DNODE_FIND_HOLE|DNODE_FIND_BACKWARDS, offset, 1, 1, 0); |
|
391 if (err == ESRCH) |
|
392 *offset = limit; |
|
393 else if (err) |
|
394 return (err); |
|
395 |
|
396 ASSERT3U(*offset, <=, initial_offset); |
|
397 delta = initial_offset - *offset; |
|
398 if (delta >= chunk_len) { |
|
399 *offset += delta - chunk_len; |
|
400 return (0); |
|
401 } |
|
402 chunk_len -= delta; |
|
403 |
|
404 /* skip over unallocated data */ |
|
405 err = dnode_next_offset(dn, |
|
406 DNODE_FIND_BACKWARDS, offset, 1, 1, 0); |
|
407 if (err == ESRCH) |
|
408 *offset = limit; |
|
409 else if (err) |
|
410 return (err); |
|
411 |
|
412 if (*offset < limit) |
|
413 *offset = limit; |
|
414 ASSERT3U(*offset, <, initial_offset); |
|
415 } |
|
416 return (0); |
|
417 } |
|
418 |
|
419 static int |
|
420 dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset, |
|
421 uint64_t length, boolean_t free_dnode) |
|
422 { |
|
423 dmu_tx_t *tx; |
|
424 uint64_t object_size, start, end, len; |
|
425 boolean_t trunc = (length == DMU_OBJECT_END); |
|
426 int align, err; |
|
427 |
|
428 align = 1 << dn->dn_datablkshift; |
|
429 ASSERT(align > 0); |
|
430 object_size = align == 1 ? dn->dn_datablksz : |
|
431 (dn->dn_maxblkid + 1) << dn->dn_datablkshift; |
|
432 |
|
433 if (trunc || (end = offset + length) > object_size) |
|
434 end = object_size; |
|
435 if (end <= offset) |
|
436 return (0); |
|
437 length = end - offset; |
|
438 |
|
439 while (length) { |
|
440 start = end; |
|
441 err = get_next_chunk(dn, &start, offset); |
|
442 if (err) |
|
443 return (err); |
|
444 len = trunc ? DMU_OBJECT_END : end - start; |
|
445 |
|
446 tx = dmu_tx_create(os); |
|
447 dmu_tx_hold_free(tx, dn->dn_object, start, len); |
|
448 err = dmu_tx_assign(tx, TXG_WAIT); |
|
449 if (err) { |
|
450 dmu_tx_abort(tx); |
|
451 return (err); |
|
452 } |
|
453 |
|
454 dnode_free_range(dn, start, trunc ? -1 : len, tx); |
|
455 |
|
456 if (start == 0 && trunc && free_dnode) |
|
457 dnode_free(dn, tx); |
|
458 |
|
459 length -= end - start; |
|
460 |
|
461 dmu_tx_commit(tx); |
|
462 end = start; |
|
463 trunc = FALSE; |
|
464 } |
|
465 return (0); |
|
466 } |
|
467 |
|
468 int |
|
469 dmu_free_long_range(objset_t *os, uint64_t object, |
|
470 uint64_t offset, uint64_t length) |
|
471 { |
|
472 dnode_t *dn; |
|
473 int err; |
|
474 |
|
475 err = dnode_hold(os->os, object, FTAG, &dn); |
|
476 if (err != 0) |
|
477 return (err); |
|
478 err = dmu_free_long_range_impl(os, dn, offset, length, FALSE); |
|
479 dnode_rele(dn, FTAG); |
|
480 return (err); |
|
481 } |
|
482 |
|
483 int |
|
484 dmu_free_object(objset_t *os, uint64_t object) |
|
485 { |
|
486 dnode_t *dn; |
|
487 dmu_tx_t *tx; |
|
488 int err; |
|
489 |
|
490 err = dnode_hold_impl(os->os, object, DNODE_MUST_BE_ALLOCATED, |
|
491 FTAG, &dn); |
|
492 if (err != 0) |
|
493 return (err); |
|
494 if (dn->dn_nlevels == 1) { |
|
495 tx = dmu_tx_create(os); |
|
496 dmu_tx_hold_bonus(tx, object); |
|
497 dmu_tx_hold_free(tx, dn->dn_object, 0, DMU_OBJECT_END); |
|
498 err = dmu_tx_assign(tx, TXG_WAIT); |
|
499 if (err == 0) { |
|
500 dnode_free_range(dn, 0, DMU_OBJECT_END, tx); |
|
501 dnode_free(dn, tx); |
|
502 dmu_tx_commit(tx); |
|
503 } else { |
|
504 dmu_tx_abort(tx); |
|
505 } |
|
506 } else { |
|
507 err = dmu_free_long_range_impl(os, dn, 0, DMU_OBJECT_END, TRUE); |
|
508 } |
|
509 dnode_rele(dn, FTAG); |
|
510 return (err); |
|
511 } |
|
512 |
367 int |
513 int |
368 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset, |
514 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset, |
369 uint64_t size, dmu_tx_t *tx) |
515 uint64_t size, dmu_tx_t *tx) |
370 { |
516 { |
371 dnode_t *dn; |
517 dnode_t *dn; |