summaryrefslogtreecommitdiffstats
path: root/module/zfs/sa.c
diff options
context:
space:
mode:
authorTim Chase <[email protected]>2014-05-10 20:13:12 -0500
committerBrian Behlendorf <[email protected]>2014-05-19 11:55:50 -0700
commit83021b47c2870c0ba948cbcfe08f41bd7730f5fb (patch)
tree33b90baa091ae8c9e1f284bdfd6de6c553fe2020 /module/zfs/sa.c
parent3937ab20f32fc7b79cacfd91c0891f4e1b4ab2de (diff)
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 <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Signed-off-by: Ned Bass <[email protected]> Issue #2214 Issue #2228 Issue #2316 Issue #2343
Diffstat (limited to 'module/zfs/sa.c')
-rw-r--r--module/zfs/sa.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/module/zfs/sa.c b/module/zfs/sa.c
index fcc5f3ba0..25153a839 100644
--- a/module/zfs/sa.c
+++ b/module/zfs/sa.c
@@ -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;
@@ -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.
@@ -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);
@@ -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)