diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c --- a/stand/libsa/zfs/zfsimpl.c +++ b/stand/libsa/zfs/zfsimpl.c @@ -1267,6 +1267,19 @@ return (rc); } +static void +vdev_free(struct vdev *vdev) +{ + struct vdev *kid, *safe; + + STAILQ_FOREACH_SAFE(kid, &vdev->v_children, v_childlink, safe) + vdev_free(kid); + /* See comment in vdev_create(). Root vdev isn't linked. */ + if (vdev->v_read != NULL) + STAILQ_REMOVE(&zfs_vdevs, vdev, vdev, v_alllink); + free(vdev); +} + static int vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) { @@ -1373,13 +1386,6 @@ spa->spa_uberblock = &spa->spa_uberblock_master; spa->spa_mos = &spa->spa_mos_master; spa->spa_guid = guid; - spa->spa_root_vdev = vdev_create(guid, NULL); - if (spa->spa_root_vdev == NULL) { - free(spa->spa_name); - free(spa); - return (NULL); - } - spa->spa_root_vdev->v_name = strdup("root"); STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); return (spa); @@ -2006,7 +2012,7 @@ vdev_t *vdev; nvlist_t *nvl; uint64_t val; - uint64_t guid, vdev_children; + uint64_t guid; uint64_t pool_txg, pool_guid; const char *pool_name; int rc, namelen; @@ -2067,7 +2073,9 @@ nvlist_find(nvl, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, NULL, &pool_guid, NULL) != 0 || nvlist_find(nvl, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, - NULL, &pool_name, &namelen) != 0) { + NULL, &pool_name, &namelen) != 0 || + nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid, NULL) != 0) { /* * Cache and spare devices end up here - just ignore * them. @@ -2083,8 +2091,6 @@ if (spa == NULL) { char *name; - nvlist_find(nvl, ZPOOL_CONFIG_VDEV_CHILDREN, - DATA_TYPE_UINT64, NULL, &vdev_children, NULL); name = malloc(namelen + 1); if (name == NULL) { nvlist_destroy(nvl); @@ -2098,10 +2104,22 @@ nvlist_destroy(nvl); return (ENOMEM); } - spa->spa_root_vdev->v_nchildren = vdev_children; + } else if (pool_txg > spa->spa_txg) { + printf("ZFS: pool %s ignoring stale config:txg 0x%jx:0x%jx, " + "new config:txg 0x%jx:0x%jx\n", spa->spa_name, + spa->spa_root_vdev->v_guid, spa->spa_txg, + guid, pool_txg); + vdev_free(spa->spa_root_vdev); + spa->spa_root_vdev = NULL; } - if (pool_txg > spa->spa_txg) + + if (spa->spa_root_vdev == NULL) { + spa->spa_root_vdev = vdev_create(pool_guid, NULL); + if (spa->spa_root_vdev == NULL) + return (ENOMEM); + spa->spa_root_vdev->v_name = spa->spa_name; spa->spa_txg = pool_txg; + } /* * Get the vdev tree and create our in-core copy of it. @@ -2109,11 +2127,6 @@ * be some kind of alias (overlapping slices, dangerously dedicated * disks etc). */ - if (nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid, NULL) != 0) { - nvlist_destroy(nvl); - return (EIO); - } vdev = vdev_find(guid); /* Has this vdev already been inited? */ if (vdev && vdev->v_phys_read) { @@ -3541,8 +3554,10 @@ return (EIO); } rc = load_nvlist(spa, config_object, &nvlist); - if (rc != 0) + if (rc != 0) { + printf("ZFS: failed to load pool %s nvlist\n", spa->spa_name); return (rc); + } rc = zap_lookup(spa, &dir, DMU_POOL_ZPOOL_CHECKPOINT, sizeof(uint64_t), sizeof(checkpoint) / sizeof(uint64_t),