From e6e24a1e97e1f5d7b1b9d9b8d3132d9f3510b2f6 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Thu, 16 Apr 2015 08:23:22 +0300 Subject: zfs: com.delphix:embedded_data feature support Origin: upstream, http://git.savannah.gnu.org/cgit/grub.git/commit/?id=4a7ea4003bd9f39e9bf2ebadbe4ab38f8874be66 Last-Update: 2016-01-22 Patch-Name: zfs-embedded-data.patch --- grub-core/fs/zfs/zfs.c | 84 +++++++++++++++++++++++++++++++++++++++++--------- include/grub/zfs/spa.h | 27 +++++++++++++--- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index b01c34f..a95e7e3 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -282,6 +282,7 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key static const char *spa_feature_names[] = { "org.illumos:lz4_compress", "com.delphix:hole_birth", + "com.delphix:embedded_data", NULL }; @@ -1800,6 +1801,39 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, } /* + * buf must be at least BPE_GET_PSIZE(bp) bytes long (which will never be + * more than BPE_PAYLOAD_SIZE bytes). + */ +static grub_err_t +decode_embedded_bp_compressed(const blkptr_t *bp, void *buf) +{ + grub_size_t psize, i; + grub_uint8_t *buf8 = buf; + grub_uint64_t w = 0; + const grub_uint64_t *bp64 = (const grub_uint64_t *)bp; + + psize = BPE_GET_PSIZE(bp); + + /* + * Decode the words of the block pointer into the byte array. + * Low bits of first word are the first byte (little endian). + */ + for (i = 0; i < psize; i++) + { + if (i % sizeof (w) == 0) + { + /* beginning of a word */ + w = *bp64; + bp64++; + if (!BPE_IS_PAYLOADWORD(bp, bp64)) + bp64++; + } + buf8[i] = BF64_GET(w, (i % sizeof (w)) * 8, 8); + } + return GRUB_ERR_NONE; +} + +/* * Read in a block of data, verify its checksum, decompress if needed, * and put the uncompressed data in buf. */ @@ -1817,12 +1851,26 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; - comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff; + comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7f; encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3); - lsize = (BP_IS_HOLE(bp) ? 0 : - (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) - << SPA_MINBLOCKSHIFT)); - psize = get_psize (bp, endian); + if (BP_IS_EMBEDDED(bp)) + { + if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported embedded BP (type=%u)\n", + BPE_GET_ETYPE(bp)); + lsize = BPE_GET_LSIZE(bp); + psize = BF64_GET_SB(grub_zfs_to_cpu64 ((bp)->blk_prop, endian), 25, 7, 0, 1); + } + else + { + lsize = (BP_IS_HOLE(bp) ? 0 : + (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) + << SPA_MINBLOCKSHIFT)); + psize = get_psize (bp, endian); + } + grub_dprintf("zfs", "zio_read: E %d: size %" PRIdGRUB_SSIZE "/%" + PRIdGRUB_SSIZE "\n", (int)BP_IS_EMBEDDED(bp), lsize, psize); if (size) *size = lsize; @@ -1846,23 +1894,31 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, compbuf = *buf = grub_malloc (lsize); grub_dprintf ("zfs", "endian = %d\n", endian); - err = zio_read_data (bp, endian, compbuf, data); + if (BP_IS_EMBEDDED(bp)) + err = decode_embedded_bp_compressed(bp, compbuf); + else + { + err = zio_read_data (bp, endian, compbuf, data); + grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); + } if (err) { grub_free (compbuf); *buf = NULL; return err; } - grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); - err = zio_checksum_verify (zc, checksum, endian, - compbuf, psize); - if (err) + if (!BP_IS_EMBEDDED(bp)) { - grub_dprintf ("zfs", "incorrect checksum\n"); - grub_free (compbuf); - *buf = NULL; - return err; + err = zio_checksum_verify (zc, checksum, endian, + compbuf, psize); + if (err) + { + grub_dprintf ("zfs", "incorrect checksum\n"); + grub_free (compbuf); + *buf = NULL; + return err; + } } if (encrypted) diff --git a/include/grub/zfs/spa.h b/include/grub/zfs/spa.h index df43b6b..8dd1fa8 100644 --- a/include/grub/zfs/spa.h +++ b/include/grub/zfs/spa.h @@ -126,7 +126,7 @@ typedef struct zio_cksum { * +-------+-------+-------+-------+-------+-------+-------+-------+ * 5 |G| offset3 | * +-------+-------+-------+-------+-------+-------+-------+-------+ - * 6 |BDX|lvl| type | cksum | comp | PSIZE | LSIZE | + * 6 |BDX|lvl| type | cksum |E| comp| PSIZE | LSIZE | * +-------+-------+-------+-------+-------+-------+-------+-------+ * 7 | padding | * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -160,7 +160,8 @@ typedef struct zio_cksum { * G gang block indicator * B byteorder (endianness) * D dedup - * X unused + * X encryption + * E blkptr_t contains embedded data * lvl level of indirection * type DMU object type * phys birth txg of block allocation; zero if same as logical birth txg @@ -203,8 +204,8 @@ typedef struct blkptr { #define BP_SET_LSIZE(bp, x) \ BF64_SET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x) -#define BP_GET_COMPRESS(bp) BF64_GET((bp)->blk_prop, 32, 8) -#define BP_SET_COMPRESS(bp, x) BF64_SET((bp)->blk_prop, 32, 8, x) +#define BP_GET_COMPRESS(bp) BF64_GET((bp)->blk_prop, 32, 7) +#define BP_SET_COMPRESS(bp, x) BF64_SET((bp)->blk_prop, 32, 7, x) #define BP_GET_CHECKSUM(bp) BF64_GET((bp)->blk_prop, 40, 8) #define BP_SET_CHECKSUM(bp, x) BF64_SET((bp)->blk_prop, 40, 8, x) @@ -215,6 +216,8 @@ typedef struct blkptr { #define BP_GET_LEVEL(bp) BF64_GET((bp)->blk_prop, 56, 5) #define BP_SET_LEVEL(bp, x) BF64_SET((bp)->blk_prop, 56, 5, x) +#define BP_IS_EMBEDDED(bp) BF64_GET((bp)->blk_prop, 39, 1) + #define BP_GET_PROP_BIT_61(bp) BF64_GET((bp)->blk_prop, 61, 1) #define BP_SET_PROP_BIT_61(bp, x) BF64_SET((bp)->blk_prop, 61, 1, x) @@ -277,6 +280,22 @@ typedef struct blkptr { (zcp)->zc_word[3] = w3; \ } +#define BPE_GET_ETYPE(bp) BP_GET_CHECKSUM(bp) +#define BPE_GET_LSIZE(bp) \ + BF64_GET_SB((bp)->blk_prop, 0, 25, 0, 1) +#define BPE_GET_PSIZE(bp) \ + BF64_GET_SB((bp)->blk_prop, 25, 7, 0, 1) + +typedef enum bp_embedded_type { + BP_EMBEDDED_TYPE_DATA, + NUM_BP_EMBEDDED_TYPES +} bp_embedded_type_t; + +#define BPE_NUM_WORDS 14 +#define BPE_PAYLOAD_SIZE (BPE_NUM_WORDS * sizeof(grub_uint64_t)) +#define BPE_IS_PAYLOADWORD(bp, wp) \ + ((wp) != &(bp)->blk_prop && (wp) != &(bp)->blk_birth) + #define BP_IDENTITY(bp) (&(bp)->blk_dva[0]) #define BP_IS_GANG(bp) DVA_GET_GANG(BP_IDENTITY(bp)) #define DVA_IS_EMPTY(dva) ((dva)->dva_word[0] == 0ULL && \