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)