summaryrefslogtreecommitdiff
path: root/stand
diff options
context:
space:
mode:
authorToomas Soome <tsoome@FreeBSD.org>2020-07-09 13:19:00 +0000
committerToomas Soome <tsoome@FreeBSD.org>2020-07-09 13:19:00 +0000
commit1a4b982e1e22dc0bbcddbff082ee16abb2874871 (patch)
tree59132734e3aa258a9cc1d9c1ef6ce5fde510225e /stand
parentb23a7fbaab633193caf11799f36eed4dc86b3fb0 (diff)
downloadsrc-test-1a4b982e1e22dc0bbcddbff082ee16abb2874871.tar.gz
src-test-1a4b982e1e22dc0bbcddbff082ee16abb2874871.zip
loader: setting vdev size based on label asize is not working
Because we need to read asize from vdev_tree. We also need to consider different vdev type difference. Reviewed by: allanjude Sponsored by: Netflix, Klara Inc. Differential Revision: https://reviews.freebsd.org/D25586
Notes
Notes: svn path=/head/; revision=363042
Diffstat (limited to 'stand')
-rw-r--r--stand/libsa/zfs/zfsimpl.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index effd7cf0f1b3d..0e97e06245b39 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -1586,6 +1586,57 @@ vdev_label_read(vdev_t *vd, int l, void *buf, uint64_t offset,
return (vdev_read_phys(vd, &bp, buf, off, size));
}
+static uint64_t
+vdev_get_label_asize(nvlist_t *nvl)
+{
+ nvlist_t *vdevs;
+ uint64_t asize;
+ const char *type;
+ int len;
+
+ asize = 0;
+ /* Get vdev tree */
+ if (nvlist_find(nvl, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST,
+ NULL, &vdevs, NULL) != 0)
+ return (asize);
+
+ /*
+ * Get vdev type. We will calculate asize for raidz, mirror and disk.
+ * For raidz, the asize is raw size of all children.
+ */
+ if (nvlist_find(vdevs, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING,
+ NULL, &type, &len) != 0)
+ goto done;
+
+ if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 &&
+ memcmp(type, VDEV_TYPE_DISK, len) != 0 &&
+ memcmp(type, VDEV_TYPE_RAIDZ, len) != 0)
+ goto done;
+
+ if (nvlist_find(vdevs, ZPOOL_CONFIG_ASIZE, DATA_TYPE_UINT64,
+ NULL, &asize, NULL) != 0)
+ goto done;
+
+ if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) {
+ nvlist_t *kids;
+ int nkids;
+
+ if (nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN,
+ DATA_TYPE_NVLIST_ARRAY, &nkids, &kids, NULL) != 0) {
+ asize = 0;
+ goto done;
+ }
+
+ asize /= nkids;
+ nvlist_destroy(kids);
+ }
+
+ asize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE;
+done:
+ nvlist_destroy(vdevs);
+ return (asize);
+}
+
static nvlist_t *
vdev_label_read_config(vdev_t *vd, uint64_t txg)
{
@@ -1631,10 +1682,9 @@ vdev_label_read_config(vdev_t *vd, uint64_t txg)
* Use asize from pool config. We need this
* because we can get bad value from BIOS.
*/
- if (nvlist_find(nvl, ZPOOL_CONFIG_ASIZE,
- DATA_TYPE_UINT64, NULL, &asize, NULL) == 0) {
- vd->v_psize = asize +
- VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE;
+ asize = vdev_get_label_asize(nvl);
+ if (asize != 0) {
+ vd->v_psize = asize;
}
}
nvlist_destroy(tmp);