Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c @@ -61,6 +61,9 @@ SYSCTL_INT(_vfs_zfs_vdev, OID_AUTO, bio_delete_disable, CTLFLAG_RWTUN, &vdev_geom_bio_delete_disable, 0, "Disable BIO_DELETE"); +/* Declare local functions */ +static void vdev_geom_detach(struct g_consumer *cp, boolean_t open_for_read); + /* * Thread local storage used to indicate when a thread is probing geoms * for their guids. If NULL, this thread is not tasting geoms. If non NULL, @@ -168,6 +171,17 @@ g_topology_assert(); ZFS_LOG(1, "Attaching to %s.", pp->name); + + if (pp->sectorsize > VDEV_PAD_SIZE || !ISP2(pp->sectorsize)) { + ZFS_LOG(1, "Failing attach of %s. Incompatible sectorsize %d\n", + pp->name, pp->sectorsize); + return (NULL); + } else if (pp->mediasize < SPA_MINDEVSIZE) { + ZFS_LOG(1, "Failing attach of %s. Incompatible mediasize %ju\n", + pp->name, pp->mediasize); + return (NULL); + } + /* Do we have geom already? No? Create one. */ LIST_FOREACH(gp, &zfs_vdev_class.geom, geom) { if (gp->flags & G_GEOM_WITHER) @@ -185,14 +199,14 @@ if (error != 0) { ZFS_LOG(1, "%s(%d): g_attach failed: %d\n", __func__, __LINE__, error); - g_wither_geom(gp, ENXIO); + vdev_geom_detach(cp, B_FALSE); return (NULL); } error = g_access(cp, 1, 0, 1); if (error != 0) { ZFS_LOG(1, "%s(%d): g_access failed: %d\n", __func__, __LINE__, error); - g_wither_geom(gp, ENXIO); + vdev_geom_detach(cp, B_FALSE); return (NULL); } ZFS_LOG(1, "Created geom and consumer for %s.", pp->name); @@ -210,15 +224,14 @@ if (error != 0) { ZFS_LOG(1, "%s(%d): g_attach failed: %d\n", __func__, __LINE__, error); - g_destroy_consumer(cp); + vdev_geom_detach(cp, B_FALSE); return (NULL); } error = g_access(cp, 1, 0, 1); if (error != 0) { ZFS_LOG(1, "%s(%d): g_access failed: %d\n", __func__, __LINE__, error); - g_detach(cp); - g_destroy_consumer(cp); + vdev_geom_detach(cp, B_FALSE); return (NULL); } ZFS_LOG(1, "Created consumer for %s.", pp->name); @@ -244,39 +257,41 @@ * 2) Set it to a linked list of vdevs, not just a single vdev */ cp->private = vd; - vd->vdev_tsd = cp; + if (vd != NULL) + vd->vdev_tsd = cp; cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; return (cp); } static void -vdev_geom_close_locked(vdev_t *vd) +vdev_geom_detach(struct g_consumer *cp, boolean_t open_for_read) { struct g_geom *gp; - struct g_consumer *cp; + vdev_t *vd; g_topology_assert(); - cp = vd->vdev_tsd; - if (cp == NULL) - return; + ZFS_LOG(1, "Detaching consumer. Provider %s.", + cp->provider && cp->provider->name ? cp->provider->name : "NULL"); - ZFS_LOG(1, "Closing access to %s.", cp->provider->name); - KASSERT(vd->vdev_tsd == cp, ("%s: vdev_tsd is not cp", __func__)); - vd->vdev_tsd = NULL; - vd->vdev_delayed_close = B_FALSE; + vd = cp->private; + if (vd != NULL) { + vd->vdev_tsd = NULL; + vd->vdev_delayed_close = B_FALSE; + } cp->private = NULL; gp = cp->geom; - g_access(cp, -1, 0, -1); + if (open_for_read) + g_access(cp, -1, 0, -1); /* Destroy consumer on last close. */ if (cp->acr == 0 && cp->ace == 0) { if (cp->acw > 0) g_access(cp, 0, -cp->acw, 0); if (cp->provider != NULL) { - ZFS_LOG(1, "Destroyed consumer to %s.", - cp->provider->name); + ZFS_LOG(1, "Destroying consumer to %s.", + cp->provider->name ? cp->provider->name : "NULL"); g_detach(cp); } g_destroy_consumer(cp); @@ -289,6 +304,22 @@ } static void +vdev_geom_close_locked(vdev_t *vd) +{ + struct g_consumer *cp; + + g_topology_assert(); + + cp = vd->vdev_tsd; + if (cp == NULL) + return; + + ZFS_LOG(1, "Closing access to %s.", cp->provider->name); + + vdev_geom_detach(cp, B_TRUE); +} + +static void nvlist_get_guids(nvlist_t *list, uint64_t *pguid, uint64_t *vguid) { @@ -331,13 +362,6 @@ return (error); } -static void -vdev_geom_taste_orphan(struct g_consumer *cp) -{ - ZFS_LOG(0, "WARNING: Orphan %s while tasting its VDev GUID.", - cp->provider->name); -} - static int vdev_geom_read_config(struct g_consumer *cp, nvlist_t **config) { @@ -470,41 +494,12 @@ nvlist_free(cfg); } -static int -vdev_geom_attach_taster(struct g_consumer *cp, struct g_provider *pp) -{ - int error; - - if (pp->flags & G_PF_WITHER) - return (EINVAL); - g_attach(cp, pp); - error = g_access(cp, 1, 0, 0); - if (error == 0) { - if (pp->sectorsize > VDEV_PAD_SIZE || !ISP2(pp->sectorsize)) - error = EINVAL; - else if (pp->mediasize < SPA_MINDEVSIZE) - error = EINVAL; - if (error != 0) - g_access(cp, -1, 0, 0); - } - if (error != 0) - g_detach(cp); - return (error); -} - -static void -vdev_geom_detach_taster(struct g_consumer *cp) -{ - g_access(cp, -1, 0, 0); - g_detach(cp); -} - int vdev_geom_read_pool_label(const char *name, nvlist_t ***configs, uint64_t *count) { struct g_class *mp; - struct g_geom *gp, *zgp; + struct g_geom *gp; struct g_provider *pp; struct g_consumer *zcp; nvlist_t *vdev_cfg; @@ -514,11 +509,6 @@ DROP_GIANT(); g_topology_lock(); - zgp = g_new_geomf(&zfs_vdev_class, "zfs::vdev::taste"); - /* This orphan function should be never called. */ - zgp->orphan = vdev_geom_taste_orphan; - zcp = g_new_consumer(zgp); - *configs = NULL; *count = 0; pool_guid = 0; @@ -531,12 +521,13 @@ LIST_FOREACH(pp, &gp->provider, provider) { if (pp->flags & G_PF_WITHER) continue; - if (vdev_geom_attach_taster(zcp, pp) != 0) + zcp = vdev_geom_attach(pp, NULL); + if (zcp == NULL) continue; g_topology_unlock(); error = vdev_geom_read_config(zcp, &vdev_cfg); g_topology_lock(); - vdev_geom_detach_taster(zcp); + vdev_geom_detach(zcp, B_TRUE); if (error) continue; ZFS_LOG(1, "successfully read vdev config"); @@ -546,9 +537,6 @@ } } } - - g_destroy_consumer(zcp); - g_destroy_geom(zgp); g_topology_unlock(); PICKUP_GIANT(); @@ -570,21 +558,55 @@ } } +static boolean_t +vdev_attach_ok(vdev_t *vd, struct g_provider *pp) +{ + uint64_t pool_guid; + uint64_t vdev_guid; + struct g_consumer *zcp; + boolean_t pool_ok; + boolean_t vdev_ok; + + zcp = vdev_geom_attach(pp, NULL); + if (zcp == NULL) { + ZFS_LOG(1, "Unable to attach tasting instance to %s.", + pp->name); + return (B_FALSE); + } + g_topology_unlock(); + vdev_geom_read_guids(zcp, &pool_guid, &vdev_guid); + g_topology_lock(); + vdev_geom_detach(zcp, B_TRUE); + + /* + * Check that the label's vdev guid matches the desired guid. If the + * label has a pool guid, check that it matches too. (Inactive spares + * and L2ARCs do not have any pool guid in the label.) + */ + if ((pool_guid == 0 || pool_guid == spa_guid(vd->vdev_spa)) && + vdev_guid == vd->vdev_guid) { + ZFS_LOG(1, "guids match for provider %s.", vd->vdev_path); + return (B_TRUE); + } else { + ZFS_LOG(1, "guid mismatch for provider %s: " + "%ju:%ju != %ju:%ju.", vd->vdev_path, + (uintmax_t)spa_guid(vd->vdev_spa), + (uintmax_t)vd->vdev_guid, + (uintmax_t)pool_guid, (uintmax_t)vdev_guid); + return (B_FALSE); + } +} + static struct g_consumer * vdev_geom_attach_by_guids(vdev_t *vd) { struct g_class *mp; - struct g_geom *gp, *zgp; + struct g_geom *gp; struct g_provider *pp; - struct g_consumer *cp, *zcp; - uint64_t pguid, vguid; + struct g_consumer *cp; g_topology_assert(); - zgp = g_new_geomf(&zfs_vdev_class, "zfs::vdev::taste"); - zgp->orphan = vdev_geom_taste_orphan; - zcp = g_new_consumer(zgp); - cp = NULL; LIST_FOREACH(mp, &g_classes, class) { if (mp == &zfs_vdev_class) @@ -593,22 +615,7 @@ if (gp->flags & G_GEOM_WITHER) continue; LIST_FOREACH(pp, &gp->provider, provider) { - if (vdev_geom_attach_taster(zcp, pp) != 0) - continue; - g_topology_unlock(); - vdev_geom_read_guids(zcp, &pguid, &vguid); - g_topology_lock(); - vdev_geom_detach_taster(zcp); - /* - * Check that the label's vdev guid matches the - * desired guid. If the label has a pool guid, - * check that it matches too. (Inactive spares - * and L2ARCs do not have any pool guid in the - * label.) - */ - if ((pguid != 0 && - pguid != spa_guid(vd->vdev_spa)) || - vguid != vd->vdev_guid) + if (!vdev_attach_ok(vd, pp)) continue; cp = vdev_geom_attach(pp, vd); if (cp == NULL) { @@ -625,8 +632,6 @@ break; } end: - g_destroy_consumer(zcp); - g_destroy_geom(zgp); return (cp); } @@ -667,7 +672,6 @@ { struct g_provider *pp; struct g_consumer *cp; - uint64_t pguid, vguid; g_topology_assert(); @@ -675,34 +679,8 @@ pp = g_provider_by_name(vd->vdev_path + sizeof("/dev/") - 1); if (pp != NULL) { ZFS_LOG(1, "Found provider by name %s.", vd->vdev_path); - cp = vdev_geom_attach(pp, vd); - if (cp != NULL && check_guid && ISP2(pp->sectorsize) && - pp->sectorsize <= VDEV_PAD_SIZE) { - g_topology_unlock(); - vdev_geom_read_guids(cp, &pguid, &vguid); - g_topology_lock(); - /* - * Check that the label's vdev guid matches the - * desired guid. If the label has a pool guid, - * check that it matches too. (Inactive spares - * and L2ARCs do not have any pool guid in the - * label.) - */ - if ((pguid != 0 && - pguid != spa_guid(vd->vdev_spa)) || - vguid != vd->vdev_guid) { - vdev_geom_close_locked(vd); - cp = NULL; - ZFS_LOG(1, "guid mismatch for provider %s: " - "%ju:%ju != %ju:%ju.", vd->vdev_path, - (uintmax_t)spa_guid(vd->vdev_spa), - (uintmax_t)vd->vdev_guid, - (uintmax_t)pguid, (uintmax_t)vguid); - } else { - ZFS_LOG(1, "guid match for provider %s.", - vd->vdev_path); - } - } + if (!check_guid || vdev_attach_ok(vd, pp)) + cp = vdev_geom_attach(pp, vd); } return (cp);