Fix RAIDZ(2).
* grub-core/fs/zfs/zfs.c (grub_zfs_device_desc): New member ashift. (fill_vdev_info_real): Set ashift. (read_device): Rewrite RAIDZ part based on reverse engineering.
This commit is contained in:
parent
7c01e783dc
commit
ce8ca56ed9
2 changed files with 64 additions and 14 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2011-11-01 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Fix RAIDZ(2).
|
||||||
|
|
||||||
|
* grub-core/fs/zfs/zfs.c (grub_zfs_device_desc): New member ashift.
|
||||||
|
(fill_vdev_info_real): Set ashift.
|
||||||
|
(read_device): Rewrite RAIDZ part based on reverse engineering.
|
||||||
|
|
||||||
2011-10-31 Vladimir Serbinenko <phcoder@gmail.com>
|
2011-10-31 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* grub-core/fs/btrfs.c (grub_btrfs_extent_read): Add sanity check and
|
* grub-core/fs/btrfs.c (grub_btrfs_extent_read): Add sanity check and
|
||||||
|
|
|
@ -152,6 +152,7 @@ struct grub_zfs_device_desc
|
||||||
|
|
||||||
/* Valid only for RAIDZ. */
|
/* Valid only for RAIDZ. */
|
||||||
unsigned nparity;
|
unsigned nparity;
|
||||||
|
unsigned ashift;
|
||||||
|
|
||||||
/* Valid only for leaf devices. */
|
/* Valid only for leaf devices. */
|
||||||
grub_device_t dev;
|
grub_device_t dev;
|
||||||
|
@ -516,6 +517,9 @@ fill_vdev_info_real (struct grub_zfs_data *data,
|
||||||
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par))
|
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par))
|
||||||
return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
|
return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
|
||||||
fill->nparity = par;
|
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);
|
nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, ZPOOL_CONFIG_CHILDREN);
|
||||||
|
@ -882,36 +886,74 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
|
||||||
}
|
}
|
||||||
case DEVICE_RAIDZ:
|
case DEVICE_RAIDZ:
|
||||||
{
|
{
|
||||||
grub_uint64_t sector;
|
|
||||||
grub_uint32_t bsize;
|
|
||||||
unsigned c = 0;
|
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;
|
/* (4,1) -> 2, (3,1) -> 1 */
|
||||||
sector = offset >> 9;
|
if (desc->nparity == 1)
|
||||||
|
s = asize + desc->n_children - 2;
|
||||||
|
else
|
||||||
|
s = asize + desc->n_children - 3;
|
||||||
|
high = grub_divmod64 ((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)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
grub_size_t csize;
|
grub_size_t csize;
|
||||||
grub_uint64_t high;
|
grub_uint32_t bsize;
|
||||||
grub_uint64_t devn;
|
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
high = grub_divmod64 (sector + (asize > 2) + c, desc->n_children,
|
bsize = s / desc->n_children;
|
||||||
&devn);
|
|
||||||
csize = bsize << 9;
|
while (1)
|
||||||
|
{
|
||||||
|
high = grub_divmod64 ((offset >> desc->ashift) + c,
|
||||||
|
desc->n_children, &devn);
|
||||||
|
if (devn != redundancy_strip && devn != redundancy_strip2)
|
||||||
|
break;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
csize = bsize << desc->ashift;
|
||||||
if (csize > len)
|
if (csize > len)
|
||||||
csize = len;
|
csize = len;
|
||||||
|
|
||||||
grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T
|
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",
|
PRIxGRUB_UINT64_T ")\n",
|
||||||
sector,(asize > 2), c, high, devn);
|
offset >> desc->ashift, c, asize, bsize, high,
|
||||||
err = read_device (high << 9, &desc->children[devn],
|
devn);
|
||||||
|
err = read_device ((high << desc->ashift)
|
||||||
|
| (offset & ((1 << desc->ashift) - 1)),
|
||||||
|
&desc->children[devn],
|
||||||
bsize, csize, buf);
|
bsize, csize, buf);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
c++;
|
c++;
|
||||||
|
s--;
|
||||||
buf = (char *) buf + csize;
|
buf = (char *) buf + csize;
|
||||||
len -= csize;
|
len -= csize;
|
||||||
}
|
}
|
||||||
return GRUB_ERR_NONE;
|
|
||||||
}
|
}
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue