Print this page
NEX-5736 implement autoreplace matching based on FRU slot number
NEX-6200 hot spares are not reactivated after reinserting into enclosure
NEX-9403 need to update FRU for spare and l2cache devices
NEX-9404 remove lofi autoreplace support from syseventd
NEX-9409 hotsparing doesn't work for vdevs without FRU
NEX-9424 zfs`vdev_online() needs better notification about state changes
Portions contributed by: Alek Pinchuk <alek@nexenta.com>
Portions contributed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2846 Enable Automatic/Intelligent Hot Sparing capability
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>

*** 20,29 **** --- 20,30 ---- */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Nexenta Systems, Inc. */ #include <dlfcn.h> #include <errno.h> #include <libintl.h>
*** 33,42 **** --- 34,44 ---- #include <unistd.h> #include <libzfs.h> #include <fm/libtopo.h> + #include <fm/topo_hc.h> #include <sys/fm/protocol.h> #include <sys/systeminfo.h> #include "libzfs_impl.h"
*** 75,84 **** --- 77,88 ---- static char *(*_topo_node_name)(tnode_t *); static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *, char **, int *); static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *); static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *); + static int (*_topo_fmri_str2nvl)(topo_hdl_t *, const char *, nvlist_t **, + int *); static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *, const char *); #define ZFS_FRU_HASH_SIZE 257
*** 184,193 **** --- 188,266 ---- return (TOPO_WALK_NEXT); } /* + * Given a disk FRU, check that FRU contains a slot number and remove FRU + * details that aren't needed when comparing FRUs by slot number. + */ + static char * + diskfru_to_slot(libzfs_handle_t *hdl, const char *diskfru) + { + nvlist_t *nvl, **hc; + char *hc_name, *tmp = NULL; + int ret, i; + uint_t hc_cnt; + + /* string -> nvlist */ + if (_topo_fmri_str2nvl(hdl->libzfs_topo_hdl, diskfru, &nvl, &ret) != 0) + return (NULL); + + /* Need slot (bay) number in the FRU */ + if (nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hc, + &hc_cnt) != 0) + goto out; + + for (i = 0; i < hc_cnt; i++) { + if (nvlist_lookup_string(hc[i], FM_FMRI_HC_NAME, + &hc_name) == 0 && strcmp(hc_name, BAY) == 0) + break; + } + if (i == hc_cnt) + goto out; + + /* Drop the unwanted components */ + (void) nvlist_remove_all(nvl, FM_FMRI_HC_SERIAL_ID); + (void) nvlist_remove_all(nvl, FM_FMRI_HC_PART); + (void) nvlist_remove_all(nvl, FM_FMRI_HC_REVISION); + + /* nvlist -> string */ + if (_topo_fmri_nvl2str(hdl->libzfs_topo_hdl, nvl, &tmp, &ret) != 0) + tmp = NULL; + out: + nvlist_free(nvl); + return (tmp); + } + + /* + * Check if given FRUs match by slot number to skip comparing disk specific + * fields of the FRU. + */ + /* ARGSUSED */ + int + libzfs_fru_cmp_slot(libzfs_handle_t *hdl, const char *a, const char *b, + size_t len) + { + char *slota, *slotb; + int ret = -1; + + if (a == NULL || b == NULL) + return (-1); + + slota = diskfru_to_slot(hdl, a); + slotb = diskfru_to_slot(hdl, b); + + if (slota != NULL && slotb != NULL) + ret = strcmp(slota, slotb); + + _topo_hdl_strfree(hdl->libzfs_topo_hdl, slota); + _topo_hdl_strfree(hdl->libzfs_topo_hdl, slotb); + + return (ret); + } + + /* * Called during initialization to setup the dynamic libtopo connection. */ #pragma init(libzfs_init_fru) static void libzfs_init_fru(void)
*** 229,248 **** dlsym(_topo_dlhandle, "topo_prop_get_string"); _topo_node_fru = (int (*)()) dlsym(_topo_dlhandle, "topo_node_fru"); _topo_fmri_nvl2str = (int (*)()) dlsym(_topo_dlhandle, "topo_fmri_nvl2str"); _topo_fmri_strcmp_noauth = (int (*)()) dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth"); if (_topo_open == NULL || _topo_close == NULL || _topo_snap_hold == NULL || _topo_snap_release == NULL || _topo_walk_init == NULL || _topo_walk_step == NULL || _topo_walk_fini == NULL || _topo_hdl_strfree == NULL || _topo_node_name == NULL || _topo_prop_get_string == NULL || _topo_node_fru == NULL || _topo_fmri_nvl2str == NULL || ! _topo_fmri_strcmp_noauth == NULL) { (void) dlclose(_topo_dlhandle); _topo_dlhandle = NULL; } } --- 302,323 ---- dlsym(_topo_dlhandle, "topo_prop_get_string"); _topo_node_fru = (int (*)()) dlsym(_topo_dlhandle, "topo_node_fru"); _topo_fmri_nvl2str = (int (*)()) dlsym(_topo_dlhandle, "topo_fmri_nvl2str"); + _topo_fmri_str2nvl = (int (*)()) + dlsym(_topo_dlhandle, "topo_fmri_str2nvl"); _topo_fmri_strcmp_noauth = (int (*)()) dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth"); if (_topo_open == NULL || _topo_close == NULL || _topo_snap_hold == NULL || _topo_snap_release == NULL || _topo_walk_init == NULL || _topo_walk_step == NULL || _topo_walk_fini == NULL || _topo_hdl_strfree == NULL || _topo_node_name == NULL || _topo_prop_get_string == NULL || _topo_node_fru == NULL || _topo_fmri_nvl2str == NULL || ! _topo_fmri_str2nvl == NULL || _topo_fmri_strcmp_noauth == NULL) { (void) dlclose(_topo_dlhandle); _topo_dlhandle = NULL; } }
*** 290,300 **** * for disks to add to the hash. */ twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC, libzfs_fru_gather, hdl, &err); if (twp != NULL) { ! (void) _topo_walk_step(twp, TOPO_WALK_CHILD); _topo_walk_fini(twp); } } /* --- 365,378 ---- * for disks to add to the hash. */ twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC, libzfs_fru_gather, hdl, &err); if (twp != NULL) { ! int status; ! ! status = _topo_walk_step(twp, TOPO_WALK_CHILD); ! assert(status != TOPO_WALK_NEXT); _topo_walk_fini(twp); } } /*
*** 418,427 **** --- 496,533 ---- return (B_FALSE); return (B_TRUE); } + /* + * Check if both FRUs belong to the same enclosure. + */ + boolean_t + libzfs_fru_cmp_enclosure(const char *fru_a, const char *fru_b) + { + int a, b; + char *encl_a, *encl_b; + const char *encl_str = "/ses-enclosure="; + size_t encl_str_len = strlen(encl_str); + + encl_a = strstr(fru_a, encl_str); + encl_b = strstr(fru_b, encl_str); + /* If both FRUs don't contain enclosure field, consider it a match */ + if (encl_a == NULL && encl_b == NULL) + return (B_TRUE); + /* If one FRU has the enclosure field, but the other one doesn't */ + if (encl_a == NULL || encl_b == NULL) + return (B_FALSE); + + encl_a += encl_str_len; + encl_b += encl_str_len; + if (sscanf(encl_a, "%d", &a) != 1 || sscanf(encl_b, "%d", &b) != 1) + return (B_FALSE); + + return (a == b); + } + /* * Clear memory associated with the FRU hash. */ void libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)