From cb0ff292728acdd5b65db0285400309c74b1bb56 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Tue, 8 Nov 2011 18:15:47 +0000 Subject: [PATCH 01/12] ZFS zlib support --- debian/patches/series | 1 + debian/patches/zfs_update.patch | 75 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 debian/patches/zfs_update.patch diff --git a/debian/patches/series b/debian/patches/series index f548787df..f4c76a3cb 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -28,3 +28,4 @@ kfreebsd_mfi_devices.patch probe_canonicalise.patch mkconfig_skip_readme.patch kfreebsd_lvm.patch +zfs_update.patch diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch new file mode 100644 index 000000000..ee51c60d5 --- /dev/null +++ b/debian/patches/zfs_update.patch @@ -0,0 +1,75 @@ + +Revisions: + +3340: ZFS zlib support + +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -51,6 +51,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -163,13 +164,30 @@ + grub_disk_addr_t vdev_phys_sector; + }; + ++static grub_err_t ++zlib_decompress (void *s, void *d, ++ grub_size_t slen, grub_size_t dlen) ++{ ++ if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0) ++ return grub_errno; ++ return GRUB_ERR_NONE; ++} ++ + static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = { + {"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */ + {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */ + {"off", NULL}, /* ZIO_COMPRESS_OFF */ + {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */ + {"empty", NULL}, /* ZIO_COMPRESS_EMPTY */ +- {"gzip", NULL}, /* ZIO_COMPRESS_GZIP */ ++ {"gzip-1", zlib_decompress}, /* ZIO_COMPRESS_GZIP1 */ ++ {"gzip-2", zlib_decompress}, /* ZIO_COMPRESS_GZIP2 */ ++ {"gzip-3", zlib_decompress}, /* ZIO_COMPRESS_GZIP3 */ ++ {"gzip-4", zlib_decompress}, /* ZIO_COMPRESS_GZIP4 */ ++ {"gzip-5", zlib_decompress}, /* ZIO_COMPRESS_GZIP5 */ ++ {"gzip-6", zlib_decompress}, /* ZIO_COMPRESS_GZIP6 */ ++ {"gzip-7", zlib_decompress}, /* ZIO_COMPRESS_GZIP7 */ ++ {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */ ++ {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */ + }; + + static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, +@@ -527,7 +545,7 @@ + *buf = NULL; + + checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; +- comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7; ++ comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff; + lsize = (BP_IS_HOLE(bp) ? 0 : + (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) + << SPA_MINBLOCKSHIFT)); +--- a/include/grub/zfs/zio.h ++++ b/include/grub/zfs/zio.h +@@ -77,7 +77,15 @@ + ZIO_COMPRESS_OFF, + ZIO_COMPRESS_LZJB, + ZIO_COMPRESS_EMPTY, +- ZIO_COMPRESS_GZIP, ++ ZIO_COMPRESS_GZIP1, ++ ZIO_COMPRESS_GZIP2, ++ ZIO_COMPRESS_GZIP3, ++ ZIO_COMPRESS_GZIP4, ++ ZIO_COMPRESS_GZIP5, ++ ZIO_COMPRESS_GZIP6, ++ ZIO_COMPRESS_GZIP7, ++ ZIO_COMPRESS_GZIP8, ++ ZIO_COMPRESS_GZIP9, + ZIO_COMPRESS_FUNCTIONS + }; + From 0cc5c3b9185514242778562a2d43cb409e87b1fb Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Tue, 8 Nov 2011 19:06:24 +0000 Subject: [PATCH 02/12] 3474: Fix 2G limit on ZFS --- debian/patches/zfs_update.patch | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index ee51c60d5..a15d58cd1 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -2,6 +2,7 @@ Revisions: 3340: ZFS zlib support +3474: Fix 2G limit on ZFS --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -45,6 +46,24 @@ Revisions: }; static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, +@@ -224,7 +242,7 @@ + */ + static grub_err_t + zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, +- grub_zfs_endian_t endian, char *buf, int size) ++ grub_zfs_endian_t endian, char *buf, grub_size_t size) + { + zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; + zio_checksum_info_t *ci = &zio_checksum_table[checksum]; +@@ -319,7 +337,7 @@ + * + */ + static grub_err_t +-uberblock_verify (uberblock_phys_t * ub, int offset) ++uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset) + { + uberblock_t *uber = &ub->ubp_uberblock; + grub_err_t err; @@ -527,7 +545,7 @@ *buf = NULL; @@ -54,6 +73,34 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); +@@ -602,7 +620,8 @@ + dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) + { +- int idx, level; ++ int level; ++ grub_off_t idx; + blkptr_t *bp_array = dn->dn.dn_blkptr; + int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; + blkptr_t *bp; +@@ -2248,7 +2267,7 @@ + grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) + { + struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; +- int blksz, movesize; ++ grub_size_t blksz, movesize; + grub_size_t length; + grub_size_t read; + grub_err_t err; +@@ -2302,7 +2321,7 @@ + data->file_start = blkid * blksz; + data->file_end = data->file_start + blksz; + +- movesize = MIN (length, data->file_end - (int) file->offset - read); ++ movesize = MIN (length, data->file_end - file->offset - read); + + grub_memmove (buf, data->file_buf + file->offset + read + - data->file_start, movesize); --- a/include/grub/zfs/zio.h +++ b/include/grub/zfs/zio.h @@ -77,7 +77,15 @@ From ad2e0d4f890d241bd3081d207fb573106d392383 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Tue, 8 Nov 2011 19:44:31 +0000 Subject: [PATCH 03/12] 3486: ZFS fixes --- debian/patches/zfs_update.patch | 114 +++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index a15d58cd1..b25f4e7f4 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -3,6 +3,7 @@ Revisions: 3340: ZFS zlib support 3474: Fix 2G limit on ZFS +3486: ZFS fixes --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -83,7 +84,116 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -2248,7 +2267,7 @@ +@@ -922,7 +941,7 @@ + { + zap_leaf_phys_t *l; + void *l_in; +- grub_uint64_t idx, blkid; ++ grub_uint64_t idx, idx2, blkid; + grub_uint16_t chunk; + int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); +@@ -945,10 +964,16 @@ + grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); + return 0; + } +- for (idx = 0; idx < zap->zap_ptrtbl.zt_numblks; idx++) ++ for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) + { + blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; + ++ for (idx2 = 0; idx2 < idx; idx2++) ++ if (blkid == ((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))]) ++ break; ++ if (idx2 != idx) ++ continue; ++ + err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); + l = l_in; + if (err) +@@ -1074,7 +1099,7 @@ + return 0; + block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); + +- grub_dprintf ("zfs", "zap read\n"); ++ grub_dprintf ("zfs", "zap iterate\n"); + + if (block_type == ZBT_MICRO) + { +@@ -1291,22 +1316,55 @@ + break; + + *path = ch; +-#if 0 +- if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa && ch) ++ if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { ++ char *sym_value; ++ grub_size_t avail_in_dnode; ++ grub_size_t sym_sz; ++ int free_symval = 0; + char *oldpath = path, *oldpathbuf = path_buf; +- path = path_buf +- = grub_malloc (sizeof (dnode_path->dn.dn.dn_bonus) +- - sizeof (znode_phys_t) + grub_strlen (oldpath) + 1); ++ sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys)); ++ avail_in_dnode = (char *) (&dnode_path->dn + 1) - sym_value; ++ ++ sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian); ++ ++ if (sym_sz > avail_in_dnode - 8) ++ { ++ grub_size_t block; ++ grub_size_t blksz; ++ blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, ++ dnode_path->dn.endian) ++ << SPA_MINBLOCKSHIFT); ++ ++ sym_value = grub_malloc (sym_sz); ++ if (!sym_value) ++ return grub_errno; ++ for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++) ++ { ++ void *t; ++ grub_size_t movesize; ++ ++ err = dmu_read (&(dnode_path->dn), block, &t, 0, data); ++ if (err) ++ return err; ++ ++ movesize = MIN (sym_sz - block * blksz, blksz); ++ ++ grub_memcpy (sym_value + block * blksz, t, movesize); ++ grub_free (t); ++ } ++ free_symval = 1; ++ } ++ path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + if (!path_buf) + { + grub_free (oldpathbuf); + return grub_errno; + } +- grub_memcpy (path, +- (char *) DN_BONUS(&dnode_path->dn.dn) + sizeof (znode_phys_t), +- sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t)); +- path [sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t)] = 0; ++ grub_memcpy (path, sym_value, sym_sz); ++ if (free_symval) ++ grub_free (sym_value); ++ path [sym_sz] = 0; + grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); + +@@ -1324,7 +1382,6 @@ + grub_free (dn_new); + } + } +-#endif + } + + if (!err) +@@ -2248,7 +2305,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -92,7 +202,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2321,7 @@ +@@ -2302,7 +2359,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; From 43a7a2d513c25c0e2df138345f6ed45091c1e0d5 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Tue, 8 Nov 2011 20:43:04 +0000 Subject: [PATCH 04/12] 3488: ZFS multi-device and version 33 support --- debian/patches/zfs_update.patch | 1579 ++++++++++++++++++++++++++++++- 1 file changed, 1557 insertions(+), 22 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index b25f4e7f4..f4bd66d59 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -4,6 +4,7 @@ Revisions: 3340: ZFS zlib support 3474: Fix 2G limit on ZFS 3486: ZFS fixes +3488: ZFS multi-device and version 33 support --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -15,8 +16,54 @@ Revisions: GRUB_MOD_LICENSE ("GPLv3+"); -@@ -163,13 +164,30 @@ - grub_disk_addr_t vdev_phys_sector; +@@ -139,6 +140,26 @@ + grub_zfs_endian_t endian; + } dnode_end_t; + ++struct grub_zfs_device_desc ++{ ++ enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type; ++ grub_uint64_t id; ++ grub_uint64_t guid; ++ ++ /* Valid only for non-leafs. */ ++ unsigned n_children; ++ struct grub_zfs_device_desc *children; ++ ++ /* Valid only for RAIDZ. */ ++ unsigned nparity; ++ ++ /* Valid only for leaf devices. */ ++ grub_device_t dev; ++ grub_disk_addr_t vdev_phys_sector; ++ uberblock_t current_uberblock; ++ int original; ++}; ++ + struct grub_zfs_data + { + /* cache for a file block of the currently zfs_open()-ed file */ +@@ -153,23 +174,45 @@ + grub_uint64_t dnode_end; + grub_zfs_endian_t dnode_endian; + +- uberblock_t current_uberblock; +- grub_disk_t disk; +- + dnode_end_t mos; + dnode_end_t mdn; + dnode_end_t dnode; + +- grub_disk_addr_t vdev_phys_sector; ++ struct grub_zfs_device_desc *devices_attached; ++ unsigned n_devices_attached; ++ unsigned n_devices_allocated; ++ struct grub_zfs_device_desc *device_original; ++ ++ uberblock_t current_uberblock; ++ ++ int mounted; ++ grub_uint64_t guid; }; +static grub_err_t @@ -47,7 +94,7 @@ Revisions: }; static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, -@@ -224,7 +242,7 @@ +@@ -224,7 +267,7 @@ */ static grub_err_t zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, @@ -56,7 +103,24 @@ Revisions: { zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; zio_checksum_info_t *ci = &zio_checksum_table[checksum]; -@@ -319,7 +337,7 @@ +@@ -253,13 +296,13 @@ + || (actual_cksum.zc_word[2] != zc.zc_word[2]) + || (actual_cksum.zc_word[3] != zc.zc_word[3])) + { +- grub_dprintf ("zfs", "checksum %d verification failed\n", checksum); +- grub_dprintf ("zfs", "actual checksum %16llx %16llx %16llx %16llx\n", ++ grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name); ++ grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n", + (unsigned long long) actual_cksum.zc_word[0], + (unsigned long long) actual_cksum.zc_word[1], + (unsigned long long) actual_cksum.zc_word[2], + (unsigned long long) actual_cksum.zc_word[3]); +- grub_dprintf ("zfs", "expected checksum %16llx %16llx %16llx %16llx\n", ++ grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n", + (unsigned long long) zc.zc_word[0], + (unsigned long long) zc.zc_word[1], + (unsigned long long) zc.zc_word[2], +@@ -319,7 +362,7 @@ * */ static grub_err_t @@ -65,7 +129,572 @@ Revisions: { uberblock_t *uber = &ub->ubp_uberblock; grub_err_t err; -@@ -527,7 +545,7 @@ +@@ -392,7 +435,7 @@ + } + + static grub_uint64_t +-dva_get_offset (dva_t * dva, grub_zfs_endian_t endian) ++dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian) + { + grub_dprintf ("zfs", "dva=%llx, %llx\n", + (unsigned long long) dva->dva_word[0], +@@ -401,6 +444,510 @@ + endian) << SPA_MINBLOCKSHIFT; + } + ++static grub_err_t ++zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist) ++{ ++ grub_err_t err; ++ ++ *nvlist = grub_malloc (VDEV_PHYS_SIZE); ++ if (!diskdesc->dev) ++ return grub_error (GRUB_ERR_BAD_FS, "member drive unknown"); ++ ++ /* Read in the vdev name-value pair list (112K). */ ++ err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0, ++ VDEV_PHYS_SIZE, *nvlist); ++ if (err) ++ { ++ grub_free (*nvlist); ++ *nvlist = 0; ++ return err; ++ } ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++fill_vdev_info_real (struct grub_zfs_data *data, ++ const char *nvlist, ++ struct grub_zfs_device_desc *fill, ++ struct grub_zfs_device_desc *insert) ++{ ++ char *type; ++ ++ type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE); ++ ++ if (!type) ++ return grub_errno; ++ ++ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id))) ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); ++ ++ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid))) ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); ++ ++ if (grub_strcmp (type, VDEV_TYPE_DISK) == 0 ++ || grub_strcmp (type, VDEV_TYPE_FILE) == 0) ++ { ++ fill->type = DEVICE_LEAF; ++ ++ if (!fill->dev && fill->guid == insert->guid) ++ { ++ fill->dev = insert->dev; ++ fill->vdev_phys_sector = insert->vdev_phys_sector; ++ fill->current_uberblock = insert->current_uberblock; ++ fill->original = insert->original; ++ if (!data->device_original) ++ data->device_original = fill; ++ } ++ ++ return GRUB_ERR_NONE; ++ } ++ ++ if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0 ++ || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0) ++ { ++ int nelm, i; ++ ++ if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) ++ fill->type = DEVICE_MIRROR; ++ else ++ { ++ grub_uint64_t par; ++ fill->type = DEVICE_RAIDZ; ++ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par)) ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity"); ++ fill->nparity = par; ++ } ++ ++ nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, ZPOOL_CONFIG_CHILDREN); ++ ++ if (nelm <= 0) ++ return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV"); ++ ++ if (!fill->children) ++ { ++ fill->n_children = nelm; ++ ++ fill->children = grub_zalloc (fill->n_children ++ * sizeof (fill->children[0])); ++ } ++ ++ for (i = 0; i < nelm; i++) ++ { ++ char *child; ++ grub_err_t err; ++ ++ child = grub_zfs_nvlist_lookup_nvlist_array ++ (nvlist, ZPOOL_CONFIG_CHILDREN, i); ++ ++ err = fill_vdev_info_real (data, child, &fill->children[i], insert); ++ ++ grub_free (child); ++ ++ if (err) ++ return err; ++ } ++ return GRUB_ERR_NONE; ++ } ++ ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported", ++ type); ++} ++ ++static grub_err_t ++fill_vdev_info (struct grub_zfs_data *data, ++ char *nvlist, struct grub_zfs_device_desc *diskdesc) ++{ ++ grub_uint64_t id; ++ unsigned i; ++ ++ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id)) ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); ++ ++ for (i = 0; i < data->n_devices_attached; i++) ++ if (data->devices_attached[i].id == id) ++ return fill_vdev_info_real (data, nvlist, &data->devices_attached[i], ++ diskdesc); ++ ++ data->n_devices_attached++; ++ if (data->n_devices_attached > data->n_devices_allocated) ++ { ++ void *tmp; ++ data->n_devices_allocated = 2 * data->n_devices_attached + 1; ++ data->devices_attached ++ = grub_realloc (tmp = data->devices_attached, ++ data->n_devices_allocated ++ * sizeof (data->devices_attached[0])); ++ if (!data->devices_attached) ++ { ++ data->devices_attached = tmp; ++ return grub_errno; ++ } ++ } ++ ++ grub_memset (&data->devices_attached[data->n_devices_attached - 1], ++ 0, sizeof (data->devices_attached[data->n_devices_attached - 1])); ++ ++ return fill_vdev_info_real (data, nvlist, ++ &data->devices_attached[data->n_devices_attached - 1], ++ diskdesc); ++} ++ ++/* ++ * Check the disk label information and retrieve needed vdev name-value pairs. ++ * ++ */ ++static grub_err_t ++check_pool_label (struct grub_zfs_data *data, ++ struct grub_zfs_device_desc *diskdesc) ++{ ++ grub_uint64_t pool_state, txg = 0; ++ char *nvlist; ++#if 0 ++ char *nv; ++#endif ++ grub_uint64_t poolguid; ++ grub_uint64_t version; ++ int found; ++ grub_err_t err; ++ ++ err = zfs_fetch_nvlist (diskdesc, &nvlist); ++ if (err) ++ return err; ++ ++ grub_dprintf ("zfs", "check 2 passed\n"); ++ ++ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE, ++ &pool_state); ++ if (! found) ++ { ++ grub_free (nvlist); ++ if (! grub_errno) ++ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found"); ++ return grub_errno; ++ } ++ grub_dprintf ("zfs", "check 3 passed\n"); ++ ++ if (pool_state == POOL_STATE_DESTROYED) ++ { ++ grub_free (nvlist); ++ return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed"); ++ } ++ grub_dprintf ("zfs", "check 4 passed\n"); ++ ++ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg); ++ if (!found) ++ { ++ grub_free (nvlist); ++ if (! grub_errno) ++ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found"); ++ return grub_errno; ++ } ++ grub_dprintf ("zfs", "check 6 passed\n"); ++ ++ /* not an active device */ ++ if (txg == 0) ++ { ++ grub_free (nvlist); ++ return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active"); ++ } ++ grub_dprintf ("zfs", "check 7 passed\n"); ++ ++ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION, ++ &version); ++ if (! found) ++ { ++ grub_free (nvlist); ++ if (! grub_errno) ++ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found"); ++ return grub_errno; ++ } ++ grub_dprintf ("zfs", "check 8 passed\n"); ++ ++ if (version > SPA_VERSION) ++ { ++ grub_free (nvlist); ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "too new version %llu > %llu", ++ (unsigned long long) version, ++ (unsigned long long) SPA_VERSION); ++ } ++ grub_dprintf ("zfs", "check 9 passed\n"); ++ ++ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, ++ &(diskdesc->guid)); ++ if (! found) ++ { ++ grub_free (nvlist); ++ if (! grub_errno) ++ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found"); ++ return grub_errno; ++ } ++ ++ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, ++ &poolguid); ++ if (! found) ++ { ++ grub_free (nvlist); ++ if (! grub_errno) ++ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found"); ++ return grub_errno; ++ } ++ ++ grub_dprintf ("zfs", "check 11 passed\n"); ++ ++ if (data->mounted && data->guid != poolguid) ++ return grub_error (GRUB_ERR_BAD_FS, "another zpool"); ++ else ++ data->guid = poolguid; ++ ++ { ++ char *nv; ++ nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); ++ ++ if (!nv) ++ { ++ grub_free (nvlist); ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree"); ++ } ++ err = fill_vdev_info (data, nv, diskdesc); ++ if (err) ++ { ++ grub_free (nvlist); ++ return err; ++ } ++ } ++ grub_dprintf ("zfs", "check 10 passed\n"); ++ ++ grub_free (nvlist); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++scan_disk (grub_device_t dev, struct grub_zfs_data *data, ++ int original) ++{ ++ int label = 0; ++ uberblock_phys_t *ub_array, *ubbest = NULL; ++ vdev_boot_header_t *bh; ++ grub_err_t err; ++ int vdevnum; ++ struct grub_zfs_device_desc desc; ++ ++ ub_array = grub_malloc (VDEV_UBERBLOCK_RING); ++ if (!ub_array) ++ return grub_errno; ++ ++ bh = grub_malloc (VDEV_BOOT_HEADER_SIZE); ++ if (!bh) ++ { ++ grub_free (ub_array); ++ return grub_errno; ++ } ++ ++ vdevnum = VDEV_LABELS; ++ ++ desc.dev = dev; ++ desc.original = original; ++ ++ /* Don't check back labels on CDROM. */ ++ if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) ++ vdevnum = VDEV_LABELS / 2; ++ ++ for (label = 0; ubbest == NULL && label < vdevnum; label++) ++ { ++ desc.vdev_phys_sector ++ = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) ++ + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) ++ + (label < VDEV_LABELS / 2 ? 0 : grub_disk_get_size (dev->disk) ++ - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); ++ ++ /* Read in the uberblock ring (128K). */ ++ err = grub_disk_read (dev->disk, desc.vdev_phys_sector ++ + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT), ++ 0, VDEV_UBERBLOCK_RING, (char *) ub_array); ++ if (err) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ continue; ++ } ++ grub_dprintf ("zfs", "label ok %d\n", label); ++ ++ ubbest = find_bestub (ub_array, desc.vdev_phys_sector); ++ if (!ubbest) ++ { ++ grub_dprintf ("zfs", "No uberblock found\n"); ++ grub_errno = GRUB_ERR_NONE; ++ continue; ++ } ++ ++ grub_memmove (&(desc.current_uberblock), ++ &ubbest->ubp_uberblock, sizeof (uberblock_t)); ++ if (original) ++ grub_memmove (&(data->current_uberblock), ++ &ubbest->ubp_uberblock, sizeof (uberblock_t)); ++ ++ err = check_pool_label (data, &desc); ++ if (err) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ continue; ++ } ++#if 0 ++ if (find_best_root && ++ vdev_uberblock_compare (&ubbest->ubp_uberblock, ++ &(current_uberblock)) <= 0) ++ continue; ++#endif ++ grub_free (ub_array); ++ grub_free (bh); ++ return GRUB_ERR_NONE; ++ } ++ ++ grub_free (ub_array); ++ grub_free (bh); ++ ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label"); ++} ++ ++static grub_err_t ++scan_devices (struct grub_zfs_data *data) ++{ ++ auto int hook (const char *name); ++ int hook (const char *name) ++ { ++ grub_device_t dev; ++ grub_err_t err; ++ dev = grub_device_open (name); ++ if (!dev) ++ return 0; ++ if (!dev->disk) ++ { ++ grub_device_close (dev); ++ return 0; ++ } ++ err = scan_disk (dev, data, 0); ++ if (err == GRUB_ERR_BAD_FS) ++ { ++ grub_device_close (dev); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (err) ++ { ++ grub_device_close (dev); ++ grub_print_error (); ++ return 0; ++ } ++ ++ return 0; ++ } ++ grub_device_iterate (hook); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, ++ grub_uint32_t asize, grub_size_t len, void *buf) ++{ ++ switch (desc->type) ++ { ++ case DEVICE_LEAF: ++ { ++ grub_uint64_t sector; ++ sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); ++ if (!desc->dev) ++ { ++ return grub_error (GRUB_ERR_BAD_FS, "member drive unknown"); ++ } ++ /* read in a data block */ ++ return grub_disk_read (desc->dev->disk, sector, 0, len, buf); ++ } ++ case DEVICE_MIRROR: ++ { ++ grub_err_t err = 0; ++ unsigned i; ++ if (desc->n_children <= 0) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "non-positive number of mirror children"); ++ for (i = 0; i < desc->n_children; i++) ++ { ++ err = read_device (offset, &desc->children[i], asize, ++ len, buf); ++ if (!err) ++ break; ++ grub_errno = GRUB_ERR_NONE; ++ } ++ return (grub_errno = err); ++ } ++ case DEVICE_RAIDZ: ++ { ++ grub_uint64_t sector; ++ grub_uint32_t bsize; ++ unsigned c = 0; ++ ++ bsize = (asize + desc->nparity) / desc->n_children; ++ sector = offset >> 9; ++ while (len > 0) ++ { ++ grub_size_t csize; ++ grub_uint64_t high; ++ grub_uint64_t devn; ++ grub_err_t err; ++ high = grub_divmod64_full (sector + (asize > 2) + c, desc->n_children, ++ &devn); ++ csize = bsize << 9; ++ if (csize > len) ++ csize = len; ++ grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T ++ "+%d+%u -> (0x%" PRIxGRUB_UINT64_T ", 0x%" ++ PRIxGRUB_UINT64_T ")\n", ++ sector,(asize > 2), c, high, devn); ++ err = read_device (high << 9, &desc->children[devn], ++ bsize, csize, buf); ++ if (err) ++ return err; ++ c++; ++ buf = (char *) buf + csize; ++ len -= csize; ++ } ++ return GRUB_ERR_NONE; ++ } ++ return GRUB_ERR_NONE; ++ } ++ return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); ++} ++ ++static grub_err_t ++read_dva (const dva_t *dva, ++ grub_zfs_endian_t endian, struct grub_zfs_data *data, ++ void *buf, grub_size_t len) ++{ ++ grub_uint64_t offset; ++ unsigned i; ++ grub_err_t err; ++ int try = 0; ++ offset = dva_get_offset (dva, endian); ++ ++ for (try = 0; try < 2; try++) ++ { ++ for (i = 0; i < data->n_devices_attached; i++) ++ if (data->devices_attached[i].id == DVA_GET_VDEV (dva)) ++ { ++ err = read_device (offset, &data->devices_attached[i], ++ dva->dva_word[0] & 0xffffff, len, buf); ++ if (!err) ++ return GRUB_ERR_NONE; ++ break; ++ } ++ if (try == 1) ++ break; ++ err = scan_devices (data); ++ if (err) ++ return err; ++ } ++ return err; ++} + + /* + * Read a block of data based on the gang block address dva, +@@ -412,7 +959,6 @@ + struct grub_zfs_data *data) + { + zio_gbh_phys_t *zio_gb; +- grub_uint64_t offset, sector; + unsigned i; + grub_err_t err; + zio_cksum_t zc; +@@ -424,13 +970,8 @@ + return grub_errno; + grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" + :"big-endian gang\n"); +- offset = dva_get_offset (dva, endian); +- sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); +- grub_dprintf ("zfs", "offset=%llx\n", (unsigned long long) offset); + +- /* read in the gang block header */ +- err = grub_disk_read (data->disk, sector, 0, SPA_GANGBLOCKSIZE, +- (char *) zio_gb); ++ err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); + if (err) + { + grub_free (zio_gb); +@@ -483,20 +1024,13 @@ + /* pick a good dva from the block pointer */ + for (i = 0; i < SPA_DVAS_PER_BP; i++) + { +- grub_uint64_t offset, sector; +- + if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0) + continue; + + if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1) + err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data); + else +- { +- /* read in a data block */ +- offset = dva_get_offset (&bp->blk_dva[i], endian); +- sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); +- err = grub_disk_read (data->disk, sector, 0, psize, buf); +- } ++ err = read_dva (&bp->blk_dva[i], endian, data, buf, psize); + if (!err) + return GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; +@@ -527,7 +1061,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -74,7 +703,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +620,8 @@ +@@ -602,7 +1136,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -84,7 +713,56 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -922,7 +941,7 @@ +@@ -816,7 +1351,7 @@ + return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); + + for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); +- chunk != CHAIN_END; chunk = le->le_next) ++ chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian)) + { + + if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) +@@ -840,7 +1375,8 @@ + { + struct zap_leaf_array *la; + +- if (le->le_int_size != 8 || le->le_value_length != 1) ++ if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length, ++ endian) != 1) + return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); + + /* get the uint64_t property value */ +@@ -858,9 +1394,9 @@ + + /* Verify if this is a fat zap header block */ + static grub_err_t +-zap_verify (zap_phys_t *zap) ++zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian) + { +- if (zap->zap_magic != (grub_uint64_t) ZAP_MAGIC) ++ if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC) + return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); + + if (zap->zap_flags != 0) +@@ -888,7 +1424,7 @@ + grub_err_t err; + grub_zfs_endian_t leafendian; + +- err = zap_verify (zap); ++ err = zap_verify (zap, zap_dnode->endian); + if (err) + return err; + +@@ -899,7 +1435,7 @@ + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); +- blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; ++ blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian); + + /* Get the leaf block */ + if ((1U << blksft) < sizeof (zap_leaf_phys_t)) +@@ -922,14 +1458,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -93,25 +771,60 @@ Revisions: grub_uint16_t chunk; int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << DNODE_SHIFT); -@@ -945,10 +964,16 @@ + grub_err_t err; + grub_zfs_endian_t endian; + +- if (zap_verify (zap)) ++ if (zap_verify (zap, zap_dnode->endian)) + return 0; + + /* get block id from index */ +@@ -945,9 +1481,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } - for (idx = 0; idx < zap->zap_ptrtbl.zt_numblks; idx++) + for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) { - blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; - +- blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; ++ blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], ++ zap_dnode->endian); ++ + for (idx2 = 0; idx2 < idx; idx2++) -+ if (blkid == ((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))]) ++ if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))], ++ zap_dnode->endian)) + break; + if (idx2 != idx) + continue; -+ + err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; - if (err) -@@ -1074,7 +1099,7 @@ +@@ -983,8 +1527,11 @@ + + buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + + 1); +- if (zap_leaf_array_get (l, endian, blksft, le->le_name_chunk, +- le->le_name_length, buf)) ++ if (zap_leaf_array_get (l, endian, blksft, ++ grub_zfs_to_cpu16 (le->le_name_chunk, ++ endian), ++ grub_zfs_to_cpu16 (le->le_name_length, ++ endian), buf)) + { + grub_free (buf); + continue; +@@ -996,7 +1543,9 @@ + continue; + + /* get the uint64_t property value */ +- la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk).l_array; ++ la = &ZAP_LEAF_CHUNK (l, blksft, ++ grub_zfs_to_cpu16 (le->le_value_chunk, ++ endian)).l_array; + val = grub_be_to_cpu64 (la->la_array64); + if (hook (buf, val)) + return 1; +@@ -1074,7 +1623,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -120,16 +833,16 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1316,55 @@ +@@ -1291,22 +1840,54 @@ break; *path = ch; -#if 0 - if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa && ch) -+ if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) ++ if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE ++ && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) { + char *sym_value; -+ grub_size_t avail_in_dnode; + grub_size_t sym_sz; + int free_symval = 0; char *oldpath = path, *oldpathbuf = path_buf; @@ -137,11 +850,10 @@ Revisions: - = grub_malloc (sizeof (dnode_path->dn.dn.dn_bonus) - - sizeof (znode_phys_t) + grub_strlen (oldpath) + 1); + sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys)); -+ avail_in_dnode = (char *) (&dnode_path->dn + 1) - sym_value; + + sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian); + -+ if (sym_sz > avail_in_dnode - 8) ++ if (dnode_path->dn.dn.dn_flags & 1) + { + grub_size_t block; + grub_size_t blksz; @@ -185,15 +897,668 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1382,6 @@ +@@ -1324,7 +1905,62 @@ grub_free (dn_new); } } -#endif ++ if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA) ++ { ++ void *sahdrp; ++ int hdrsize; ++ ++ if (dnode_path->dn.dn.dn_bonuslen != 0) ++ { ++ sahdrp = DN_BONUS (&dnode_path->dn.dn); ++ } ++ else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) ++ { ++ blkptr_t *bp = &dnode_path->dn.dn.dn_spill; ++ ++ err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); ++ if (err) ++ return err; ++ } ++ else ++ { ++ return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); ++ } ++ ++ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); ++ ++ if (((grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_TYPE_OFFSET), dnode_path->dn.endian) >> 12) & 0xf) == 0xa) ++ { ++ char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET; ++ grub_size_t sym_sz = ++ grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), dnode_path->dn.endian); ++ char *oldpath = path, *oldpathbuf = path_buf; ++ path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); ++ if (!path_buf) ++ { ++ grub_free (oldpathbuf); ++ return grub_errno; ++ } ++ grub_memcpy (path, sym_value, sym_sz); ++ path [sym_sz] = 0; ++ grub_memcpy (path + grub_strlen (path), oldpath, ++ grub_strlen (oldpath) + 1); ++ ++ grub_free (oldpathbuf); ++ if (path[0] != '/') ++ { ++ dn_new = dnode_path; ++ dnode_path = dn_new->next; ++ grub_free (dn_new); ++ } ++ else while (dnode_path != root) ++ { ++ dn_new = dnode_path; ++ dnode_path = dn_new->next; ++ grub_free (dn_new); ++ } ++ } ++ } } if (!err) -@@ -2248,7 +2305,7 @@ +@@ -1625,11 +2261,12 @@ + */ + + static int +-nvlist_find_value (char *nvlist, char *name, int valtype, char **val, ++nvlist_find_value (const char *nvlist, const char *name, ++ int valtype, char **val, + grub_size_t *size_out, grub_size_t *nelm_out) + { + int name_len, type, encode_size; +- char *nvpair, *nvp_name; ++ const char *nvpair, *nvp_name; + + /* Verify if the 1st and 2nd byte in the nvlist are valid. */ + /* NOTE: independently of what endianness header announces all +@@ -1671,7 +2308,7 @@ + + if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) + { +- *val = nvpair; ++ *val = (char *) nvpair; + *size_out = encode_size; + if (nelm_out) + *nelm_out = nelm; +@@ -1684,7 +2321,8 @@ + } + + int +-grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, grub_uint64_t * out) ++grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name, ++ grub_uint64_t * out) + { + char *nvpair; + grub_size_t size; +@@ -1704,7 +2342,7 @@ + } + + char * +-grub_zfs_nvlist_lookup_string (char *nvlist, char *name) ++grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name) + { + char *nvpair; + char *ret; +@@ -1732,7 +2370,7 @@ + } + + char * +-grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name) ++grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name) + { + char *nvpair; + char *ret; +@@ -1753,199 +2391,113 @@ + } + + int +-grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name) +-{ +- char *nvpair; +- grub_size_t nelm, size; +- int found; +- +- found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, +- &size, &nelm); +- if (! found) +- return -1; +- return nelm; +-} +- +-char * +-grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name, +- grub_size_t index) +-{ +- char *nvpair, *nvpairptr; +- int found; +- char *ret; +- grub_size_t size; +- unsigned i; +- grub_size_t nelm; +- +- found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, +- &size, &nelm); +- if (!found) +- return 0; +- if (index >= nelm) +- { +- grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array"); +- return 0; +- } +- +- nvpairptr = nvpair; +- +- for (i = 0; i < index; i++) +- { +- grub_uint32_t encode_size; +- +- /* skip the header, nvl_version, and nvl_nvflag */ +- nvpairptr = nvpairptr + 4 * 2; +- +- while (nvpairptr < nvpair + size +- && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) nvpairptr))) +- nvlist += encode_size; /* goto the next nvpair */ +- +- nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */ +- } +- +- if (nvpairptr >= nvpair + size +- || nvpairptr + grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2)) +- >= nvpair + size) +- { +- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); +- return 0; +- } +- +- ret = grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2)) +- + 3 * sizeof (grub_uint32_t)); +- if (!ret) +- return 0; +- grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); +- +- grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, size); +- return ret; +-} +- +-static grub_err_t +-zfs_fetch_nvlist (struct grub_zfs_data * data, char **nvlist) +-{ +- grub_err_t err; +- +- *nvlist = grub_malloc (VDEV_PHYS_SIZE); +- /* Read in the vdev name-value pair list (112K). */ +- err = grub_disk_read (data->disk, data->vdev_phys_sector, 0, +- VDEV_PHYS_SIZE, *nvlist); +- if (err) +- { +- grub_free (*nvlist); +- *nvlist = 0; +- return err; +- } +- return GRUB_ERR_NONE; +-} +- +-/* +- * Check the disk label information and retrieve needed vdev name-value pairs. +- * +- */ +-static grub_err_t +-check_pool_label (struct grub_zfs_data *data) ++grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist, ++ const char *name) + { +- grub_uint64_t pool_state, txg = 0; +- char *nvlist; +-#if 0 +- char *nv; +-#endif +- grub_uint64_t diskguid; +- grub_uint64_t version; ++ char *nvpair; ++ grub_size_t nelm, size; + int found; +- grub_err_t err; + +- err = zfs_fetch_nvlist (data, &nvlist); +- if (err) +- return err; ++ found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, ++ &size, &nelm); ++ if (! found) ++ return -1; ++ return nelm; ++} + +- grub_dprintf ("zfs", "check 2 passed\n"); ++static int ++get_nvlist_size (const char *beg, const char *limit) ++{ ++ const char *ptr; ++ grub_uint32_t encode_size; ++ ++ ptr = beg + 8; + +- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE, +- &pool_state); +- if (! found) +- { +- grub_free (nvlist); +- if (! grub_errno) +- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found"); +- return grub_errno; +- } +- grub_dprintf ("zfs", "check 3 passed\n"); ++ while (ptr < limit ++ && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) ptr))) ++ ptr += encode_size; /* goto the next nvpair */ ++ ptr += 8; ++ return (ptr > limit) ? -1 : (ptr - beg); ++} + +- if (pool_state == POOL_STATE_DESTROYED) +- { +- grub_free (nvlist); +- return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed"); +- } +- grub_dprintf ("zfs", "check 4 passed\n"); ++char * ++grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, ++ grub_size_t index) ++{ ++ char *nvpair, *nvpairptr; ++ int found; ++ char *ret; ++ grub_size_t size; ++ unsigned i; ++ grub_size_t nelm; ++ int elemsize = 0; + +- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg); ++ found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, ++ &size, &nelm); + if (!found) ++ return 0; ++ if (index >= nelm) + { +- grub_free (nvlist); +- if (! grub_errno) +- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found"); +- return grub_errno; ++ grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array"); ++ return 0; + } +- grub_dprintf ("zfs", "check 6 passed\n"); + +- /* not an active device */ +- if (txg == 0) +- { +- grub_free (nvlist); +- return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active"); +- } +- grub_dprintf ("zfs", "check 7 passed\n"); ++ nvpairptr = nvpair; + +- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION, +- &version); +- if (! found) ++ for (i = 0; i < index; i++) + { +- grub_free (nvlist); +- if (! grub_errno) +- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found"); +- return grub_errno; +- } +- grub_dprintf ("zfs", "check 8 passed\n"); ++ int r; ++ r = get_nvlist_size (nvpairptr, nvpair + size); + +- if (version > SPA_VERSION) +- { +- grub_free (nvlist); +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "too new version %llu > %llu", +- (unsigned long long) version, +- (unsigned long long) SPA_VERSION); +- } +- grub_dprintf ("zfs", "check 9 passed\n"); +-#if 0 +- if (nvlist_lookup_value (nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv, +- DATA_TYPE_NVLIST, NULL)) +- { +- grub_free (vdev); +- return (GRUB_ERR_BAD_FS); ++ if (r < 0) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); ++ return NULL; ++ } ++ nvpairptr += r; + } +- grub_dprintf ("zfs", "check 10 passed\n"); +-#endif + +- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, &diskguid); +- if (! found) ++ elemsize = get_nvlist_size (nvpairptr, nvpair + size); ++ ++ if (elemsize < 0) + { +- grub_free (nvlist); +- if (! grub_errno) +- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found"); +- return grub_errno; ++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); ++ return 0; + } +- grub_dprintf ("zfs", "check 11 passed\n"); + +- grub_free (nvlist); ++ ret = grub_zalloc (elemsize + sizeof (grub_uint32_t)); ++ if (!ret) ++ return 0; ++ grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); + +- return GRUB_ERR_NONE; ++ grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize); ++ return ret; ++} ++ ++static void ++unmount_device (struct grub_zfs_device_desc *desc) ++{ ++ unsigned i; ++ switch (desc->type) ++ { ++ case DEVICE_LEAF: ++ if (!desc->original && desc->dev) ++ grub_device_close (desc->dev); ++ return; ++ case DEVICE_RAIDZ: ++ case DEVICE_MIRROR: ++ for (i = 0; i < desc->n_children; i++) ++ unmount_device (&desc->children[i]); ++ return; ++ } + } + + static void + zfs_unmount (struct grub_zfs_data *data) + { ++ unsigned i; ++ for (i = 0; i < data->n_devices_attached; i++) ++ unmount_device (&data->devices_attached[i]); + grub_free (data->dnode_buf); + grub_free (data->dnode_mdn); + grub_free (data->file_buf); +@@ -1961,13 +2513,11 @@ + zfs_mount (grub_device_t dev) + { + struct grub_zfs_data *data = 0; +- int label = 0; +- uberblock_phys_t *ub_array, *ubbest = NULL; +- vdev_boot_header_t *bh; +- void *osp = 0; +- grub_size_t ospsize; + grub_err_t err; +- int vdevnum; ++ objset_phys_t *osp = 0; ++ grub_size_t ospsize; ++ grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; ++ uberblock_t *ub; + + if (! dev->disk) + { +@@ -1975,119 +2525,56 @@ + return 0; + } + +- data = grub_malloc (sizeof (*data)); ++ data = grub_zalloc (sizeof (*data)); + if (!data) + return 0; +- grub_memset (data, 0, sizeof (*data)); + #if 0 + /* if it's our first time here, zero the best uberblock out */ + if (data->best_drive == 0 && data->best_part == 0 && find_best_root) + grub_memset (¤t_uberblock, 0, sizeof (uberblock_t)); + #endif + +- data->disk = dev->disk; +- +- ub_array = grub_malloc (VDEV_UBERBLOCK_RING); +- if (!ub_array) ++ data->n_devices_allocated = 16; ++ data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) ++ * data->n_devices_allocated); ++ data->n_devices_attached = 0; ++ err = scan_disk (dev, data, 1); ++ if (err) + { + zfs_unmount (data); +- return 0; ++ return NULL; + } + +- bh = grub_malloc (VDEV_BOOT_HEADER_SIZE); +- if (!bh) ++ ub = &(data->current_uberblock); ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ? LITTLE_ENDIAN : BIG_ENDIAN); ++ ++ err = zio_read (&ub->ub_rootbp, ub_endian, ++ (void **) &osp, &ospsize, data); ++ if (err) + { + zfs_unmount (data); +- grub_free (ub_array); +- return 0; ++ return NULL; + } + +- vdevnum = VDEV_LABELS; +- +- /* Don't check back labels on CDROM. */ +- if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) +- vdevnum = VDEV_LABELS / 2; +- +- for (label = 0; ubbest == NULL && label < vdevnum; label++) ++ if (ospsize < OBJSET_PHYS_SIZE_V14) + { +- grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; +- grub_dprintf ("zfs", "label %d\n", label); +- +- data->vdev_phys_sector +- = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) +- + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) +- + (label < VDEV_LABELS / 2 ? 0 : grub_disk_get_size (dev->disk) +- - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); +- +- /* Read in the uberblock ring (128K). */ +- err = grub_disk_read (data->disk, data->vdev_phys_sector +- + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT), +- 0, VDEV_UBERBLOCK_RING, (char *) ub_array); +- if (err) +- { +- grub_errno = GRUB_ERR_NONE; +- continue; +- } +- grub_dprintf ("zfs", "label ok %d\n", label); +- +- ubbest = find_bestub (ub_array, data->vdev_phys_sector); +- if (!ubbest) +- { +- grub_dprintf ("zfs", "No uberblock found\n"); +- grub_errno = GRUB_ERR_NONE; +- continue; +- } +- ub_endian = (grub_zfs_to_cpu64 (ubbest->ubp_uberblock.ub_magic, +- LITTLE_ENDIAN) == UBERBLOCK_MAGIC +- ? LITTLE_ENDIAN : BIG_ENDIAN); +- err = zio_read (&ubbest->ubp_uberblock.ub_rootbp, +- ub_endian, +- &osp, &ospsize, data); +- if (err) +- { +- grub_dprintf ("zfs", "couldn't zio_read\n"); +- grub_errno = GRUB_ERR_NONE; +- continue; +- } +- +- if (ospsize < OBJSET_PHYS_SIZE_V14) +- { +- grub_dprintf ("zfs", "osp too small\n"); +- grub_free (osp); +- continue; +- } +- grub_dprintf ("zfs", "ubbest %p\n", ubbest); +- +- err = check_pool_label (data); +- if (err) +- { +- grub_errno = GRUB_ERR_NONE; +- continue; +- } +-#if 0 +- if (find_best_root && +- vdev_uberblock_compare (&ubbest->ubp_uberblock, +- &(current_uberblock)) <= 0) +- continue; +-#endif +- /* Got the MOS. Save it at the memory addr MOS. */ +- grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode, +- DNODE_SIZE); +- data->mos.endian = (grub_zfs_to_cpu64 (ubbest->ubp_uberblock.ub_rootbp.blk_prop, ub_endian) >> 63) & 1; +- grub_memmove (&(data->current_uberblock), +- &ubbest->ubp_uberblock, sizeof (uberblock_t)); +- grub_free (ub_array); +- grub_free (bh); ++ grub_error (GRUB_ERR_BAD_FS, "OSP too small"); + grub_free (osp); +- return data; ++ zfs_unmount (data); ++ return NULL; + } +- grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label"); +- zfs_unmount (data); +- grub_free (ub_array); +- grub_free (bh); ++ ++ /* Got the MOS. Save it at the memory addr MOS. */ ++ grub_memmove (&(data->mos.dn), &osp->os_meta_dnode, DNODE_SIZE); ++ data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop, ++ ub_endian) >> 63) & 1; + grub_free (osp); + +- return 0; ++ data->mounted = 1; ++ ++ return data; + } + + grub_err_t +@@ -2099,7 +2586,7 @@ + zfs = zfs_mount (dev); + if (!zfs) + return grub_errno; +- err = zfs_fetch_nvlist (zfs, nvlist); ++ err = zfs_fetch_nvlist (zfs->device_original, nvlist); + zfs_unmount (zfs); + return err; + } +@@ -2115,7 +2602,7 @@ + if (! data) + return grub_errno; + +- err = zfs_fetch_nvlist (data, &nvlist); ++ err = zfs_fetch_nvlist (data->device_original, &nvlist); + if (err) + { + zfs_unmount (data); +@@ -2131,11 +2618,7 @@ + static grub_err_t + zfs_uuid (grub_device_t device, char **uuid) + { +- char *nvlist; +- int found; + struct grub_zfs_data *data; +- grub_uint64_t guid; +- grub_err_t err; + + *uuid = 0; + +@@ -2143,24 +2626,36 @@ + if (! data) + return grub_errno; + +- err = zfs_fetch_nvlist (data, &nvlist); +- if (err) +- { +- zfs_unmount (data); +- return err; +- } +- +- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid); +- if (! found) +- return grub_errno; +- grub_free (nvlist); +- *uuid = grub_xasprintf ("%016llx", (long long unsigned) guid); ++ *uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid); + zfs_unmount (data); + if (! *uuid) + return grub_errno; + return GRUB_ERR_NONE; + } + ++static grub_err_t ++zfs_mtime (grub_device_t device, grub_int32_t *mt) ++{ ++ struct grub_zfs_data *data; ++ grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; ++ uberblock_t *ub; ++ ++ *mt = 0; ++ ++ data = zfs_mount (device); ++ if (! data) ++ return grub_errno; ++ ++ ub = &(data->current_uberblock); ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ? LITTLE_ENDIAN : BIG_ENDIAN); ++ ++ *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian); ++ zfs_unmount (data); ++ return GRUB_ERR_NONE; ++} ++ + /* + * zfs_open() locates a file in the rootpool by following the + * MOS and places the dnode of the file in the memory address DNODE. +@@ -2227,12 +2722,14 @@ + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); +- file->size = *(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET); ++ file->size = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian); + } +- else ++ else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE) + { + file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian); + } ++ else ++ return grub_error (GRUB_ERR_BAD_FS, "bad bonus type"); + + file->data = data; + file->offset = 0; +@@ -2248,7 +2745,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -202,7 +1567,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2359,7 @@ +@@ -2302,7 +2799,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -211,6 +1576,115 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); +@@ -2391,8 +2888,39 @@ + return; + } + +- info->mtimeset = 1; +- info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian); ++ if (dn.dn.dn_bonustype == DMU_OT_SA) ++ { ++ void *sahdrp; ++ int hdrsize; ++ ++ if (dn.dn.dn_bonuslen != 0) ++ { ++ sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn); ++ } ++ else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) ++ { ++ blkptr_t *bp = &dn.dn.dn_spill; ++ ++ err = zio_read (bp, dn.endian, &sahdrp, NULL, data); ++ if (err) ++ return; ++ } ++ else ++ { ++ grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); ++ return; ++ } ++ ++ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); ++ info->mtimeset = 1; ++ info->mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); ++ } ++ ++ if (dn.dn.dn_bonustype == DMU_OT_ZNODE) ++ { ++ info->mtimeset = 1; ++ info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian); ++ } + return; + } + +@@ -2416,10 +2944,47 @@ + grub_memset (&info, 0, sizeof (info)); + + dnode_get (&(data->mdn), val, 0, &dn, data); +- info.mtimeset = 1; +- info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian); +- info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); +- grub_dprintf ("zfs", "type=%d, name=%s\n", ++ ++ if (dn.dn.dn_bonustype == DMU_OT_SA) ++ { ++ void *sahdrp; ++ int hdrsize; ++ ++ if (dn.dn.dn_bonuslen != 0) ++ { ++ sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn); ++ } ++ else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) ++ { ++ blkptr_t *bp = &dn.dn.dn_spill; ++ ++ err = zio_read (bp, dn.endian, &sahdrp, NULL, data); ++ if (err) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ } ++ else ++ { ++ grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); ++ info.mtimeset = 1; ++ info.mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); ++ } ++ ++ if (dn.dn.dn_bonustype == DMU_OT_ZNODE) ++ { ++ info.mtimeset = 1; ++ info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], ++ dn.endian); ++ } ++ info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); ++ grub_dprintf ("zfs", "type=%d, name=%s\n", + (int)dn.dn.dn_type, (char *)name); + return hook (name, &info); + } +@@ -2532,12 +3097,13 @@ + .close = grub_zfs_close, + .label = zfs_label, + .uuid = zfs_uuid, +- .mtime = 0, ++ .mtime = zfs_mtime, + .next = 0 + }; + + GRUB_MOD_INIT (zfs) + { ++ COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE); + grub_fs_register (&grub_zfs_fs); + #ifndef GRUB_UTIL + my_mod = mod; --- a/include/grub/zfs/zio.h +++ b/include/grub/zfs/zio.h @@ -77,7 +77,15 @@ @@ -230,3 +1704,64 @@ Revisions: ZIO_COMPRESS_FUNCTIONS }; +--- a/grub-core/fs/zfs/zfsinfo.c ++++ b/grub-core/fs/zfs/zfsinfo.c +@@ -141,7 +141,6 @@ + } + grub_printf ("Mirror VDEV with %d children\n", nelm); + print_state (nvlist, tab); +- + for (i = 0; i < nelm; i++) + { + char *child; +@@ -161,6 +160,7 @@ + + grub_free (child); + } ++ return GRUB_ERR_NONE; + } + + print_tabs (tab); +--- a/include/grub/zfs/sa_impl.h ++++ b/include/grub/zfs/sa_impl.h +@@ -29,6 +29,9 @@ + } sa_hdr_phys_t; + + #define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0) ++#define SA_TYPE_OFFSET 0x0 + #define SA_SIZE_OFFSET 0x8 ++#define SA_MTIME_OFFSET 0x38 ++#define SA_SYMLINK_OFFSET 0xa0 + + #endif /* _SYS_SA_IMPL_H */ +--- a/include/grub/zfs/zfs.h ++++ b/include/grub/zfs/zfs.h +@@ -28,7 +28,7 @@ + /* + * On-disk version number. + */ +-#define SPA_VERSION 28ULL ++#define SPA_VERSION 33ULL + + /* + * The following are configuration names used in the nvlist describing a pool's +@@ -112,12 +112,14 @@ + grub_err_t grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename, + grub_uint64_t *mdnobj); + +-char *grub_zfs_nvlist_lookup_string (char *nvlist, char *name); +-char *grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name); +-int grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, ++char *grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name); ++char *grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name); ++int grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name, + grub_uint64_t *out); +-char *grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name, ++char *grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, ++ const char *name, + grub_size_t index); +-int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name); ++int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist, ++ const char *name); + + #endif /* ! GRUB_ZFS_HEADER */ From 9ed8b60ae1d2fb800718a9137e8b3588eb6b8220 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Tue, 8 Nov 2011 20:45:17 +0000 Subject: [PATCH 05/12] 3494: Fix memory leak --- debian/patches/zfs_update.patch | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index f4bd66d59..198819cbd 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -5,6 +5,7 @@ Revisions: 3474: Fix 2G limit on ZFS 3486: ZFS fixes 3488: ZFS multi-device and version 33 support +3494: Fix memory leak --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -563,7 +564,7 @@ Revisions: + } + case DEVICE_MIRROR: + { -+ grub_err_t err = 0; ++ grub_err_t err = GRUB_ERR_NONE; + unsigned i; + if (desc->n_children <= 0) + return grub_error (GRUB_ERR_BAD_FS, @@ -1013,7 +1014,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2391,113 @@ +@@ -1753,199 +2391,114 @@ } int @@ -1292,10 +1293,11 @@ Revisions: + unsigned i; + for (i = 0; i < data->n_devices_attached; i++) + unmount_device (&data->devices_attached[i]); ++ grub_free (data->devices_attached); grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2513,11 @@ +@@ -1961,13 +2514,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1313,7 +1315,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2525,56 @@ +@@ -1975,119 +2526,56 @@ return 0; } @@ -1462,7 +1464,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2586,7 @@ +@@ -2099,7 +2587,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1471,7 +1473,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2602,7 @@ +@@ -2115,7 +2603,7 @@ if (! data) return grub_errno; @@ -1480,7 +1482,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2618,7 @@ +@@ -2131,11 +2619,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1492,7 +1494,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2626,36 @@ +@@ -2143,24 +2627,36 @@ if (! data) return grub_errno; @@ -1541,7 +1543,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2722,14 @@ +@@ -2227,12 +2723,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1558,7 +1560,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2745,7 @@ +@@ -2248,7 +2746,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1567,7 +1569,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2799,7 @@ +@@ -2302,7 +2800,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1576,7 +1578,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2888,39 @@ +@@ -2391,8 +2889,39 @@ return; } @@ -1618,7 +1620,7 @@ Revisions: return; } -@@ -2416,10 +2944,47 @@ +@@ -2416,10 +2945,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1670,7 +1672,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3097,13 @@ +@@ -2532,12 +3098,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From 37705561dfea03037c909630b1e4520572ff30ae Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 06:47:13 +0000 Subject: [PATCH 06/12] 3518: Rewrite RAIDZ part based on reverse engineering --- debian/patches/zfs_update.patch | 155 ++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 56 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index 198819cbd..a0446046c 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -6,6 +6,7 @@ Revisions: 3486: ZFS fixes 3488: ZFS multi-device and version 33 support 3494: Fix memory leak +3518: Rewrite RAIDZ part based on reverse engineering --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -17,7 +18,7 @@ Revisions: GRUB_MOD_LICENSE ("GPLv3+"); -@@ -139,6 +140,26 @@ +@@ -139,6 +140,27 @@ grub_zfs_endian_t endian; } dnode_end_t; @@ -33,6 +34,7 @@ Revisions: + + /* Valid only for RAIDZ. */ + unsigned nparity; ++ unsigned ashift; + + /* Valid only for leaf devices. */ + grub_device_t dev; @@ -44,7 +46,7 @@ Revisions: struct grub_zfs_data { /* cache for a file block of the currently zfs_open()-ed file */ -@@ -153,23 +174,45 @@ +@@ -153,23 +175,45 @@ grub_uint64_t dnode_end; grub_zfs_endian_t dnode_endian; @@ -95,7 +97,7 @@ Revisions: }; static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, -@@ -224,7 +267,7 @@ +@@ -224,7 +268,7 @@ */ static grub_err_t zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, @@ -104,7 +106,7 @@ Revisions: { zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; zio_checksum_info_t *ci = &zio_checksum_table[checksum]; -@@ -253,13 +296,13 @@ +@@ -253,13 +297,13 @@ || (actual_cksum.zc_word[2] != zc.zc_word[2]) || (actual_cksum.zc_word[3] != zc.zc_word[3])) { @@ -121,7 +123,7 @@ Revisions: (unsigned long long) zc.zc_word[0], (unsigned long long) zc.zc_word[1], (unsigned long long) zc.zc_word[2], -@@ -319,7 +362,7 @@ +@@ -319,7 +363,7 @@ * */ static grub_err_t @@ -130,7 +132,7 @@ Revisions: { uberblock_t *uber = &ub->ubp_uberblock; grub_err_t err; -@@ -392,7 +435,7 @@ +@@ -392,7 +436,7 @@ } static grub_uint64_t @@ -139,7 +141,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +444,510 @@ +@@ -401,6 +445,551 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -215,6 +217,9 @@ Revisions: + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par)) + return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity"); + fill->nparity = par; ++ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par)) ++ return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz ashift"); ++ fill->ashift = par; + } + + nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, ZPOOL_CONFIG_CHILDREN); @@ -581,38 +586,76 @@ Revisions: + } + case DEVICE_RAIDZ: + { -+ grub_uint64_t sector; -+ grub_uint32_t bsize; + unsigned c = 0; ++ grub_uint64_t high; ++ grub_uint64_t devn; ++ grub_uint64_t redundancy_strip = 0, m; ++ grub_uint64_t redundancy_strip2 = 0; ++ grub_uint32_t s; + -+ bsize = (asize + desc->nparity) / desc->n_children; -+ sector = offset >> 9; ++ /* (4,1) -> 2, (3,1) -> 1 */ ++ if (desc->nparity == 1) ++ s = asize + desc->n_children - 2; ++ else ++ s = asize + desc->n_children - 3; ++ high = grub_divmod64_full ((offset >> desc->ashift), ++ desc->n_children, &m); ++ ++ if (desc->nparity == 1) ++ { ++ redundancy_strip = m; ++ redundancy_strip += ((offset >> (desc->ashift + 11)) & 1); ++ if (redundancy_strip == desc->n_children) ++ redundancy_strip = 0; ++ redundancy_strip2 = redundancy_strip; ++ } ++ else ++ { ++ redundancy_strip = m; ++ redundancy_strip2 = m + 1; ++ if (redundancy_strip2 == desc->n_children) ++ redundancy_strip2 = 0; ++ } ++ grub_dprintf ("zfs", "rs = %x, %llx\n", ++ (int) redundancy_strip, ++ (unsigned long long) high); + while (len > 0) + { + grub_size_t csize; -+ grub_uint64_t high; -+ grub_uint64_t devn; ++ grub_uint32_t bsize; + grub_err_t err; -+ high = grub_divmod64_full (sector + (asize > 2) + c, desc->n_children, -+ &devn); -+ csize = bsize << 9; ++ bsize = s / desc->n_children; ++ ++ while (1) ++ { ++ high = grub_divmod64_full ((offset >> desc->ashift) + c, ++ desc->n_children, &devn); ++ if (devn != redundancy_strip && devn != redundancy_strip2) ++ break; ++ c++; ++ } ++ csize = bsize << desc->ashift; + if (csize > len) + csize = len; ++ + grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T -+ "+%d+%u -> (0x%" PRIxGRUB_UINT64_T ", 0x%" ++ "+%u (%d, %d) -> (0x%" PRIxGRUB_UINT64_T ", 0x%" + PRIxGRUB_UINT64_T ")\n", -+ sector,(asize > 2), c, high, devn); -+ err = read_device (high << 9, &desc->children[devn], ++ offset >> desc->ashift, c, asize, bsize, high, ++ devn); ++ err = read_device ((high << desc->ashift) ++ | (offset & ((1 << desc->ashift) - 1)), ++ &desc->children[devn], + bsize, csize, buf); + if (err) + return err; + c++; ++ s--; + buf = (char *) buf + csize; + len -= csize; + } -+ return GRUB_ERR_NONE; + } -+ return GRUB_ERR_NONE; ++ return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); +} @@ -650,7 +693,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +959,6 @@ +@@ -412,7 +1001,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -658,7 +701,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +970,8 @@ +@@ -424,13 +1012,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -673,7 +716,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1024,13 @@ +@@ -483,20 +1066,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -695,7 +738,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1061,7 @@ +@@ -527,7 +1103,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -704,7 +747,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1136,8 @@ +@@ -602,7 +1178,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -714,7 +757,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1351,7 @@ +@@ -816,7 +1393,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -723,7 +766,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1375,8 @@ +@@ -840,7 +1417,8 @@ { struct zap_leaf_array *la; @@ -733,7 +776,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1394,9 @@ +@@ -858,9 +1436,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -745,7 +788,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1424,7 @@ +@@ -888,7 +1466,7 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -754,7 +797,7 @@ Revisions: if (err) return err; -@@ -899,7 +1435,7 @@ +@@ -899,7 +1477,7 @@ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -763,7 +806,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1458,14 @@ +@@ -922,14 +1500,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -780,7 +823,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1481,17 @@ +@@ -945,9 +1523,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -800,7 +843,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1527,11 @@ +@@ -983,8 +1569,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -814,7 +857,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1543,9 @@ +@@ -996,7 +1585,9 @@ continue; /* get the uint64_t property value */ @@ -825,7 +868,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1623,7 @@ +@@ -1074,7 +1665,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -834,7 +877,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1840,54 @@ +@@ -1291,22 +1882,54 @@ break; *path = ch; @@ -898,7 +941,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1905,62 @@ +@@ -1324,7 +1947,62 @@ grub_free (dn_new); } } @@ -962,7 +1005,7 @@ Revisions: } if (!err) -@@ -1625,11 +2261,12 @@ +@@ -1625,11 +2303,12 @@ */ static int @@ -977,7 +1020,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2308,7 @@ +@@ -1671,7 +2350,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -986,7 +1029,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2321,8 @@ +@@ -1684,7 +2363,8 @@ } int @@ -996,7 +1039,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2342,7 @@ +@@ -1704,7 +2384,7 @@ } char * @@ -1005,7 +1048,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2370,7 @@ +@@ -1732,7 +2412,7 @@ } char * @@ -1014,7 +1057,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2391,114 @@ +@@ -1753,199 +2433,114 @@ } int @@ -1297,7 +1340,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2514,11 @@ +@@ -1961,13 +2556,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1315,7 +1358,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2526,56 @@ +@@ -1975,119 +2568,56 @@ return 0; } @@ -1464,7 +1507,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2587,7 @@ +@@ -2099,7 +2629,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1473,7 +1516,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2603,7 @@ +@@ -2115,7 +2645,7 @@ if (! data) return grub_errno; @@ -1482,7 +1525,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2619,7 @@ +@@ -2131,11 +2661,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1494,7 +1537,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2627,36 @@ +@@ -2143,24 +2669,36 @@ if (! data) return grub_errno; @@ -1543,7 +1586,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2723,14 @@ +@@ -2227,12 +2765,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1560,7 +1603,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2746,7 @@ +@@ -2248,7 +2788,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1569,7 +1612,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2800,7 @@ +@@ -2302,7 +2842,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1578,7 +1621,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2889,39 @@ +@@ -2391,8 +2931,39 @@ return; } @@ -1620,7 +1663,7 @@ Revisions: return; } -@@ -2416,10 +2945,47 @@ +@@ -2416,10 +2987,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1672,7 +1715,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3098,13 @@ +@@ -2532,12 +3140,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From 2ff851ba293874fb8c1deed00f3552f178309332 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 17:57:02 +0000 Subject: [PATCH 07/12] 3519: Fix RAIDZ(2) for >= 5 devices --- debian/patches/zfs_update.patch | 115 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index a0446046c..0bff9ad5e 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -7,6 +7,7 @@ Revisions: 3488: ZFS multi-device and version 33 support 3494: Fix memory leak 3518: Rewrite RAIDZ part based on reverse engineering +3519: Fix RAIDZ(2) for >= 5 devices --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -141,7 +142,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +445,551 @@ +@@ -401,6 +445,557 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -552,7 +553,7 @@ Revisions: + +static grub_err_t +read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, -+ grub_uint32_t asize, grub_size_t len, void *buf) ++ grub_size_t len, void *buf) +{ + switch (desc->type) + { @@ -576,7 +577,7 @@ Revisions: + "non-positive number of mirror children"); + for (i = 0; i < desc->n_children; i++) + { -+ err = read_device (offset, &desc->children[i], asize, ++ err = read_device (offset, &desc->children[i], + len, buf); + if (!err) + break; @@ -593,28 +594,32 @@ Revisions: + grub_uint64_t redundancy_strip2 = 0; + grub_uint32_t s; + -+ /* (4,1) -> 2, (3,1) -> 1 */ -+ if (desc->nparity == 1) -+ s = asize + desc->n_children - 2; -+ else -+ s = asize + desc->n_children - 3; ++ if (desc->nparity < 1 || desc->nparity > 2) ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "raidz%d is not supported", desc->nparity); ++ ++ s = (((len + (1 << desc->ashift) - 1) >> desc->ashift) ++ + (desc->n_children - desc->nparity) - 1); ++ + high = grub_divmod64_full ((offset >> desc->ashift), + desc->n_children, &m); + -+ if (desc->nparity == 1) ++ ++ switch (desc->nparity) + { ++ case 1: + redundancy_strip = m; + redundancy_strip += ((offset >> (desc->ashift + 11)) & 1); + if (redundancy_strip == desc->n_children) + redundancy_strip = 0; + redundancy_strip2 = redundancy_strip; -+ } -+ else -+ { ++ break; ++ case 2: + redundancy_strip = m; + redundancy_strip2 = m + 1; + if (redundancy_strip2 == desc->n_children) + redundancy_strip2 = 0; ++ break; + } + grub_dprintf ("zfs", "rs = %x, %llx\n", + (int) redundancy_strip, @@ -624,8 +629,8 @@ Revisions: + grub_size_t csize; + grub_uint32_t bsize; + grub_err_t err; -+ bsize = s / desc->n_children; -+ ++ bsize = s / (desc->n_children - desc->nparity); ++ + while (1) + { + high = grub_divmod64_full ((offset >> desc->ashift) + c, @@ -634,21 +639,24 @@ Revisions: + break; + c++; + } ++ + csize = bsize << desc->ashift; + if (csize > len) + csize = len; + + grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T -+ "+%u (%d, %d) -> (0x%" PRIxGRUB_UINT64_T ", 0x%" ++ "+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T ++ ") -> (0x%" PRIxGRUB_UINT64_T ", 0x%" + PRIxGRUB_UINT64_T ")\n", -+ offset >> desc->ashift, c, asize, bsize, high, ++ offset >> desc->ashift, c, len, bsize, high, + devn); + err = read_device ((high << desc->ashift) + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], -+ bsize, csize, buf); ++ csize, buf); + if (err) + return err; ++ + c++; + s--; + buf = (char *) buf + csize; @@ -676,8 +684,7 @@ Revisions: + for (i = 0; i < data->n_devices_attached; i++) + if (data->devices_attached[i].id == DVA_GET_VDEV (dva)) + { -+ err = read_device (offset, &data->devices_attached[i], -+ dva->dva_word[0] & 0xffffff, len, buf); ++ err = read_device (offset, &data->devices_attached[i], len, buf); + if (!err) + return GRUB_ERR_NONE; + break; @@ -693,7 +700,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +1001,6 @@ +@@ -412,7 +1007,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -701,7 +708,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +1012,8 @@ +@@ -424,13 +1018,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -716,7 +723,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1066,13 @@ +@@ -483,20 +1072,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -738,7 +745,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1103,7 @@ +@@ -527,7 +1109,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -747,7 +754,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1178,8 @@ +@@ -602,7 +1184,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -757,7 +764,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1393,7 @@ +@@ -816,7 +1399,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -766,7 +773,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1417,8 @@ +@@ -840,7 +1423,8 @@ { struct zap_leaf_array *la; @@ -776,7 +783,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1436,9 @@ +@@ -858,9 +1442,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -788,7 +795,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1466,7 @@ +@@ -888,7 +1472,7 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -797,7 +804,7 @@ Revisions: if (err) return err; -@@ -899,7 +1477,7 @@ +@@ -899,7 +1483,7 @@ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -806,7 +813,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1500,14 @@ +@@ -922,14 +1506,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -823,7 +830,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1523,17 @@ +@@ -945,9 +1529,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -843,7 +850,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1569,11 @@ +@@ -983,8 +1575,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -857,7 +864,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1585,9 @@ +@@ -996,7 +1591,9 @@ continue; /* get the uint64_t property value */ @@ -868,7 +875,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1665,7 @@ +@@ -1074,7 +1671,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -877,7 +884,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1882,54 @@ +@@ -1291,22 +1888,54 @@ break; *path = ch; @@ -941,7 +948,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1947,62 @@ +@@ -1324,7 +1953,62 @@ grub_free (dn_new); } } @@ -1005,7 +1012,7 @@ Revisions: } if (!err) -@@ -1625,11 +2303,12 @@ +@@ -1625,11 +2309,12 @@ */ static int @@ -1020,7 +1027,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2350,7 @@ +@@ -1671,7 +2356,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1029,7 +1036,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2363,8 @@ +@@ -1684,7 +2369,8 @@ } int @@ -1039,7 +1046,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2384,7 @@ +@@ -1704,7 +2390,7 @@ } char * @@ -1048,7 +1055,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2412,7 @@ +@@ -1732,7 +2418,7 @@ } char * @@ -1057,7 +1064,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2433,114 @@ +@@ -1753,199 +2439,114 @@ } int @@ -1340,7 +1347,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2556,11 @@ +@@ -1961,13 +2562,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1358,7 +1365,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2568,56 @@ +@@ -1975,119 +2574,56 @@ return 0; } @@ -1507,7 +1514,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2629,7 @@ +@@ -2099,7 +2635,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1516,7 +1523,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2645,7 @@ +@@ -2115,7 +2651,7 @@ if (! data) return grub_errno; @@ -1525,7 +1532,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2661,7 @@ +@@ -2131,11 +2667,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1537,7 +1544,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2669,36 @@ +@@ -2143,24 +2675,36 @@ if (! data) return grub_errno; @@ -1586,7 +1593,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2765,14 @@ +@@ -2227,12 +2771,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1603,7 +1610,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2788,7 @@ +@@ -2248,7 +2794,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1612,7 +1619,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2842,7 @@ +@@ -2302,7 +2848,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1621,7 +1628,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2931,39 @@ +@@ -2391,8 +2937,39 @@ return; } @@ -1663,7 +1670,7 @@ Revisions: return; } -@@ -2416,10 +2987,47 @@ +@@ -2416,10 +2993,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1715,7 +1722,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3140,13 @@ +@@ -2532,12 +3146,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From 251323a490c73ac6abad27c4cbcf66295e31abd4 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 19:06:15 +0000 Subject: [PATCH 08/12] 3520: Add ability to sustain a single drive failure on both raidz and raidz2 --- debian/patches/zfs_update.patch | 173 +++++++++++++++++++------------- 1 file changed, 103 insertions(+), 70 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index 0bff9ad5e..b6c2f90bc 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -8,6 +8,7 @@ Revisions: 3494: Fix memory leak 3518: Rewrite RAIDZ part based on reverse engineering 3519: Fix RAIDZ(2) for >= 5 devices +3520: Add ability to sustain a single drive failure on both raidz and raidz2 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -142,7 +143,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +445,557 @@ +@@ -401,6 +445,589 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -551,6 +552,14 @@ Revisions: + return GRUB_ERR_NONE; +} + ++static inline void ++xor (grub_uint64_t *a, const grub_uint64_t *b, grub_size_t s) ++{ ++ s /= sizeof (grub_uint64_t); ++ while (s--) ++ *a++ ^= *b++; ++} ++ +static grub_err_t +read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + grub_size_t len, void *buf) @@ -590,40 +599,26 @@ Revisions: + unsigned c = 0; + grub_uint64_t high; + grub_uint64_t devn; -+ grub_uint64_t redundancy_strip = 0, m; -+ grub_uint64_t redundancy_strip2 = 0; -+ grub_uint32_t s; ++ grub_uint64_t m; ++ grub_uint32_t s, orig_s; ++ void *orig_buf = buf; ++ grub_size_t orig_len = len; ++ void *recovery_buf = NULL; ++ grub_size_t recovery_len = 0; + + if (desc->nparity < 1 || desc->nparity > 2) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "raidz%d is not supported", desc->nparity); + -+ s = (((len + (1 << desc->ashift) - 1) >> desc->ashift) -+ + (desc->n_children - desc->nparity) - 1); ++ orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift) ++ + (desc->n_children - desc->nparity) - 1); ++ s = orig_s; + + high = grub_divmod64_full ((offset >> desc->ashift), + desc->n_children, &m); + -+ -+ switch (desc->nparity) -+ { -+ case 1: -+ redundancy_strip = m; -+ redundancy_strip += ((offset >> (desc->ashift + 11)) & 1); -+ if (redundancy_strip == desc->n_children) -+ redundancy_strip = 0; -+ redundancy_strip2 = redundancy_strip; -+ break; -+ case 2: -+ redundancy_strip = m; -+ redundancy_strip2 = m + 1; -+ if (redundancy_strip2 == desc->n_children) -+ redundancy_strip2 = 0; -+ break; -+ } -+ grub_dprintf ("zfs", "rs = %x, %llx\n", -+ (int) redundancy_strip, -+ (unsigned long long) high); ++ if (desc->nparity == 2) ++ c = 2; + while (len > 0) + { + grub_size_t csize; @@ -631,15 +626,12 @@ Revisions: + grub_err_t err; + bsize = s / (desc->n_children - desc->nparity); + -+ while (1) -+ { -+ high = grub_divmod64_full ((offset >> desc->ashift) + c, -+ desc->n_children, &devn); -+ if (devn != redundancy_strip && devn != redundancy_strip2) -+ break; -+ c++; -+ } ++ if (desc->nparity == 1 ++ && ((offset >> (desc->ashift + 11)) & 1) == c) ++ c++; + ++ high = grub_divmod64_full ((offset >> desc->ashift) + c, ++ desc->n_children, &devn); + csize = bsize << desc->ashift; + if (csize > len) + csize = len; @@ -654,6 +646,13 @@ Revisions: + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], + csize, buf); ++ /* No raidz2 recovery yet. */ ++ if (err && recovery_len == 0) ++ { ++ recovery_buf = buf; ++ recovery_len = csize; ++ grub_errno = err = 0; ++ } + if (err) + return err; + @@ -662,8 +661,42 @@ Revisions: + buf = (char *) buf + csize; + len -= csize; + } ++ if (recovery_buf) ++ { ++ grub_err_t err; ++ high = grub_divmod64_full ((offset >> desc->ashift) ++ + ++ ((desc->nparity == 1) ++ && ((offset >> (desc->ashift + 11)) & 1)), ++ desc->n_children, &devn); ++ err = read_device ((high << desc->ashift) ++ | (offset & ((1 << desc->ashift) - 1)), ++ &desc->children[devn], ++ recovery_len, recovery_buf); ++ if (err) ++ return err; ++ buf = orig_buf; ++ len = orig_len; ++ s = orig_s; ++ while (len > 0) ++ { ++ grub_size_t csize; ++ csize = ((s / (desc->n_children - desc->nparity)) ++ << desc->ashift); ++ if (csize > len) ++ csize = len; ++ ++ if (buf != recovery_buf) ++ xor (recovery_buf, buf, ++ csize < recovery_len ? csize : recovery_len); ++ ++ s--; ++ buf = (char *) buf + csize; ++ len -= csize; ++ } ++ } ++ return GRUB_ERR_NONE; + } -+ return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); +} @@ -700,7 +733,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +1007,6 @@ +@@ -412,7 +1039,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -708,7 +741,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +1018,8 @@ +@@ -424,13 +1050,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -723,7 +756,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1072,13 @@ +@@ -483,20 +1104,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -745,7 +778,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1109,7 @@ +@@ -527,7 +1141,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -754,7 +787,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1184,8 @@ +@@ -602,7 +1216,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -764,7 +797,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1399,7 @@ +@@ -816,7 +1431,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -773,7 +806,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1423,8 @@ +@@ -840,7 +1455,8 @@ { struct zap_leaf_array *la; @@ -783,7 +816,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1442,9 @@ +@@ -858,9 +1474,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -795,7 +828,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1472,7 @@ +@@ -888,7 +1504,7 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -804,7 +837,7 @@ Revisions: if (err) return err; -@@ -899,7 +1483,7 @@ +@@ -899,7 +1515,7 @@ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -813,7 +846,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1506,14 @@ +@@ -922,14 +1538,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -830,7 +863,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1529,17 @@ +@@ -945,9 +1561,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -850,7 +883,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1575,11 @@ +@@ -983,8 +1607,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -864,7 +897,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1591,9 @@ +@@ -996,7 +1623,9 @@ continue; /* get the uint64_t property value */ @@ -875,7 +908,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1671,7 @@ +@@ -1074,7 +1703,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -884,7 +917,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1888,54 @@ +@@ -1291,22 +1920,54 @@ break; *path = ch; @@ -948,7 +981,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1953,62 @@ +@@ -1324,7 +1985,62 @@ grub_free (dn_new); } } @@ -1012,7 +1045,7 @@ Revisions: } if (!err) -@@ -1625,11 +2309,12 @@ +@@ -1625,11 +2341,12 @@ */ static int @@ -1027,7 +1060,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2356,7 @@ +@@ -1671,7 +2388,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1036,7 +1069,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2369,8 @@ +@@ -1684,7 +2401,8 @@ } int @@ -1046,7 +1079,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2390,7 @@ +@@ -1704,7 +2422,7 @@ } char * @@ -1055,7 +1088,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2418,7 @@ +@@ -1732,7 +2450,7 @@ } char * @@ -1064,7 +1097,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2439,114 @@ +@@ -1753,199 +2471,114 @@ } int @@ -1347,7 +1380,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2562,11 @@ +@@ -1961,13 +2594,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1365,7 +1398,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2574,56 @@ +@@ -1975,119 +2606,56 @@ return 0; } @@ -1514,7 +1547,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2635,7 @@ +@@ -2099,7 +2667,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1523,7 +1556,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2651,7 @@ +@@ -2115,7 +2683,7 @@ if (! data) return grub_errno; @@ -1532,7 +1565,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2667,7 @@ +@@ -2131,11 +2699,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1544,7 +1577,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2675,36 @@ +@@ -2143,24 +2707,36 @@ if (! data) return grub_errno; @@ -1593,7 +1626,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2771,14 @@ +@@ -2227,12 +2803,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1610,7 +1643,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2794,7 @@ +@@ -2248,7 +2826,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1619,7 +1652,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2848,7 @@ +@@ -2302,7 +2880,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1628,7 +1661,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2937,39 @@ +@@ -2391,8 +2969,39 @@ return; } @@ -1670,7 +1703,7 @@ Revisions: return; } -@@ -2416,10 +2993,47 @@ +@@ -2416,10 +3025,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1722,7 +1755,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3146,13 @@ +@@ -2532,12 +3178,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From f86cfb50212326d3bf5d0a34b4c8c5e42c8dfdda Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 19:08:08 +0000 Subject: [PATCH 09/12] 3521: Support raidz3 --- debian/patches/zfs_update.patch | 78 +++++++++++++++++---------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index b6c2f90bc..e04dfaf86 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -9,6 +9,7 @@ Revisions: 3518: Rewrite RAIDZ part based on reverse engineering 3519: Fix RAIDZ(2) for >= 5 devices 3520: Add ability to sustain a single drive failure on both raidz and raidz2 +3521: Support raidz3 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -143,7 +144,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +445,589 @@ +@@ -401,6 +445,590 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -606,7 +607,7 @@ Revisions: + void *recovery_buf = NULL; + grub_size_t recovery_len = 0; + -+ if (desc->nparity < 1 || desc->nparity > 2) ++ if (desc->nparity < 1 || desc->nparity > 3) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "raidz%d is not supported", desc->nparity); + @@ -616,9 +617,10 @@ Revisions: + + high = grub_divmod64_full ((offset >> desc->ashift), + desc->n_children, &m); -+ + if (desc->nparity == 2) + c = 2; ++ if (desc->nparity == 3) ++ c = 3; + while (len > 0) + { + grub_size_t csize; @@ -733,7 +735,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +1039,6 @@ +@@ -412,7 +1040,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -741,7 +743,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +1050,8 @@ +@@ -424,13 +1051,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -756,7 +758,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1104,13 @@ +@@ -483,20 +1105,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -778,7 +780,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1141,7 @@ +@@ -527,7 +1142,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -787,7 +789,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1216,8 @@ +@@ -602,7 +1217,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -797,7 +799,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1431,7 @@ +@@ -816,7 +1432,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -806,7 +808,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1455,8 @@ +@@ -840,7 +1456,8 @@ { struct zap_leaf_array *la; @@ -816,7 +818,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1474,9 @@ +@@ -858,9 +1475,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -828,7 +830,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1504,7 @@ +@@ -888,7 +1505,7 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -837,7 +839,7 @@ Revisions: if (err) return err; -@@ -899,7 +1515,7 @@ +@@ -899,7 +1516,7 @@ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -846,7 +848,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1538,14 @@ +@@ -922,14 +1539,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -863,7 +865,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1561,17 @@ +@@ -945,9 +1562,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -883,7 +885,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1607,11 @@ +@@ -983,8 +1608,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -897,7 +899,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1623,9 @@ +@@ -996,7 +1624,9 @@ continue; /* get the uint64_t property value */ @@ -908,7 +910,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1703,7 @@ +@@ -1074,7 +1704,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -917,7 +919,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1920,54 @@ +@@ -1291,22 +1921,54 @@ break; *path = ch; @@ -981,7 +983,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1985,62 @@ +@@ -1324,7 +1986,62 @@ grub_free (dn_new); } } @@ -1045,7 +1047,7 @@ Revisions: } if (!err) -@@ -1625,11 +2341,12 @@ +@@ -1625,11 +2342,12 @@ */ static int @@ -1060,7 +1062,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2388,7 @@ +@@ -1671,7 +2389,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1069,7 +1071,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2401,8 @@ +@@ -1684,7 +2402,8 @@ } int @@ -1079,7 +1081,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2422,7 @@ +@@ -1704,7 +2423,7 @@ } char * @@ -1088,7 +1090,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2450,7 @@ +@@ -1732,7 +2451,7 @@ } char * @@ -1097,7 +1099,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2471,114 @@ +@@ -1753,199 +2472,114 @@ } int @@ -1380,7 +1382,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2594,11 @@ +@@ -1961,13 +2595,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1398,7 +1400,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2606,56 @@ +@@ -1975,119 +2607,56 @@ return 0; } @@ -1547,7 +1549,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2667,7 @@ +@@ -2099,7 +2668,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1556,7 +1558,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2683,7 @@ +@@ -2115,7 +2684,7 @@ if (! data) return grub_errno; @@ -1565,7 +1567,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2699,7 @@ +@@ -2131,11 +2700,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1577,7 +1579,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2707,36 @@ +@@ -2143,24 +2708,36 @@ if (! data) return grub_errno; @@ -1626,7 +1628,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2803,14 @@ +@@ -2227,12 +2804,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1643,7 +1645,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2826,7 @@ +@@ -2248,7 +2827,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1652,7 +1654,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2880,7 @@ +@@ -2302,7 +2881,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1661,7 +1663,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2969,39 @@ +@@ -2391,8 +2970,39 @@ return; } @@ -1703,7 +1705,7 @@ Revisions: return; } -@@ -2416,10 +3025,47 @@ +@@ -2416,10 +3026,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1755,7 +1757,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3178,13 @@ +@@ -2532,12 +3179,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From c3463d769a762c84361751fef99f9e0f2af8a4ba Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 20:04:18 +0000 Subject: [PATCH 10/12] 3533: Support second redundancy strip on raidz(2,3) --- debian/patches/zfs_update.patch | 281 +++++++++++++++++++++++++------- 1 file changed, 222 insertions(+), 59 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index e04dfaf86..2667fb0c4 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -10,6 +10,7 @@ Revisions: 3519: Fix RAIDZ(2) for >= 5 devices 3520: Add ability to sustain a single drive failure on both raidz and raidz2 3521: Support raidz3 +3533: Support second redundancy strip on raidz(2,3) --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -144,7 +145,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +445,590 @@ +@@ -401,6 +445,752 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -561,6 +562,92 @@ Revisions: + *a++ ^= *b++; +} + ++/* x**y. */ ++static grub_uint8_t powx[255 * 2]; ++/* Such an s that x**s = y */ ++static int powx_inv[256]; ++static const grub_uint8_t poly = 0x1d; ++ ++/* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */ ++static inline void ++xor_out (void *a_in, const void *b_in, grub_size_t s, ++ int known_idx, int recovery_pow) ++{ ++ int add; ++ grub_uint8_t *a = a_in; ++ const grub_uint8_t *b = b_in; ++ ++ /* Simple xor. */ ++ if (known_idx == 0 || recovery_pow == 0) ++ { ++ xor (a_in, b_in, s); ++ return; ++ } ++ add = (known_idx * recovery_pow) % 255; ++ for (;s--; b++, a++) ++ if (*b) ++ *a ^= powx[powx_inv[*b] + add]; ++} ++ ++static inline grub_uint8_t ++gf_mul (grub_uint8_t a, grub_uint8_t b) ++{ ++ if (a == 0 || b == 0) ++ return 0; ++ return powx[powx_inv[a] + powx_inv[b]]; ++} ++ ++static inline void ++recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, ++ const unsigned *powers, ++ const int *idx) ++{ ++ /* Now we have */ ++ /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/ ++ /* Since nbufs <= 3 let's be lazy. */ ++ switch (nbufs) ++ { ++ /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */ ++ case 1: ++ { ++ int add; ++ grub_uint8_t *a; ++ if (powers[0] == 0 || idx[0] == 0) ++ return; ++ add = 255 - ((powers[0] * idx[0]) % 255); ++ for (a = bufs[0]; s--; a++) ++ if (*a) ++ *a = powx[powx_inv[*a] + add]; ++ return; ++ } ++ /* b_0 = r_0 * (x ** (powers[0] * idx[0])) + r_1 * (x ** (powers[0] * idx[1])) ++ b_1 = r_0 * (x ** (powers[1] * idx[0])) + r_1 * (x ** (powers[1] * idx[1])) ++ */ ++ case 2: ++ { ++ grub_uint8_t det, det_inv; ++ grub_uint8_t det0, det1; ++ unsigned i; ++ /* The determinant is: */ ++ det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255] ++ ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]); ++ det_inv = powx[255 - powx_inv[det]]; ++ for (i = 0; i < s; i++) ++ { ++ det0 = (gf_mul (bufs[0][i], powx[(powers[1] * idx[1]) % 255]) ++ ^ gf_mul (bufs[1][i], powx[(powers[0] * idx[1]) % 255])); ++ det1 = (gf_mul (bufs[0][i], powx[(powers[1] * idx[0]) % 255]) ++ ^ gf_mul (bufs[1][i], powx[(powers[0] * idx[0]) % 255])); ++ ++ bufs[0][i] = gf_mul (det0, det_inv); ++ bufs[1][i] = gf_mul (det1, det_inv); ++ } ++ break; ++ } ++ } ++ ++} ++ +static grub_err_t +read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + grub_size_t len, void *buf) @@ -604,8 +691,11 @@ Revisions: + grub_uint32_t s, orig_s; + void *orig_buf = buf; + grub_size_t orig_len = len; -+ void *recovery_buf = NULL; -+ grub_size_t recovery_len = 0; ++ grub_uint8_t *recovery_buf[4]; ++ grub_size_t recovery_len[4]; ++ int recovery_idx[4]; ++ unsigned failed_devices = 0; ++ int idx, orig_idx; + + if (desc->nparity < 1 || desc->nparity > 3) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, @@ -621,6 +711,12 @@ Revisions: + c = 2; + if (desc->nparity == 3) + c = 3; ++ if (((len + (1 << desc->ashift) - 1) >> desc->ashift) ++ >= (desc->n_children - desc->nparity)) ++ idx = (desc->n_children - desc->nparity - 1); ++ else ++ idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1; ++ orig_idx = idx; + while (len > 0) + { + grub_size_t csize; @@ -648,38 +744,84 @@ Revisions: + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], + csize, buf); -+ /* No raidz2 recovery yet. */ -+ if (err && recovery_len == 0) ++ /* No raidz3 recovery yet. */ ++ if (err ++ && failed_devices < desc->nparity ++ && failed_devices < 2) + { -+ recovery_buf = buf; -+ recovery_len = csize; ++ recovery_buf[failed_devices] = buf; ++ recovery_len[failed_devices] = csize; ++ recovery_idx[failed_devices] = idx; ++ failed_devices++; + grub_errno = err = 0; + } + if (err) + return err; + + c++; ++ idx--; + s--; + buf = (char *) buf + csize; + len -= csize; + } -+ if (recovery_buf) ++ if (failed_devices) + { -+ grub_err_t err; -+ high = grub_divmod64_full ((offset >> desc->ashift) -+ + -+ ((desc->nparity == 1) -+ && ((offset >> (desc->ashift + 11)) & 1)), -+ desc->n_children, &devn); -+ err = read_device ((high << desc->ashift) -+ | (offset & ((1 << desc->ashift) - 1)), -+ &desc->children[devn], -+ recovery_len, recovery_buf); -+ if (err) -+ return err; ++ unsigned redundancy_pow[4]; ++ unsigned cur_redundancy_pow = 0; ++ unsigned n_redundancy = 0; ++ unsigned i, j; ++ ++ /* Compute mul. x**s has a period of 255. */ ++ if (powx[0] == 0) ++ { ++ grub_uint8_t cur = 1; ++ for (i = 0; i < 255; i++) ++ { ++ powx[i] = cur; ++ powx[i + 255] = cur; ++ powx_inv[cur] = i; ++ if (cur & 0x80) ++ cur = (cur << 1) ^ poly; ++ else ++ cur <<= 1; ++ } ++ } ++ ++ /* Read redundancy data. */ ++ for (n_redundancy = 0, cur_redundancy_pow = 0; ++ n_redundancy < failed_devices; ++ cur_redundancy_pow++) ++ { ++ grub_err_t err; ++ high = grub_divmod64_full ((offset >> desc->ashift) ++ + cur_redundancy_pow ++ + ((desc->nparity == 1) ++ && ((offset >> (desc->ashift + 11)) ++ & 1)), ++ desc->n_children, &devn); ++ err = read_device ((high << desc->ashift) ++ | (offset & ((1 << desc->ashift) - 1)), ++ &desc->children[devn], ++ recovery_len[n_redundancy], ++ recovery_buf[n_redundancy]); ++ /* Ignore error if we may still have enough devices. */ ++ if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1 ++ >= failed_devices) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ continue; ++ } ++ if (err) ++ return err; ++ redundancy_pow[n_redundancy] = cur_redundancy_pow; ++ n_redundancy++; ++ } ++ /* Now xor-our the parts we already know. */ + buf = orig_buf; + len = orig_len; + s = orig_s; ++ idx = orig_idx; ++ + while (len > 0) + { + grub_size_t csize; @@ -688,14 +830,35 @@ Revisions: + if (csize > len) + csize = len; + -+ if (buf != recovery_buf) -+ xor (recovery_buf, buf, -+ csize < recovery_len ? csize : recovery_len); ++ for (j = 0; j < failed_devices; j++) ++ if (buf == recovery_buf[j]) ++ break; ++ ++ if (j == failed_devices) ++ for (j = 0; j < failed_devices; j++) ++ xor_out (recovery_buf[j], buf, ++ csize < recovery_len[j] ? csize : recovery_len[j], ++ idx, redundancy_pow[j]); + + s--; + buf = (char *) buf + csize; + len -= csize; -+ } ++ idx--; ++ } ++ for (i = 0; i < failed_devices ++ && recovery_len[i] == recovery_len[0]; ++ i++); ++ /* Since the chunks have variable length handle the last block ++ separately. */ ++ if (i != failed_devices) ++ { ++ grub_uint8_t *tmp_recovery_buf[4]; ++ for (j = 0; j < i; j++) ++ tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[j] - 1; ++ recovery (tmp_recovery_buf, 1, i, redundancy_pow, recovery_idx); ++ } ++ recovery (recovery_buf, recovery_len[failed_devices - 1], ++ failed_devices, redundancy_pow, recovery_idx); + } + return GRUB_ERR_NONE; + } @@ -735,7 +898,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +1040,6 @@ +@@ -412,7 +1202,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -743,7 +906,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +1051,8 @@ +@@ -424,13 +1213,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -758,7 +921,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1105,13 @@ +@@ -483,20 +1267,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -780,7 +943,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1142,7 @@ +@@ -527,7 +1304,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -789,7 +952,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1217,8 @@ +@@ -602,7 +1379,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -799,7 +962,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1432,7 @@ +@@ -816,7 +1594,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -808,7 +971,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1456,8 @@ +@@ -840,7 +1618,8 @@ { struct zap_leaf_array *la; @@ -818,7 +981,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1475,9 @@ +@@ -858,9 +1637,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -830,7 +993,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1505,7 @@ +@@ -888,7 +1667,7 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -839,7 +1002,7 @@ Revisions: if (err) return err; -@@ -899,7 +1516,7 @@ +@@ -899,7 +1678,7 @@ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -848,7 +1011,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1539,14 @@ +@@ -922,14 +1701,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -865,7 +1028,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1562,17 @@ +@@ -945,9 +1724,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -885,7 +1048,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1608,11 @@ +@@ -983,8 +1770,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -899,7 +1062,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1624,9 @@ +@@ -996,7 +1786,9 @@ continue; /* get the uint64_t property value */ @@ -910,7 +1073,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1704,7 @@ +@@ -1074,7 +1866,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -919,7 +1082,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +1921,54 @@ +@@ -1291,22 +2083,54 @@ break; *path = ch; @@ -983,7 +1146,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +1986,62 @@ +@@ -1324,7 +2148,62 @@ grub_free (dn_new); } } @@ -1047,7 +1210,7 @@ Revisions: } if (!err) -@@ -1625,11 +2342,12 @@ +@@ -1625,11 +2504,12 @@ */ static int @@ -1062,7 +1225,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2389,7 @@ +@@ -1671,7 +2551,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1071,7 +1234,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2402,8 @@ +@@ -1684,7 +2564,8 @@ } int @@ -1081,7 +1244,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2423,7 @@ +@@ -1704,7 +2585,7 @@ } char * @@ -1090,7 +1253,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2451,7 @@ +@@ -1732,7 +2613,7 @@ } char * @@ -1099,7 +1262,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2472,114 @@ +@@ -1753,199 +2634,114 @@ } int @@ -1382,7 +1545,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2595,11 @@ +@@ -1961,13 +2757,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1400,7 +1563,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2607,56 @@ +@@ -1975,119 +2769,56 @@ return 0; } @@ -1549,7 +1712,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2668,7 @@ +@@ -2099,7 +2830,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1558,7 +1721,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2684,7 @@ +@@ -2115,7 +2846,7 @@ if (! data) return grub_errno; @@ -1567,7 +1730,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2700,7 @@ +@@ -2131,11 +2862,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1579,7 +1742,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2708,36 @@ +@@ -2143,24 +2870,36 @@ if (! data) return grub_errno; @@ -1628,7 +1791,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2804,14 @@ +@@ -2227,12 +2966,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1645,7 +1808,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2827,7 @@ +@@ -2248,7 +2989,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1654,7 +1817,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +2881,7 @@ +@@ -2302,7 +3043,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1663,7 +1826,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +2970,39 @@ +@@ -2391,8 +3132,39 @@ return; } @@ -1705,7 +1868,7 @@ Revisions: return; } -@@ -2416,10 +3026,47 @@ +@@ -2416,10 +3188,47 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1757,7 +1920,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3179,13 @@ +@@ -2532,12 +3341,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From 1c703a3b634f07c0812ce888821eb5f6b9058cd1 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Wed, 9 Nov 2011 20:54:53 +0000 Subject: [PATCH 11/12] 3534: Support case-insensitive ZFS subvolumes --- debian/patches/zfs_update.patch | 367 +++++++++++++++++++++++++++++--- 1 file changed, 337 insertions(+), 30 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index 2667fb0c4..a53880e83 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -11,6 +11,7 @@ Revisions: 3520: Add ability to sustain a single drive failure on both raidz and raidz2 3521: Support raidz3 3533: Support second redundancy strip on raidz(2,3) +3534: Support case-insensitive ZFS subvolumes --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -962,7 +963,108 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -816,7 +1594,7 @@ +@@ -670,7 +1448,8 @@ + */ + static grub_err_t + mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, +- int objsize, char *name, grub_uint64_t * value) ++ int objsize, char *name, grub_uint64_t * value, ++ int case_insensitive) + { + int i, chunks; + mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; +@@ -678,7 +1457,8 @@ + chunks = objsize / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) + { +- if (grub_strcmp (mzap_ent[i].mze_name, name) == 0) ++ if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0) ++ : (grub_strcmp (mzap_ent[i].mze_name, name) == 0)) + { + *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian); + return GRUB_ERR_NONE; +@@ -711,7 +1491,8 @@ + } + + static grub_uint64_t +-zap_hash (grub_uint64_t salt, const char *name) ++zap_hash (grub_uint64_t salt, const char *name, ++ int case_insensitive) + { + static grub_uint64_t table[256]; + const grub_uint8_t *cp; +@@ -729,8 +1510,12 @@ + } + } + +- for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) +- crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF]; ++ if (case_insensitive) ++ for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) ++ crc = (crc >> 8) ^ table[(crc ^ grub_toupper (c)) & 0xFF]; ++ else ++ for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) ++ crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF]; + + /* + * Only use 28 bits, since we need 4 bits in the cookie for the +@@ -748,10 +1533,34 @@ + * array_len is actual len in bytes (not encoded le_value_length). + * buf is null-terminated. + */ ++ ++static inline int ++name_cmp (const char *s1, const char *s2, grub_size_t n, ++ int case_insensitive) ++{ ++ const char *t1 = (const char *) s1; ++ const char *t2 = (const char *) s2; ++ ++ if (!case_insensitive) ++ return grub_memcmp (t1, t2, n); ++ ++ while (n--) ++ { ++ if (grub_toupper (*t1) != grub_toupper (*t2)) ++ return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); ++ ++ t1++; ++ t2++; ++ } ++ ++ return 0; ++} ++ + /* XXX */ + static int + zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian, +- int blksft, int chunk, int array_len, const char *buf) ++ int blksft, int chunk, int array_len, const char *buf, ++ int case_insensitive) + { + int bseen = 0; + +@@ -763,7 +1572,8 @@ + if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) + return (0); + +- if (grub_memcmp (la->la_array, buf + bseen, toread) != 0) ++ if (name_cmp ((char *) la->la_array, buf + bseen, toread, ++ case_insensitive) != 0) + break; + chunk = grub_zfs_to_cpu16 (la->la_next, endian); + bseen += toread; +@@ -804,7 +1614,8 @@ + static grub_err_t + zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + int blksft, grub_uint64_t h, +- const char *name, grub_uint64_t * value) ++ const char *name, grub_uint64_t * value, ++ int case_insensitive) + { + grub_uint16_t chunk; + struct zap_leaf_entry *le; +@@ -816,7 +1627,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -971,7 +1073,12 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -840,7 +1618,8 @@ +@@ -836,11 +1647,12 @@ + if (zap_leaf_array_equal (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk,endian), + grub_zfs_to_cpu16 (le->le_name_length, endian), +- name)) ++ name, case_insensitive)) { struct zap_leaf_array *la; @@ -981,7 +1088,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1637,9 @@ +@@ -858,9 +1670,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -993,7 +1100,17 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -888,7 +1667,7 @@ +@@ -879,7 +1691,8 @@ + /* XXX */ + static grub_err_t + fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, +- char *name, grub_uint64_t * value, struct grub_zfs_data *data) ++ char *name, grub_uint64_t * value, struct grub_zfs_data *data, ++ int case_insensitive) + { + void *l; + grub_uint64_t hash, idx, blkid; +@@ -888,18 +1701,18 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -1002,7 +1119,11 @@ Revisions: if (err) return err; -@@ -899,7 +1678,7 @@ +- hash = zap_hash (zap->zap_salt, name); ++ hash = zap_hash (zap->zap_salt, name, case_insensitive); + + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "external pointer tables not supported"); idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); @@ -1011,7 +1132,17 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -922,14 +1701,14 @@ +@@ -908,7 +1721,8 @@ + if (err) + return err; + +- err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value); ++ err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value, ++ case_insensitive); + grub_free (l); + return err; + } +@@ -922,14 +1736,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -1028,7 +1159,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1724,17 @@ +@@ -945,9 +1759,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -1048,7 +1179,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1770,11 @@ +@@ -983,8 +1805,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -1062,7 +1193,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1786,9 @@ +@@ -996,7 +1821,9 @@ continue; /* get the uint64_t property value */ @@ -1073,7 +1204,36 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1074,7 +1866,7 @@ +@@ -1014,7 +1841,7 @@ + */ + static grub_err_t + zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val, +- struct grub_zfs_data *data) ++ struct grub_zfs_data *data, int case_insensitive) + { + grub_uint64_t block_type; + int size; +@@ -1037,7 +1864,8 @@ + if (block_type == ZBT_MICRO) + { + grub_dprintf ("zfs", "micro zap\n"); +- err = (mzap_lookup (zapbuf, endian, size, name, val)); ++ err = mzap_lookup (zapbuf, endian, size, name, val, ++ case_insensitive); + grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; +@@ -1046,7 +1874,8 @@ + { + grub_dprintf ("zfs", "fat zap\n"); + /* this is a fat zap */ +- err = (fzap_lookup (zap_dnode, zapbuf, name, val, data)); ++ err = fzap_lookup (zap_dnode, zapbuf, name, val, data, ++ case_insensitive); + grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; +@@ -1074,7 +1903,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -1082,7 +1242,63 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1291,22 +2083,54 @@ +@@ -1172,9 +2001,9 @@ + */ + static grub_err_t + dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, +- struct grub_zfs_data *data) ++ struct grub_zfs_data *data, int *case_insensitive) + { +- grub_uint64_t objnum, version; ++ grub_uint64_t objnum, version, insensitivity; + char *cname, ch; + grub_err_t err = GRUB_ERR_NONE; + char *path, *path_buf; +@@ -1199,19 +2028,31 @@ + return err; + } + +- err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, data); ++ err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, ++ data, 0); + if (err) + { + grub_free (dn_new); + return err; + } ++ + if (version > ZPL_VERSION) + { + grub_free (dn_new); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version"); + } +- +- err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data); ++ ++ err = zap_lookup (&(dnode_path->dn), "casesensitivity", &insensitivity, ++ data, 0); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ insensitivity = 0; ++ } ++ if (case_insensitive) ++ *case_insensitive = insensitivity; ++ ++ err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_free (dn_new); +@@ -1272,7 +2113,7 @@ + grub_free (path_buf); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + } +- err = zap_lookup (&(dnode_path->dn), cname, &objnum, data); ++ err = zap_lookup (&(dnode_path->dn), cname, &objnum, data, insensitivity); + if (err) + break; + +@@ -1291,22 +2132,54 @@ break; *path = ch; @@ -1146,7 +1362,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +2148,62 @@ +@@ -1324,7 +2197,62 @@ grub_free (dn_new); } } @@ -1210,7 +1426,52 @@ Revisions: } if (!err) -@@ -1625,11 +2504,12 @@ +@@ -1417,7 +2345,7 @@ + + grub_dprintf ("zfs", "alive\n"); + +- err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data); ++ err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0); + if (err) + return err; + +@@ -1452,7 +2380,7 @@ + if (err) + return err; + +- err = zap_lookup (mdn, cname, &objnum, data); ++ err = zap_lookup (mdn, cname, &objnum, data, 0); + if (err) + return err; + +@@ -1495,7 +2423,7 @@ + static grub_err_t + dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, + grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs, +- struct grub_zfs_data *data) ++ struct grub_zfs_data *data, int *case_insensitive) + { + char *fsname, *snapname; + const char *ptr_at, *filename; +@@ -1573,7 +2501,7 @@ + err = dnode_get (&(data->mos), snapobj, + DMU_OT_DSL_DS_SNAP_MAP, mdn, data); + if (!err) +- err = zap_lookup (mdn, snapname, &headobj, data); ++ err = zap_lookup (mdn, snapname, &headobj, data, 0); + if (!err) + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data); + if (err) +@@ -1597,7 +2525,7 @@ + grub_free (snapname); + return GRUB_ERR_NONE; + } +- err = dnode_get_path (mdn, filename, dn, data); ++ err = dnode_get_path (mdn, filename, dn, data, case_insensitive); + grub_free (fsname); + grub_free (snapname); + return err; +@@ -1625,11 +2553,12 @@ */ static int @@ -1225,7 +1486,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2551,7 @@ +@@ -1671,7 +2600,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1234,7 +1495,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2564,8 @@ +@@ -1684,7 +2613,8 @@ } int @@ -1244,7 +1505,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2585,7 @@ +@@ -1704,7 +2634,7 @@ } char * @@ -1253,7 +1514,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2613,7 @@ +@@ -1732,7 +2662,7 @@ } char * @@ -1262,7 +1523,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2634,114 @@ +@@ -1753,199 +2683,114 @@ } int @@ -1545,7 +1806,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2757,11 @@ +@@ -1961,13 +2806,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1563,7 +1824,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2769,56 @@ +@@ -1975,119 +2818,56 @@ return 0; } @@ -1712,7 +1973,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2830,7 @@ +@@ -2099,7 +2879,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1721,7 +1982,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2846,7 @@ +@@ -2115,7 +2895,7 @@ if (! data) return grub_errno; @@ -1730,7 +1991,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2862,7 @@ +@@ -2131,11 +2911,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -1742,7 +2003,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2870,36 @@ +@@ -2143,24 +2919,36 @@ if (! data) return grub_errno; @@ -1791,7 +2052,16 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2227,12 +2966,14 @@ +@@ -2177,7 +2965,7 @@ + return grub_errno; + + err = dnode_get_fullpath (fsfilename, &(data->mdn), 0, +- &(data->dnode), &isfs, data); ++ &(data->dnode), &isfs, data, NULL); + if (err) + { + zfs_unmount (data); +@@ -2227,12 +3015,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -1808,7 +2078,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +2989,7 @@ +@@ -2248,7 +3038,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -1817,7 +2087,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +3043,7 @@ +@@ -2302,7 +3092,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -1826,7 +2096,25 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2391,8 +3132,39 @@ +@@ -2339,7 +3129,7 @@ + return grub_errno; + + err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj, +- &(data->dnode), &isfs, data); ++ &(data->dnode), &isfs, data, NULL); + zfs_unmount (data); + return err; + } +@@ -2377,7 +3167,7 @@ + return; + } + +- err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data); ++ err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); +@@ -2391,8 +3181,39 @@ return; } @@ -1868,7 +2156,15 @@ Revisions: return; } -@@ -2416,10 +3188,47 @@ +@@ -2403,6 +3224,7 @@ + struct grub_zfs_data *data; + grub_err_t err; + int isfs; ++ int case_insensitive = 0; + auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val); + auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, + grub_uint64_t val); +@@ -2416,10 +3238,48 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -1907,6 +2203,7 @@ Revisions: + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); + info.mtimeset = 1; + info.mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); ++ info.case_insensitive = case_insensitive; + } + + if (dn.dn.dn_bonustype == DMU_OT_ZNODE) @@ -1920,7 +2217,17 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2532,12 +3341,13 @@ +@@ -2464,7 +3324,8 @@ + data = zfs_mount (device); + if (! data) + return grub_errno; +- err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data); ++ err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data, ++ &case_insensitive); + if (err) + { + zfs_unmount (data); +@@ -2532,12 +3393,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, From a850bd34e93fbacc1354ad0e5db36d08ea231f8c Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Thu, 10 Nov 2011 06:11:12 +0000 Subject: [PATCH 12/12] 3535: Support third redundancy strip on raidz3 --- debian/patches/zfs_update.patch | 261 +++++++++++++++++++++----------- 1 file changed, 176 insertions(+), 85 deletions(-) diff --git a/debian/patches/zfs_update.patch b/debian/patches/zfs_update.patch index a53880e83..12e4599e3 100644 --- a/debian/patches/zfs_update.patch +++ b/debian/patches/zfs_update.patch @@ -12,6 +12,7 @@ Revisions: 3521: Support raidz3 3533: Support second redundancy strip on raidz(2,3) 3534: Support case-insensitive ZFS subvolumes +3535: Support third redundancy strip on raidz3 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -146,7 +147,7 @@ Revisions: { grub_dprintf ("zfs", "dva=%llx, %llx\n", (unsigned long long) dva->dva_word[0], -@@ -401,6 +445,752 @@ +@@ -401,6 +445,842 @@ endian) << SPA_MINBLOCKSHIFT; } @@ -598,14 +599,15 @@ Revisions: + return powx[powx_inv[a] + powx_inv[b]]; +} + -+static inline void ++static inline grub_err_t +recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + const unsigned *powers, + const int *idx) +{ ++ grub_dprintf ("zfs", "recovering %u bufers\n", nbufs); + /* Now we have */ + /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/ -+ /* Since nbufs <= 3 let's be lazy. */ ++ /* Let's invert the matrix in question. */ + switch (nbufs) + { + /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */ @@ -614,39 +616,126 @@ Revisions: + int add; + grub_uint8_t *a; + if (powers[0] == 0 || idx[0] == 0) -+ return; ++ return GRUB_ERR_NONE; + add = 255 - ((powers[0] * idx[0]) % 255); + for (a = bufs[0]; s--; a++) + if (*a) + *a = powx[powx_inv[*a] + add]; -+ return; ++ return GRUB_ERR_NONE; + } -+ /* b_0 = r_0 * (x ** (powers[0] * idx[0])) + r_1 * (x ** (powers[0] * idx[1])) -+ b_1 = r_0 * (x ** (powers[1] * idx[0])) + r_1 * (x ** (powers[1] * idx[1])) -+ */ ++ /* Case 2x2: Let's use the determinant formula. */ + case 2: + { + grub_uint8_t det, det_inv; -+ grub_uint8_t det0, det1; ++ grub_uint8_t matrixinv[2][2]; + unsigned i; + /* The determinant is: */ + det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255] + ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]); ++ if (det == 0) ++ return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); + det_inv = powx[255 - powx_inv[det]]; ++ matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv); ++ matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv); ++ matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv); ++ matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv); + for (i = 0; i < s; i++) + { -+ det0 = (gf_mul (bufs[0][i], powx[(powers[1] * idx[1]) % 255]) -+ ^ gf_mul (bufs[1][i], powx[(powers[0] * idx[1]) % 255])); -+ det1 = (gf_mul (bufs[0][i], powx[(powers[1] * idx[0]) % 255]) -+ ^ gf_mul (bufs[1][i], powx[(powers[0] * idx[0]) % 255])); ++ grub_uint8_t b0, b1; ++ b0 = bufs[0][i]; ++ b1 = bufs[1][i]; + -+ bufs[0][i] = gf_mul (det0, det_inv); -+ bufs[1][i] = gf_mul (det1, det_inv); ++ bufs[0][i] = (gf_mul (b0, matrixinv[0][0]) ++ ^ gf_mul (b1, matrixinv[0][1])); ++ bufs[1][i] = (gf_mul (b0, matrixinv[1][0]) ++ ^ gf_mul (b1, matrixinv[1][1])); + } -+ break; ++ return GRUB_ERR_NONE; + } -+ } -+ ++ /* Otherwise use Gauss. */ ++ default: ++ { ++ grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs]; ++ int i, j, k; ++ ++ for (i = 0; i < nbufs; i++) ++ for (j = 0; j < nbufs; j++) ++ matrix1[i][j] = powx[(powers[i] * idx[j]) % 255]; ++ for (i = 0; i < nbufs; i++) ++ for (j = 0; j < nbufs; j++) ++ matrix2[i][j] = 0; ++ for (i = 0; i < nbufs; i++) ++ matrix2[i][i] = 1; ++ ++ for (i = 0; i < nbufs; i++) ++ { ++ grub_uint8_t mul; ++ for (j = i; j < nbufs; j++) ++ if (matrix1[i][j]) ++ break; ++ if (j == nbufs) ++ return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); ++ if (j != i) ++ { ++ int xchng; ++ xchng = j; ++ for (j = 0; j < nbufs; j++) ++ { ++ grub_uint8_t t; ++ t = matrix1[xchng][j]; ++ matrix1[xchng][j] = matrix1[i][j]; ++ matrix1[i][j] = t; ++ } ++ for (j = 0; j < nbufs; j++) ++ { ++ grub_uint8_t t; ++ t = matrix2[xchng][j]; ++ matrix2[xchng][j] = matrix2[i][j]; ++ matrix2[i][j] = t; ++ } ++ } ++ mul = powx[255 - powx_inv[matrix1[i][i]]]; ++ for (j = 0; j < nbufs; j++) ++ matrix1[i][j] = gf_mul (matrix1[i][j], mul); ++ for (j = 0; j < nbufs; j++) ++ matrix2[i][j] = gf_mul (matrix2[i][j], mul); ++ for (j = i + 1; j < nbufs; j++) ++ { ++ mul = matrix1[j][i]; ++ for (k = 0; k < nbufs; k++) ++ matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); ++ for (k = 0; k < nbufs; k++) ++ matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); ++ } ++ } ++ for (i = nbufs - 1; i >= 0; i--) ++ { ++ for (j = 0; j < i; j++) ++ { ++ grub_uint8_t mul; ++ mul = matrix1[j][i]; ++ for (k = 0; k < nbufs; k++) ++ matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); ++ for (k = 0; k < nbufs; k++) ++ matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); ++ } ++ } ++ ++ for (i = 0; i < (int) s; i++) ++ { ++ grub_uint8_t b[nbufs]; ++ for (j = 0; j < nbufs; j++) ++ b[j] = bufs[j][i]; ++ for (j = 0; j < nbufs; j++) ++ { ++ bufs[j][i] = 0; ++ for (k = 0; k < nbufs; k++) ++ bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]); ++ } ++ } ++ return GRUB_ERR_NONE; ++ } ++ } +} + +static grub_err_t @@ -745,10 +834,7 @@ Revisions: + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], + csize, buf); -+ /* No raidz3 recovery yet. */ -+ if (err -+ && failed_devices < desc->nparity -+ && failed_devices < 2) ++ if (err && failed_devices < desc->nparity) + { + recovery_buf[failed_devices] = buf; + recovery_len[failed_devices] = csize; @@ -771,6 +857,7 @@ Revisions: + unsigned cur_redundancy_pow = 0; + unsigned n_redundancy = 0; + unsigned i, j; ++ grub_err_t err; + + /* Compute mul. x**s has a period of 255. */ + if (powx[0] == 0) @@ -793,7 +880,6 @@ Revisions: + n_redundancy < failed_devices; + cur_redundancy_pow++) + { -+ grub_err_t err; + high = grub_divmod64_full ((offset >> desc->ashift) + + cur_redundancy_pow + + ((desc->nparity == 1) @@ -856,10 +942,15 @@ Revisions: + grub_uint8_t *tmp_recovery_buf[4]; + for (j = 0; j < i; j++) + tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[j] - 1; -+ recovery (tmp_recovery_buf, 1, i, redundancy_pow, recovery_idx); ++ err = recovery (tmp_recovery_buf, 1, i, redundancy_pow, ++ recovery_idx); ++ if (err) ++ return err; + } -+ recovery (recovery_buf, recovery_len[failed_devices - 1], -+ failed_devices, redundancy_pow, recovery_idx); ++ err = recovery (recovery_buf, recovery_len[failed_devices - 1], ++ failed_devices, redundancy_pow, recovery_idx); ++ if (err) ++ return err; + } + return GRUB_ERR_NONE; + } @@ -899,7 +990,7 @@ Revisions: /* * Read a block of data based on the gang block address dva, -@@ -412,7 +1202,6 @@ +@@ -412,7 +1292,6 @@ struct grub_zfs_data *data) { zio_gbh_phys_t *zio_gb; @@ -907,7 +998,7 @@ Revisions: unsigned i; grub_err_t err; zio_cksum_t zc; -@@ -424,13 +1213,8 @@ +@@ -424,13 +1303,8 @@ return grub_errno; grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); @@ -922,7 +1013,7 @@ Revisions: if (err) { grub_free (zio_gb); -@@ -483,20 +1267,13 @@ +@@ -483,20 +1357,13 @@ /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { @@ -944,7 +1035,7 @@ Revisions: if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; -@@ -527,7 +1304,7 @@ +@@ -527,7 +1394,7 @@ *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; @@ -953,7 +1044,7 @@ Revisions: lsize = (BP_IS_HOLE(bp) ? 0 : (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) << SPA_MINBLOCKSHIFT)); -@@ -602,7 +1379,8 @@ +@@ -602,7 +1469,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) { @@ -963,7 +1054,7 @@ Revisions: blkptr_t *bp_array = dn->dn.dn_blkptr; int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; blkptr_t *bp; -@@ -670,7 +1448,8 @@ +@@ -670,7 +1538,8 @@ */ static grub_err_t mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, @@ -973,7 +1064,7 @@ Revisions: { int i, chunks; mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; -@@ -678,7 +1457,8 @@ +@@ -678,7 +1547,8 @@ chunks = objsize / MZAP_ENT_LEN - 1; for (i = 0; i < chunks; i++) { @@ -983,7 +1074,7 @@ Revisions: { *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian); return GRUB_ERR_NONE; -@@ -711,7 +1491,8 @@ +@@ -711,7 +1581,8 @@ } static grub_uint64_t @@ -993,7 +1084,7 @@ Revisions: { static grub_uint64_t table[256]; const grub_uint8_t *cp; -@@ -729,8 +1510,12 @@ +@@ -729,8 +1600,12 @@ } } @@ -1008,7 +1099,7 @@ Revisions: /* * Only use 28 bits, since we need 4 bits in the cookie for the -@@ -748,10 +1533,34 @@ +@@ -748,10 +1623,34 @@ * array_len is actual len in bytes (not encoded le_value_length). * buf is null-terminated. */ @@ -1044,7 +1135,7 @@ Revisions: { int bseen = 0; -@@ -763,7 +1572,8 @@ +@@ -763,7 +1662,8 @@ if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) return (0); @@ -1054,7 +1145,7 @@ Revisions: break; chunk = grub_zfs_to_cpu16 (la->la_next, endian); bseen += toread; -@@ -804,7 +1614,8 @@ +@@ -804,7 +1704,8 @@ static grub_err_t zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, grub_uint64_t h, @@ -1064,7 +1155,7 @@ Revisions: { grub_uint16_t chunk; struct zap_leaf_entry *le; -@@ -816,7 +1627,7 @@ +@@ -816,7 +1717,7 @@ return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian); @@ -1073,7 +1164,7 @@ Revisions: { if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) -@@ -836,11 +1647,12 @@ +@@ -836,11 +1737,12 @@ if (zap_leaf_array_equal (l, endian, blksft, grub_zfs_to_cpu16 (le->le_name_chunk,endian), grub_zfs_to_cpu16 (le->le_name_length, endian), @@ -1088,7 +1179,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); /* get the uint64_t property value */ -@@ -858,9 +1670,9 @@ +@@ -858,9 +1760,9 @@ /* Verify if this is a fat zap header block */ static grub_err_t @@ -1100,7 +1191,7 @@ Revisions: return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); if (zap->zap_flags != 0) -@@ -879,7 +1691,8 @@ +@@ -879,7 +1781,8 @@ /* XXX */ static grub_err_t fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, @@ -1110,7 +1201,7 @@ Revisions: { void *l; grub_uint64_t hash, idx, blkid; -@@ -888,18 +1701,18 @@ +@@ -888,18 +1791,18 @@ grub_err_t err; grub_zfs_endian_t leafendian; @@ -1132,7 +1223,7 @@ Revisions: /* Get the leaf block */ if ((1U << blksft) < sizeof (zap_leaf_phys_t)) -@@ -908,7 +1721,8 @@ +@@ -908,7 +1811,8 @@ if (err) return err; @@ -1142,7 +1233,7 @@ Revisions: grub_free (l); return err; } -@@ -922,14 +1736,14 @@ +@@ -922,14 +1826,14 @@ { zap_leaf_phys_t *l; void *l_in; @@ -1159,7 +1250,7 @@ Revisions: return 0; /* get block id from index */ -@@ -945,9 +1759,17 @@ +@@ -945,9 +1849,17 @@ grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } @@ -1179,7 +1270,7 @@ Revisions: err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); l = l_in; -@@ -983,8 +1805,11 @@ +@@ -983,8 +1895,11 @@ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + 1); @@ -1193,7 +1284,7 @@ Revisions: { grub_free (buf); continue; -@@ -996,7 +1821,9 @@ +@@ -996,7 +1911,9 @@ continue; /* get the uint64_t property value */ @@ -1204,7 +1295,7 @@ Revisions: val = grub_be_to_cpu64 (la->la_array64); if (hook (buf, val)) return 1; -@@ -1014,7 +1841,7 @@ +@@ -1014,7 +1931,7 @@ */ static grub_err_t zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val, @@ -1213,7 +1304,7 @@ Revisions: { grub_uint64_t block_type; int size; -@@ -1037,7 +1864,8 @@ +@@ -1037,7 +1954,8 @@ if (block_type == ZBT_MICRO) { grub_dprintf ("zfs", "micro zap\n"); @@ -1223,7 +1314,7 @@ Revisions: grub_dprintf ("zfs", "returned %d\n", err); grub_free (zapbuf); return err; -@@ -1046,7 +1874,8 @@ +@@ -1046,7 +1964,8 @@ { grub_dprintf ("zfs", "fat zap\n"); /* this is a fat zap */ @@ -1233,7 +1324,7 @@ Revisions: grub_dprintf ("zfs", "returned %d\n", err); grub_free (zapbuf); return err; -@@ -1074,7 +1903,7 @@ +@@ -1074,7 +1993,7 @@ return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); @@ -1242,7 +1333,7 @@ Revisions: if (block_type == ZBT_MICRO) { -@@ -1172,9 +2001,9 @@ +@@ -1172,9 +2091,9 @@ */ static grub_err_t dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, @@ -1254,7 +1345,7 @@ Revisions: char *cname, ch; grub_err_t err = GRUB_ERR_NONE; char *path, *path_buf; -@@ -1199,19 +2028,31 @@ +@@ -1199,19 +2118,31 @@ return err; } @@ -1289,7 +1380,7 @@ Revisions: if (err) { grub_free (dn_new); -@@ -1272,7 +2113,7 @@ +@@ -1272,7 +2203,7 @@ grub_free (path_buf); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); } @@ -1298,7 +1389,7 @@ Revisions: if (err) break; -@@ -1291,22 +2132,54 @@ +@@ -1291,22 +2222,54 @@ break; *path = ch; @@ -1362,7 +1453,7 @@ Revisions: grub_memcpy (path + grub_strlen (path), oldpath, grub_strlen (oldpath) + 1); -@@ -1324,7 +2197,62 @@ +@@ -1324,7 +2287,62 @@ grub_free (dn_new); } } @@ -1426,7 +1517,7 @@ Revisions: } if (!err) -@@ -1417,7 +2345,7 @@ +@@ -1417,7 +2435,7 @@ grub_dprintf ("zfs", "alive\n"); @@ -1435,7 +1526,7 @@ Revisions: if (err) return err; -@@ -1452,7 +2380,7 @@ +@@ -1452,7 +2470,7 @@ if (err) return err; @@ -1444,7 +1535,7 @@ Revisions: if (err) return err; -@@ -1495,7 +2423,7 @@ +@@ -1495,7 +2513,7 @@ static grub_err_t dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs, @@ -1453,7 +1544,7 @@ Revisions: { char *fsname, *snapname; const char *ptr_at, *filename; -@@ -1573,7 +2501,7 @@ +@@ -1573,7 +2591,7 @@ err = dnode_get (&(data->mos), snapobj, DMU_OT_DSL_DS_SNAP_MAP, mdn, data); if (!err) @@ -1462,7 +1553,7 @@ Revisions: if (!err) err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data); if (err) -@@ -1597,7 +2525,7 @@ +@@ -1597,7 +2615,7 @@ grub_free (snapname); return GRUB_ERR_NONE; } @@ -1471,7 +1562,7 @@ Revisions: grub_free (fsname); grub_free (snapname); return err; -@@ -1625,11 +2553,12 @@ +@@ -1625,11 +2643,12 @@ */ static int @@ -1486,7 +1577,7 @@ Revisions: /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all -@@ -1671,7 +2600,7 @@ +@@ -1671,7 +2690,7 @@ if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { @@ -1495,7 +1586,7 @@ Revisions: *size_out = encode_size; if (nelm_out) *nelm_out = nelm; -@@ -1684,7 +2613,8 @@ +@@ -1684,7 +2703,8 @@ } int @@ -1505,7 +1596,7 @@ Revisions: { char *nvpair; grub_size_t size; -@@ -1704,7 +2634,7 @@ +@@ -1704,7 +2724,7 @@ } char * @@ -1514,7 +1605,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1732,7 +2662,7 @@ +@@ -1732,7 +2752,7 @@ } char * @@ -1523,7 +1614,7 @@ Revisions: { char *nvpair; char *ret; -@@ -1753,199 +2683,114 @@ +@@ -1753,199 +2773,114 @@ } int @@ -1806,7 +1897,7 @@ Revisions: grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); -@@ -1961,13 +2806,11 @@ +@@ -1961,13 +2896,11 @@ zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; @@ -1824,7 +1915,7 @@ Revisions: if (! dev->disk) { -@@ -1975,119 +2818,56 @@ +@@ -1975,119 +2908,56 @@ return 0; } @@ -1973,7 +2064,7 @@ Revisions: } grub_err_t -@@ -2099,7 +2879,7 @@ +@@ -2099,7 +2969,7 @@ zfs = zfs_mount (dev); if (!zfs) return grub_errno; @@ -1982,7 +2073,7 @@ Revisions: zfs_unmount (zfs); return err; } -@@ -2115,7 +2895,7 @@ +@@ -2115,7 +2985,7 @@ if (! data) return grub_errno; @@ -1991,7 +2082,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2131,11 +2911,7 @@ +@@ -2131,11 +3001,7 @@ static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { @@ -2003,7 +2094,7 @@ Revisions: *uuid = 0; -@@ -2143,24 +2919,36 @@ +@@ -2143,24 +3009,36 @@ if (! data) return grub_errno; @@ -2052,7 +2143,7 @@ Revisions: /* * zfs_open() locates a file in the rootpool by following the * MOS and places the dnode of the file in the memory address DNODE. -@@ -2177,7 +2965,7 @@ +@@ -2177,7 +3055,7 @@ return grub_errno; err = dnode_get_fullpath (fsfilename, &(data->mdn), 0, @@ -2061,7 +2152,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2227,12 +3015,14 @@ +@@ -2227,12 +3105,14 @@ } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); @@ -2078,7 +2169,7 @@ Revisions: file->data = data; file->offset = 0; -@@ -2248,7 +3038,7 @@ +@@ -2248,7 +3128,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; @@ -2087,7 +2178,7 @@ Revisions: grub_size_t length; grub_size_t read; grub_err_t err; -@@ -2302,7 +3092,7 @@ +@@ -2302,7 +3182,7 @@ data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; @@ -2096,7 +2187,7 @@ Revisions: grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); -@@ -2339,7 +3129,7 @@ +@@ -2339,7 +3219,7 @@ return grub_errno; err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj, @@ -2105,7 +2196,7 @@ Revisions: zfs_unmount (data); return err; } -@@ -2377,7 +3167,7 @@ +@@ -2377,7 +3257,7 @@ return; } @@ -2114,7 +2205,7 @@ Revisions: if (err) { grub_dprintf ("zfs", "failed here\n"); -@@ -2391,8 +3181,39 @@ +@@ -2391,8 +3271,39 @@ return; } @@ -2156,7 +2247,7 @@ Revisions: return; } -@@ -2403,6 +3224,7 @@ +@@ -2403,6 +3314,7 @@ struct grub_zfs_data *data; grub_err_t err; int isfs; @@ -2164,7 +2255,7 @@ Revisions: auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val); auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, grub_uint64_t val); -@@ -2416,10 +3238,48 @@ +@@ -2416,10 +3328,48 @@ grub_memset (&info, 0, sizeof (info)); dnode_get (&(data->mdn), val, 0, &dn, data); @@ -2217,7 +2308,7 @@ Revisions: (int)dn.dn.dn_type, (char *)name); return hook (name, &info); } -@@ -2464,7 +3324,8 @@ +@@ -2464,7 +3414,8 @@ data = zfs_mount (device); if (! data) return grub_errno; @@ -2227,7 +2318,7 @@ Revisions: if (err) { zfs_unmount (data); -@@ -2532,12 +3393,13 @@ +@@ -2532,12 +3483,13 @@ .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid,