Merge pull request #24 from plieven/master

Various patches to libiscsi
This commit is contained in:
Ronnie Sahlberg
2012-10-18 20:01:23 -07:00
11 changed files with 147 additions and 10 deletions

View File

@@ -65,6 +65,7 @@ struct iscsi_context {
const char *initiator_name; const char *initiator_name;
const char *target_name; const char *target_name;
const char *target_address; /* If a redirect */ const char *target_address; /* If a redirect */
const char *connected_portal;
const char *alias; const char *alias;
const char *user; const char *user;
@@ -84,6 +85,8 @@ struct iscsi_context {
int fd; int fd;
int is_connected; int is_connected;
int tcp_user_timeout;
int current_phase; int current_phase;
int next_phase; int next_phase;
#define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0 #define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0
@@ -120,6 +123,7 @@ struct iscsi_context {
const char *portal; const char *portal;
int no_auto_reconnect; int no_auto_reconnect;
int reconnect_deferred; int reconnect_deferred;
int debug;
}; };
#define ISCSI_PDU_IMMEDIATE 0x40 #define ISCSI_PDU_IMMEDIATE 0x40

View File

@@ -231,6 +231,7 @@ enum scsi_status {
SCSI_STATUS_GOOD = 0, SCSI_STATUS_GOOD = 0,
SCSI_STATUS_CHECK_CONDITION = 2, SCSI_STATUS_CHECK_CONDITION = 2,
SCSI_STATUS_RESERVATION_CONFLICT = 0x18, SCSI_STATUS_RESERVATION_CONFLICT = 0x18,
SCSI_STATUS_REDIRECT = 0x101,
SCSI_STATUS_CANCELLED = 0x0f000000, SCSI_STATUS_CANCELLED = 0x0f000000,
SCSI_STATUS_ERROR = 0x0f000001 SCSI_STATUS_ERROR = 0x0f000001
}; };
@@ -958,6 +959,21 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi,
EXTERN void EXTERN void
iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi);
#define DPRINTF(iscsi,level,fmt,args...) do { if ((iscsi)->debug >= level) {fprintf(stderr,"libiscsi: ");fprintf(stderr, (fmt), ##args); fprintf(stderr,"\n");} } while (0);
/*
* This function is to set the debugging level (0=disabled).
*/
EXTERN void
iscsi_set_debug(struct iscsi_context *iscsi, int level);
/*
* This function is to set the TCP_USER_TIMEOUT option. It has to be called after iscsi
* context creation. The value given in ms is then applied each time a new socket is created.
*/
EXTERN void
iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -35,6 +35,10 @@ struct connect_task {
int lun; int lun;
}; };
static void
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_,
void *private_data);
static void static void
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *private_data) void *command_data, void *private_data)
@@ -82,6 +86,14 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_,
{ {
struct connect_task *ct = private_data; struct connect_task *ct = private_data;
if (status == 0x101 && iscsi->target_address) {
iscsi_disconnect(iscsi);
if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) {
return;
}
return;
}
if (status != 0) { if (status != 0) {
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
return; return;
@@ -158,6 +170,8 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi)
{ {
struct iscsi_context *iscsi = old_iscsi; struct iscsi_context *iscsi = old_iscsi;
DPRINTF(iscsi,2,"reconnect initiated");
/* This is mainly for tests, where we do not want to automatically /* This is mainly for tests, where we do not want to automatically
reconnect but rather want the commands to fail with an error reconnect but rather want the commands to fail with an error
if the target drops the session. if the target drops the session.
@@ -195,6 +209,9 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi)
return 0; return 0;
} }
int retry = 0;
srand (time(NULL)^getpid());
try_again: try_again:
iscsi = iscsi_create_context(old_iscsi->initiator_name); iscsi = iscsi_create_context(old_iscsi->initiator_name);
@@ -214,9 +231,23 @@ try_again:
iscsi->portal = strdup(old_iscsi->portal); iscsi->portal = strdup(old_iscsi->portal);
iscsi->debug = old_iscsi->debug;
iscsi->tcp_user_timeout = old_iscsi->tcp_user_timeout;
if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) {
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
sleep(1); int backoff=retry;
if (backoff > 10) {
backoff+=rand()%10;
backoff-=5;
}
if (backoff > 30) {
backoff=30;
}
DPRINTF(iscsi,1,"reconnect try %d failed, waiting %d seconds",retry,backoff);
sleep(backoff);
retry++;
goto try_again; goto try_again;
} }

View File

@@ -244,6 +244,11 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
free(discard_const(iscsi->chap_c)); free(discard_const(iscsi->chap_c));
iscsi->chap_c = NULL; iscsi->chap_c = NULL;
if (iscsi->connected_portal != NULL) {
free(discard_const(iscsi->connected_portal));
iscsi->connected_portal = NULL;
}
iscsi->connect_data = NULL; iscsi->connect_data = NULL;
free(iscsi); free(iscsi);
@@ -251,8 +256,6 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
return 0; return 0;
} }
void void
iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
{ {
@@ -270,9 +273,18 @@ iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
free(iscsi->error_string); free(iscsi->error_string);
iscsi->error_string = str; iscsi->error_string = str;
va_end(ap); va_end(ap);
DPRINTF(iscsi,1,str);
} }
void
iscsi_set_debug(struct iscsi_context *iscsi, int level)
{
iscsi->debug = level;
DPRINTF(iscsi,2,"set debug level to %d",level);
}
const char * const char *
iscsi_get_error(struct iscsi_context *iscsi) iscsi_get_error(struct iscsi_context *iscsi)

View File

@@ -62,6 +62,7 @@ iscsi_scsi_command_sync
iscsi_scsi_task_cancel iscsi_scsi_task_cancel
iscsi_service iscsi_service
iscsi_set_alias iscsi_set_alias
iscsi_set_debug
iscsi_set_header_digest iscsi_set_header_digest
iscsi_set_initiator_username_pwd iscsi_set_initiator_username_pwd
iscsi_set_isid_en iscsi_set_isid_en
@@ -71,6 +72,7 @@ iscsi_set_isid_reserved
iscsi_set_session_type iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -60,6 +60,7 @@ iscsi_scsi_command_sync
iscsi_scsi_task_cancel iscsi_scsi_task_cancel
iscsi_service iscsi_service
iscsi_set_alias iscsi_set_alias
iscsi_set_debug
iscsi_set_header_digest iscsi_set_header_digest
iscsi_set_initiator_username_pwd iscsi_set_initiator_username_pwd
iscsi_set_isid_en iscsi_set_isid_en
@@ -69,6 +70,7 @@ iscsi_set_isid_reserved
iscsi_set_session_type iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -1088,6 +1088,13 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
size -= len + 1; size -= len + 1;
} }
if (status == 0x101 && iscsi->target_address) {
DPRINTF(iscsi,2,"target requests redirect to %s",iscsi->target_address);
pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL,
pdu->private_data);
return 0;
}
if (status != 0) { if (status != 0) {
iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)", iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)",
login_error_str(status), status); login_error_str(status), status);

View File

@@ -242,8 +242,8 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) { if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) {
uint32_t len = data.size; uint32_t len = data.size;
if (len > iscsi->target_max_recv_data_segment_length) { if (len > iscsi->first_burst_length) {
len = iscsi->target_max_recv_data_segment_length; len = iscsi->first_burst_length;
} }
if (iscsi_pdu_add_data(iscsi, pdu, data.data, len) if (iscsi_pdu_add_data(iscsi, pdu, data.data, len)
@@ -302,7 +302,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
} }
/* Can we send some unsolicited data ? */ /* Can we send some unsolicited data ? */
if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO && iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_NO) {
uint32_t len = pdu->nidata.size - offset; uint32_t len = pdu->nidata.size - offset;
if (len > iscsi->first_burst_length) { if (len > iscsi->first_burst_length) {

View File

@@ -68,6 +68,8 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
struct addrinfo *ai = NULL; struct addrinfo *ai = NULL;
int socksize; int socksize;
DPRINTF(iscsi,2,"connecting to portal %s",portal);
if (iscsi->fd != -1) { if (iscsi->fd != -1) {
iscsi_set_error(iscsi, iscsi_set_error(iscsi,
"Trying to connect but already connected."); "Trying to connect but already connected.");
@@ -158,6 +160,12 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
set_nonblocking(iscsi->fd); set_nonblocking(iscsi->fd);
iscsi_set_tcp_keepalive(iscsi, 30, 3, 30);
if (iscsi->tcp_user_timeout > 0) {
set_tcp_user_timeout(iscsi);
}
if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 if (connect(iscsi->fd, ai->ai_addr, socksize) != 0
&& errno != EINPROGRESS) { && errno != EINPROGRESS) {
iscsi_set_error(iscsi, "Connect failed with errno : " iscsi_set_error(iscsi, "Connect failed with errno : "
@@ -169,6 +177,10 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
} }
freeaddrinfo(ai); freeaddrinfo(ai);
if (iscsi->connected_portal) free(iscsi->connected_portal);
iscsi->connected_portal=strdup(portal);
return 0; return 0;
} }
@@ -183,6 +195,9 @@ iscsi_disconnect(struct iscsi_context *iscsi)
close(iscsi->fd); close(iscsi->fd);
if (iscsi->connected_portal)
DPRINTF(iscsi,2,"disconnected from portal %s",iscsi->connected_portal);
iscsi->fd = -1; iscsi->fd = -1;
iscsi->is_connected = 0; iscsi->is_connected = 0;
@@ -437,7 +452,6 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
return -1; return -1;
} }
iscsi_set_tcp_keepalive(iscsi, 30, 3, 30);
iscsi->is_connected = 1; iscsi->is_connected = 1;
iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL,
iscsi->connect_data); iscsi->connect_data);
@@ -515,6 +529,40 @@ iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue)
} }
} }
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 18
#endif
int set_tcp_user_timeout(struct iscsi_context *iscsi)
{
int level, value;
#if defined(__FreeBSD__) || defined(__sun)
struct protoent *buf;
if ((buf = getprotobyname("tcp")) != NULL)
level = buf->p_proto;
else
return -1;
#else
level = SOL_TCP;
#endif
value = iscsi->tcp_user_timeout;
if (setsockopt(iscsi->fd, level, TCP_USER_TIMEOUT, &value, sizeof(value)) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp user timeout. Error %s(%d)", strerror(errno), errno);
return -1;
}
DPRINTF(iscsi,3,"TCP_USER_TIMEOUT set to %d",value);
return 0;
}
void iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms)
{
iscsi->tcp_user_timeout=timeout_ms;
DPRINTF(iscsi,2,"TCP_USER_TIMEOUT will be set to %dms on next socket creation",timeout_ms);
}
int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval) int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval)
{ {
int level, value; int level, value;
@@ -535,6 +583,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in
iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"SO_KEEPALIVE set to %d",value);
#endif #endif
#ifdef TCP_KEEPCNT #ifdef TCP_KEEPCNT
value = count; value = count;
@@ -542,6 +591,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPCNT set to %d",value);
#endif #endif
#ifdef TCP_KEEPINTVL #ifdef TCP_KEEPINTVL
value = interval; value = interval;
@@ -549,6 +599,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPINTVL set to %d",value);
#endif #endif
#ifdef TCP_KEEPIDLE #ifdef TCP_KEEPIDLE
value = idle; value = idle;
@@ -556,6 +607,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPIDLE set to %d",value);
#endif #endif
return 0; return 0;

View File

@@ -196,6 +196,7 @@ void print_help(void)
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -e, --evpd=integer evpd\n"); fprintf(stderr, " -e, --evpd=integer evpd\n");
fprintf(stderr, " -c, --pagecode=integer page code\n"); fprintf(stderr, " -c, --pagecode=integer page code\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n"); fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " -?, --help Show this help message\n");
@@ -218,7 +219,7 @@ int main(int argc, const char *argv[])
const char *url = NULL; const char *url = NULL;
struct iscsi_url *iscsi_url = NULL; struct iscsi_url *iscsi_url = NULL;
int evpd = 0, pagecode = 0; int evpd = 0, pagecode = 0;
int show_help = 0, show_usage = 0; int show_help = 0, show_usage = 0, debug = 0;
int res; int res;
struct poptOption popt_options[] = { struct poptOption popt_options[] = {
@@ -227,6 +228,7 @@ int main(int argc, const char *argv[])
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" }, { "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" },
{ "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" }, { "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" },
{ "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" },
POPT_TABLEEND POPT_TABLEEND
}; };
@@ -263,6 +265,10 @@ int main(int argc, const char *argv[])
exit(10); exit(10);
} }
if (debug > 0) {
iscsi_set_debug(iscsi, debug);
}
if (url == NULL) { if (url == NULL) {
fprintf(stderr, "You must specify the URL\n"); fprintf(stderr, "You must specify the URL\n");
print_usage(); print_usage();

View File

@@ -291,6 +291,7 @@ void print_help(void)
fprintf(stderr, "Usage: iscsi-ls [OPTION...] <iscsi-url>\n"); fprintf(stderr, "Usage: iscsi-ls [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -s, --show-luns Show the luns for each target\n"); fprintf(stderr, " -s, --show-luns Show the luns for each target\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n"); fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " -?, --help Show this help message\n");
@@ -314,13 +315,14 @@ int main(int argc, const char *argv[])
const char *url = NULL; const char *url = NULL;
poptContext pc; poptContext pc;
int res; int res;
int show_help = 0, show_usage = 0; int show_help = 0, show_usage = 0, debug = 0;
struct poptOption popt_options[] = { struct poptOption popt_options[] = {
{ "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL },
{ "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL },
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL }, { "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL },
{ "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" },
POPT_TABLEEND POPT_TABLEEND
}; };
@@ -353,7 +355,6 @@ int main(int argc, const char *argv[])
poptFreeContext(pc); poptFreeContext(pc);
if (url == NULL) { if (url == NULL) {
fprintf(stderr, "You must specify iscsi target portal.\n"); fprintf(stderr, "You must specify iscsi target portal.\n");
print_usage(); print_usage();
@@ -366,6 +367,10 @@ int main(int argc, const char *argv[])
exit(10); exit(10);
} }
if (debug > 0) {
iscsi_set_debug(iscsi, debug);
}
iscsi_url = iscsi_parse_portal_url(iscsi, url); iscsi_url = iscsi_parse_portal_url(iscsi, url);
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n", fprintf(stderr, "Failed to parse URL: %s\n",