diff options
author | Toomas Soome <tsoome@FreeBSD.org> | 2020-07-09 13:19:00 +0000 |
---|---|---|
committer | Toomas Soome <tsoome@FreeBSD.org> | 2020-07-09 13:19:00 +0000 |
commit | 1a4b982e1e22dc0bbcddbff082ee16abb2874871 (patch) | |
tree | 59132734e3aa258a9cc1d9c1ef6ce5fde510225e /stand | |
parent | b23a7fbaab633193caf11799f36eed4dc86b3fb0 (diff) | |
download | src-1a4b982e1e22dc0bbcddbff082ee16abb2874871.tar.gz src-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.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c index effd7cf0f1b3..0e97e06245b3 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); |