Skip to content

Commit

Permalink
Calculate header size correctly in sa_find_sizes()
Browse files Browse the repository at this point in the history
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 openzfs#2214
Issue openzfs#2228
Issue openzfs#2316
Issue openzfs#2343
  • Loading branch information
dweeezil authored and FransUrbo committed May 20, 2014
1 parent 83401fe commit df2fecc
Showing 1 changed file with 8 additions and 6 deletions.
14 changes: 8 additions & 6 deletions module/zfs/sa.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
ASSERT(IS_P2ALIGNED(full_space, 8));

for (i = 0; i != attr_count; i++) {
boolean_t is_var_sz;
boolean_t is_var_sz, might_spill_here;

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

might_spill_here =
buftype == SA_BONUS && *index == -1 &&
(*total + P2ROUNDUP(hdrsize, 8)) >
(full_space - sizeof (blkptr_t));

if (is_var_sz && var_size > 1) {
/*
* Don't worry that the spill block might overflow.
Expand All @@ -622,7 +627,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
* spill-over.
*/
hdrsize += sizeof (uint16_t);
if (*index != -1)
if (*index != -1 || might_spill_here)
extra_hdrsize += sizeof (uint16_t);
} else {
ASSERT(buftype == SA_BONUS);
Expand All @@ -639,11 +644,8 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
* space. The sum is used later for sizing bonus
* and spill buffer.
*/
if (buftype == SA_BONUS && *index == -1 &&
(*total + P2ROUNDUP(hdrsize, 8)) >
(full_space - sizeof (blkptr_t))) {
if (might_spill_here)
*index = i;
}

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

0 comments on commit df2fecc

Please sign in to comment.