summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-04-02 11:09:47 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-04-02 11:09:47 +0000
commit080b163baec0c5a81b2717cf504cac1e0e1f143f (patch)
tree4eacda3b227a9fa30fbb91930f726a8eeb045ba3
parentee42d232c75feb49ab18a118a8a3b7fc3ea9f0c4 (diff)
parent30c304d9746f4a048a7de56d31333b0fa8e43dee (diff)
downloadillumos-joyent-080b163baec0c5a81b2717cf504cac1e0e1f143f.tar.gz
[illumos-gate merge]
commit 30c304d9746f4a048a7de56d31333b0fa8e43dee 7119 boot should handle change in physical path to ZFS root devices commit 476d5ff73c235a63ab06a9852e510910a3ce1793 12432 vntsd: NULL pointer errors commit 86e38daa32bf0ca85f79384da2d3e43bf87f328b 12402 audiocmihd: variable may be used uninitialized commit f70049b72ff8162093254e3d617172d6df9705f1 12415 ecpp: variable may be used uninitialized
-rw-r--r--usr/src/cmd/vntsd/console.c34
-rw-r--r--usr/src/cmd/vntsd/read.c3
-rw-r--r--usr/src/cmd/vntsd/vntsd.c2
-rw-r--r--usr/src/cmd/vntsd/vntsdvcc.c8
-rw-r--r--usr/src/cmd/vntsd/write.c3
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c46
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa_boot.h5
-rw-r--r--usr/src/uts/common/fs/zfs/sys/vdev_impl.h9
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_disk.c181
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c68
-rw-r--r--usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c8
-rw-r--r--usr/src/uts/common/io/ecpp.c2
-rw-r--r--usr/src/uts/common/os/devcfg.c103
-rw-r--r--usr/src/uts/common/sys/ddi_implfuncs.h11
-rw-r--r--usr/src/uts/intel/zfs/spa_boot.c11
-rw-r--r--usr/src/uts/sparc/zfs/spa_boot.c11
17 files changed, 447 insertions, 62 deletions
diff --git a/usr/src/cmd/vntsd/console.c b/usr/src/cmd/vntsd/console.c
index 6cd29c5f7c..543f117e8d 100644
--- a/usr/src/cmd/vntsd/console.c
+++ b/usr/src/cmd/vntsd/console.c
@@ -22,7 +22,6 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Listen thread creates a console thread whenever there is a tcp client
@@ -95,8 +94,7 @@ write_connect_msg(vntsd_client_t *clientp, char *group_name,
}
if ((rv = vntsd_write_line(clientp,
- gettext("Press ~? for control options .."))) !=
- VNTSD_SUCCESS) {
+ gettext("Press ~? for control options .."))) != VNTSD_SUCCESS) {
return (rv);
}
@@ -112,7 +110,7 @@ create_write_thread(vntsd_cons_t *consp)
/* create write thread for the console */
(void) mutex_lock(&consp->lock);
if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread,
- (void *)consp, NULL, &consp->wr_tid)) {
+ (void *)consp, 0, &consp->wr_tid)) {
DERR(stderr, "t@%d create_rd_wr_thread@%d: "
"create write thread failed\n",
@@ -156,7 +154,7 @@ list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp)
(void) mutex_lock(&groupp->lock);
if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name,
- &(clientp->sockfd)) != NULL) {
+ &(clientp->sockfd)) != NULL) {
rv = VNTSD_ERR_WRITE_CLIENT;
}
@@ -172,8 +170,8 @@ display_help(vntsd_client_t *clientp)
int rv = VNTSD_SUCCESS;
char *bufp;
- if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
- != VNTSD_SUCCESS) {
+ rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN);
+ if (rv != VNTSD_SUCCESS) {
return (rv);
}
@@ -208,7 +206,7 @@ display_help(vntsd_client_t *clientp)
*/
bufp = gettext("c{id}, n{name} -- connect to a console of domain {id}"
- " or domain {name}");
+ " or domain {name}");
if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
return (rv);
@@ -234,7 +232,7 @@ name_to_cons_no(vntsd_group_t *groupp, char *name)
vntsd_cons_t *consp;
consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq,
- (compare_func_t)cons_by_name, name);
+ (compare_func_t)cons_by_name, name);
if (consp == NULL) {
return (-1);
@@ -280,7 +278,7 @@ select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp,
case 'c':
/* c{id} or c {id} */
if (isspace(buf[i])) {
- continue;
+ continue;
}
if (!isdigit(buf[i])) {
@@ -293,7 +291,7 @@ select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp,
case 'n':
/* n{name) or n {name} */
if (isspace(buf[i])) {
- continue;
+ continue;
}
buf[n-1] = 0;
@@ -318,7 +316,7 @@ select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp,
(void) mutex_lock(&groupp->lock);
*consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq,
- (compare_func_t)vntsd_cons_by_consno, &cons_no);
+ (compare_func_t)vntsd_cons_by_consno, &cons_no);
if (*consp == NULL) {
/* during console selection, the console has been deleted */
@@ -487,13 +485,13 @@ read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd)
clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD;
(void) mutex_unlock(&clientp->lock);
- if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
- != VNTSD_SUCCESS) {
+ rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN);
+ if (rv != VNTSD_SUCCESS) {
return (rv);
}
- if ((rv = vntsd_write_client(clientp, prompt, strlen(prompt)))
- != VNTSD_SUCCESS) {
+ rv = vntsd_write_client(clientp, prompt, strlen(prompt));
+ if (rv != VNTSD_SUCCESS) {
return (rv);
}
@@ -778,11 +776,11 @@ vntsd_console_thread(vntsd_thr_arg_t *argp)
}
if (snprintf(prompt, sizeof (prompt),
- "%s-vnts-%s: h, l, c{id}, n{name}, q:",
+ "%s-vnts-%s: h, l, c{id}, n{name}, q:",
buf, groupp->group_name) >= sizeof (prompt)) {
/* long prompt doesn't fit, use short one */
(void) snprintf(prompt, sizeof (prompt),
- "vnts: h, l, c{id}, n{name}, q:");
+ "vnts: h, l, c{id}, n{name}, q:");
}
diff --git a/usr/src/cmd/vntsd/read.c b/usr/src/cmd/vntsd/read.c
index d3cc711603..75b377cd02 100644
--- a/usr/src/cmd/vntsd/read.c
+++ b/usr/src/cmd/vntsd/read.c
@@ -18,7 +18,6 @@
*
* CDDL HEADER END
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
@@ -284,5 +283,5 @@ vntsd_read(vntsd_client_t *clientp)
}
/*NOTREACHED*/
- return (NULL);
+ return (0);
}
diff --git a/usr/src/cmd/vntsd/vntsd.c b/usr/src/cmd/vntsd/vntsd.c
index d32d88f3f3..9fd07d2b69 100644
--- a/usr/src/cmd/vntsd/vntsd.c
+++ b/usr/src/cmd/vntsd/vntsd.c
@@ -358,7 +358,7 @@ main(int argc, char ** argv)
"descriptor limit.");
(void) enable_extended_FILE_stdio(-1, -1);
- vntsdp = calloc(sizeof (vntsd_t), 1);
+ vntsdp = calloc(1, sizeof (vntsd_t));
if (vntsdp == NULL) {
vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp");
exit(1);
diff --git a/usr/src/cmd/vntsd/vntsdvcc.c b/usr/src/cmd/vntsd/vntsdvcc.c
index ff93bc36cc..4274c0ff7d 100644
--- a/usr/src/cmd/vntsd/vntsdvcc.c
+++ b/usr/src/cmd/vntsd/vntsdvcc.c
@@ -22,7 +22,6 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Configuration and setup interface to vcc driver.
@@ -206,7 +205,7 @@ vntsd_delete_cons(vntsd_t *vntsdp)
(void) mutex_lock(&groupp->vntsd->lock);
(void) vntsd_que_rm(&groupp->vntsd->grouppq,
- groupp);
+ groupp);
(void) mutex_unlock(&groupp->vntsd->lock);
/* clean up the group */
@@ -459,7 +458,7 @@ alloc_cons_with_group(vntsd_t *vntsdp, vcc_console_t *consp,
/* intialize console */
if (alloc_cons(groupp, consp) == NULL) {
/* no memory */
- if (new_groupp != NULL) {
+ if (*new_groupp != NULL) {
/* clean up new group */
free_group(groupp);
}
@@ -488,8 +487,7 @@ create_listen_thread(vntsd_group_t *groupp)
D1(stderr, "t@%d create_listen:%lld\n", thr_self(), groupp->tcp_port);
if ((rv = thr_create(NULL, 0, (thr_func_t)vntsd_listen_thread,
- (void *)groupp, THR_DETACHED, &groupp->listen_tid))
- != 0) {
+ (void *)groupp, THR_DETACHED, &groupp->listen_tid)) != 0) {
(void) (void) snprintf(err_msg, sizeof (err_msg),
"Can not create listen thread for"
"group %s tcp %llx\n", groupp->group_name,
diff --git a/usr/src/cmd/vntsd/write.c b/usr/src/cmd/vntsd/write.c
index 9110056c11..a56c60e7dd 100644
--- a/usr/src/cmd/vntsd/write.c
+++ b/usr/src/cmd/vntsd/write.c
@@ -22,7 +22,6 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* write thread - read from vcc console and write to tcp client. There are one
@@ -198,7 +197,7 @@ write_one_client(vntsd_client_t *clientp, write_buf_t *write_buf)
(void) mutex_lock(&clientp->lock);
clientp->status |= VNTSD_CLIENT_IO_ERR;
assert(clientp->cons);
- (void) thr_kill(clientp->cons_tid, NULL);
+ (void) thr_kill(clientp->cons_tid, 0);
(void) mutex_unlock(&clientp->lock);
}
return (B_FALSE);
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 95c35a0f5f..193e65c229 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -31,6 +31,7 @@
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2017 Datto Inc.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
/*
@@ -5375,10 +5376,9 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
* Get the root pool information from the root disk, then import the root pool
* during the system boot up time.
*/
-extern int vdev_disk_read_rootlabel(char *, char *, nvlist_t **);
-
static nvlist_t *
-spa_generate_rootconf(char *devpath, char *devid, uint64_t *guid)
+spa_generate_rootconf(const char *devpath, const char *devid, uint64_t *guid,
+ uint64_t pool_guid)
{
nvlist_t *config;
nvlist_t *nvtop, *nvroot;
@@ -5396,6 +5396,19 @@ spa_generate_rootconf(char *devpath, char *devid, uint64_t *guid)
&pgid) == 0);
VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, guid) == 0);
+ if (pool_guid != 0 && pool_guid != pgid) {
+ /*
+ * The boot loader provided a pool GUID, but it does not match
+ * the one we found in the label. Return failure so that we
+ * can fall back to the full device scan.
+ */
+ zfs_dbgmsg("spa_generate_rootconf: loader pool guid %llu != "
+ "label pool guid %llu", (u_longlong_t)pool_guid,
+ (u_longlong_t)pgid);
+ nvlist_free(config);
+ return (NULL);
+ }
+
/*
* Put this pool's top-level vdevs into a root vdev.
*/
@@ -5462,7 +5475,8 @@ spa_alt_rootvdev(vdev_t *vd, vdev_t **avd, uint64_t *txg)
* "/pci@1f,0/ide@d/disk@0,0:a"
*/
int
-spa_import_rootpool(char *devpath, char *devid)
+spa_import_rootpool(char *devpath, char *devid, uint64_t pool_guid,
+ uint64_t vdev_guid)
{
spa_t *spa;
vdev_t *rvd, *bvd, *avd = NULL;
@@ -5470,11 +5484,12 @@ spa_import_rootpool(char *devpath, char *devid)
uint64_t guid, txg;
char *pname;
int error;
+ const char *altdevpath = NULL;
/*
* Read the label from the boot device and generate a configuration.
*/
- config = spa_generate_rootconf(devpath, devid, &guid);
+ config = spa_generate_rootconf(devpath, devid, &guid, pool_guid);
#if defined(_OBP) && defined(_KERNEL)
if (config == NULL) {
if (strstr(devpath, "/iscsi/ssd") != NULL) {
@@ -5484,6 +5499,27 @@ spa_import_rootpool(char *devpath, char *devid)
}
}
#endif
+
+ /*
+ * We were unable to import the pool using the /devices path or devid
+ * provided by the boot loader. This may be the case if the boot
+ * device has been connected to a different location in the system, or
+ * if a new boot environment has changed the driver used to access the
+ * boot device.
+ *
+ * Attempt an exhaustive scan of all visible block devices to see if we
+ * can locate an alternative /devices path with a label that matches
+ * the expected pool and vdev GUID.
+ */
+ if (config == NULL && (altdevpath =
+ vdev_disk_preroot_lookup(pool_guid, vdev_guid)) != NULL) {
+ cmn_err(CE_NOTE, "Original /devices path (%s) not available; "
+ "ZFS is trying an alternate path (%s)", devpath,
+ altdevpath);
+ config = spa_generate_rootconf(altdevpath, NULL, &guid,
+ pool_guid);
+ }
+
if (config == NULL) {
cmn_err(CE_NOTE, "Cannot read the pool label from '%s'",
devpath);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index e017462613..31faac4f77 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -28,6 +28,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017, Intel Corporation.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#ifndef _SYS_SPA_H
@@ -759,7 +760,8 @@ extern int spa_get_stats(const char *pool, nvlist_t **config, char *altroot,
size_t buflen);
extern int spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
nvlist_t *zplprops, struct dsl_crypto_params *dcp);
-extern int spa_import_rootpool(char *devpath, char *devid);
+extern int spa_import_rootpool(char *devpath, char *devid, uint64_t pool_guid,
+ uint64_t vdev_guid);
extern int spa_import(const char *pool, nvlist_t *config, nvlist_t *props,
uint64_t flags);
extern nvlist_t *spa_tryimport(nvlist_t *tryconfig);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa_boot.h b/usr/src/uts/common/fs/zfs/sys/spa_boot.h
index 8df5072a55..b1b100e17e 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa_boot.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa_boot.h
@@ -25,6 +25,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#ifndef _SYS_SPA_BOOT_H
@@ -36,8 +37,8 @@
extern "C" {
#endif
-extern char *spa_get_bootprop(char *prop);
-extern void spa_free_bootprop(char *prop);
+extern char *spa_get_bootprop(const char *propname);
+extern void spa_free_bootprop(char *propval);
extern void spa_arch_init(void);
diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
index 774ed92db5..fc0f90c8c9 100644
--- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
@@ -24,6 +24,7 @@
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
* Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#ifndef _SYS_VDEV_IMPL_H
@@ -556,6 +557,14 @@ typedef struct vdev_buf {
zio_t *vb_io; /* pointer back to the original zio_t */
} vdev_buf_t;
+/*
+ * Support routines used during boot from a ZFS pool
+ */
+extern int vdev_disk_read_rootlabel(const char *, const char *, nvlist_t **);
+extern void vdev_disk_preroot_init(void);
+extern void vdev_disk_preroot_fini(void);
+extern const char *vdev_disk_preroot_lookup(uint64_t, uint64_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/fs/zfs/vdev_disk.c b/usr/src/uts/common/fs/zfs/vdev_disk.c
index 9408ec68fb..4be567d551 100644
--- a/usr/src/uts/common/fs/zfs/vdev_disk.c
+++ b/usr/src/uts/common/fs/zfs/vdev_disk.c
@@ -23,6 +23,7 @@
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2020 Joyent, Inc.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#include <sys/zfs_context.h>
@@ -365,7 +366,6 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
error = EINVAL; /* presume failure */
if (vd->vdev_path != NULL) {
-
if (vd->vdev_wholedisk == -1ULL) {
size_t len = strlen(vd->vdev_path) + 3;
char *buf = kmem_alloc(len, KM_SLEEP);
@@ -480,6 +480,28 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
}
}
+ /*
+ * If this is early in boot, a sweep of available block devices may
+ * locate an alternative path that we can try.
+ */
+ if (error != 0) {
+ const char *altdevpath = vdev_disk_preroot_lookup(
+ spa_guid(spa), vd->vdev_guid);
+
+ if (altdevpath != NULL) {
+ vdev_dbgmsg(vd, "Trying alternate preroot path (%s)",
+ altdevpath);
+
+ validate_devid = B_TRUE;
+
+ if ((error = ldi_open_by_name((char *)altdevpath,
+ spa_mode(spa), kcred, &dvd->vd_lh, zfs_li)) != 0) {
+ vdev_dbgmsg(vd, "Failed to open by preroot "
+ "path (%s)", altdevpath);
+ }
+ }
+ }
+
if (error != 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]",
@@ -1063,7 +1085,8 @@ vdev_ops_t vdev_disk_ops = {
* the device, and construct a configuration nvlist.
*/
int
-vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
+vdev_disk_read_rootlabel(const char *devpath, const char *devid,
+ nvlist_t **config)
{
ldi_handle_t vd_lh;
vdev_label_t *label;
@@ -1076,7 +1099,7 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
/*
* Read the device label and build the nvlist.
*/
- if (devid != NULL && ddi_devid_str_decode(devid, &tmpdevid,
+ if (devid != NULL && ddi_devid_str_decode((char *)devid, &tmpdevid,
&minor_name) == 0) {
error = ldi_open_by_devid(tmpdevid, minor_name,
FREAD, kcred, &vd_lh, zfs_li);
@@ -1084,9 +1107,10 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
ddi_devid_str_free(minor_name);
}
- if (error && (error = ldi_open_by_name(devpath, FREAD, kcred, &vd_lh,
- zfs_li)))
+ if (error != 0 && (error = ldi_open_by_name((char *)devpath, FREAD,
+ kcred, &vd_lh, zfs_li)) != 0) {
return (error);
+ }
if (ldi_get_size(vd_lh, &s)) {
(void) ldi_close(vd_lh, FREAD, kcred);
@@ -1136,3 +1160,150 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
return (error);
}
+
+struct veb {
+ list_t veb_ents;
+ boolean_t veb_scanned;
+};
+
+struct veb_ent {
+ uint64_t vebe_pool_guid;
+ uint64_t vebe_vdev_guid;
+
+ char *vebe_devpath;
+
+ list_node_t vebe_link;
+};
+
+static kmutex_t veb_lock;
+static struct veb *veb;
+
+static int
+vdev_disk_preroot_scan_walk(const char *devpath, void *arg)
+{
+ int r;
+ nvlist_t *cfg = NULL;
+ uint64_t pguid = 0, vguid = 0;
+
+ /*
+ * Attempt to read the label from this block device.
+ */
+ if ((r = vdev_disk_read_rootlabel(devpath, NULL, &cfg)) != 0) {
+ /*
+ * Many of the available block devices will represent slices or
+ * partitions of disks, or may represent disks that are not at
+ * all initialised with ZFS. As this is a best effort
+ * mechanism to locate an alternate path to a particular vdev,
+ * we will ignore any failures and keep scanning.
+ */
+ return (PREROOT_WALK_BLOCK_DEVICES_NEXT);
+ }
+
+ /*
+ * Determine the pool and vdev GUID read from the label for this
+ * device. Both values must be present and have a non-zero value.
+ */
+ if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &pguid) != 0 ||
+ nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_GUID, &vguid) != 0 ||
+ pguid == 0 || vguid == 0) {
+ /*
+ * This label was not complete.
+ */
+ goto out;
+ }
+
+ /*
+ * Keep track of all of the GUID-to-devpath mappings we find so that
+ * vdev_disk_preroot_lookup() can search them.
+ */
+ struct veb_ent *vebe = kmem_zalloc(sizeof (*vebe), KM_SLEEP);
+ vebe->vebe_pool_guid = pguid;
+ vebe->vebe_vdev_guid = vguid;
+ vebe->vebe_devpath = spa_strdup(devpath);
+
+ list_insert_tail(&veb->veb_ents, vebe);
+
+out:
+ nvlist_free(cfg);
+ return (PREROOT_WALK_BLOCK_DEVICES_NEXT);
+}
+
+const char *
+vdev_disk_preroot_lookup(uint64_t pool_guid, uint64_t vdev_guid)
+{
+ if (pool_guid == 0 || vdev_guid == 0) {
+ /*
+ * If we aren't provided both a pool and a vdev GUID, we cannot
+ * perform a lookup.
+ */
+ return (NULL);
+ }
+
+ mutex_enter(&veb_lock);
+ if (veb == NULL) {
+ /*
+ * If vdev_disk_preroot_fini() has been called already, there
+ * is nothing we can do.
+ */
+ mutex_exit(&veb_lock);
+ return (NULL);
+ }
+
+ /*
+ * We want to perform at most one scan of all block devices per boot.
+ */
+ if (!veb->veb_scanned) {
+ cmn_err(CE_NOTE, "Performing full ZFS device scan!");
+
+ preroot_walk_block_devices(vdev_disk_preroot_scan_walk, NULL);
+
+ veb->veb_scanned = B_TRUE;
+ }
+
+ const char *path = NULL;
+ for (struct veb_ent *vebe = list_head(&veb->veb_ents); vebe != NULL;
+ vebe = list_next(&veb->veb_ents, vebe)) {
+ if (vebe->vebe_pool_guid == pool_guid &&
+ vebe->vebe_vdev_guid == vdev_guid) {
+ path = vebe->vebe_devpath;
+ break;
+ }
+ }
+
+ mutex_exit(&veb_lock);
+
+ return (path);
+}
+
+void
+vdev_disk_preroot_init(void)
+{
+ mutex_init(&veb_lock, NULL, MUTEX_DEFAULT, NULL);
+
+ VERIFY3P(veb, ==, NULL);
+ veb = kmem_zalloc(sizeof (*veb), KM_SLEEP);
+ list_create(&veb->veb_ents, sizeof (struct veb_ent),
+ offsetof(struct veb_ent, vebe_link));
+ veb->veb_scanned = B_FALSE;
+}
+
+void
+vdev_disk_preroot_fini(void)
+{
+ mutex_enter(&veb_lock);
+
+ if (veb != NULL) {
+ while (!list_is_empty(&veb->veb_ents)) {
+ struct veb_ent *vebe = list_remove_head(&veb->veb_ents);
+
+ spa_strfree(vebe->vebe_devpath);
+
+ kmem_free(vebe, sizeof (*vebe));
+ }
+
+ kmem_free(veb, sizeof (*veb));
+ veb = NULL;
+ }
+
+ mutex_exit(&veb_lock);
+}
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 6b61cd7a84..47c4a190cf 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -25,6 +25,7 @@
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -64,10 +65,12 @@
#include <sys/zfs_ctldir.h>
#include <sys/zfs_fuid.h>
#include <sys/bootconf.h>
+#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/dnlc.h>
#include <sys/dmu_objset.h>
#include <sys/spa_boot.h>
+#include <sys/vdev_impl.h>
#include "zfs_comutil.h"
int zfsfstype;
@@ -1711,6 +1714,36 @@ zfs_mount_label_policy(vfs_t *vfsp, char *osname)
return (retv);
}
+/*
+ * Load a string-valued boot property and attempt to convert it to a 64-bit
+ * unsigned integer. If the value is not present, or the conversion fails,
+ * return the provided default value.
+ */
+static uint64_t
+spa_get_bootprop_uint64(const char *name, uint64_t defval)
+{
+ char *propval;
+ u_longlong_t r;
+ int e;
+
+ if ((propval = spa_get_bootprop(name)) == NULL) {
+ /*
+ * The property does not exist.
+ */
+ return (defval);
+ }
+
+ e = ddi_strtoull(propval, NULL, 10, &r);
+
+ spa_free_bootprop(propval);
+
+ /*
+ * If the conversion succeeded, return the value. If there was any
+ * kind of failure, just return the default value.
+ */
+ return (e == 0 ? r : defval);
+}
+
static int
zfs_mountroot(vfs_t *vfsp, enum whymountroot why)
{
@@ -1721,6 +1754,8 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why)
vnode_t *vp = NULL;
char *zfs_bootfs;
char *zfs_devid;
+ uint64_t zfs_bootpool;
+ uint64_t zfs_bootvdev;
ASSERT(vfsp);
@@ -1732,6 +1767,7 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why)
if (why == ROOT_INIT) {
if (zfsrootdone++)
return (SET_ERROR(EBUSY));
+
/*
* the process of doing a spa_load will require the
* clock to be set before we could (for example) do
@@ -1746,23 +1782,47 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why)
return (SET_ERROR(EINVAL));
}
zfs_devid = spa_get_bootprop("diskdevid");
- error = spa_import_rootpool(rootfs.bo_name, zfs_devid);
- if (zfs_devid)
- spa_free_bootprop(zfs_devid);
- if (error) {
+
+ /*
+ * The boot loader may also provide us with the GUID for both
+ * the pool and the nominated boot vdev. A GUID value of 0 is
+ * explicitly invalid (see "spa_change_guid()"), so we use this
+ * as a sentinel value when no GUID is present.
+ */
+ zfs_bootpool = spa_get_bootprop_uint64("zfs-bootpool", 0);
+ zfs_bootvdev = spa_get_bootprop_uint64("zfs-bootvdev", 0);
+
+ /*
+ * Initialise the early boot device rescan mechanism. A scan
+ * will not actually be performed unless we need to do so in
+ * order to find the correct /devices path for a relocated
+ * device.
+ */
+ vdev_disk_preroot_init();
+
+ error = spa_import_rootpool(rootfs.bo_name, zfs_devid,
+ zfs_bootpool, zfs_bootvdev);
+
+ spa_free_bootprop(zfs_devid);
+
+ if (error != 0) {
spa_free_bootprop(zfs_bootfs);
+ vdev_disk_preroot_fini();
cmn_err(CE_NOTE, "spa_import_rootpool: error %d",
error);
return (error);
}
+
if (error = zfs_parse_bootfs(zfs_bootfs, rootfs.bo_name)) {
spa_free_bootprop(zfs_bootfs);
+ vdev_disk_preroot_fini();
cmn_err(CE_NOTE, "zfs_parse_bootfs: error %d",
error);
return (error);
}
spa_free_bootprop(zfs_bootfs);
+ vdev_disk_preroot_fini();
if (error = vfs_lock(vfsp))
return (error);
diff --git a/usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c b/usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c
index 89117995e2..d6c754c1ee 100644
--- a/usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c
+++ b/usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c
@@ -118,7 +118,7 @@ static audio_engine_ops_t cmediahd_engine_ops = {
cmediahd_channels,
cmediahd_rate,
cmediahd_sync,
- NULL, /* qlen */
+ NULL, /* qlen */
cmediahd_chinfo,
NULL /* playahead */
};
@@ -322,7 +322,7 @@ cs4398_init(void *arg, int codec)
i2c_write(devc, codec, CS4398_MODE_CTRL, 0x00);
i2c_write(devc, codec, 3, 0x09);
i2c_write(devc, codec, 4, 0x82); /* PCM Automute */
- i2c_write(devc, codec, 5, 0x80); /* Vol A+B to -64dB */
+ i2c_write(devc, codec, 5, 0x80); /* Vol A+B to -64dB */
i2c_write(devc, codec, 6, 0x80);
i2c_write(devc, codec, 7, 0xf0); /* soft ramping on */
@@ -369,7 +369,6 @@ cs4362a_init(void *arg, int codec)
static void
cmediahd_generic_set_play_volume(cmediahd_devc_t *devc, int codec_id,
int left, int right)
-
{
spi_write(devc, codec_id, AK4396_LchATTCtl | 0x20, mix_scale(left, 8));
spi_write(devc, codec_id, AK4396_RchATTCtl | 0x20, mix_scale(right, 8));
@@ -707,6 +706,9 @@ cmediahd_reset_port(cmediahd_portc_t *portc)
case 8:
channels = 3;
break;
+ default:
+ channels = 0x0;
+ break;
}
OUTB(devc, (INB(devc, MULTICH_MODE) & ~0x3) | channels,
MULTICH_MODE);
diff --git a/usr/src/uts/common/io/ecpp.c b/usr/src/uts/common/io/ecpp.c
index 2bbe70798f..a999ea7d91 100644
--- a/usr/src/uts/common/io/ecpp.c
+++ b/usr/src/uts/common/io/ecpp.c
@@ -3052,6 +3052,8 @@ ecpp_isr(caddr_t arg)
int retval = DDI_INTR_UNCLAIMED;
hrtime_t now;
+ dsr = 0;
+ dcsr = 0;
mutex_enter(&pp->umutex);
/*
* interrupt may occur while other thread is holding the lock
diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c
index cbcc4db3d8..c82a8f86d9 100644
--- a/usr/src/uts/common/os/devcfg.c
+++ b/usr/src/uts/common/os/devcfg.c
@@ -24,6 +24,7 @@
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#include <sys/note.h>
@@ -62,6 +63,7 @@
#include <sys/varargs.h>
#include <sys/modhash.h>
#include <sys/instance.h>
+#include <sys/sysevent/eventdefs.h>
#if defined(__amd64) && !defined(__xpv)
#include <sys/iommulib.h>
@@ -1486,12 +1488,12 @@ postattach_node(dev_info_t *dip)
/*
* Plumbing during postattach may fail because of the
* underlying device is not ready. This will fail ndi_devi_config()
- * in dv_filldir() and a warning message is issued. The message
- * from here will explain what happened
+ * in dv_filldir().
*/
if (rval != DACF_SUCCESS) {
- cmn_err(CE_WARN, "Postattach failed for %s%d\n",
- ddi_driver_name(dip), ddi_get_instance(dip));
+ NDI_CONFIG_DEBUG((CE_CONT, "postattach_node: %s%d (%p) "
+ "postattach failed\n", ddi_driver_name(dip),
+ ddi_get_instance(dip), (void *)dip));
return (DDI_FAILURE);
}
@@ -3560,7 +3562,6 @@ walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg,
* They include, but not limited to, _init(9e), _fini(9e), probe(9e),
* attach(9e), and detach(9e).
*/
-
void
ddi_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
{
@@ -3580,7 +3581,6 @@ ddi_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
*
* N.B. The same restrictions from ddi_walk_devs() apply.
*/
-
void
e_ddi_walk_driver(char *drv, int (*f)(dev_info_t *, void *), void *arg)
{
@@ -3609,6 +3609,91 @@ e_ddi_walk_driver(char *drv, int (*f)(dev_info_t *, void *), void *arg)
UNLOCK_DEV_OPS(&dnp->dn_lock);
}
+struct preroot_walk_block_devices_arg {
+ int (*prwb_func)(const char *, void *);
+ void *prwb_arg;
+};
+
+static int
+preroot_walk_block_devices_walker(dev_info_t *dip, void *arg)
+{
+ struct preroot_walk_block_devices_arg *prwb = arg;
+
+ if (i_ddi_devi_class(dip) == NULL ||
+ strcmp(i_ddi_devi_class(dip), ESC_DISK) != 0) {
+ /*
+ * We do not think that this is a disk.
+ */
+ return (DDI_WALK_CONTINUE);
+ }
+
+ for (struct ddi_minor_data *md = DEVI(dip)->devi_minor; md != NULL;
+ md = md->next) {
+ if (md->ddm_spec_type != S_IFBLK) {
+ /*
+ * We don't want the raw version of any block device.
+ */
+ continue;
+ }
+
+ /*
+ * The node type taxonomy is hierarchical, with each level
+ * separated by colons. Nodes of interest are either of the
+ * BLOCK type, or are prefixed with that type.
+ */
+ if (strcmp(md->ddm_node_type, DDI_NT_BLOCK) != 0 &&
+ strncmp(md->ddm_node_type, DDI_NT_BLOCK ":",
+ strlen(DDI_NT_BLOCK ":")) != 0) {
+ /*
+ * This minor node does not represent a block device.
+ */
+ continue;
+ }
+
+ char buf[MAXPATHLEN];
+ int r;
+ if ((r = prwb->prwb_func(ddi_pathname_minor(md, buf),
+ prwb->prwb_arg)) == PREROOT_WALK_BLOCK_DEVICES_CANCEL) {
+ /*
+ * The consumer does not need any more minor nodes.
+ */
+ return (DDI_WALK_TERMINATE);
+ }
+ VERIFY3S(r, ==, PREROOT_WALK_BLOCK_DEVICES_NEXT);
+ }
+
+ return (DDI_WALK_CONTINUE);
+}
+
+/*
+ * Private routine for ZFS when it needs to attach and scan all of the block
+ * device minors in the system while looking for vdev labels.
+ *
+ * The callback function accepts a physical device path and the context
+ * argument (arg) passed to this function; it should return
+ * PREROOT_WALK_BLOCK_DEVICES_NEXT when more devices are required and
+ * PREROOT_WALK_BLOCK_DEVICES_CANCEL to stop the walk.
+ */
+void
+preroot_walk_block_devices(int (*callback)(const char *, void *), void *arg)
+{
+ /*
+ * First, force everything which can attach to do so. The device class
+ * is not derived until at least one minor mode is created, so we
+ * cannot walk the device tree looking for a device class of ESC_DISK
+ * until everything is attached.
+ */
+ (void) ndi_devi_config(ddi_root_node(), NDI_CONFIG | NDI_DEVI_PERSIST |
+ NDI_NO_EVENT | NDI_DRV_CONF_REPROBE);
+
+ struct preroot_walk_block_devices_arg prwb;
+ prwb.prwb_func = callback;
+ prwb.prwb_arg = arg;
+
+ ddi_walk_devs(ddi_root_node(), preroot_walk_block_devices_walker,
+ &prwb);
+}
+
/*
* argument to i_find_devi, a devinfo node search callback function.
*/
@@ -3823,8 +3908,8 @@ ddi_is_pci_dip(dev_info_t *dip)
* to ioc's bus_config entry point.
*/
int
-resolve_pathname(char *pathname,
- dev_info_t **dipp, dev_t *devtp, int *spectypep)
+resolve_pathname(char *pathname, dev_info_t **dipp, dev_t *devtp,
+ int *spectypep)
{
int error;
dev_info_t *parent, *child;
@@ -9055,7 +9140,7 @@ out:
char *
ddi_curr_redirect(char *curr)
{
- char *alias;
+ char *alias;
int i;
if (ddi_aliases_present == B_FALSE)
diff --git a/usr/src/uts/common/sys/ddi_implfuncs.h b/usr/src/uts/common/sys/ddi_implfuncs.h
index e7d218844b..522366aa23 100644
--- a/usr/src/uts/common/sys/ddi_implfuncs.h
+++ b/usr/src/uts/common/sys/ddi_implfuncs.h
@@ -25,6 +25,7 @@
*/
/*
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#ifndef _SYS_DDI_IMPLFUNCS_H
@@ -237,6 +238,16 @@ extern void i_ddi_decr_locked_memory(proc_t *, rctl_qty_t);
*/
extern void translate_devid(dev_info_t *dip);
+/*
+ * Support routine for file systems that need to scan block devices searching
+ * for a label as part of mounting the root file system.
+ */
+extern void preroot_walk_block_devices(int (*)(const char *, void *), void *);
+
+#define PREROOT_WALK_BLOCK_DEVICES_NEXT 1
+#define PREROOT_WALK_BLOCK_DEVICES_CANCEL 2
+
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/intel/zfs/spa_boot.c b/usr/src/uts/intel/zfs/spa_boot.c
index adbcffaef0..abcaac7ce9 100644
--- a/usr/src/uts/intel/zfs/spa_boot.c
+++ b/usr/src/uts/intel/zfs/spa_boot.c
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#include <sys/zio.h>
@@ -36,19 +37,25 @@
extern int zfs_deadman_enabled;
char *
-spa_get_bootprop(char *propname)
+spa_get_bootprop(const char *propname)
{
char *value;
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
- DDI_PROP_DONTPASS, propname, &value) != DDI_SUCCESS)
+ DDI_PROP_DONTPASS, (char *)propname, &value) != DDI_SUCCESS) {
return (NULL);
+ }
+
return (value);
}
void
spa_free_bootprop(char *value)
{
+ if (value == NULL) {
+ return;
+ }
+
ddi_prop_free(value);
}
diff --git a/usr/src/uts/sparc/zfs/spa_boot.c b/usr/src/uts/sparc/zfs/spa_boot.c
index 71a8b9ed51..8109d0e2f9 100644
--- a/usr/src/uts/sparc/zfs/spa_boot.c
+++ b/usr/src/uts/sparc/zfs/spa_boot.c
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
*/
#include <sys/zio.h>
@@ -35,7 +36,7 @@
extern int zfs_deadman_enabled;
char *
-spa_get_bootprop(char *propname)
+spa_get_bootprop(const char *propname)
{
int proplen;
char *value;
@@ -54,9 +55,13 @@ spa_get_bootprop(char *propname)
}
void
-spa_free_bootprop(char *propname)
+spa_free_bootprop(char *propval)
{
- kmem_free(propname, strlen(propname) + 1);
+ if (propval == NULL) {
+ return;
+ }
+
+ kmem_free(propval, strlen(propval) + 1);
}
void