From 5d7b4d438c4a51eccc95e77a83a437b4d48380eb Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Thu, 5 Jun 2014 13:19:08 -0800 Subject: 4757 ZFS embedded-data block pointers ("zero block compression") 4913 zfs release should not be subject to space checks Reviewed by: Adam Leventhal Reviewed by: Max Grossman Reviewed by: George Wilson Reviewed by: Christopher Siden Reviewed by: Dan McDonald Approved by: Dan McDonald --- usr/src/grub/capability | 2 +- usr/src/grub/grub-0.97/stage2/fsys_zfs.c | 90 +++++++++++++++++++++++-- usr/src/grub/grub-0.97/stage2/zfs-include/spa.h | 27 ++++++-- 3 files changed, 109 insertions(+), 10 deletions(-) (limited to 'usr/src/grub') diff --git a/usr/src/grub/capability b/usr/src/grub/capability index 964cbe9306..e0f25f1275 100644 --- a/usr/src/grub/capability +++ b/usr/src/grub/capability @@ -29,7 +29,7 @@ # GRUB necessitating that the boot blocks be reinstalled for that fix or # enhancement to take effect. # -VERSION=23 +VERSION=24 dboot xVM zfs diff --git a/usr/src/grub/grub-0.97/stage2/fsys_zfs.c b/usr/src/grub/grub-0.97/stage2/fsys_zfs.c index 950f3ce880..341b6cd971 100644 --- a/usr/src/grub/grub-0.97/stage2/fsys_zfs.c +++ b/usr/src/grub/grub-0.97/stage2/fsys_zfs.c @@ -166,12 +166,15 @@ zio_checksum_verify(blkptr_t *bp, char *data, int size) zio_checksum_info_t *ci = &zio_checksum_table[checksum]; zio_cksum_t actual_cksum, expected_cksum; - /* byteswap is not supported */ - if (byteswap) + if (byteswap) { + grub_printf("byteswap not supported\n"); return (-1); + } - if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) + if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) { + grub_printf("checksum algorithm %u not supported\n", checksum); return (-1); + } if (ci->ci_eck) { expected_cksum = zec->zec_cksum; @@ -179,7 +182,6 @@ zio_checksum_verify(blkptr_t *bp, char *data, int size) ci->ci_func[0](data, size, &actual_cksum); zec->zec_cksum = expected_cksum; zc = expected_cksum; - } else { ci->ci_func[byteswap](data, size, &actual_cksum); } @@ -378,6 +380,72 @@ zio_read_data(blkptr_t *bp, void *buf, char *stack) return (1); } +/* + * buf must be at least BPE_GET_PSIZE(bp) bytes long (which will never be + * more than BPE_PAYLOAD_SIZE bytes). + */ +static void +decode_embedded_bp_compressed(const blkptr_t *bp, void *buf) +{ + int psize, i; + uint8_t *buf8 = buf; + uint64_t w = 0; + const uint64_t *bp64 = (const 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)) * NBBY, NBBY); + } +} + +/* + * Fill in the buffer with the (decompressed) payload of the embedded + * blkptr_t. Takes into account compression and byteorder (the payload is + * treated as a stream of bytes). + * Return 0 on success, or ENOSPC if it won't fit in the buffer. + */ +static int +decode_embedded_bp(const blkptr_t *bp, void *buf) +{ + int comp; + int lsize, psize; + uint8_t *dst = buf; + uint64_t w = 0; + + lsize = BPE_GET_LSIZE(bp); + psize = BPE_GET_PSIZE(bp); + comp = BP_GET_COMPRESS(bp); + + if (comp != ZIO_COMPRESS_OFF) { + uint8_t dstbuf[BPE_PAYLOAD_SIZE]; + + if ((unsigned int)comp >= ZIO_COMPRESS_FUNCTIONS || + decomp_table[comp].decomp_func == NULL) { + grub_printf("compression algorithm not supported\n"); + return (ERR_FSYS_CORRUPT); + } + + decode_embedded_bp_compressed(bp, dstbuf); + decomp_table[comp].decomp_func(dstbuf, buf, psize, lsize); + } else { + decode_embedded_bp_compressed(bp, buf); + } + + return (0); +} + /* * Read in a block of data, verify its checksum, decompress if needed, * and put the uncompressed data in buf. @@ -392,6 +460,15 @@ zio_read(blkptr_t *bp, void *buf, char *stack) int lsize, psize, comp; char *retbuf; + if (BP_IS_EMBEDDED(bp)) { + if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA) { + grub_printf("unsupported embedded BP (type=%u)\n", + (int)BPE_GET_ETYPE(bp)); + return (ERR_FSYS_CORRUPT); + } + return (decode_embedded_bp(bp, buf)); + } + comp = BP_GET_COMPRESS(bp); lsize = BP_GET_LSIZE(bp); psize = BP_GET_PSIZE(bp); @@ -404,7 +481,8 @@ zio_read(blkptr_t *bp, void *buf, char *stack) } if ((char *)buf < stack && ((char *)buf) + lsize > stack) { - grub_printf("not enough memory allocated\n"); + grub_printf("not enough memory to fit %u bytes on stack\n", + lsize); return (ERR_WONT_FIT); } @@ -764,6 +842,7 @@ zap_iterate(dnode_phys_t *zap_dnode, zap_cb_t *cb, void *arg, char *stack) * Input * mdn - metadnode to get the object dnode * objnum - object number for the object dnode + * type - if nonzero, object must be of this type * buf - data buffer that holds the returning dnode * stack - scratch area * @@ -968,6 +1047,7 @@ static const char *spa_feature_names[] = { "org.illumos:lz4_compress", "com.delphix:hole_birth", "com.delphix:extensible_dataset", + "com.delphix:embedded_data", NULL }; diff --git a/usr/src/grub/grub-0.97/stage2/zfs-include/spa.h b/usr/src/grub/grub-0.97/stage2/zfs-include/spa.h index 8d53ad6866..19fe52f13f 100644 --- a/usr/src/grub/grub-0.97/stage2/zfs-include/spa.h +++ b/usr/src/grub/grub-0.97/stage2/zfs-include/spa.h @@ -116,7 +116,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 | * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -150,7 +150,8 @@ typedef struct zio_cksum { * G gang block indicator * B byteorder (endianness) * D dedup - * X unused + * X encryption (on version 30, which is not supported) + * 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 @@ -204,8 +205,8 @@ typedef struct blkptr { #define BP_SET_PSIZE(bp, x) \ BF64_SET_SB((bp)->blk_prop, 16, SPA_PSIZEBITS, 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) @@ -216,6 +217,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_DEDUP(bp) BF64_GET((bp)->blk_prop, 62, 1) #define BP_SET_DEDUP(bp, x) BF64_SET((bp)->blk_prop, 62, 1, x) @@ -297,6 +300,22 @@ typedef struct blkptr { ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0); \ } +#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 (uint64_t)) +#define BPE_IS_PAYLOADWORD(bp, wp) \ + ((wp) != &(bp)->blk_prop && (wp) != &(bp)->blk_birth) + #ifdef _BIG_ENDIAN #define ZFS_HOST_BYTEORDER (0ULL) #else -- cgit v1.2.3