Esempio n. 1
0
/*
 * Solve a given ZFS case.  This first checks to make sure the diagnosis is
 * still valid, as well as cleaning up any pending timer associated with the
 * case.
 */
static void
zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname,
    boolean_t checkunusable)
{
	nvlist_t *detector, *fault;
	boolean_t serialize;
	nvlist_t *fru = NULL;
	fmd_hdl_debug(hdl, "solving fault '%s'", faultname);

	/*
	 * Construct the detector from the case data.  The detector is in the
	 * ZFS scheme, and is either the pool or the vdev, depending on whether
	 * this is a vdev or pool fault.
	 */
	detector = fmd_nvl_alloc(hdl, FMD_SLEEP);

	(void) nvlist_add_uint8(detector, FM_VERSION, ZFS_SCHEME_VERSION0);
	(void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS);
	(void) nvlist_add_uint64(detector, FM_FMRI_ZFS_POOL,
	    zcp->zc_data.zc_pool_guid);
	if (zcp->zc_data.zc_vdev_guid != 0) {
		(void) nvlist_add_uint64(detector, FM_FMRI_ZFS_VDEV,
		    zcp->zc_data.zc_vdev_guid);
	}

	fault = fmd_nvl_create_fault(hdl, faultname, 100, detector,
	    fru, detector);
	fmd_case_add_suspect(hdl, zcp->zc_case, fault);

	nvlist_free(fru);

	fmd_case_solve(hdl, zcp->zc_case);

	serialize = B_FALSE;
	if (zcp->zc_data.zc_has_remove_timer) {
		fmd_timer_remove(hdl, zcp->zc_remove_timer);
		zcp->zc_data.zc_has_remove_timer = 0;
		serialize = B_TRUE;
	}
	if (serialize)
		zfs_case_serialize(hdl, zcp);

	nvlist_free(detector);
}
Esempio n. 2
0
/*ARGSUSED*/
uint_t
fmevt_pp_smf(char *classes[FMEVT_FANOUT_MAX],
    nvlist_t *attr[FMEVT_FANOUT_MAX], const char *ruleset,
    const nvlist_t *detector, nvlist_t *rawattr,
    const struct fmevt_ppargs *eap)
{
	int32_t transition, from, to;
	const char *fromstr, *tostr;
	char *svcname, *rsn, *rsnl;
	nvlist_t *myattr;
	nvlist_t *fmri;
	uint32_t ver;

	if (!fmd_prop_get_int32(fmevt_hdl, "inbound_postprocess_smf"))
		return (0);

	if (rawattr == NULL ||
	    strcmp(eap->pp_rawclass, "state-transition") != 0 ||
	    nvlist_lookup_string(rawattr, "fmri", &svcname) != 0 ||
	    nvlist_lookup_int32(rawattr, "transition", &transition) != 0 ||
	    nvlist_lookup_string(rawattr, "reason-short", &rsn) != 0 ||
	    nvlist_lookup_string(rawattr, "reason-long", &rsnl) != 0 ||
	    nvlist_lookup_uint32(rawattr, "reason-version", &ver) != 0)
		return (0);

	from = transition >> 16;
	to = transition & 0xffff;

	fromstr = smf_state_to_string(from);
	tostr = smf_state_to_string(to);

	if (fromstr == NULL || tostr == NULL)
		return (0);

	if (strcmp(eap->pp_rawsubclass, tostr) != 0)
		return (0);

	if ((fmri = shortfmri_to_fmri(fmevt_hdl, svcname)) == NULL)
		return (0);

	if (snprintf(classes[0], FMEVT_MAX_CLASS, "%s.%s.%s.%s",
	    FM_IREPORT_CLASS, "os.smf", eap->pp_rawclass,
	    eap->pp_rawsubclass) >= FMEVT_MAX_CLASS - 1)
		return (0);

	if ((myattr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP)) == NULL)
		return (0);

	if (nvlist_add_nvlist(myattr, "svc", fmri) != 0 ||
	    nvlist_add_string(myattr, "svc-string", svcname) != 0 ||
	    nvlist_add_string(myattr, "from-state", fromstr) != 0 ||
	    nvlist_add_string(myattr, "to-state", tostr) != 0 ||
	    nvlist_add_uint32(myattr, "reason-version", ver) != 0 ||
	    nvlist_add_string(myattr, "reason-short", rsn) != 0 ||
	    nvlist_add_string(myattr, "reason-long", rsnl) != 0) {
		nvlist_free(fmri);
		nvlist_free(myattr);
		return (0);
	}

	attr[0] = myattr;
	nvlist_free(fmri);

	return (1);
}
Esempio n. 3
0
/*
 * Solve a given ZFS case.  This first checks to make sure the diagnosis is
 * still valid, as well as cleaning up any pending timer associated with the
 * case.
 */
