Beispiel #1
0
Datei: zvol.c Projekt: alek-p/zfs
/*
 * ZFS_IOC_CREATE callback handles dmu zvol and zap object creation.
 */
void
zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
	zfs_creat_t *zct = arg;
	nvlist_t *nvprops = zct->zct_props;
	int error;
	uint64_t volblocksize, volsize;

	VERIFY(nvlist_lookup_uint64(nvprops,
	    zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0);
	if (nvlist_lookup_uint64(nvprops,
	    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0)
		volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);

	/*
	 * These properties must be removed from the list so the generic
	 * property setting step won't apply to them.
	 */
	VERIFY(nvlist_remove_all(nvprops,
	    zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0);
	(void) nvlist_remove_all(nvprops,
	    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE));

	error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize,
	    DMU_OT_NONE, 0, tx);
	ASSERT(error == 0);

	error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP,
	    DMU_OT_NONE, 0, tx);
	ASSERT(error == 0);

	error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx);
	ASSERT(error == 0);
}
Beispiel #2
0
static int
cpu_present(fmd_hdl_t *hdl, nvlist_t *asru, uint32_t *cpuid)
{
    nvlist_t *cp_asru;
    uint32_t i;

    if (nvlist_dup(asru, &cp_asru, 0) != 0) {
        fmd_hdl_debug(hdl, "unable to alloc asru for thread\n");
        return (-1);
    }

    for (i = *cpuid; i < *cpuid + UTS2_CPUS_PER_CHIP; i++) {

        (void) nvlist_remove_all(cp_asru, FM_FMRI_CPU_ID);

        if (nvlist_add_uint32(cp_asru, FM_FMRI_CPU_ID, i) == 0) {
            if (fmd_nvl_fmri_present(hdl, cp_asru) &&
                    !fmd_nvl_fmri_unusable(hdl, cp_asru)) {
                nvlist_free(cp_asru);
                *cpuid = i;
                return (0);
            }
        }
    }
    nvlist_free(cp_asru);
    return (-1);
}
Beispiel #3
0
static int
jailparam_del(const char *name)
{

	nvlist_remove_all(jailparams, name);
	return (0);
}
Beispiel #4
0
/*
 * Validate a proposed value against the iSER and/or iSCSI RFC's minimum and
 * maximum values, and set an alternate, if necessary.  Note that the value
 * 'iser_max_value" represents our implementation maximum (typically the max).
 */
