aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2013-02-11 14:29:38 +0000
committerMartin Matuska <mm@FreeBSD.org>2013-02-11 14:29:38 +0000
commit9689178c3f935a4830f82c1aebaea23f81d26b1a (patch)
tree35e24045b8da81e7362591b3f37b214b466f621a
parentbb038474186084968710e72a6a61c7f80adf09c8 (diff)
parentf1a1c55d517b91643ef2fc066361b6783094ca93 (diff)
downloadsrc-9689178c3f935a4830f82c1aebaea23f81d26b1a.tar.gz
src-9689178c3f935a4830f82c1aebaea23f81d26b1a.zip
MFV r246633:
Import vendor bugfixes regarding SA rounding, header size and layout. This was already partially fixed by avg. Illumos ZFS issues: 3512 rounding discrepancy in sa_find_sizes() 3513 mismatch between SA header size and layout References: https://www.illumos.org/issues/3512 https://www.illumos.org/issues/3513 MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=246678
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c
index 894bbc3d0deb..7f209ea05001 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c
@@ -553,6 +553,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;
@@ -574,11 +575,13 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
sizeof (sa_hdr_phys_t);
full_space = (buftype == SA_BONUS) ? DN_MAX_BONUSLEN : db->db_size;
+ ASSERT(IS_P2ALIGNED(full_space, 8));
for (i = 0; i != attr_count; i++) {
boolean_t is_var_sz;
- *total += P2ROUNDUP(attr_desc[i].sa_length, 8);
+ *total = P2ROUNDUP(*total, 8);
+ *total += attr_desc[i].sa_length;
if (done)
goto next;
@@ -590,7 +593,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;
@@ -619,6 +629,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);
}
@@ -709,6 +727,8 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
for (i = 0, len_idx = 0, hash = -1ULL; i != attr_count; i++) {
uint16_t length;
+ ASSERT(IS_P2ALIGNED(data_start, 8));
+ ASSERT(IS_P2ALIGNED(buf_space, 8));
attrs[i] = attr_desc[i].sa_attr;
length = SA_REGISTERED_LEN(sa, attrs[i]);
if (length == 0)
@@ -717,6 +737,7 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
VERIFY(length == attr_desc[i].sa_length);
if (buf_space < length) { /* switch to spill buffer */
+ VERIFY(spilling);
VERIFY(bonustype == DMU_OT_SA);
if (buftype == SA_BONUS && !sa->sa_force_spill) {
sa_find_layout(hdl->sa_os, hash, attrs_start,