diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-02-03 12:58:04 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-02-03 12:58:04 +0000 |
commit | b69deb59db49c8958cbaea43a0d6bf9029f5b19e (patch) | |
tree | 4961beb6bfb113069d54b6dfb460e9b51bf0a0a9 | |
parent | f0dcd619b1421138ac11033df8e0cf904ba1efcf (diff) | |
parent | 8a2b682e57a046b828f37bcde1776f131ef4629f (diff) | |
download | illumos-joyent-b69deb59db49c8958cbaea43a0d6bf9029f5b19e.tar.gz |
[illumos-gate merge]
commit 8a2b682e57a046b828f37bcde1776f131ef4629f
12206 Want datalink properties in topo
commit 1b500975aaacf8b5d0e18c9a117bf5560069ffc3
4454 ldi notifications trigger vdev_disk_free() without spa_config_lock()
commit 4e995f2a014b6efa1fa6b0cf17c7f63ed51acf69
12256 reboot(1m) looks for 32-bit kernel only
-rw-r--r-- | usr/src/cmd/halt/halt.c | 15 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/libtopo/common/topo_hc.h | 14 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/nic/topo_nic.c | 220 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/shared/topo_port.c | 13 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/shared/topo_port.h | 4 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_disk.c | 67 |
7 files changed, 279 insertions, 56 deletions
diff --git a/usr/src/cmd/halt/halt.c b/usr/src/cmd/halt/halt.c index 0f096c6638..ca0ed8e77f 100644 --- a/usr/src/cmd/halt/halt.c +++ b/usr/src/cmd/halt/halt.c @@ -646,6 +646,19 @@ validate_disk(char *arg, char *mountpoint) if (rc != 0) return (rc); + /* + * Check for the usual case: 64-bit kernel + */ + (void) snprintf(kernpath, MAXPATHLEN, + "%s/platform/i86pc/kernel/amd64/unix", mountpoint); + if (stat64(kernpath, &statbuf) == 0) + return (0); + + /* + * We no longer build 32-bit kernel but in a case we are trying to boot + * some ancient filesystem with 32-bit only kernel we should be able to + * proceed too + */ (void) snprintf(kernpath, MAXPATHLEN, "%s/platform/i86pc/kernel/unix", mountpoint); @@ -1151,7 +1164,7 @@ parse_fastboot_args(char *bootargs_buf, size_t buf_size, } else if (mplen != 0) { /* * No unix argument, but mountpoint is not empty, use - * /platform/i86pc/$ISADIR/kernel/unix as default. + * /platform/i86pc/kernel/$ISADIR/unix as default. */ char isa[20]; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h index 8f245c1cf0..19b60b004d 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -183,6 +183,7 @@ extern "C" { #define TOPO_PROP_PORT_TYPE "type" #define TOPO_PROP_PORT_TYPE_SFF "sff" #define TOPO_PROP_PORT_TYPE_USB "usb" +#define TOPO_PROP_PORT_TYPE_UNKNOWN "unknown" #define TOPO_PGROUP_TRANSCEIVER "transceiver" #define TOPO_PROP_TRANSCEIVER_TYPE "type" @@ -290,6 +291,19 @@ extern "C" { #define TOPO_PROP_UFM_SLOT_MODE "ufm-slot-mode" #define TOPO_PROP_UFM_SLOT_ACTIVE "ufm-slot-active" +#define TOPO_PGROUP_DATALINK "datalink" +#define TOPO_PGROUP_DATALINK_PMAC "primary-mac-address" +#define TOPO_PGROUP_DATALINK_LINK_SPEED "link-speed" +#define TOPO_PGROUP_DATALINK_LINK_STATUS "link-status" +#define TOPO_PGROUP_DATALINK_LINK_STATUS_UP "up" +#define TOPO_PGROUP_DATALINK_LINK_STATUS_DOWN "down" +#define TOPO_PGROUP_DATALINK_LINK_STATUS_UNKNOWN "unknown" +#define TOPO_PGROUP_DATALINK_LINK_DUPLEX "link-duplex" +#define TOPO_PGROUP_DATALINK_LINK_DUPLEX_FULL "full" +#define TOPO_PGROUP_DATALINK_LINK_DUPLEX_HALF "half" +#define TOPO_PGROUP_DATALINK_LINK_DUPLEX_UNKNOWN "unknown" +#define TOPO_PGROUP_DATALINK_LINK_NAME "link-name" + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c index 51c37142c5..cd272a0c73 100644 --- a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c +++ b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c @@ -11,6 +11,7 @@ /* * Copyright (c) 2017, Joyent, Inc. + * Copyright 2020 Robert Mustacchi */ /* @@ -23,10 +24,12 @@ #include <libdevinfo.h> #include <libdladm.h> #include <libdllink.h> +#include <libdlstat.h> #include <libsff.h> #include <unistd.h> #include <sys/dld_ioc.h> #include <sys/dld.h> +#include <sys/mac.h> #include <sys/fm/protocol.h> #include <fm/topo_mod.h> @@ -38,13 +41,199 @@ #include "topo_nic.h" +typedef enum { + NIC_PORT_UNKNOWN, + NIC_PORT_SFF +} nic_port_type_t; + +static const topo_pgroup_info_t datalink_pgroup = { + TOPO_PGROUP_DATALINK, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +typedef struct nic_port_mac { + char npm_mac[ETHERADDRSTRL]; + boolean_t npm_valid; + topo_mod_t *npm_mod; +} nic_port_mac_t; + +/* + * The first MAC address is always the primary MAC address, so we only worry + * about the first. Thus this function always returns B_FALSE, to terminate + * iteration. + */ +static boolean_t +nic_port_datalink_mac_cb(void *arg, dladm_macaddr_attr_t *attr) +{ + nic_port_mac_t *mac = arg; + + if (attr->ma_addrlen != ETHERADDRL) { + topo_mod_dprintf(mac->npm_mod, + "found address with bad length: %u\n", attr->ma_addrlen); + return (B_FALSE); + } + + (void) snprintf(mac->npm_mac, sizeof (mac->npm_mac), + "%02x:%02x:%02x:%02x:%02x:%02x", + attr->ma_addr[0], attr->ma_addr[1], attr->ma_addr[2], + attr->ma_addr[3], attr->ma_addr[4], attr->ma_addr[5]); + mac->npm_valid = B_TRUE; + return (B_FALSE); +} + +static int +nic_port_datalink_props(topo_mod_t *mod, tnode_t *port, dladm_handle_t handle, + datalink_id_t linkid) +{ + int err; + dladm_status_t status; + uint64_t ifspeed; + link_duplex_t duplex; + link_state_t state; + const char *duplex_str, *state_str; + datalink_class_t dlclass; + uint32_t media; + char dlname[MAXLINKNAMELEN * 2]; + char dlerr[DLADM_STRSIZE]; + nic_port_mac_t mac; + + status = dladm_datalink_id2info(handle, linkid, NULL, &dlclass, &media, + dlname, sizeof (dlname)); + if (status != DLADM_STATUS_OK) { + topo_mod_dprintf(mod, "failed to get link info: %s\n", + dladm_status2str(status, dlerr)); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + if (dlclass != DATALINK_CLASS_PHYS) { + return (0); + } + + status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", + KSTAT_DATA_UINT64, &ifspeed); + if (status != DLADM_STATUS_OK) { + topo_mod_dprintf(mod, "failed to get ifspeed: %s\n", + dladm_status2str(status, dlerr)); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", + KSTAT_DATA_UINT32, &duplex); + if (status != DLADM_STATUS_OK) { + topo_mod_dprintf(mod, "failed to get link_duplex: %s\n", + dladm_status2str(status, dlerr)); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + switch (duplex) { + case LINK_DUPLEX_HALF: + duplex_str = TOPO_PGROUP_DATALINK_LINK_DUPLEX_HALF; + break; + case LINK_DUPLEX_FULL: + duplex_str = TOPO_PGROUP_DATALINK_LINK_DUPLEX_FULL; + break; + default: + duplex_str = TOPO_PGROUP_DATALINK_LINK_DUPLEX_UNKNOWN; + break; + } + + status = dladm_get_single_mac_stat(handle, linkid, "link_state", + KSTAT_DATA_UINT32, &state); + if (status != DLADM_STATUS_OK) { + topo_mod_dprintf(mod, "failed to get link_duplex: %s\n", + dladm_status2str(status, dlerr)); + return (topo_mod_seterrno(mod, status)); + } + + switch (state) { + case LINK_STATE_UP: + state_str = TOPO_PGROUP_DATALINK_LINK_STATUS_UP; + break; + case LINK_STATE_DOWN: + state_str = TOPO_PGROUP_DATALINK_LINK_STATUS_DOWN; + break; + default: + state_str = TOPO_PGROUP_DATALINK_LINK_STATUS_UNKNOWN; + break; + } + + /* + * Override the duplex if the link is down. Some devices will leave it + * set at half as opposed to unknown. + */ + if (state == LINK_STATE_DOWN || state == LINK_STATE_UNKNOWN) { + duplex_str = TOPO_PGROUP_DATALINK_LINK_DUPLEX_UNKNOWN; + } + + mac.npm_mac[0] = '\0'; + mac.npm_valid = B_FALSE; + mac.npm_mod = mod; + if (media == DL_ETHER) { + (void) dladm_walk_macaddr(handle, linkid, &mac, + nic_port_datalink_mac_cb); + } + + if (topo_pgroup_create(port, &datalink_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "falied to create property group %s: " + "%s\n", TOPO_PGROUP_DATALINK, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + + if (topo_prop_set_uint64(port, TOPO_PGROUP_DATALINK, + TOPO_PGROUP_DATALINK_LINK_SPEED, TOPO_PROP_IMMUTABLE, ifspeed, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PGROUP_DATALINK_LINK_SPEED, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + + if (topo_prop_set_string(port, TOPO_PGROUP_DATALINK, + TOPO_PGROUP_DATALINK_LINK_DUPLEX, TOPO_PROP_IMMUTABLE, duplex_str, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PGROUP_DATALINK_LINK_DUPLEX, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + + if (topo_prop_set_string(port, TOPO_PGROUP_DATALINK, + TOPO_PGROUP_DATALINK_LINK_STATUS, TOPO_PROP_IMMUTABLE, state_str, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PGROUP_DATALINK_LINK_STATUS, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + + if (topo_prop_set_string(port, TOPO_PGROUP_DATALINK, + TOPO_PGROUP_DATALINK_LINK_NAME, TOPO_PROP_IMMUTABLE, dlname, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s propery: %s\n", + TOPO_PGROUP_DATALINK_LINK_NAME, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + + if (mac.npm_valid) { + if (topo_prop_set_string(port, TOPO_PGROUP_DATALINK, + TOPO_PGROUP_DATALINK_PMAC, TOPO_PROP_IMMUTABLE, + mac.npm_mac, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s propery: %s\n", + TOPO_PGROUP_DATALINK_PMAC, topo_strerror(err)); + return (topo_mod_seterrno(mod, err)); + } + } + + + return (0); +} + /* * Create an instance of a transceiver with the specified id. We must create * both its port and the transceiver node. */ static int nic_create_transceiver(topo_mod_t *mod, tnode_t *pnode, dladm_handle_t handle, - datalink_id_t linkid, uint_t tranid) + datalink_id_t linkid, uint_t tranid, nic_port_type_t port_type) { int ret; tnode_t *port; @@ -55,9 +244,21 @@ nic_create_transceiver(topo_mod_t *mod, tnode_t *pnode, dladm_handle_t handle, char *vendor = NULL, *part = NULL, *rev = NULL, *serial = NULL; nvlist_t *nvl = NULL; - if ((ret = port_create_sff(mod, pnode, tranid, &port)) != 0) + switch (port_type) { + case NIC_PORT_UNKNOWN: + ret = port_create_unknown(mod, pnode, tranid, &port); + break; + case NIC_PORT_SFF: + ret = port_create_sff(mod, pnode, tranid, &port); + break; + } + + if ((ret = nic_port_datalink_props(mod, port, handle, linkid)) != 0) return (ret); + if (port_type != NIC_PORT_SFF) + return (0); + bzero(&dgt, sizeof (dgt)); dgt.dgt_linkid = linkid; dgt.dgt_tran_id = tranid; @@ -139,6 +340,7 @@ nic_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, dld_ioc_gettran_t dgt; uint_t ntrans, i; char dname[MAXNAMELEN]; + nic_port_type_t pt; if (strcmp(name, NIC) != 0) { topo_mod_dprintf(mod, "nic_enum: asked to enumerate unknown " @@ -172,9 +374,13 @@ nic_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, dgt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN; if (ioctl(dladm_dld_fd(handle), DLDIOC_GETTRAN, &dgt) != 0) { - if (errno == ENOTSUP) - return (0); - return (-1); + if (errno != ENOTSUP) { + return (-1); + } + pt = NIC_PORT_UNKNOWN; + dgt.dgt_tran_id = 1; + } else { + pt = NIC_PORT_SFF; } ntrans = dgt.dgt_tran_id; @@ -185,8 +391,10 @@ nic_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, return (-1); for (i = 0; i < ntrans; i++) { - if (nic_create_transceiver(mod, pnode, handle, linkid, i) != 0) + if (nic_create_transceiver(mod, pnode, handle, linkid, i, + pt) != 0) { return (-1); + } } return (0); diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.c b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c index 5dfd947c0e..d6cbd7423e 100644 --- a/usr/src/lib/fm/topo/modules/common/shared/topo_port.c +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c @@ -155,3 +155,16 @@ port_create_usb(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, *nodep = tn; return (0); } + +int +port_create_unknown(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, + tnode_t **nodep) +{ + tnode_t *tn; + + tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_UNKNOWN); + if (tn == NULL) + return (-1); + *nodep = tn; + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.h b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h index df85ff84fd..861ea8d8e5 100644 --- a/usr/src/lib/fm/topo/modules/common/shared/topo_port.h +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h @@ -20,6 +20,8 @@ * Routines to manage and create ports. */ +#include <fm/topo_mod.h> + #ifdef __cplusplus extern "C" { #endif @@ -30,6 +32,8 @@ extern int port_create_sff(topo_mod_t *, tnode_t *, topo_instance_t, tnode_t **); extern int port_create_usb(topo_mod_t *, tnode_t *, topo_instance_t, tnode_t **); +extern int port_create_unknown(topo_mod_t *, tnode_t *, topo_instance_t, + tnode_t **); #ifdef __cplusplus } diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h index f371598739..b0bfbc2024 100644 --- a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h @@ -20,6 +20,8 @@ * Routines to manage and create ports. */ +#include <fm/topo_mod.h> + #ifdef __cplusplus extern "C" { #endif diff --git a/usr/src/uts/common/fs/zfs/vdev_disk.c b/usr/src/uts/common/fs/zfs/vdev_disk.c index f8604896ca..9408ec68fb 100644 --- a/usr/src/uts/common/fs/zfs/vdev_disk.c +++ b/usr/src/uts/common/fs/zfs/vdev_disk.c @@ -22,7 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. - * Copyright 2019 Joyent, Inc. + * Copyright 2020 Joyent, Inc. */ #include <sys/zfs_context.h> @@ -128,10 +128,9 @@ vdev_disk_free(vdev_t *vd) vd->vdev_tsd = NULL; } -/* ARGSUSED */ static int -vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg, - void *ev_data) +vdev_disk_off_notify(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie, + void *arg, void *ev_data __unused) { vdev_t *vd = (vdev_t *)arg; vdev_disk_t *dvd = vd->vdev_tsd; @@ -143,19 +142,15 @@ vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg, return (LDI_EV_SUCCESS); /* - * All LDI handles must be closed for the state change to succeed, so - * call on vdev_disk_close() to do this. - * - * We inform vdev_disk_close that it is being called from offline - * notify context so it will defer cleanup of LDI event callbacks and - * freeing of vd->vdev_tsd to the offline finalize or a reopen. + * Tell any new threads that stumble upon this vdev that they should not + * try to do I/O. */ dvd->vd_ldi_offline = B_TRUE; - vdev_disk_close(vd); /* - * Now that the device is closed, request that the spa_async_thread - * mark the device as REMOVED and notify FMA of the removal. + * Request that the spa_async_thread mark the device as REMOVED and + * notify FMA of the removal. This should also trigger a vdev_close() + * in the async thread. */ zfs_post_remove(vd->vdev_spa, vd); vd->vdev_remove_wanted = B_TRUE; @@ -164,10 +159,9 @@ vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg, return (LDI_EV_SUCCESS); } -/* ARGSUSED */ static void -vdev_disk_off_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, - int ldi_result, void *arg, void *ev_data) +vdev_disk_off_finalize(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie, + int ldi_result, void *arg, void *ev_data __unused) { vdev_t *vd = (vdev_t *)arg; vdev_disk_t *dvd = vd->vdev_tsd; @@ -180,12 +174,6 @@ vdev_disk_off_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, return; /* - * We have already closed the LDI handle in notify. - * Clean up the LDI event callbacks and free vd->vdev_tsd. - */ - vdev_disk_free(vd); - - /* * Request that the vdev be reopened if the offline state change was * unsuccessful. */ @@ -201,10 +189,9 @@ static ldi_ev_callback_t vdev_disk_off_callb = { .cb_finalize = vdev_disk_off_finalize }; -/* ARGSUSED */ static void -vdev_disk_dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, - int ldi_result, void *arg, void *ev_data) +vdev_disk_dgrd_finalize(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie, + int ldi_result, void *arg, void *ev_data __unused) { vdev_t *vd = (vdev_t *)arg; @@ -329,17 +316,8 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, * just update the physical size of the device. */ if (dvd != NULL) { - if (dvd->vd_ldi_offline && dvd->vd_lh == NULL) { - /* - * If we are opening a device in its offline notify - * context, the LDI handle was just closed. Clean - * up the LDI event callbacks and free vd->vdev_tsd. - */ - vdev_disk_free(vd); - } else { - ASSERT(vd->vdev_reopening); - goto skip_open; - } + ASSERT(vd->vdev_reopening); + goto skip_open; } /* @@ -772,14 +750,6 @@ vdev_disk_close(vdev_t *vd) } vd->vdev_delayed_close = B_FALSE; - /* - * If we closed the LDI handle due to an offline notify from LDI, - * don't free vd->vdev_tsd or unregister the callbacks here; - * the offline finalize callback or a reopen will take care of it. - */ - if (dvd->vd_ldi_offline) - return; - vdev_disk_free(vd); } @@ -813,7 +783,8 @@ vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data, static int vdev_disk_dumpio(vdev_t *vd, caddr_t data, size_t size, - uint64_t offset, uint64_t origoffset, boolean_t doread, boolean_t isdump) + uint64_t offset, uint64_t origoffset __unused, boolean_t doread, + boolean_t isdump) { vdev_disk_t *dvd = vd->vdev_tsd; int flags = doread ? B_READ : B_WRITE; @@ -821,11 +792,9 @@ vdev_disk_dumpio(vdev_t *vd, caddr_t data, size_t size, /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. - * - * XXX-mg there is still a race here with off_notify */ if (dvd == NULL || dvd->vd_ldi_offline) { - return (EIO); + return (SET_ERROR(ENXIO)); } ASSERT(vd->vdev_ops == &vdev_disk_ops); @@ -909,7 +878,7 @@ vdev_disk_io_start(zio_t *zio) * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ - if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) { + if (dvd == NULL || dvd->vd_ldi_offline) { zio->io_error = ENXIO; zio_interrupt(zio); return; |