static kv_status_t
iser_handle_numerical(nvpair_t *nvp, uint64_t value, const idm_kv_xlate_t *ikvx,
                      uint64_t min_value, uint64_t max_value, uint64_t iser_max_value,
                      nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
{
    kv_status_t		kvrc;
    int			nvrc;
    boolean_t		respond;

    /* Validate against standard */
    if ((value < min_value) || (value > max_value)) {
        kvrc = KV_VALUE_ERROR;
    } else {
        if (value > iser_max_value) {
            /*
             * Respond back to initiator with our value, and
             * set the return value to unset the transit bit.
             */
            value = iser_max_value;
            kvrc = KV_HANDLED_NO_TRANSIT;
            nvrc = 0;
            respond = B_TRUE;
        } else {
            /* Add this to our negotiated values */
            nvrc = nvlist_add_nvpair(negotiated_nvl, nvp);
            /* Respond if this is not a declarative */
            respond = (ikvx->ik_declarative == B_FALSE);
        }

        /* Response of Simple-value Negotiation */
        if (nvrc == 0 && respond) {
            nvrc = nvlist_add_uint64(response_nvl,
                                     ikvx->ik_key_name, value);
            /* Remove from the request (we've handled it) */
            (void) nvlist_remove_all(request_nvl,
                                     ikvx->ik_key_name);
        }
    }

    if (kvrc == KV_HANDLED_NO_TRANSIT) {
        return (kvrc);
    }

    return (idm_nvstat_to_kvstat(nvrc));
}
Beispiel #5
0
/* Ensure that "None" is an option in the digest list, and select it */
static kv_status_t
iser_handle_digest(nvpair_t *choices, const idm_kv_xlate_t *ikvx,
                   nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
{
    kv_status_t		kvrc = KV_VALUE_ERROR;
    int			nvrc = 0;
    nvpair_t		*digest_choice;
    char			*digest_choice_string;

    /*
     * Loop through all digest choices.  We need to enforce no
     * "None" for both header and data digest.  If we find our
     * required value, add the value to our negotiated values list
     * and respond with that value in the login response. If not,
     * indicate a value error for the iSCSI layer to work with.
     */
    digest_choice = idm_get_next_listvalue(choices, NULL);
    while (digest_choice != NULL) {
        nvrc = nvpair_value_string(digest_choice,
                                   &digest_choice_string);
        ASSERT(nvrc == 0);

        if (strcasecmp(digest_choice_string, "none") == 0) {

            /* Add to negotiated values list */
            nvrc = nvlist_add_string(negotiated_nvl,
                                     ikvx->ik_key_name, digest_choice_string);
            kvrc = idm_nvstat_to_kvstat(nvrc);
            if (nvrc == 0) {
                /* Add to login response list */
                nvrc = nvlist_add_string(response_nvl,
                                         ikvx->ik_key_name, digest_choice_string);
                kvrc = idm_nvstat_to_kvstat(nvrc);
                /* Remove from the request (we've handled it) */
                (void) nvlist_remove_all(request_nvl,
                                         ikvx->ik_key_name);
            }
            break;
        }
        digest_choice = idm_get_next_listvalue(choices,
                                               digest_choice);
    }

    return (kvrc);
}
Beispiel #6
0
static int
ippctl_extract_op(
	nvlist_t	*nvlp,
	uint8_t		*valp)
{
	int		rc;

	/*
	 * Look-up and remove the opcode passed from libipp from the
	 * nvlist.
	 */

	if ((rc = nvlist_lookup_byte(nvlp, IPPCTL_OP, valp)) != 0)
		return (rc);

	(void) nvlist_remove_all(nvlp, IPPCTL_OP);
	return (0);
}
Beispiel #7
0
static int
ippctl_extract_flags(
	nvlist_t	*nvlp,
	ipp_flags_t	*valp)
{
	int		rc;

	/*
	 * Look-up and remove the flags passed from libipp from the
	 * nvlist.
	 */

	if ((rc = nvlist_lookup_uint32(nvlp, IPPCTL_FLAGS,
	    (uint32_t *)valp)) != 0)
		return (rc);

	(void) nvlist_remove_all(nvlp, IPPCTL_FLAGS);
	return (0);
}
Beispiel #8
0
static int
ippctl_extract_modname(
	nvlist_t	*nvlp,
	char		**valp)
{
	int		rc;
	char		*ptr;

	/*
	 * Look-up and remove the module name passed from libipp from the
	 * nvlist.
	 */

	if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0)
		return (rc);

	*valp = kmem_alloc(strlen(ptr) + 1, KM_SLEEP);
	(void) strcpy(*valp, ptr);
	(void) nvlist_remove_all(nvlp, IPPCTL_MODNAME);
	return (0);
}
Beispiel #9
0
int
spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
{
	int err = 0;
	dmu_tx_t *tx;
	nvlist_t *nvarg, *in_nvl = NULL;

	if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY || !spa_writeable(spa))
		return (SET_ERROR(EINVAL));

	err = nvlist_lookup_nvlist(nvl, ZPOOL_HIST_INPUT_NVL, &in_nvl);
	if (err == 0) {
		(void) nvlist_remove_all(in_nvl, ZPOOL_HIDDEN_ARGS);
	}

	tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
	err = dmu_tx_assign(tx, TXG_WAIT);
	if (err) {
		dmu_tx_abort(tx);
		return (err);
	}

	VERIFY0(nvlist_dup(nvl, &nvarg, KM_SLEEP));
	if (spa_history_zone() != NULL) {
		fnvlist_add_string(nvarg, ZPOOL_HIST_ZONE,
		    spa_history_zone());
	}
	fnvlist_add_uint64(nvarg, ZPOOL_HIST_WHO, crgetruid(CRED()));

	/* Kick this off asynchronously; errors are ignored. */
	dsl_sync_task_nowait(spa_get_dsl(spa), spa_history_log_sync,
	    nvarg, 0, ZFS_SPACE_CHECK_NONE, tx);
	dmu_tx_commit(tx);

	/* spa_history_log_sync will free nvl */
	return (err);

}
Beispiel #10
0
void
fnvlist_remove(nvlist_t *nvl, const char *name)
{
	VERIFY0(nvlist_remove_all(nvl, name));
}
Beispiel #11
0
int
main(int argc, char **argv)
{
	int fd_pool;
	int fd_log;
	vdev_label_t vl_pool;
	vdev_label_t vl_log;
	nvlist_t *config_pool;
	nvlist_t *config_log;

	uint64_t guid;		// ZPOOL_CONFIG_GUID
	uint64_t is_log;	// ZPOOL_CONFIG_IS_LOG
	nvlist_t *vdev_tree;	// ZPOOL_CONFIG_VDEV_TREE

	char *buf;
	size_t buflen;

	VERIFY(argc == 4);
	VERIFY((fd_pool = open(argv[1], O_RDWR)) != -1);
	VERIFY((fd_log = open(argv[2], O_RDWR)) != -1);
	VERIFY(sscanf(argv[3], "%" SCNu64 , &guid) == 1);
	//guid = 9851295902337437618ULL;

	VERIFY(pread64(fd_pool, &vl_pool, sizeof (vdev_label_t), 0) ==
	    sizeof (vdev_label_t));
	VERIFY(nvlist_unpack(vl_pool.vl_vdev_phys.vp_nvlist,
	    sizeof (vl_pool.vl_vdev_phys.vp_nvlist), &config_pool, 0) == 0);
	VERIFY(pread64(fd_log, &vl_log, sizeof (vdev_label_t), 0) ==
	    sizeof (vdev_label_t));
	VERIFY(nvlist_unpack(vl_log.vl_vdev_phys.vp_nvlist,
	    sizeof (vl_log.vl_vdev_phys.vp_nvlist), &config_log, 0) == 0);

	// save what we want from config_log -- is_log, vdev_tree
	VERIFY(nvlist_lookup_uint64(config_log, ZPOOL_CONFIG_IS_LOG, &is_log) == 0);
	VERIFY(nvlist_lookup_nvlist(config_log, ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) == 0);

	// fix guid for vdev_log
	VERIFY(nvlist_remove_all(vdev_tree, ZPOOL_CONFIG_GUID) == 0);
	VERIFY(nvlist_add_uint64(vdev_tree, ZPOOL_CONFIG_GUID, guid) == 0);

	// remove what we are going to replace on config_pool
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_TOP_GUID) == 0);
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_GUID) == 0);
	VERIFY(nvlist_remove_all(config_pool, ZPOOL_CONFIG_VDEV_TREE) == 0);

	// add back what we want 
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_TOP_GUID, guid) == 0);
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_GUID, guid) == 0);
	VERIFY(nvlist_add_uint64(config_pool, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
	VERIFY(nvlist_add_nvlist(config_pool, ZPOOL_CONFIG_VDEV_TREE, vdev_tree) == 0);

	buf = vl_pool.vl_vdev_phys.vp_nvlist;
	buflen = sizeof (vl_pool.vl_vdev_phys.vp_nvlist);
	VERIFY(nvlist_pack(config_pool, &buf, &buflen, NV_ENCODE_XDR, 0) == 0);

	label_write(fd_log, offsetof(vdev_label_t, vl_vdev_phys),
	    VDEV_PHYS_SIZE, &vl_pool.vl_vdev_phys);

	fsync(fd_log);

	return (0);
}
Beispiel #12
0
/*
 * Function:  it_tgt_setprop()
 *
 * Validate the provided property list and set the properties for
 * the specified target.  If errlist is not NULL, returns detailed
 * errors for each property that failed.  The format for errorlist
 * is key = property, value = error string.
 *
 * Parameters:
 *
 *    cfg		The current iSCSI configuration obtained from
 *			it_config_load()
 *    tgt		Pointer to an iSCSI target structure
 *    proplist		nvlist_t containing properties for this target.
 *    errlist		(optional)  nvlist_t of errors encountered when
 *			validating the properties.
 *
 * Return Values:
 *    0			Success
 *    EINVAL		Invalid property
 *
 */
int
it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist,
    nvlist_t **errlist)
{
	int		ret;
	nvlist_t	*errs = NULL;
	nvlist_t	*tprops = NULL;
	char		*val = NULL;

	if (!cfg || !tgt || !proplist) {
		return (EINVAL);
	}

	/* verify the target name in case the target node is renamed */
	if (!validate_iscsi_name(tgt->tgt_name)) {
		return (EINVAL);
	}
	canonical_iscsi_name(tgt->tgt_name);

	if (errlist) {
		(void) nvlist_alloc(&errs, 0, 0);
		*errlist = errs;
	}

	/*
	 * copy the existing properties, merge, then validate
	 * the merged properties before committing them.
	 */
	if (tgt->tgt_properties) {
		ret = nvlist_dup(tgt->tgt_properties, &tprops, 0);
	} else {
		ret = nvlist_alloc(&tprops, NV_UNIQUE_NAME, 0);
	}

	if (ret != 0) {
		return (ret);
	}

	ret = nvlist_merge(tprops, proplist, 0);
	if (ret != 0) {
		nvlist_free(tprops);
		return (ret);
	}

	/* unset chap username or alias if requested */
	val = NULL;
	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_USER, &val);
	if (val && (strcasecmp(val, "none") == 0)) {
		(void) nvlist_remove_all(tprops, PROP_TARGET_CHAP_USER);
	}

	val = NULL;
	(void) nvlist_lookup_string(proplist, PROP_ALIAS, &val);
	if (val && (strcasecmp(val, "none") == 0)) {
		(void) nvlist_remove_all(tprops, PROP_ALIAS);
	}

	/* base64 encode the CHAP secret, if it's changed */
	val = NULL;
	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_SECRET, &val);
	if (val) {
		char		bsecret[MAX_BASE64_LEN];

		ret = it_val_pass(PROP_TARGET_CHAP_SECRET, val, errs);

		if (ret == 0) {
			(void) memset(bsecret, 0, MAX_BASE64_LEN);

			ret = iscsi_binary_to_base64_str((uint8_t *)val,
			    strlen(val), bsecret, MAX_BASE64_LEN);

			if (ret == 0) {
				/* replace the value in the nvlist */
				ret = nvlist_add_string(tprops,
				    PROP_TARGET_CHAP_SECRET, bsecret);
			}
		}
	}

	if (ret == 0) {
		ret = it_validate_tgtprops(tprops, errs);
	}

	if (ret != 0) {
		if (tprops) {
			nvlist_free(tprops);
		}
		return (ret);
	}

	if (tgt->tgt_properties) {
		nvlist_free(tgt->tgt_properties);
	}
	tgt->tgt_properties = tprops;

	free_empty_errlist(errlist);

	return (0);
}
Beispiel #13
0
/*
 * Function:  it_config_setprop()
 *
 * Validate the provided property list and set the global properties
 * for iSCSI Target.  If errlist is not NULL, returns detailed
 * errors for each property that failed.  The format for errorlist
 * is key = property, value = error string.
 *
 * Parameters:
 *
 *    cfg		The current iSCSI configuration obtained from
 *			it_config_load()
 *    proplist		nvlist_t containing properties for this target.
 *    errlist		(optional)  nvlist_t of errors encountered when
 *                      validating the properties.
 *
 * Return Values:
 *    0			Success
 *    EINVAL		Invalid property
 *
 */
