feat: read and validate unit serial number after login
this patch adds a read of VPD page 0x80 (unit serial number) after successful login. The serial is then validated on secutive reconnects to avoid the accidental mismatch of LUN ids if some kind of remapping appears between loss of connection and a later reconnect. An additional url parameter force_usn is added to enforce the usn right from the beginning. If not set via url or the new iscsi_set_unit_serial_number function the usn is learned at the first successful login. Signed-off-by: Peter Lieven <pl@dlhnet.de>
This commit is contained in:
@@ -76,6 +76,50 @@ iscsi_testunitready_connect(struct iscsi_context *iscsi, int lun,
|
||||
return task;
|
||||
}
|
||||
|
||||
static struct scsi_task *
|
||||
iscsi_inquiry_page_0x80_connect(struct iscsi_context *iscsi, int lun,
|
||||
iscsi_command_cb cb, void *private_data)
|
||||
{
|
||||
struct scsi_task *task;
|
||||
struct iscsi_context *old_iscsi = iscsi->old_iscsi;
|
||||
|
||||
iscsi->old_iscsi = NULL;
|
||||
task = iscsi_inquiry_task(iscsi, lun, 1, 0x80, MAX_STRING_SIZE + 64,
|
||||
cb, private_data);
|
||||
iscsi->old_iscsi = old_iscsi;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_inquiry_page_0x80_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *private_data)
|
||||
{
|
||||
struct connect_task *ct = private_data;
|
||||
struct scsi_task *task = command_data;
|
||||
struct scsi_inquiry_unit_serial_number *inq;
|
||||
|
||||
if (!status) {
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (!iscsi->unit_serial_number[0]) {
|
||||
ISCSI_LOG(iscsi, 2, "unit serial number is [%s]", inq->usn);
|
||||
strncpy(iscsi->unit_serial_number, inq->usn, MAX_STRING_SIZE);
|
||||
} else if (strncmp(iscsi->unit_serial_number, inq->usn, MAX_STRING_SIZE)) {
|
||||
iscsi_set_error(iscsi, "unit serial number mismatch. got [%s] expected [%s]",
|
||||
inq->usn, iscsi->unit_serial_number);
|
||||
status = 1;
|
||||
} else {
|
||||
ISCSI_LOG(iscsi, 2, "successfully validated unit serial number [%s]", inq->usn);
|
||||
}
|
||||
} else {
|
||||
iscsi_set_error(iscsi, "iscsi_inquiry_task failed. could not read vpd page 0x80.");
|
||||
}
|
||||
|
||||
ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL, ct->private_data);
|
||||
scsi_free_scsi_task(task);
|
||||
iscsi_free(iscsi, ct);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *private_data)
|
||||
@@ -137,10 +181,21 @@ iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
|
||||
status = 0;
|
||||
}
|
||||
|
||||
ct->cb(iscsi, status?SCSI_STATUS_ERROR:SCSI_STATUS_GOOD, NULL,
|
||||
ct->private_data);
|
||||
scsi_free_scsi_task(task);
|
||||
iscsi_free(iscsi, ct);
|
||||
if (status != 0) {
|
||||
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||
ct->private_data);
|
||||
scsi_free_scsi_task(task);
|
||||
iscsi_free(iscsi, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iscsi_inquiry_page_0x80_connect(iscsi, ct->lun,
|
||||
iscsi_inquiry_page_0x80_cb,
|
||||
ct) == NULL) {
|
||||
iscsi_set_error(iscsi, "iscsi_inquiry_task failed.");
|
||||
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
|
||||
iscsi_free(iscsi, ct);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -178,8 +233,13 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
iscsi_free(iscsi, ct);
|
||||
}
|
||||
} else {
|
||||
ct->cb(iscsi, SCSI_STATUS_GOOD, NULL, ct->private_data);
|
||||
iscsi_free(iscsi, ct);
|
||||
if (iscsi_inquiry_page_0x80_connect(iscsi, ct->lun,
|
||||
iscsi_inquiry_page_0x80_cb,
|
||||
ct) == NULL) {
|
||||
iscsi_set_error(iscsi, "iscsi_inquiry_task failed.");
|
||||
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
|
||||
iscsi_free(iscsi, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +431,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi->frees += old_iscsi->frees;
|
||||
|
||||
free(old_iscsi);
|
||||
|
||||
|
||||
/* avoid a reconnect faster than 3 seconds */
|
||||
iscsi->next_reconnect = time(NULL) + 3;
|
||||
|
||||
@@ -443,10 +503,12 @@ static int reconnect(struct iscsi_context *iscsi, int force)
|
||||
tmp_iscsi->lun = iscsi->lun;
|
||||
|
||||
strncpy(tmp_iscsi->portal, iscsi->portal, MAX_STRING_SIZE);
|
||||
|
||||
|
||||
strncpy(tmp_iscsi->bind_interfaces, iscsi->bind_interfaces, MAX_STRING_SIZE);
|
||||
tmp_iscsi->bind_interfaces_cnt = iscsi->bind_interfaces_cnt;
|
||||
|
||||
|
||||
strncpy(tmp_iscsi->unit_serial_number, iscsi->unit_serial_number, MAX_STRING_SIZE);
|
||||
|
||||
tmp_iscsi->log_level = iscsi->log_level;
|
||||
tmp_iscsi->log_fn = iscsi->log_fn;
|
||||
tmp_iscsi->tcp_user_timeout = iscsi->tcp_user_timeout;
|
||||
|
||||
34
lib/init.c
34
lib/init.c
@@ -215,7 +215,7 @@ iscsi_create_context(const char *initiator_name)
|
||||
iscsi->tcp_keepcnt=3;
|
||||
iscsi->tcp_keepintvl=30;
|
||||
iscsi->tcp_keepidle=30;
|
||||
|
||||
|
||||
iscsi->reconnect_max_retries = -1;
|
||||
iscsi->chap_auth = ISCSI_CHAP_MD5;
|
||||
|
||||
@@ -345,6 +345,26 @@ iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iscsi_set_unit_serial_number(struct iscsi_context *iscsi, const char *usn)
|
||||
{
|
||||
if (iscsi->is_loggedin != 0) {
|
||||
iscsi_set_error(iscsi, "Already logged in when adding "
|
||||
"unit_serial_number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(iscsi->unit_serial_number,usn,MAX_STRING_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
iscsi_get_unit_serial_number(struct iscsi_context *iscsi)
|
||||
{
|
||||
return iscsi ? iscsi->unit_serial_number : "";
|
||||
}
|
||||
|
||||
int
|
||||
iscsi_destroy_context(struct iscsi_context *iscsi)
|
||||
{
|
||||
@@ -383,7 +403,7 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
|
||||
|
||||
iscsi_mt_spin_destroy(&iscsi->iscsi_lock);
|
||||
iscsi_mt_mutex_destroy(&iscsi->iscsi_mutex);
|
||||
|
||||
|
||||
memset(iscsi, 0, sizeof(struct iscsi_context));
|
||||
free(iscsi);
|
||||
|
||||
@@ -521,6 +541,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
char *passwd = NULL;
|
||||
char *target_user = NULL;
|
||||
char *target_passwd = NULL;
|
||||
char *usn = NULL;
|
||||
char *target = NULL;
|
||||
char *lun;
|
||||
char *tmp;
|
||||
@@ -628,6 +649,9 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
iscsi->rdma_ack_timeout = atoi(value);
|
||||
#endif
|
||||
}
|
||||
if (!strcmp(key, "force_usn")) {
|
||||
usn = value;
|
||||
}
|
||||
tmp = next;
|
||||
}
|
||||
}
|
||||
@@ -691,7 +715,7 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
*tmp=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (iscsi != NULL) {
|
||||
iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url));
|
||||
} else {
|
||||
@@ -743,6 +767,9 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
|
||||
iscsi_set_targetname(iscsi, iscsi_url->target);
|
||||
iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd);
|
||||
iscsi_set_target_username_pwd(iscsi, iscsi_url->target_user, iscsi_url->target_passwd);
|
||||
if (usn) {
|
||||
iscsi_set_unit_serial_number(iscsi, usn);
|
||||
}
|
||||
}
|
||||
|
||||
return iscsi_url;
|
||||
@@ -854,4 +881,3 @@ iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth)
|
||||
{
|
||||
iscsi->chap_auth = auth;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user