static void
zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname,
    boolean_t checkunusable)
{
	libzfs_handle_t *zhdl = fmd_hdl_getspecific(hdl);
	nvlist_t *detector, *fault;
	boolean_t serialize;
	nvlist_t *fmri, *fru;
	topo_hdl_t *thp;
	int err;

	/*
	 * Construct the detector from the case data.  The detector is in the
	 * ZFS scheme, and is either the pool or the vdev, depending on whether
	 * this is a vdev or pool fault.
	 */
	detector = fmd_nvl_alloc(hdl, FMD_SLEEP);

	(void) nvlist_add_uint8(detector, FM_VERSION, ZFS_SCHEME_VERSION0);
	(void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS);
	(void) nvlist_add_uint64(detector, FM_FMRI_ZFS_POOL,
	    zcp->zc_data.zc_pool_guid);
	if (zcp->zc_data.zc_vdev_guid != 0) {
		(void) nvlist_add_uint64(detector, FM_FMRI_ZFS_VDEV,
		    zcp->zc_data.zc_vdev_guid);
	}

	/*
	 * We also want to make sure that the detector (pool or vdev) properly
	 * reflects the diagnosed state, when the fault corresponds to internal
	 * ZFS state (i.e. not checksum or I/O error-induced).  Otherwise, a
	 * device which was unavailable early in boot (because the driver/file
	 * wasn't available) and is now healthy will be mis-diagnosed.
	 */
	if (!fmd_nvl_fmri_present(hdl, detector) ||
	    (checkunusable && !fmd_nvl_fmri_unusable(hdl, detector))) {
		fmd_case_close(hdl, zcp->zc_case);
		nvlist_free(detector);
		return;
	}


	fru = NULL;
	if (zcp->zc_fru != NULL &&
	    (thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) != NULL) {
		/*
		 * If the vdev had an associated FRU, then get the FRU nvlist
		 * from the topo handle and use that in the suspect list.  We
		 * explicitly lookup the FRU because the fmri reported from the
		 * kernel may not have up to date details about the disk itself
		 * (serial, part, etc).
		 */
		if (topo_fmri_str2nvl(thp, zcp->zc_fru, &fmri, &err) == 0) {
			/*
			 * If the disk is part of the system chassis, but the
			 * FRU indicates a different chassis ID than our
			 * current system, then ignore the error.  This
			 * indicates that the device was part of another
			 * cluster head, and for obvious reasons cannot be
			 * imported on this system.
			 */
			if (libzfs_fru_notself(zhdl, zcp->zc_fru)) {
				fmd_case_close(hdl, zcp->zc_case);
				nvlist_free(fmri);
				fmd_hdl_topo_rele(hdl, thp);
				nvlist_free(detector);
				return;
			}

			/*
			 * If the device is no longer present on the system, or
			 * topo_fmri_fru() fails for other reasons, then fall
			 * back to the fmri specified in the vdev.
			 */
			if (topo_fmri_fru(thp, fmri, &fru, &err) != 0)
				fru = fmd_nvl_dup(hdl, fmri, FMD_SLEEP);
			nvlist_free(fmri);
		}

		fmd_hdl_topo_rele(hdl, thp);
	}

	fault = fmd_nvl_create_fault(hdl, faultname, 100, detector,
	    fru, detector);
	fmd_case_add_suspect(hdl, zcp->zc_case, fault);

	nvlist_free(fru);

	fmd_case_solve(hdl, zcp->zc_case);

	serialize = B_FALSE;
	if (zcp->zc_data.zc_has_remove_timer) {
		fmd_timer_remove(hdl, zcp->zc_remove_timer);
		zcp->zc_data.zc_has_remove_timer = 0;
		serialize = B_TRUE;
	}
	if (serialize)
		zfs_case_serialize(hdl, zcp);

	nvlist_free(detector);
}
Esempio n. 4
0
/*ARGSUSED3*/
static nvlist_t *
fmevt_detector(nvlist_t *attr, char *ruleset, int user, int priv,
    fmev_pri_t pri)
{
	char buf[FMEV_MAX_RULESET_LEN + 1];
	char *ns, *subsys;
	nvlist_t *obj, *dtcr, *site, *ctxt;
	char *execname = NULL;
	int32_t i32;
	int64_t i64;
	int err = 0;
	char *str;

	(void) strncpy(buf, ruleset, sizeof (buf));
	if (!fmevt_rs_burst(NULL, buf, &ns, &subsys, B_FALSE))
		return (NULL);

	obj = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
	dtcr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
	site = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
	ctxt = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);

	if (obj == NULL || dtcr == NULL || site == NULL || ctxt == NULL) {
		err++;
		goto done;
	}

	/*
	 * Build up 'object' nvlist.
	 */
	if (nvlist_lookup_string(attr, "__fmev_execname", &execname) == 0)
		err += nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, execname);

	/*
	 * Build up 'site' nvlist.  We should have source file and line
	 * number and, if the producer was compiled with C99, function name.
	 */
	if (nvlist_lookup_string(attr, "__fmev_file", &str) == 0) {
		err += nvlist_add_string(site, FM_FMRI_SW_SITE_FILE, str);
		(void) nvlist_remove(attr, "__fmev_file", DATA_TYPE_STRING);
	}

	if (nvlist_lookup_string(attr, "__fmev_func", &str) == 0) {
		err += nvlist_add_string(site, FM_FMRI_SW_SITE_FUNC, str);
		(void) nvlist_remove(attr, "__fmev_func", DATA_TYPE_STRING);
	}

	if (nvlist_lookup_int64(attr, "__fmev_line", &i64) == 0) {
		err += nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, i64);
		(void) nvlist_remove(attr, "__fmev_line", DATA_TYPE_INT64);
	}

	/*
	 * Build up 'context' nvlist.  We do not include contract id at
	 * this time.
	 */

	err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN,
	    user ? "userland" : "kernel");

	if (execname) {
		err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME,
		    execname);
		(void) nvlist_remove(attr, "__fmev_execname", DATA_TYPE_STRING);
	}

	if (nvlist_lookup_int32(attr, "__fmev_pid", &i32) == 0) {
		err += nvlist_add_int32(ctxt, FM_FMRI_SW_CTXT_PID, i32);
		(void) nvlist_remove(attr, "__fmev_pid", DATA_TYPE_INT32);
	}

	if (!isglobalzone)
		err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ZONE, zonename);

	/* Put it all together */

	err += nvlist_add_uint8(dtcr, FM_VERSION, SW_SCHEME_VERSION0);
	err += nvlist_add_string(dtcr, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW);
	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_OBJ, obj);
	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_SITE, site);
	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_CTXT, ctxt);

done:
	nvlist_free(obj);
	nvlist_free(site);
	nvlist_free(ctxt);

	if (err == 0) {
		return (dtcr);
	} else {
		nvlist_free(dtcr);
		return (NULL);
	}
}