int
it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist)
{
	int		ret;
	nvlist_t	*errs = NULL;
	it_portal_t	*isns = NULL;
	it_portal_t	*pnext = NULL;
	it_portal_t	*newisnslist = NULL;
	char		**arr;
	uint32_t	count;
	uint32_t	newcount;
	nvlist_t	*cprops = NULL;
	char		*val = NULL;

	if (!cfg || !proplist) {
		return (EINVAL);
	}

	if (errlist) {
		(void) nvlist_alloc(&errs, 0, 0);
		*errlist = errs;
	}

	/*
	 * copy the existing properties, merge, then validate
	 * the merged properties before committing them.
	 */
	if (cfg->config_global_properties) {
		ret = nvlist_dup(cfg->config_global_properties, &cprops, 0);
	} else {
		ret = nvlist_alloc(&cprops, NV_UNIQUE_NAME, 0);
	}

	if (ret != 0) {
		return (ret);
	}

	ret = nvlist_merge(cprops, proplist, 0);
	if (ret != 0) {
		nvlist_free(cprops);
		return (ret);
	}

	/*
	 * base64 encode the radius secret, if it's changed.
	 */
	val = NULL;
	(void) nvlist_lookup_string(proplist, PROP_RADIUS_SECRET, &val);
	if (val) {
		char		bsecret[MAX_BASE64_LEN];

		ret = it_val_pass(PROP_RADIUS_SECRET, val, errs);

		if (ret == 0) {
			(void) memset(bsecret, 0, MAX_BASE64_LEN);

			ret = iscsi_binary_to_base64_str((uint8_t *)val,
			    strlen(val), bsecret, MAX_BASE64_LEN);

			if (ret == 0) {
				/* replace the value in the nvlist */
				ret = nvlist_add_string(cprops,
				    PROP_RADIUS_SECRET, bsecret);
			}
		}
	}

	if (ret != 0) {
		nvlist_free(cprops);
		return (ret);
	}

	/* see if we need to remove the radius server setting */
	val = NULL;
	(void) nvlist_lookup_string(cprops, PROP_RADIUS_SERVER, &val);
	if (val && (strcasecmp(val, "none") == 0)) {
		(void) nvlist_remove_all(cprops, PROP_RADIUS_SERVER);
	}

	/* and/or remove the alias */
	val = NULL;
	(void) nvlist_lookup_string(cprops, PROP_ALIAS, &val);
	if (val && (strcasecmp(val, "none") == 0)) {
		(void) nvlist_remove_all(cprops, PROP_ALIAS);
	}

	ret = it_validate_configprops(cprops, errs);
	if (ret != 0) {
		if (cprops) {
			nvlist_free(cprops);
		}
		return (ret);
	}

	/*
	 * Update iSNS server list, if exists in provided property list.
	 */
	ret = nvlist_lookup_string_array(proplist, PROP_ISNS_SERVER,
	    &arr, &count);

	if (ret == 0) {
		/* special case:  if "none", remove all defined */
		if (strcasecmp(arr[0], "none") != 0) {
			ret = it_array_to_portallist(arr, count,
			    ISNS_DEFAULT_SERVER_PORT, &newisnslist, &newcount);
		} else {
			newisnslist = NULL;
			newcount = 0;
			(void) nvlist_remove_all(cprops, PROP_ISNS_SERVER);
		}

		if (ret == 0) {
			isns = cfg->config_isns_svr_list;
			while (isns) {
				pnext = isns->portal_next;
				free(isns);
				isns = pnext;
			}

			cfg->config_isns_svr_list = newisnslist;
			cfg->config_isns_svr_count = newcount;

			/*
			 * Replace the array in the nvlist to ensure
			 * duplicates are properly removed & port numbers
			 * are added.
			 */
			if (newcount > 0) {
				int	i = 0;
				char	**newarray;

				newarray = malloc(sizeof (char *) * newcount);
				if (newarray == NULL) {
					ret = ENOMEM;
				} else {
					for (isns = newisnslist; isns != NULL;
					    isns = isns->portal_next) {
						(void) sockaddr_to_str(
						    &(isns->portal_addr),
						    &(newarray[i++]));
					}
					(void) nvlist_add_string_array(cprops,
					    PROP_ISNS_SERVER, newarray,
					    newcount);

					for (i = 0; i < newcount; i++) {
						if (newarray[i]) {
							free(newarray[i]);
						}
					}
					free(newarray);
				}
			}
		}
	} else if (ret == ENOENT) {
		/* not an error */
		ret = 0;
	}

	if (ret == 0) {
		/* replace the global properties list */
		nvlist_free(cfg->config_global_properties);
		cfg->config_global_properties = cprops;
	} else {
		if (cprops) {
			nvlist_free(cprops);
		}
	}

	if (ret == 0)
		free_empty_errlist(errlist);

	return (ret);
}
Beispiel #14
0
/*
 * Function:  it_config_commit()
 *
 * Informs the iscsit service that the configuration has changed and
 * commits the new configuration to persistent store by calling
 * stmfSetProviderData.  This function can be called multiple times
 * during a configuration sequence if necessary.
 *
 * Parameters:
 *    cfg	A C representation of the current iSCSI configuration
 *
 * Return Values:
 *    0		Success
 *    ENOMEM	Could not allocate resources
 *    EINVAL	Invalid it_config_t structure
 *    TBD	ioctl() failed
 *    TBD	could not save config to STMF
 */
