summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/zfs/sa.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/module/zfs/sa.c b/module/zfs/sa.c
index 91d4074af..f4d264f71 100644
--- a/module/zfs/sa.c
+++ b/module/zfs/sa.c
@@ -572,6 +572,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
{
int var_size = 0;
int i;
+ int j = -1;
int full_space;
int hdrsize;
boolean_t done = B_FALSE;
@@ -611,7 +612,14 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
if (is_var_sz && var_size > 1) {
if (P2ROUNDUP(hdrsize + sizeof (uint16_t), 8) +
*total < full_space) {
+ /*
+ * Account for header space used by array of
+ * optional sizes of variable-length attributes.
+ * Record the index in case this increase needs
+ * to be reversed due to spill-over.
+ */
hdrsize += sizeof (uint16_t);
+ j = i;
} else {
done = B_TRUE;
*index = i;
@@ -640,6 +648,14 @@ next:
*will_spill = B_TRUE;
}
+ /*
+ * j holds the index of the last variable-sized attribute for
+ * which hdrsize was increased. Reverse the increase if that
+ * attribute will be relocated to the spill block.
+ */
+ if (*will_spill && j == *index)
+ hdrsize -= sizeof (uint16_t);
+
hdrsize = P2ROUNDUP(hdrsize, 8);
return (hdrsize);
}