static ssize_t target_pr_res_aptpl_metadata_store()

in target_core_configfs.c [1963:2146]


static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item,
		const char *page, size_t count)
{
	struct se_device *dev = pr_to_dev(item);
	unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL;
	unsigned char *t_fabric = NULL, *t_port = NULL;
	char *orig, *ptr, *opts;
	substring_t args[MAX_OPT_ARGS];
	unsigned long long tmp_ll;
	u64 sa_res_key = 0;
	u64 mapped_lun = 0, target_lun = 0;
	int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token;
	u16 tpgt = 0;
	u8 type = 0;

	if (!dev->dev_attrib.emulate_pr ||
	    (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR))
		return count;
	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
		return count;

	if (dev->export_count) {
		pr_debug("Unable to process APTPL metadata while"
			" active fabric exports exist\n");
		return -EINVAL;
	}

	opts = kstrdup(page, GFP_KERNEL);
	if (!opts)
		return -ENOMEM;

	orig = opts;
	while ((ptr = strsep(&opts, ",\n")) != NULL) {
		if (!*ptr)
			continue;

		token = match_token(ptr, tokens, args);
		switch (token) {
		case Opt_initiator_fabric:
			i_fabric = match_strdup(args);
			if (!i_fabric) {
				ret = -ENOMEM;
				goto out;
			}
			break;
		case Opt_initiator_node:
			i_port = match_strdup(args);
			if (!i_port) {
				ret = -ENOMEM;
				goto out;
			}
			if (strlen(i_port) >= PR_APTPL_MAX_IPORT_LEN) {
				pr_err("APTPL metadata initiator_node="
					" exceeds PR_APTPL_MAX_IPORT_LEN: %d\n",
					PR_APTPL_MAX_IPORT_LEN);
				ret = -EINVAL;
				break;
			}
			break;
		case Opt_initiator_sid:
			isid = match_strdup(args);
			if (!isid) {
				ret = -ENOMEM;
				goto out;
			}
			if (strlen(isid) >= PR_REG_ISID_LEN) {
				pr_err("APTPL metadata initiator_isid"
					"= exceeds PR_REG_ISID_LEN: %d\n",
					PR_REG_ISID_LEN);
				ret = -EINVAL;
				break;
			}
			break;
		case Opt_sa_res_key:
			ret = match_u64(args,  &tmp_ll);
			if (ret < 0) {
				pr_err("kstrtoull() failed for sa_res_key=\n");
				goto out;
			}
			sa_res_key = (u64)tmp_ll;
			break;
		/*
		 * PR APTPL Metadata for Reservation
		 */
		case Opt_res_holder:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			res_holder = arg;
			break;
		case Opt_res_type:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			type = (u8)arg;
			break;
		case Opt_res_scope:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			break;
		case Opt_res_all_tg_pt:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			all_tg_pt = (int)arg;
			break;
		case Opt_mapped_lun:
			ret = match_u64(args, &tmp_ll);
			if (ret)
				goto out;
			mapped_lun = (u64)tmp_ll;
			break;
		/*
		 * PR APTPL Metadata for Target Port
		 */
		case Opt_target_fabric:
			t_fabric = match_strdup(args);
			if (!t_fabric) {
				ret = -ENOMEM;
				goto out;
			}
			break;
		case Opt_target_node:
			t_port = match_strdup(args);
			if (!t_port) {
				ret = -ENOMEM;
				goto out;
			}
			if (strlen(t_port) >= PR_APTPL_MAX_TPORT_LEN) {
				pr_err("APTPL metadata target_node="
					" exceeds PR_APTPL_MAX_TPORT_LEN: %d\n",
					PR_APTPL_MAX_TPORT_LEN);
				ret = -EINVAL;
				break;
			}
			break;
		case Opt_tpgt:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			tpgt = (u16)arg;
			break;
		case Opt_port_rtpi:
			ret = match_int(args, &arg);
			if (ret)
				goto out;
			break;
		case Opt_target_lun:
			ret = match_u64(args, &tmp_ll);
			if (ret)
				goto out;
			target_lun = (u64)tmp_ll;
			break;
		default:
			break;
		}
	}

	if (!i_port || !t_port || !sa_res_key) {
		pr_err("Illegal parameters for APTPL registration\n");
		ret = -EINVAL;
		goto out;
	}

	if (res_holder && !(type)) {
		pr_err("Illegal PR type: 0x%02x for reservation"
				" holder\n", type);
		ret = -EINVAL;
		goto out;
	}

	ret = core_scsi3_alloc_aptpl_registration(&dev->t10_pr, sa_res_key,
			i_port, isid, mapped_lun, t_port, tpgt, target_lun,
			res_holder, all_tg_pt, type);
out:
	kfree(i_fabric);
	kfree(i_port);
	kfree(isid);
	kfree(t_fabric);
	kfree(t_port);
	kfree(orig);
	return (ret == 0) ? count : ret;
}