int
it_config_commit(it_config_t *cfg)
{
	int			ret;
	nvlist_t		*cfgnv = NULL;
	char			*packednv = NULL;
	int			iscsit_fd = -1;
	size_t			pnv_size;
	iscsit_ioc_set_config_t	iop;
	it_tgt_t		*tgtp;

	if (!cfg) {
		return (EINVAL);
	}

	ret = it_config_to_nv(cfg, &cfgnv);
	if (ret == 0) {
		ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE);
	}

	/*
	 * If the iscsit service is enabled, send the changes to the
	 * kernel first.  Kernel will be the final sanity check before
	 * the config is saved persistently.
	 *
	 * This somewhat leaves open the simultaneous-change hole
	 * that STMF was trying to solve, but is a better sanity
	 * check and allows for graceful handling of target renames.
	 */
	if ((ret == 0) && is_iscsit_enabled()) {
		packednv = malloc(pnv_size);
		if (!packednv) {
			ret = ENOMEM;
		} else {
			ret = nvlist_pack(cfgnv, &packednv, &pnv_size,
			    NV_ENCODE_NATIVE, 0);
		}

		if (ret == 0) {
			iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL);
			if (iscsit_fd != -1) {
				iop.set_cfg_vers = ISCSIT_API_VERS0;
				iop.set_cfg_pnvlist = packednv;
				iop.set_cfg_pnvlist_len = pnv_size;
				if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG,
				    &iop)) != 0) {
					ret = errno;
				}

				(void) close(iscsit_fd);
			} else {
				ret = errno;
			}
		}

		if (packednv != NULL) {
			free(packednv);
		}
	}

	/*
	 * Before saving the config persistently, remove any
	 * PROP_OLD_TARGET_NAME entries.  This is only interesting to
	 * the active service.
	 */
	if (ret == 0) {
		boolean_t	changed = B_FALSE;

		tgtp = cfg->config_tgt_list;
		for (; tgtp != NULL; tgtp = tgtp->tgt_next) {
			if (!tgtp->tgt_properties) {
				continue;
			}
			if (nvlist_exists(tgtp->tgt_properties,
			    PROP_OLD_TARGET_NAME)) {
				(void) nvlist_remove_all(tgtp->tgt_properties,
				    PROP_OLD_TARGET_NAME);
				changed = B_TRUE;
			}
		}

		if (changed) {
			/* rebuild the config nvlist */
			nvlist_free(cfgnv);
			cfgnv = NULL;
			ret = it_config_to_nv(cfg, &cfgnv);
		}
	}

	/*
	 * stmfGetProviderDataProt() checks to ensure
	 * that the config data hasn't changed since we fetched it.
	 *
	 * The kernel now has a version we need to save persistently.
	 * CLI will 'do the right thing' and warn the user if it
	 * gets STMF_ERROR_PROV_DATA_STALE.  We'll try once to revert
	 * the kernel to the persistently saved data, but ultimately,
	 * it's up to the administrator to validate things are as they
	 * want them to be.
	 */
	if (ret == 0) {
		ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv,
		    STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token));

		if (ret == STMF_STATUS_SUCCESS) {
			ret = 0;
		} else if (ret == STMF_ERROR_NOMEM) {
			ret = ENOMEM;
		} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
			int		st;
			it_config_t	*rcfg = NULL;

			st = it_config_load(&rcfg);
			if (st == 0) {
				(void) it_config_commit(rcfg);
				it_config_free(rcfg);
			}
		}
	}

	if (cfgnv) {
		nvlist_free(cfgnv);
	}

	return (ret);
}
Beispiel #15
0
/*
 * Goes through the target property list and validates
 * each entry.  If errs is non-NULL, will return explicit errors
 * for each property that fails validation.
 */
