enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
grub_uint64_t id;
grub_uint64_t guid;
+ unsigned ashift;
/* Valid only for non-leafs. */
unsigned n_children;
/* Valid only for RAIDZ. */
unsigned nparity;
- unsigned ashift;
/* Valid only for leaf devices. */
grub_device_t dev;
* Three pieces of information are needed to verify an uberblock: the magic
* number, the version number, and the checksum.
*
- * Currently Implemented: version number, magic number
- * Need to Implement: checksum
+ * Currently Implemented: version number, magic number, checksum
*
*/
static grub_err_t
-uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset)
+uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
+ grub_size_t s)
{
uberblock_t *uber = &ub->ubp_uberblock;
grub_err_t err;
zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
- (char *) ub, UBERBLOCK_SIZE);
+ (char *) ub, s);
return err;
}
* Failure - NULL
*/
static uberblock_phys_t *
-find_bestub (uberblock_phys_t * ub_array, grub_disk_addr_t sector)
+find_bestub (uberblock_phys_t * ub_array,
+ const struct grub_zfs_device_desc *desc)
{
- uberblock_phys_t *ubbest = NULL;
+ uberblock_phys_t *ubbest = NULL, *ubptr;
int i;
grub_disk_addr_t offset;
grub_err_t err = GRUB_ERR_NONE;
+ int ub_shift;
+
+ ub_shift = desc->ashift;
+ if (ub_shift < VDEV_UBERBLOCK_SHIFT)
+ ub_shift = VDEV_UBERBLOCK_SHIFT;
- for (i = 0; i < (VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT); i++)
+ for (i = 0; i < (VDEV_UBERBLOCK_RING >> ub_shift); i++)
{
- offset = (sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE
- + (i << VDEV_UBERBLOCK_SHIFT);
+ offset = (desc->vdev_phys_sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE
+ + (i << ub_shift);
- err = uberblock_verify (&ub_array[i], offset);
+ ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array
+ + ((i << ub_shift)
+ / sizeof (grub_properly_aligned_t)));
+ err = uberblock_verify (ubptr, offset, 1 << ub_shift);
if (err)
{
grub_errno = GRUB_ERR_NONE;
continue;
}
if (ubbest == NULL
- || vdev_uberblock_compare (&(ub_array[i].ubp_uberblock),
+ || vdev_uberblock_compare (&(ubptr->ubp_uberblock),
&(ubbest->ubp_uberblock)) > 0)
- ubbest = &ub_array[i];
+ ubbest = ubptr;
}
if (!ubbest)
grub_errno = err;
const char *nvlist,
struct grub_zfs_device_desc *fill,
struct grub_zfs_device_desc *insert,
- int *inserted)
+ int *inserted,
+ unsigned ashift)
{
char *type;
return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
}
+ {
+ grub_uint64_t par;
+ if (grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par))
+ fill->ashift = par;
+ else if (ashift != 0xffffffff)
+ fill->ashift = ashift;
+ else
+ {
+ grub_free (type);
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find ashift");
+ }
+ }
+
if (grub_strcmp (type, VDEV_TYPE_DISK) == 0
|| grub_strcmp (type, VDEV_TYPE_FILE) == 0)
{
fill->original = insert->original;
if (!data->device_original)
data->device_original = fill;
+ insert->ashift = fill->ashift;
*inserted = 1;
}
return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
}
fill->nparity = par;
- if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par))
- {
- grub_free (type);
- 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,
(nvlist, ZPOOL_CONFIG_CHILDREN, i);
err = fill_vdev_info_real (data, child, &fill->children[i], insert,
- inserted);
+ inserted, fill->ashift);
grub_free (child);
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, inserted);
+ diskdesc, inserted, 0xffffffff);
data->n_devices_attached++;
if (data->n_devices_attached > data->n_devices_allocated)
return fill_vdev_info_real (data, nvlist,
&data->devices_attached[data->n_devices_attached - 1],
- diskdesc, inserted);
+ diskdesc, inserted, 0xffffffff);
}
/*
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)
+ + (label < VDEV_LABELS / 2 ? 0 :
+ ALIGN_DOWN (grub_disk_get_size (dev->disk), sizeof (vdev_label_t))
- VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT));
/* Read in the uberblock ring (128K). */
}
grub_dprintf ("zfs", "label ok %d\n", label);
- ubbest = find_bestub (ub_array, desc.vdev_phys_sector);
+ err = check_pool_label (data, &desc, inserted);
+ if (err || !*inserted)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+
+ ubbest = find_bestub (ub_array, &desc);
if (!ubbest)
{
grub_dprintf ("zfs", "No uberblock found\n");
grub_memmove (&(data->current_uberblock),
&ubbest->ubp_uberblock, sizeof (uberblock_t));
- err = check_pool_label (data, &desc, inserted);
- if (err)
- {
- grub_errno = GRUB_ERR_NONE;
- continue;
- }
#if 0
if (find_best_root &&
vdev_uberblock_compare (&ubbest->ubp_uberblock,