@@ -538,20 +538,30 @@ sa_copy_data(sa_data_locator_t *func, void *datastart, void *target, int buflen)
538538}
539539
540540/*
541- * Determine several different sizes
542- * first the sa header size
543- * the number of bytes to be stored
544- * if spill would occur the index in the attribute array is returned
541+ * Determine several different values pertaining to system attribute
542+ * buffers.
545543 *
546- * the boolean will_spill will be set when spilling is necessary. It
547- * is only set when the buftype is SA_BONUS
544+ * Return the size of the sa_hdr_phys_t header for the buffer. Each
545+ * variable length attribute except the first contributes two bytes to
546+ * the header size, which is then rounded up to an 8-byte boundary.
547+ *
548+ * The following output parameters are also computed.
549+ *
550+ * index - The index of the first attribute in attr_desc that will
551+ * spill over. Only valid if will_spill is set.
552+ *
553+ * total - The total number of bytes of all system attributes described
554+ * in attr_desc.
555+ *
556+ * will_spill - Set when spilling is necessary. It is only set when
557+ * the buftype is SA_BONUS.
548558 */
549559static int
550560sa_find_sizes (sa_os_t * sa , sa_bulk_attr_t * attr_desc , int attr_count ,
551561 dmu_buf_t * db , sa_buf_type_t buftype , int * index , int * total ,
552562 boolean_t * will_spill )
553563{
554- int var_size = 0 ;
564+ int var_size_count = 0 ;
555565 int i ;
556566 int full_space ;
557567 int hdrsize ;
@@ -577,38 +587,43 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
577587
578588 for (i = 0 ; i != attr_count ; i ++ ) {
579589 boolean_t is_var_sz , might_spill_here ;
590+ int tmp_hdrsize ;
580591
581592 * total = P2ROUNDUP (* total , 8 );
582593 * total += attr_desc [i ].sa_length ;
583594 if (* will_spill )
584595 continue ;
585596
586597 is_var_sz = (SA_REGISTERED_LEN (sa , attr_desc [i ].sa_attr ) == 0 );
587- if (is_var_sz ) {
588- var_size ++ ;
589- }
598+ if (is_var_sz )
599+ var_size_count ++ ;
600+
601+ /*
602+ * Calculate what the SA header size would be if this
603+ * attribute doesn't spill.
604+ */
605+ tmp_hdrsize = hdrsize + ((is_var_sz && var_size_count > 1 ) ?
606+ sizeof (uint16_t ) : 0 );
590607
608+ /*
609+ * Check whether this attribute spans into the space
610+ * that would be used by the spill block pointer should
611+ * a spill block be needed.
612+ */
591613 might_spill_here =
592614 buftype == SA_BONUS && * index == -1 &&
593- (* total + P2ROUNDUP (hdrsize , 8 )) >
615+ (* total + P2ROUNDUP (tmp_hdrsize , 8 )) >
594616 (full_space - sizeof (blkptr_t ));
595617
596- if (is_var_sz && var_size > 1 ) {
597- /*
598- * Don't worry that the spill block might overflow.
599- * It will be resized if needed in sa_build_layouts().
600- */
618+ if (is_var_sz && var_size_count > 1 ) {
601619 if (buftype == SA_SPILL ||
602- P2ROUNDUP (hdrsize + sizeof (uint16_t ), 8 ) +
603- * total < full_space ) {
620+ tmp_hdrsize + * total < full_space ) {
604621 /*
605- * Account for header space used by array of
606- * optional sizes of variable-length attributes.
607622 * Record the extra header size in case this
608623 * increase needs to be reversed due to
609624 * spill-over.
610625 */
611- hdrsize += sizeof ( uint16_t ) ;
626+ hdrsize = tmp_hdrsize ;
612627 if (* index != -1 || might_spill_here )
613628 extra_hdrsize += sizeof (uint16_t );
614629 } else {
@@ -621,10 +636,9 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
621636 }
622637
623638 /*
624- * find index of where spill *could* occur.
625- * Then continue to count of remainder attribute
626- * space. The sum is used later for sizing bonus
627- * and spill buffer.
639+ * Store index of where spill *could* occur. Then
640+ * continue to count the remaining attribute sizes. The
641+ * sum is used later for sizing bonus and spill buffer.
628642 */
629643 if (might_spill_here )
630644 * index = i ;
@@ -657,9 +671,9 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
657671 sa_buf_type_t buftype ;
658672 sa_hdr_phys_t * sahdr ;
659673 void * data_start ;
660- int buf_space ;
661674 sa_attr_type_t * attrs , * attrs_start ;
662675 int i , lot_count ;
676+ int spill_idx ;
663677 int hdrsize ;
664678 int spillhdrsize = 0 ;
665679 int used ;
@@ -674,7 +688,7 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
674688
675689 /* first determine bonus header size and sum of all attributes */
676690 hdrsize = sa_find_sizes (sa , attr_desc , attr_count , hdl -> sa_bonus ,
677- SA_BONUS , & i , & used , & spilling );
691+ SA_BONUS , & spill_idx , & used , & spilling );
678692
679693 if (used > SPA_MAXBLOCKSIZE )
680694 return (SET_ERROR (EFBIG ));
@@ -696,14 +710,13 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
696710 }
697711 dmu_buf_will_dirty (hdl -> sa_spill , tx );
698712
699- spillhdrsize = sa_find_sizes (sa , & attr_desc [i ],
700- attr_count - i , hdl -> sa_spill , SA_SPILL , & i ,
713+ spillhdrsize = sa_find_sizes (sa , & attr_desc [spill_idx ],
714+ attr_count - spill_idx , hdl -> sa_spill , SA_SPILL , & i ,
701715 & spill_used , & dummy );
702716
703717 if (spill_used > SPA_MAXBLOCKSIZE )
704718 return (SET_ERROR (EFBIG ));
705719
706- buf_space = hdl -> sa_spill -> db_size - spillhdrsize ;
707720 if (BUF_SPACE_NEEDED (spill_used , spillhdrsize ) >
708721 hdl -> sa_spill -> db_size )
709722 VERIFY (0 == sa_resize_spill (hdl ,
@@ -715,12 +728,6 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
715728 sahdr = (sa_hdr_phys_t * )hdl -> sa_bonus -> db_data ;
716729 buftype = SA_BONUS ;
717730
718- if (spilling )
719- buf_space = (sa -> sa_force_spill ) ?
720- 0 : SA_BLKPTR_SPACE - hdrsize ;
721- else
722- buf_space = hdl -> sa_bonus -> db_size - hdrsize ;
723-
724731 attrs_start = attrs = kmem_alloc (sizeof (sa_attr_type_t ) * attr_count ,
725732 KM_SLEEP );
726733 lot_count = 0 ;
@@ -729,14 +736,12 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
729736 uint16_t length ;
730737
731738 ASSERT (IS_P2ALIGNED (data_start , 8 ));
732- ASSERT (IS_P2ALIGNED (buf_space , 8 ));
733739 attrs [i ] = attr_desc [i ].sa_attr ;
734740 length = SA_REGISTERED_LEN (sa , attrs [i ]);
735741 if (length == 0 )
736742 length = attr_desc [i ].sa_length ;
737743
738- if (buf_space < length ) { /* switch to spill buffer */
739- VERIFY (spilling );
744+ if (spilling && i == spill_idx ) { /* switch to spill buffer */
740745 VERIFY (bonustype == DMU_OT_SA );
741746 if (buftype == SA_BONUS && !sa -> sa_force_spill ) {
742747 sa_find_layout (hdl -> sa_os , hash , attrs_start ,
@@ -753,7 +758,6 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
753758 data_start = (void * )((uintptr_t )sahdr +
754759 spillhdrsize );
755760 attrs_start = & attrs [i ];
756- buf_space = hdl -> sa_spill -> db_size - spillhdrsize ;
757761 lot_count = 0 ;
758762 }
759763 hash ^= SA_ATTR_HASH (attrs [i ]);
@@ -766,7 +770,6 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
766770 }
767771 data_start = (void * )P2ROUNDUP (((uintptr_t )data_start +
768772 length ), 8 );
769- buf_space -= P2ROUNDUP (length , 8 );
770773 lot_count ++ ;
771774 }
772775
0 commit comments