static int
it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs)
{
	int		errcnt = 0;
	nvpair_t	*nvp = NULL;
	data_type_t	nvtype;
	char		*name;
	char		*val;
	char		*auth = NULL;

	if (!nvl) {
		return (0);
	}

	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
		name = nvpair_name(nvp);
		nvtype = nvpair_type(nvp);

		if (!name) {
			continue;
		}

		val = NULL;
		if (strcmp(name, PROP_TARGET_CHAP_USER) == 0) {
			if (nvtype != DATA_TYPE_STRING) {
				PROPERR(errs, name,
				    gettext("must be a string value"));
				errcnt++;
				continue;
			}
		} else if (strcmp(name, PROP_TARGET_CHAP_SECRET) == 0) {
			/*
			 * must be between 12 and 255 chars in cleartext.
			 * will be base64 encoded when it's set.
			 */
			if (nvtype == DATA_TYPE_STRING) {
				(void) nvpair_value_string(nvp, &val);
			}

			if (!val) {
				PROPERR(errs, name,
				    gettext("must be a string value"));
				errcnt++;
				continue;
			}
		} else if (strcmp(name, PROP_ALIAS) == 0) {
			if (nvtype != DATA_TYPE_STRING) {
				PROPERR(errs, name,
				    gettext("must be a string value"));
				errcnt++;
				continue;
			}
		} else if (strcmp(name, PROP_AUTH) == 0) {
			if (nvtype == DATA_TYPE_STRING) {
				val = NULL;
				(void) nvpair_value_string(nvp, &val);
			}

			if (!val) {
				PROPERR(errs, name,
				    gettext("must be a string value"));
				errcnt++;
				continue;
			}
			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
			    (strcmp(val, PA_AUTH_RADIUS) != 0) &&
			    (strcmp(val, "default") != 0)) {
				PROPERR(errs, val, gettext(
				    "must be none, chap, radius or default"));
				errcnt++;
			}
			auth = val;
			continue;
		} else if (strcmp(name, PROP_OLD_TARGET_NAME) == 0) {
			continue;
		} else {
			/* unrecognized property */
			PROPERR(errs, name, gettext("unrecognized property"));
			errcnt++;
		}
	}

	if (errcnt) {
		return (EINVAL);
	}

	/* if auth is being set to default, remove from this nvlist */
	if (auth && (strcmp(auth, "default") == 0)) {
		(void) nvlist_remove_all(nvl, PROP_AUTH);
	}

	return (0);
}
Beispiel #16
0
/*
 * Function:  it_ini_setprop()
 *
 * Validate the provided property list and set the initiator properties.
 * If errlist is not NULL, returns detailed errors for each property
 * that failed.  The format for errorlist is key = property,
 * value = error string.
 *
 * Parameters:
 *
 *    ini		The initiator being updated.
 *    proplist		nvlist_t containing properties for this target.
 *    errlist		(optional)  nvlist_t of errors encountered when
 *			validating the properties.
 *
 * Return Values:
 *    0			Success
 *    EINVAL		Invalid property
 *
 */
