Illumos #3208 cross-endian incorrect user/group accounting
authorMatthew Ahrens <mahrens@delphix.com>
Mon, 14 Jan 2013 17:31:53 +0000 (09:31 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 14 Jan 2013 17:32:22 +0000 (09:32 -0800)
3208 moving zpool cross-endian results in incorrect user/group
accounting

Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <chris.siden@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

References:
  illumos/illumos-gate@e828a46d29ad418487f50d56b5c19e2a1f9033a7
  illumos changeset: 13835:eea81edc4f14
  https://www.illumos.org/issues/3208

Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #627
Closes #1136

include/sys/sa_impl.h
module/zfs/zfs_vfsops.c

index 6661e47..8ae05ce 100644 (file)
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #ifndef        _SYS_SA_IMPL_H
@@ -181,7 +182,7 @@ typedef struct sa_hdr_phys {
  */
 
 #define        SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10)
-#define        SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0)
+#define        SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 6, 3, 0)
 #define        SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \
 { \
        BF32_SET_SB(x, 10, 6, 3, 0, size); \
index 175dca8..fc5c2ba 100644 (file)
@@ -49,6 +49,7 @@
 #include <sys/spa.h>
 #include <sys/zap.h>
 #include <sys/sa.h>
+#include <sys/sa_impl.h>
 #include <sys/varargs.h>
 #include <sys/policy.h>
 #include <sys/atomic.h>
@@ -63,7 +64,6 @@
 #include <sys/dnlc.h>
 #include <sys/dmu_objset.h>
 #include <sys/spa_boot.h>
-#include <sys/sa.h>
 #include <sys/zpl.h>
 #include "zfs_comutil.h"
 
@@ -300,7 +300,6 @@ static int
 zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
     uint64_t *userp, uint64_t *groupp)
 {
-       znode_phys_t *znp = data;
        int error = 0;
 
        /*
@@ -319,20 +318,18 @@ zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
                return (EEXIST);
 
        if (bonustype == DMU_OT_ZNODE) {
+               znode_phys_t *znp = data;
                *userp = znp->zp_uid;
                *groupp = znp->zp_gid;
        } else {
                int hdrsize;
+               sa_hdr_phys_t *sap = data;
+               sa_hdr_phys_t sa = *sap;
+               boolean_t swap = B_FALSE;
 
                ASSERT(bonustype == DMU_OT_SA);
-               hdrsize = sa_hdrsize(data);
 
-               if (hdrsize != 0) {
-                       *userp = *((uint64_t *)((uintptr_t)data + hdrsize +
-                           SA_UID_OFFSET));
-                       *groupp = *((uint64_t *)((uintptr_t)data + hdrsize +
-                           SA_GID_OFFSET));
-               } else {
+               if (sa.sa_magic == 0) {
                        /*
                         * This should only happen for newly created
                         * files that haven't had the znode data filled
@@ -340,6 +337,25 @@ zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
                         */
                        *userp = 0;
                        *groupp = 0;
+                       return (0);
+               }
+               if (sa.sa_magic == BSWAP_32(SA_MAGIC)) {
+                       sa.sa_magic = SA_MAGIC;
+                       sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
+                       swap = B_TRUE;
+               } else {
+                       VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
+               }
+
+               hdrsize = sa_hdrsize(&sa);
+               VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
+               *userp = *((uint64_t *)((uintptr_t)data + hdrsize +
+                   SA_UID_OFFSET));
+               *groupp = *((uint64_t *)((uintptr_t)data + hdrsize +
+                   SA_GID_OFFSET));
+               if (swap) {
+                       *userp = BSWAP_64(*userp);
+                       *groupp = BSWAP_64(*groupp);
                }
        }
        return (error);