static int scsiback_add_translation_entry()

in xen-scsiback.c [858:947]


static int scsiback_add_translation_entry(struct vscsibk_info *info,
					  char *phy, struct ids_tuple *v)
{
	int err = 0;
	struct v2p_entry *new;
	unsigned long flags;
	char *lunp;
	unsigned long long unpacked_lun;
	struct se_lun *se_lun;
	struct scsiback_tpg *tpg_entry, *tpg = NULL;
	char *error = "doesn't exist";

	lunp = strrchr(phy, ':');
	if (!lunp) {
		pr_err("illegal format of physical device %s\n", phy);
		return -EINVAL;
	}
	*lunp = 0;
	lunp++;
	err = kstrtoull(lunp, 10, &unpacked_lun);
	if (err < 0) {
		pr_err("lun number not valid: %s\n", lunp);
		return err;
	}

	mutex_lock(&scsiback_mutex);
	list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) {
		if (!strcmp(phy, tpg_entry->tport->tport_name) ||
		    !strcmp(phy, tpg_entry->param_alias)) {
			mutex_lock(&tpg_entry->se_tpg.tpg_lun_mutex);
			hlist_for_each_entry(se_lun, &tpg_entry->se_tpg.tpg_lun_hlist, link) {
				if (se_lun->unpacked_lun == unpacked_lun) {
					if (!tpg_entry->tpg_nexus)
						error = "nexus undefined";
					else
						tpg = tpg_entry;
					break;
				}
			}
			mutex_unlock(&tpg_entry->se_tpg.tpg_lun_mutex);
			break;
		}
	}
	if (tpg) {
		mutex_lock(&tpg->tv_tpg_mutex);
		tpg->tv_tpg_fe_count++;
		mutex_unlock(&tpg->tv_tpg_mutex);
	}
	mutex_unlock(&scsiback_mutex);

	if (!tpg) {
		pr_err("%s:%llu %s\n", phy, unpacked_lun, error);
		return -ENODEV;
	}

	new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL);
	if (new == NULL) {
		err = -ENOMEM;
		goto out_free;
	}

	spin_lock_irqsave(&info->v2p_lock, flags);

	/* Check double assignment to identical virtual ID */
	if (scsiback_chk_translation_entry(info, v)) {
		pr_warn("Virtual ID is already used. Assignment was not performed.\n");
		err = -EEXIST;
		goto out;
	}

	/* Create a new translation entry and add to the list */
	kref_init(&new->kref);
	new->v = *v;
	new->tpg = tpg;
	new->lun = unpacked_lun;
	list_add_tail(&new->l, &info->v2p_entry_lists);

out:
	spin_unlock_irqrestore(&info->v2p_lock, flags);

out_free:
	if (err) {
		mutex_lock(&tpg->tv_tpg_mutex);
		tpg->tv_tpg_fe_count--;
		mutex_unlock(&tpg->tv_tpg_mutex);
		kfree(new);
	}

	return err;
}