int
it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist)
{
	int		ret;
	nvlist_t	*errs = NULL;
	nvlist_t	*iprops = NULL;
	char		*val = NULL;

	if (!ini || !proplist) {
		return (EINVAL);
	}

	if (errlist) {
		(void) nvlist_alloc(&errs, 0, 0);
		*errlist = errs;
	}

	/*
	 * copy the existing properties, merge, then validate
	 * the merged properties before committing them.
	 */
	if (ini->ini_properties) {
		ret = nvlist_dup(ini->ini_properties, &iprops, 0);
	} else {
		ret = nvlist_alloc(&iprops, NV_UNIQUE_NAME, 0);
	}

	if (ret != 0) {
		return (ret);
	}

	ret = nvlist_merge(iprops, proplist, 0);
	if (ret != 0) {
		nvlist_free(iprops);
		return (ret);
	}

	/* unset chap username if requested */
	if ((nvlist_lookup_string(proplist, PROP_CHAP_USER, &val)) == 0) {
		if (strcasecmp(val, "none") == 0) {
			(void) nvlist_remove_all(iprops, PROP_CHAP_USER);
		}
	}

	/* base64 encode the CHAP secret, if it's changed */
	if ((nvlist_lookup_string(proplist, PROP_CHAP_SECRET, &val)) == 0) {
		char		bsecret[MAX_BASE64_LEN];

		ret = it_val_pass(PROP_CHAP_SECRET, val, errs);
		if (ret == 0) {
			(void) memset(bsecret, 0, MAX_BASE64_LEN);

			ret = iscsi_binary_to_base64_str((uint8_t *)val,
			    strlen(val), bsecret, MAX_BASE64_LEN);

			if (ret == 0) {
				/* replace the value in the nvlist */
				ret = nvlist_add_string(iprops,
				    PROP_CHAP_SECRET, bsecret);
			}
		}
	}

	if (ret == 0) {
		ret = it_validate_iniprops(iprops, errs);
	}

	if (ret != 0) {
		if (iprops) {
			nvlist_free(iprops);
		}
		return (ret);
	}

	if (ini->ini_properties) {
		nvlist_free(ini->ini_properties);
	}
	ini->ini_properties = iprops;

	free_empty_errlist(errlist);

	return (0);
}
Beispiel #17
0
/*
 * Go through and fix up any path and/or devid information for the given vdev
 * configuration.
 */
