summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h1
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c85
-rw-r--r--cddl/usr.sbin/zfsd/zfsd_event.cc19
3 files changed, 102 insertions, 3 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
index f2a9ebf..9133238 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
@@ -774,6 +774,7 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
* 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? */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
index 1bbb8c5..a8da5b4 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
@@ -42,6 +42,7 @@
* using our derived config, and record the results.
*/
+#include <aio.h>
#include <ctype.h>
#include <devid.h>
#include <dirent.h>
@@ -915,6 +916,90 @@ zpool_read_label(int fd, nvlist_t **config)
return (-1);
}
+/*
+ * 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
+ * If a label is found, returns it via config. The caller is responsible for
+ * freeing it.
+ */
+int
+zpool_read_all_labels(int fd, nvlist_t **config)
+{
+ struct stat64 statbuf;
+ struct aiocb aiocbs[VDEV_LABELS];
+ struct aiocb *aiocbps[VDEV_LABELS];
+ int l;
+ vdev_phys_t *labels;
+ 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 ((labels = calloc(VDEV_LABELS, sizeof (vdev_phys_t))) == NULL)
+ return (0);
+
+ memset(aiocbs, 0, sizeof(aiocbs));
+ for (l = 0; l < VDEV_LABELS; l++) {
+ aiocbs[l].aio_fildes = fd;
+ aiocbs[l].aio_offset = label_offset(size, l) + VDEV_SKIP_SIZE;
+ aiocbs[l].aio_buf = &labels[l];
+ aiocbs[l].aio_nbytes = sizeof(vdev_phys_t);
+ aiocbs[l].aio_lio_opcode = LIO_READ;
+ aiocbps[l] = &aiocbs[l];
+ }
+
+ if (lio_listio(LIO_WAIT, aiocbps, VDEV_LABELS, NULL) != 0) {
+ if (errno == EAGAIN || errno == EINTR || errno == EIO) {
+ for (l = 0; l < VDEV_LABELS; l++) {
+ errno = 0;
+ int r = aio_error(&aiocbs[l]);
+ if (r != EINVAL)
+ (void)aio_return(&aiocbs[l]);
+ }
+ }
+ free(labels);
+ return (0);
+ }
+
+ for (l = 0; l < VDEV_LABELS; l++) {
+ nvlist_t *temp = NULL;
+
+ if (aio_return(&aiocbs[l]) != sizeof(vdev_phys_t))
+ continue;
+
+ if (nvlist_unpack(labels[l].vp_nvlist,
+ sizeof (labels[l].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(labels);
+ return (nlabels);
+}
+
typedef struct rdsk_node {
char *rn_name;
int rn_dfd;
diff --git a/cddl/usr.sbin/zfsd/zfsd_event.cc b/cddl/usr.sbin/zfsd/zfsd_event.cc
index c10cc18..5594b35 100644
--- a/cddl/usr.sbin/zfsd/zfsd_event.cc
+++ b/cddl/usr.sbin/zfsd/zfsd_event.cc
@@ -36,6 +36,7 @@
#include <sys/cdefs.h>
#include <sys/time.h>
#include <sys/fs/zfs.h>
+#include <sys/vdev_impl.h>
#include <syslog.h>
@@ -93,21 +94,32 @@ DevfsEvent::ReadLabel(int devFd, bool &inUse, bool &degraded)
pool_state_t poolState;
char *poolName;
boolean_t b_inuse;
+ int nlabels;
inUse = false;
degraded = false;
poolName = NULL;
if (zpool_in_use(g_zfsHandle, devFd, &poolState,
&poolName, &b_inuse) == 0) {
- nvlist_t *devLabel;
+ nvlist_t *devLabel = NULL;
inUse = b_inuse == B_TRUE;
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) {
+ nvlist_free(devLabel);
return (NULL);
+ }
try {
Vdev vdev(devLabel);
@@ -121,6 +133,7 @@ DevfsEvent::ReadLabel(int devFd, bool &inUse, bool &degraded)
exp.GetString().insert(0, context);
exp.Log();
+ nvlist_free(devLabel);
}
}
return (NULL);
OpenPOWER on IntegriCloud