Print this page
4047 panic from dbuf_free_range() from dmu_free_object() while doing zfs receive
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>


 552         } else {
 553                 nblks = (offset < dn->dn_datablksz);
 554         }
 555 
 556         if (nblks != 0) {
 557                 blkid = dbuf_whichblock(dn, offset);
 558                 for (i = 0; i < nblks; i++)
 559                         dbuf_prefetch(dn, blkid+i);
 560         }
 561 
 562         rw_exit(&dn->dn_struct_rwlock);
 563 
 564         dnode_rele(dn, FTAG);
 565 }
 566 
 567 /*
 568  * Get the next "chunk" of file data to free.  We traverse the file from
 569  * the end so that the file gets shorter over time (if we crashes in the
 570  * middle, this will leave us in a better state).  We find allocated file
 571  * data by simply searching the allocated level 1 indirects.




 572  */
 573 static int
 574 get_next_chunk(dnode_t *dn, uint64_t *start, uint64_t limit)
 575 {
 576         uint64_t len = *start - limit;
 577         uint64_t blkcnt = 0;
 578         uint64_t maxblks = DMU_MAX_ACCESS / (1ULL << (dn->dn_indblkshift + 1));
 579         uint64_t iblkrange =
 580             dn->dn_datablksz * EPB(dn->dn_indblkshift, SPA_BLKPTRSHIFT);
 581 
 582         ASSERT(limit <= *start);
 583 
 584         if (len <= iblkrange * maxblks) {
 585                 *start = limit;
 586                 return (0);
 587         }
 588         ASSERT(ISP2(iblkrange));
 589 
 590         while (*start > limit && blkcnt < maxblks) {
 591                 int err;
 592 
 593                 /* find next allocated L1 indirect */






 594                 err = dnode_next_offset(dn,
 595                     DNODE_FIND_BACKWARDS, start, 2, 1, 0);
 596 
 597                 /* if there are no more, then we are done */
 598                 if (err == ESRCH) {
 599                         *start = limit;
 600                         return (0);
 601                 } else if (err) {
 602                         return (err);
 603                 }
 604                 blkcnt += 1;
 605 
 606                 /* reset offset to end of "next" block back */
 607                 *start = P2ALIGN(*start, iblkrange);
 608                 if (*start <= limit)
 609                         *start = limit;
 610                 else
 611                         *start -= 1;
 612         }


 613         return (0);
 614 }
 615 
 616 static int
 617 dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
 618     uint64_t length, boolean_t free_dnode)
 619 {
 620         dmu_tx_t *tx;
 621         uint64_t object_size, start, end, len;
 622         boolean_t trunc = (length == DMU_OBJECT_END);
 623         int align, err;
 624 
 625         align = 1 << dn->dn_datablkshift;
 626         ASSERT(align > 0);
 627         object_size = align == 1 ? dn->dn_datablksz :
 628             (dn->dn_maxblkid + 1) << dn->dn_datablkshift;
 629 
 630         end = offset + length;
 631         if (trunc || end > object_size)
 632                 end = object_size;
 633         if (end <= offset)
 634                 return (0);
 635         length = end - offset;
 636 
 637         while (length) {
 638                 start = end;
 639                 /* assert(offset <= start) */
 640                 err = get_next_chunk(dn, &start, offset);






 641                 if (err)
 642                         return (err);
 643                 len = trunc ? DMU_OBJECT_END : end - start;

 644 
 645                 tx = dmu_tx_create(os);
 646                 dmu_tx_hold_free(tx, dn->dn_object, start, len);

 647                 err = dmu_tx_assign(tx, TXG_WAIT);
 648                 if (err) {
 649                         dmu_tx_abort(tx);
 650                         return (err);
 651                 }


 652 
 653                 dnode_free_range(dn, start, trunc ? -1 : len, tx);
 654 
 655                 if (start == 0 && free_dnode) {
 656                         ASSERT(trunc);
 657                         dnode_free(dn, tx);
 658                 }
 659 
 660                 length -= end - start;
 661 
 662                 dmu_tx_commit(tx);
 663                 end = start;
 664         }
 665         return (0);
 666 }
 667 
 668 int
 669 dmu_free_long_range(objset_t *os, uint64_t object,
 670     uint64_t offset, uint64_t length)
 671 {
 672         dnode_t *dn;
 673         int err;
 674 
 675         err = dnode_hold(os, object, FTAG, &dn);
 676         if (err != 0)
 677                 return (err);
 678         err = dmu_free_long_range_impl(os, dn, offset, length, FALSE);
 679         dnode_rele(dn, FTAG);
 680         return (err);
 681 }
 682 
 683 int
 684 dmu_free_object(objset_t *os, uint64_t object)
 685 {
 686         dnode_t *dn;
 687         dmu_tx_t *tx;
 688         int err;
 689 
 690         err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
 691             FTAG, &dn);
 692         if (err != 0)
 693                 return (err);
 694         if (dn->dn_nlevels == 1) {
 695                 tx = dmu_tx_create(os);
 696                 dmu_tx_hold_bonus(tx, object);
 697                 dmu_tx_hold_free(tx, dn->dn_object, 0, DMU_OBJECT_END);
 698                 err = dmu_tx_assign(tx, TXG_WAIT);
 699                 if (err == 0) {
 700                         dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
 701                         dnode_free(dn, tx);
 702                         dmu_tx_commit(tx);
 703                 } else {
 704                         dmu_tx_abort(tx);
 705                 }
 706         } else {
 707                 err = dmu_free_long_range_impl(os, dn, 0, DMU_OBJECT_END, TRUE);
 708         }
 709         dnode_rele(dn, FTAG);
 710         return (err);
 711 }
 712 
 713 int
 714 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
 715     uint64_t size, dmu_tx_t *tx)
 716 {
 717         dnode_t *dn;
 718         int err = dnode_hold(os, object, FTAG, &dn);
 719         if (err)
 720                 return (err);
 721         ASSERT(offset < UINT64_MAX);
 722         ASSERT(size == -1ULL || size <= UINT64_MAX - offset);
 723         dnode_free_range(dn, offset, size, tx);
 724         dnode_rele(dn, FTAG);
 725         return (0);
 726 }
 727 
 728 int
 729 dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,




 552         } else {
 553                 nblks = (offset < dn->dn_datablksz);
 554         }
 555 
 556         if (nblks != 0) {
 557                 blkid = dbuf_whichblock(dn, offset);
 558                 for (i = 0; i < nblks; i++)
 559                         dbuf_prefetch(dn, blkid+i);
 560         }
 561 
 562         rw_exit(&dn->dn_struct_rwlock);
 563 
 564         dnode_rele(dn, FTAG);
 565 }
 566 
 567 /*
 568  * Get the next "chunk" of file data to free.  We traverse the file from
 569  * the end so that the file gets shorter over time (if we crashes in the
 570  * middle, this will leave us in a better state).  We find allocated file
 571  * data by simply searching the allocated level 1 indirects.
 572  *
 573  * On input, *start should be the first offset that does not need to be
 574  * freed (e.g. "offset + length").  On return, *start will be the first
 575  * offset that should be freed.
 576  */
 577 static int
 578 get_next_chunk(dnode_t *dn, uint64_t *start, uint64_t minimum)
 579 {
 580         uint64_t maxblks = DMU_MAX_ACCESS >> (dn->dn_indblkshift + 1);
 581         /* bytes of data covered by a level-1 indirect block */

 582         uint64_t iblkrange =
 583             dn->dn_datablksz * EPB(dn->dn_indblkshift, SPA_BLKPTRSHIFT);
 584 
 585         ASSERT3U(minimum, <=, *start);
 586 
 587         if (*start - minimum <= iblkrange * maxblks) {
 588                 *start = minimum;
 589                 return (0);
 590         }
 591         ASSERT(ISP2(iblkrange));
 592 
 593         for (uint64_t blks = 0; *start > minimum && blks < maxblks; blks++) {
 594                 int err;
 595 
 596                 /*
 597                  * dnode_next_offset(BACKWARDS) will find an allocated L1
 598                  * indirect block at or before the input offset.  We must
 599                  * decrement *start so that it is at the end of the region
 600                  * to search.
 601                  */
 602                 (*start)--;
 603                 err = dnode_next_offset(dn,
 604                     DNODE_FIND_BACKWARDS, start, 2, 1, 0);
 605 
 606                 /* if there are no indirect blocks before start, we are done */
 607                 if (err == ESRCH) {
 608                         *start = minimum;
 609                         break;
 610                 } else if (err != 0) {
 611                         return (err);
 612                 }

 613 
 614                 /* set start to the beginning of this L1 indirect */
 615                 *start = P2ALIGN(*start, iblkrange);




 616         }
 617         if (*start < minimum)
 618                 *start = minimum;
 619         return (0);
 620 }
 621 
 622 static int
 623 dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
 624     uint64_t length)
 625 {
 626         uint64_t object_size = (dn->dn_maxblkid + 1) * dn->dn_datablksz;
 627         int err;


 628 
 629         if (offset >= object_size)








 630                 return (0);

 631 
 632         if (length == DMU_OBJECT_END || offset + length > object_size)
 633                 length = object_size - offset;
 634 
 635         while (length != 0) {
 636                 uint64_t chunk_end, chunk_begin;
 637 
 638                 chunk_end = chunk_begin = offset + length;
 639 
 640                 /* move chunk_begin backwards to the beginning of this chunk */
 641                 err = get_next_chunk(dn, &chunk_begin, offset);
 642                 if (err)
 643                         return (err);
 644                 ASSERT3U(chunk_begin, >=, offset);
 645                 ASSERT3U(chunk_begin, <=, chunk_end);
 646 
 647                 dmu_tx_t *tx = dmu_tx_create(os);
 648                 dmu_tx_hold_free(tx, dn->dn_object,
 649                     chunk_begin, chunk_end - chunk_begin);
 650                 err = dmu_tx_assign(tx, TXG_WAIT);
 651                 if (err) {
 652                         dmu_tx_abort(tx);
 653                         return (err);
 654                 }
 655                 dnode_free_range(dn, chunk_begin, chunk_end - chunk_begin, tx);
 656                 dmu_tx_commit(tx);
 657 
 658                 length -= chunk_end - chunk_begin;




 659         }






 660         return (0);
 661 }
 662 
 663 int
 664 dmu_free_long_range(objset_t *os, uint64_t object,
 665     uint64_t offset, uint64_t length)
 666 {
 667         dnode_t *dn;
 668         int err;
 669 
 670         err = dnode_hold(os, object, FTAG, &dn);
 671         if (err != 0)
 672                 return (err);
 673         err = dmu_free_long_range_impl(os, dn, offset, length);
 674         dnode_rele(dn, FTAG);
 675         return (err);
 676 }
 677 
 678 int
 679 dmu_free_long_object(objset_t *os, uint64_t object)
 680 {

 681         dmu_tx_t *tx;
 682         int err;
 683 
 684         err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);

 685         if (err != 0)
 686                 return (err);
 687 
 688         tx = dmu_tx_create(os);
 689         dmu_tx_hold_bonus(tx, object);
 690         dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
 691         err = dmu_tx_assign(tx, TXG_WAIT);
 692         if (err == 0) {
 693                 err = dmu_object_free(os, object, tx);

 694                 dmu_tx_commit(tx);
 695         } else {
 696                 dmu_tx_abort(tx);
 697         }
 698 



 699         return (err);
 700 }
 701 
 702 int
 703 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
 704     uint64_t size, dmu_tx_t *tx)
 705 {
 706         dnode_t *dn;
 707         int err = dnode_hold(os, object, FTAG, &dn);
 708         if (err)
 709                 return (err);
 710         ASSERT(offset < UINT64_MAX);
 711         ASSERT(size == -1ULL || size <= UINT64_MAX - offset);
 712         dnode_free_range(dn, offset, size, tx);
 713         dnode_rele(dn, FTAG);
 714         return (0);
 715 }
 716 
 717 int
 718 dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,