static int
fix_paths(nvlist_t *nv, name_entry_t *names)
{
	nvlist_t **child;
	uint_t c, children;
	uint64_t guid;
	name_entry_t *ne, *best;
	char *path, *devid;

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) == 0) {
		for (c = 0; c < children; c++)
			if (fix_paths(child[c], names) != 0)
				return (-1);
		return (0);
	}

	/*
	 * This is a leaf (file or disk) vdev.  In either case, go through
	 * the name list and see if we find a matching guid.  If so, replace
	 * the path and see if we can calculate a new devid.
	 *
	 * There may be multiple names associated with a particular guid, in
	 * which case we have overlapping partitions or multiple paths to the
	 * same disk.  In this case we prefer to use the path name which
	 * matches the ZPOOL_CONFIG_PATH.  If no matching entry is found we
	 * use the lowest order device which corresponds to the first match
	 * while traversing the ZPOOL_IMPORT_PATH search path.
	 */
	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
		path = NULL;

	best = NULL;
	for (ne = names; ne != NULL; ne = ne->ne_next) {
		if (ne->ne_guid == guid) {

			if (path == NULL) {
				best = ne;
				break;
			}

			if ((strlen(path) == strlen(ne->ne_name)) &&
			    strncmp(path, ne->ne_name, strlen(path)) == 0) {
				best = ne;
				break;
			}

			if (best == NULL) {
				best = ne;
				continue;
			}

			/* Prefer paths with move vdev labels. */
			if (ne->ne_num_labels > best->ne_num_labels) {
				best = ne;
				continue;
			}

			/* Prefer paths earlier in the search order. */
			if (ne->ne_num_labels == best->ne_num_labels &&
			    ne->ne_order < best->ne_order) {
				best = ne;
				continue;
			}
		}
	}

	if (best == NULL)
		return (0);

	if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
		return (-1);

	if ((devid = get_devid(best->ne_name)) == NULL) {
		(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
	} else {
		if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) {
			devid_str_free(devid);
			return (-1);
		}
		devid_str_free(devid);
	}

	return (0);
}
Beispiel #18
0
/*
 * Go through and fix up any path and/or devid information for the given vdev
 * configuration.
 */
