Index: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h =================================================================== --- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -772,6 +772,7 @@ * Label manipulation. */ extern int zpool_read_label(int, nvlist_t **); +extern int zpool_read_all_labels(int, nvlist_t **); extern int zpool_clear_label(int); /* is this zvol valid for use as a dump device? */ Index: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c =================================================================== --- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c +++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c @@ -914,6 +914,65 @@ return (0); } +/* + * Given a file descriptor, read the label information and return an nvlist + * describing the configuration, if there is one. + * returns the number of valid labels found + */ +int +zpool_read_all_labels(int fd, nvlist_t **config) +{ + struct stat64 statbuf; + int l; + vdev_label_t *label; + uint64_t state, txg, size; + int nlabels = 0; + + *config = NULL; + + if (fstat64(fd, &statbuf) == -1) + return (0); + size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); + + if ((label = malloc(sizeof (vdev_label_t))) == NULL) + return (0); + + for (l = 0; l < VDEV_LABELS; l++) { + nvlist_t *temp = NULL; + + /* TODO: use aio_read so we can read al 4 labels in parallel */ + if (pread64(fd, label, sizeof (vdev_label_t), + label_offset(size, l)) != sizeof (vdev_label_t)) + continue; + + if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, + sizeof (label->vl_vdev_phys.vp_nvlist), &temp, 0) != 0) + continue; + + if (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_STATE, + &state) != 0 || state > POOL_STATE_L2CACHE) { + nvlist_free(temp); + temp = NULL; + continue; + } + + if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE && + (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_TXG, + &txg) != 0 || txg == 0)) { + nvlist_free(temp); + temp = NULL; + continue; + } + if (temp) + *config = temp; + + nlabels++; + } + + free(label); + return (nlabels); +} + typedef struct rdsk_node { char *rn_name; int rn_dfd; Index: head/cddl/usr.sbin/zfsd/zfsd_event.cc =================================================================== --- head/cddl/usr.sbin/zfsd/zfsd_event.cc +++ head/cddl/usr.sbin/zfsd/zfsd_event.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -93,6 +94,7 @@ pool_state_t poolState; char *poolName; boolean_t b_inuse; + int nlabels; inUse = false; degraded = false; @@ -105,8 +107,16 @@ if (poolName != NULL) free(poolName); - if (zpool_read_label(devFd, &devLabel) != 0 - || devLabel == NULL) + nlabels = zpool_read_all_labels(devFd, &devLabel); + /* + * If we find a disk with fewer than the maximum number of + * labels, it might be the whole disk of a partitioned disk + * where ZFS resides on a partition. In that case, we should do + * nothing and wait for the partition to appear. Or, the disk + * might be damaged. In that case, zfsd should do nothing and + * wait for the sysadmin to decide. + */ + if (nlabels != VDEV_LABELS || devLabel == NULL) return (NULL); try {