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;
}