static int
fix_paths(nvlist_t *nv, name_entry_t *names)
{
	nvlist_t **child;
	uint_t c, children;
	uint64_t guid;
	name_entry_t *ne, *best;
	char *path, *devid;
	int matched;

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) == 0) {
		for (c = 0; c < children; c++)
			if (fix_paths(child[c], names) != 0)
				return (-1);
		return (0);
	}

	/*
	 * This is a leaf (file or disk) vdev.  In either case, go through
	 * the name list and see if we find a matching guid.  If so, replace
	 * the path and see if we can calculate a new devid.
	 *
	 * There may be multiple names associated with a particular guid, in
	 * which case we have overlapping slices or multiple paths to the same
	 * disk.  If this is the case, then we want to pick the path that is
	 * the most similar to the original, where "most similar" is the number
	 * of matching characters starting from the end of the path.  This will
	 * preserve slice numbers even if the disks have been reorganized, and
	 * will also catch preferred disk names if multiple paths exist.
	 */
	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
		path = NULL;

	matched = 0;
	best = NULL;
	for (ne = names; ne != NULL; ne = ne->ne_next) {
		if (ne->ne_guid == guid) {
			const char *src, *dst;
			int count;

			if (path == NULL) {
				best = ne;
				break;
			}

			src = ne->ne_name + strlen(ne->ne_name) - 1;
			dst = path + strlen(path) - 1;
			for (count = 0; src >= ne->ne_name && dst >= path;
			    src--, dst--, count++)
				if (*src != *dst)
					break;

			/*
			 * At this point, 'count' is the number of characters
			 * matched from the end.
			 */
			if (count > matched || best == NULL) {
				best = ne;
				matched = count;
			}
		}
	}

	if (best == NULL)
		return (0);

	if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
		return (-1);

	if ((devid = get_devid(best->ne_name)) == NULL) {
		(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
	} else {
		if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) {
			devid_str_free(devid);
			return (-1);
		}
		devid_str_free(devid);
	}

	return (0);
}