Skip to content

Commit 83021b4

Browse files
dweeezilbehlendorf
authored andcommitted
Calculate header size correctly in sa_find_sizes()
In the case where a variable-sized SA overlaps the spill block pointer and a new variable-sized SA is being added, the header size was improperly calculated to include the to-be-moved SA. This problem could be reproduced when xattr=sa enabled as follows: ln -s $(perl -e 'print "x" x 120') blah setfattr -n security.selinux -v blahblah -h blah The symlink is large enough to interfere with the spill block pointer and has a typical SA registration as follows (shown in modified "zdb -dddd" <SA attr layout obj> format): [ ... ZPL_DACL_COUNT ZPL_DACL_ACES ZPL_SYMLINK ] Adding the SA xattr will attempt to extend the registration to: [ ... ZPL_DACL_COUNT ZPL_DACL_ACES ZPL_SYMLINK ZPL_DXATTR ] but since the ZPL_SYMLINK SA interferes with the spill block pointer, it must also be moved to the spill block which will have a registration of: [ ZPL_SYMLINK ZPL_DXATTR ] This commit updates extra_hdrsize when this condition occurs, allowing hdrsize to be subsequently decreased appropriately. Signed-off-by: Tim Chase <tim@chase2k.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ned Bass <bass6@llnl.gov> Issue #2214 Issue #2228 Issue #2316 Issue #2343
1 parent 3937ab2 commit 83021b4

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

module/zfs/sa.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
594594
ASSERT(IS_P2ALIGNED(full_space, 8));
595595

596596
for (i = 0; i != attr_count; i++) {
597-
boolean_t is_var_sz;
597+
boolean_t is_var_sz, might_spill_here;
598598

599599
*total = P2ROUNDUP(*total, 8);
600600
*total += attr_desc[i].sa_length;
@@ -606,6 +606,11 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
606606
var_size++;
607607
}
608608

609+
might_spill_here =
610+
buftype == SA_BONUS && *index == -1 &&
611+
(*total + P2ROUNDUP(hdrsize, 8)) >
612+
(full_space - sizeof (blkptr_t));
613+
609614
if (is_var_sz && var_size > 1) {
610615
/*
611616
* Don't worry that the spill block might overflow.
@@ -622,7 +627,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
622627
* spill-over.
623628
*/
624629
hdrsize += sizeof (uint16_t);
625-
if (*index != -1)
630+
if (*index != -1 || might_spill_here)
626631
extra_hdrsize += sizeof (uint16_t);
627632
} else {
628633
ASSERT(buftype == SA_BONUS);
@@ -639,11 +644,8 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
639644
* space. The sum is used later for sizing bonus
640645
* and spill buffer.
641646
*/
642-
if (buftype == SA_BONUS && *index == -1 &&
643-
(*total + P2ROUNDUP(hdrsize, 8)) >
644-
(full_space - sizeof (blkptr_t))) {
647+
if (might_spill_here)
645648
*index = i;
646-
}
647649

648650
if ((*total + P2ROUNDUP(hdrsize, 8)) > full_space &&
649651
buftype == SA_BONUS)

0 commit comments

Comments
 (0)