diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-04-02 11:09:47 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-04-02 11:09:47 +0000 |
commit | 080b163baec0c5a81b2717cf504cac1e0e1f143f (patch) | |
tree | 4eacda3b227a9fa30fbb91930f726a8eeb045ba3 | |
parent | ee42d232c75feb49ab18a118a8a3b7fc3ea9f0c4 (diff) | |
parent | 30c304d9746f4a048a7de56d31333b0fa8e43dee (diff) | |
download | illumos-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.c | 34 | ||||
-rw-r--r-- | usr/src/cmd/vntsd/read.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/vntsd/vntsd.c | 2 | ||||
-rw-r--r-- | usr/src/cmd/vntsd/vntsdvcc.c | 8 | ||||
-rw-r--r-- | usr/src/cmd/vntsd/write.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 46 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa_boot.h | 5 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/vdev_impl.h | 9 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_disk.c | 181 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vfsops.c | 68 | ||||
-rw-r--r-- | usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/io/ecpp.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/os/devcfg.c | 103 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ddi_implfuncs.h | 11 | ||||
-rw-r--r-- | usr/src/uts/intel/zfs/spa_boot.c | 11 | ||||
-rw-r--r-- | usr/src/uts/sparc/zfs/spa_boot.c | 11 |
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 |