Merge pull request #25 from plieven/master

Fix Compiler warnings + add setters for TCP keepalive values
This commit is contained in:
Ronnie Sahlberg
2012-10-22 06:27:16 -07:00
11 changed files with 305 additions and 132 deletions

View File

@@ -86,6 +86,10 @@ struct iscsi_context {
int is_connected; int is_connected;
int tcp_user_timeout; int tcp_user_timeout;
int tcp_keepcnt;
int tcp_keepintvl;
int tcp_keepidle;
int tcp_syncnt;
int current_phase; int current_phase;
int next_phase; int next_phase;

View File

@@ -974,6 +974,28 @@ iscsi_set_debug(struct iscsi_context *iscsi, int level);
EXTERN void EXTERN void
iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms); iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms);
/*
* This function is to set the TCP_KEEPIDLE option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepidle(struct iscsi_context *iscsi, int value);
/*
* This function is to set the TCP_KEEPCNT option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepcnt(struct iscsi_context *iscsi, int value);
/*
* This function is to set the TCP_KEEPINTVL option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepintvl(struct iscsi_context *iscsi, int value);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <time.h>
#include "slist.h" #include "slist.h"
#include "iscsi.h" #include "iscsi.h"
#include "iscsi-private.h" #include "iscsi-private.h"
@@ -86,13 +87,13 @@ 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 == SCSI_STATUS_REDIRECT && iscsi->target_address) { if (status == SCSI_STATUS_REDIRECT && iscsi->target_address) {
iscsi_disconnect(iscsi); iscsi_disconnect(iscsi);
if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) { if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) {
return; return;
} }
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);
@@ -170,7 +171,7 @@ 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"); 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
@@ -209,8 +210,8 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi)
return 0; return 0;
} }
int retry = 0; int retry = 0;
srand (time(NULL)^getpid()); srand (time(NULL)^getpid());
try_again: try_again:
@@ -234,6 +235,10 @@ try_again:
iscsi->debug = old_iscsi->debug; iscsi->debug = old_iscsi->debug;
iscsi->tcp_user_timeout = old_iscsi->tcp_user_timeout; iscsi->tcp_user_timeout = old_iscsi->tcp_user_timeout;
iscsi->tcp_keepidle = old_iscsi->tcp_keepidle;
iscsi->tcp_keepcnt = old_iscsi->tcp_keepcnt;
iscsi->tcp_keepintvl = old_iscsi->tcp_keepintvl;
iscsi->tcp_syncnt = old_iscsi->tcp_syncnt;
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);

View File

@@ -71,6 +71,34 @@ iscsi_create_context(const char *initiator_name)
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C;
iscsi->tcp_keepcnt=3;
iscsi->tcp_keepintvl=30;
iscsi->tcp_keepidle=30;
if (getenv("LIBISCSI_DEBUG") != NULL) {
iscsi_set_debug(iscsi,atoi(getenv("LIBISCSI_DEBUG")));
}
if (getenv("LIBISCSI_TCP_USER_TIMEOUT") != NULL) {
iscsi_set_tcp_user_timeout(iscsi,atoi(getenv("LIBISCSI_TCP_USER_TIMEOUT")));
}
if (getenv("LIBISCSI_TCP_KEEPCNT") != NULL) {
iscsi_set_tcp_keepcnt(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPCNT")));
}
if (getenv("LIBISCSI_TCP_KEEPINTVL") != NULL) {
iscsi_set_tcp_keepintvl(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPINTVL")));
}
if (getenv("LIBISCSI_TCP_KEEPIDLE") != NULL) {
iscsi_set_tcp_keepidle(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPIDLE")));
}
if (getenv("LIBISCSI_TCP_SYNCNT") != NULL) {
iscsi_set_tcp_syncnt(iscsi,atoi(getenv("LIBISCSI_TCP_SYNCNT")));
}
return iscsi; return iscsi;
} }
@@ -244,7 +272,7 @@ 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) { if (iscsi->connected_portal != NULL) {
free(discard_const(iscsi->connected_portal)); free(discard_const(iscsi->connected_portal));
iscsi->connected_portal = NULL; iscsi->connected_portal = NULL;
} }
@@ -276,7 +304,7 @@ iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
va_end(ap); va_end(ap);
DPRINTF(iscsi,1,str); DPRINTF(iscsi,1,"%s",str);
} }
void void
@@ -559,8 +587,7 @@ iscsi_destroy_url(struct iscsi_url *iscsi_url)
int int
iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi, iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
const char *user, const char *user, const char *passwd)
const char *passwd)
{ {
free(discard_const(iscsi->user)); free(discard_const(iscsi->user));
iscsi->user = strdup(user); iscsi->user = strdup(user);

View File

@@ -73,6 +73,10 @@ iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout iscsi_set_tcp_user_timeout
iscsi_set_tcp_keepidle
iscsi_set_tcp_keepcnt
iscsi_set_tcp_keepintvl
iscsi_set_tcp_syncnt
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -71,6 +71,10 @@ iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout iscsi_set_tcp_user_timeout
iscsi_set_tcp_keepidle
iscsi_set_tcp_keepcnt
iscsi_set_tcp_keepintvl
iscsi_set_tcp_syncnt
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -1088,12 +1088,12 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
size -= len + 1; size -= len + 1;
} }
if (status == SCSI_STATUS_REDIRECT && iscsi->target_address) { if (status == SCSI_STATUS_REDIRECT && iscsi->target_address) {
DPRINTF(iscsi,2,"target requests redirect to %s",iscsi->target_address); DPRINTF(iscsi,2,"target requests redirect to %s",iscsi->target_address);
pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL, pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL,
pdu->private_data); pdu->private_data);
return 0; 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)",

View File

@@ -76,8 +76,8 @@ scsi_malloc(struct scsi_task *task, size_t size)
} }
struct value_string { struct value_string {
int value; int value;
const char *string; const char *string;
}; };
static const char * static const char *
@@ -1285,7 +1285,7 @@ scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrpr
task->xfer_dir = SCSI_XFER_WRITE; task->xfer_dir = SCSI_XFER_WRITE;
} else { } else {
task->xfer_dir = SCSI_XFER_NONE; task->xfer_dir = SCSI_XFER_NONE;
} }
task->expxferlen = xferlen; task->expxferlen = xferlen;
task->params.compareandwrite.lba = lba; task->params.compareandwrite.lba = lba;
@@ -2390,9 +2390,9 @@ scsi_get_task_private_ptr(struct scsi_task *task)
struct scsi_data_buffer { struct scsi_data_buffer {
struct scsi_data_buffer *next; struct scsi_data_buffer *next;
uint32_t len; uint32_t len;
unsigned char *data; unsigned char *data;
}; };
int int

View File

@@ -58,6 +58,52 @@ static void set_nonblocking(int fd)
#endif #endif
} }
int set_tcp_sockopt(int sockfd, int optname, int value)
{
int level;
#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
return setsockopt(sockfd, level, optname, &value, sizeof(value));
}
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 18
#endif
int set_tcp_user_timeout(struct iscsi_context *iscsi)
{
if (set_tcp_sockopt(iscsi->fd, TCP_USER_TIMEOUT, iscsi->tcp_user_timeout) != 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",iscsi->tcp_user_timeout);
return 0;
}
#ifndef TCP_SYNCNT
#define TCP_SYNCNT 7
#endif
int set_tcp_syncnt(struct iscsi_context *iscsi)
{
if (set_tcp_sockopt(iscsi->fd, TCP_SYNCNT, iscsi->tcp_syncnt) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp syn retries. Error %s(%d)", strerror(errno), errno);
return -1;
}
DPRINTF(iscsi,3,"TCP_SYNCNT set to %d",iscsi->tcp_syncnt);
return 0;
}
int int
iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
@@ -68,7 +114,7 @@ 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); DPRINTF(iscsi,2,"connecting to portal %s",portal);
if (iscsi->fd != -1) { if (iscsi->fd != -1) {
iscsi_set_error(iscsi, iscsi_set_error(iscsi,
@@ -160,12 +206,16 @@ 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); iscsi_set_tcp_keepalive(iscsi, iscsi->tcp_keepidle, iscsi->tcp_keepcnt, iscsi->tcp_keepintvl);
if (iscsi->tcp_user_timeout > 0) { if (iscsi->tcp_user_timeout > 0) {
set_tcp_user_timeout(iscsi); set_tcp_user_timeout(iscsi);
} }
if (iscsi->tcp_syncnt > 0) {
set_tcp_syncnt(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 : "
@@ -178,7 +228,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
freeaddrinfo(ai); freeaddrinfo(ai);
if (iscsi->connected_portal) free(iscsi->connected_portal); if (iscsi->connected_portal) free(discard_const(iscsi->connected_portal));
iscsi->connected_portal=strdup(portal); iscsi->connected_portal=strdup(portal);
return 0; return 0;
@@ -389,6 +439,17 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
return 0; return 0;
} }
int inline
iscsi_service_reconnect_if_loggedin(struct iscsi_context *iscsi)
{
if (iscsi->is_loggedin) {
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
}
int int
iscsi_service(struct iscsi_context *iscsi, int revents) iscsi_service(struct iscsi_context *iscsi, int revents)
{ {
@@ -410,30 +471,19 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
} }
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL,
iscsi->connect_data); iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
if (revents & POLLHUP) { if (revents & POLLHUP) {
iscsi_set_error(iscsi, "iscsi_service: POLLHUP, " iscsi_set_error(iscsi, "iscsi_service: POLLHUP, "
"socket error."); "socket error.");
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL,
iscsi->connect_data); iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) { if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) {
int err = 0; int err = 0;
socklen_t err_size = sizeof(err); socklen_t err_size = sizeof(err);
if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR, if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR,
&err, &err_size) != 0 || err != 0) { &err, &err_size) != 0 || err != 0) {
if (err == 0) { if (err == 0) {
@@ -444,14 +494,11 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
strerror(err), err); strerror(err), err);
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR,
NULL, iscsi->connect_data); NULL, iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
DPRINTF(iscsi,2,"connection to %s established",iscsi->connected_portal);
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);
@@ -460,22 +507,12 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
if (revents & POLLOUT && iscsi->outqueue != NULL) { if (revents & POLLOUT && iscsi->outqueue != NULL) {
if (iscsi_write_to_socket(iscsi) != 0) { if (iscsi_write_to_socket(iscsi) != 0) {
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
} }
if (revents & POLLIN) { if (revents & POLLIN) {
if (iscsi_read_from_socket(iscsi) != 0) { if (iscsi_read_from_socket(iscsi) != 0) {
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
} }
@@ -529,85 +566,66 @@ iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue)
} }
} }
#ifndef TCP_USER_TIMEOUT void iscsi_set_tcp_syncnt(struct iscsi_context *iscsi, int value)
#define TCP_USER_TIMEOUT 18
#endif
int set_tcp_user_timeout(struct iscsi_context *iscsi)
{ {
int level, value; iscsi->tcp_syncnt=value;
DPRINTF(iscsi,2,"TCP_SYNCNT will be set to %d on next socket creation",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) void iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int value)
{ {
iscsi->tcp_user_timeout=timeout_ms; iscsi->tcp_user_timeout=value;
DPRINTF(iscsi,2,"TCP_USER_TIMEOUT will be set to %dms on next socket creation",timeout_ms); DPRINTF(iscsi,2,"TCP_USER_TIMEOUT will be set to %dms on next socket creation",value);
}
void iscsi_set_tcp_keepidle(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepidle=value;
DPRINTF(iscsi,2,"TCP_KEEPIDLE will be set to %d on next socket creation",value);
}
void iscsi_set_tcp_keepcnt(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepcnt=value;
DPRINTF(iscsi,2,"TCP_KEEPCNT will be set to %d on next socket creation",value);
}
void iscsi_set_tcp_keepintvl(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepintvl=value;
DPRINTF(iscsi,2,"TCP_KEEPINTVL will be set to %d on next socket creation",value);
} }
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;
#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
#ifdef SO_KEEPALIVE #ifdef SO_KEEPALIVE
value =1; int value = 1;
if (setsockopt(iscsi->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) != 0) { if (setsockopt(iscsi->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) != 0) {
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); DPRINTF(iscsi,3,"SO_KEEPALIVE set to %d",value);
#endif
#ifdef TCP_KEEPCNT #ifdef TCP_KEEPCNT
value = count; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPCNT, count) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPCNT, &value, sizeof(value)) != 0) {
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); DPRINTF(iscsi,3,"TCP_KEEPCNT set to %d",count);
#endif #endif
#ifdef TCP_KEEPINTVL #ifdef TCP_KEEPINTVL
value = interval; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPINTVL, interval) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPINTVL, &value, sizeof(value)) != 0) {
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); DPRINTF(iscsi,3,"TCP_KEEPINTVL set to %d",interval);
#endif #endif
#ifdef TCP_KEEPIDLE #ifdef TCP_KEEPIDLE
value = idle; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPIDLE, idle) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPIDLE, &value, sizeof(value)) != 0) {
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); DPRINTF(iscsi,3,"TCP_KEEPIDLE set to %d",idle);
#endif
#endif #endif
return 0; return 0;

View File

@@ -30,9 +30,9 @@
#include "scsi-lowlevel.h" #include "scsi-lowlevel.h"
struct iscsi_sync_state { struct iscsi_sync_state {
int finished; int finished;
int status; int status;
struct scsi_task *task; struct scsi_task *task;
}; };
static void static void

View File

@@ -37,6 +37,10 @@ static const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:ld-iscs
#define ISCSI_MAX_FD 255 #define ISCSI_MAX_FD 255
static int debug = 0;
#define LD_ISCSI_DPRINTF(level,fmt,args...) do { if ((debug) >= level) {fprintf(stderr,"ld_iscsi: ");fprintf(stderr, (fmt), ##args); fprintf(stderr,"\n");} } while (0);
struct iscsi_fd_list { struct iscsi_fd_list {
int is_iscsi; int is_iscsi;
int dup2fd; int dup2fd;
@@ -46,6 +50,10 @@ struct iscsi_fd_list {
uint32_t block_size; uint32_t block_size;
uint64_t num_blocks; uint64_t num_blocks;
off_t offset; off_t offset;
mode_t mode;
int get_lba_status;
struct scsi_lba_status_descriptor lbasd_cached;
int lbasd_cache_valid;
}; };
static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD]; static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD];
@@ -60,19 +68,24 @@ int open(const char *path, int flags, mode_t mode)
struct iscsi_context *iscsi; struct iscsi_context *iscsi;
struct iscsi_url *iscsi_url; struct iscsi_url *iscsi_url;
struct scsi_task *task; struct scsi_task *task;
struct scsi_readcapacity10 *rc10; struct scsi_readcapacity16 *rc16;
if (mode & O_NONBLOCK) {
LD_ISCSI_DPRINTF(0,"Non-blocking I/O is currently not supported");
errno = EINVAL;
return -1;
}
iscsi = iscsi_create_context(initiator); iscsi = iscsi_create_context(initiator);
if (iscsi == NULL) { if (iscsi == NULL) {
fprintf(stderr, "ld-iscsi: Failed to create context\n"); LD_ISCSI_DPRINTF(0,"Failed to create context");
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
iscsi_url = iscsi_parse_full_url(iscsi, path); iscsi_url = iscsi_parse_full_url(iscsi, path);
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
fprintf(stderr, "ld-iscsi: Failed to parse URL: %s\n", LD_ISCSI_DPRINTF(0,"Failed to parse URL: %s\n", iscsi_get_error(iscsi));
iscsi_get_error(iscsi));
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@@ -84,7 +97,7 @@ int open(const char *path, int flags, mode_t mode)
if (iscsi_url->user != NULL) { if (iscsi_url->user != NULL) {
if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
fprintf(stderr, "Failed to set initiator username and password\n"); LD_ISCSI_DPRINTF(0,"Failed to set initiator username and password");
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
@@ -92,25 +105,25 @@ int open(const char *path, int flags, mode_t mode)
} }
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "ld-iscsi: Login Failed. %s\n", iscsi_get_error(iscsi)); LD_ISCSI_DPRINTF(0,"Login Failed. %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EIO; errno = EIO;
return -1; return -1;
} }
task = iscsi_readcapacity10_sync(iscsi, iscsi_url->lun, 0, 0); task = iscsi_readcapacity16_sync(iscsi, iscsi_url->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr, "ld-iscsi: failed to send readcapacity command\n"); LD_ISCSI_DPRINTF(0,"failed to send readcapacity command");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EIO; errno = EIO;
return -1; return -1;
} }
rc10 = scsi_datain_unmarshall(task); rc16 = scsi_datain_unmarshall(task);
if (rc10 == NULL) { if (rc16 == NULL) {
fprintf(stderr, "ld-iscsi: failed to unmarshall readcapacity10 data\n"); LD_ISCSI_DPRINTF(0,"failed to unmarshall readcapacity10 data");
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
@@ -118,9 +131,11 @@ int open(const char *path, int flags, mode_t mode)
return -1; return -1;
} }
LD_ISCSI_DPRINTF(4,"readcapacity16_sync: block_size: %d, num_blocks: %lu",rc16->block_length,rc16->returned_lba + 1);
fd = iscsi_get_fd(iscsi); fd = iscsi_get_fd(iscsi);
if (fd >= ISCSI_MAX_FD) { if (fd >= ISCSI_MAX_FD) {
fprintf(stderr, "ld-iscsi: Too many files open\n"); LD_ISCSI_DPRINTF(0,"Too many files open");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = ENFILE; errno = ENFILE;
@@ -130,10 +145,19 @@ int open(const char *path, int flags, mode_t mode)
iscsi_fd_list[fd].is_iscsi = 1; iscsi_fd_list[fd].is_iscsi = 1;
iscsi_fd_list[fd].dup2fd = -1; iscsi_fd_list[fd].dup2fd = -1;
iscsi_fd_list[fd].iscsi = iscsi; iscsi_fd_list[fd].iscsi = iscsi;
iscsi_fd_list[fd].block_size = rc10->block_size; iscsi_fd_list[fd].block_size = rc16->block_length;
iscsi_fd_list[fd].num_blocks = rc10->lba + 1; iscsi_fd_list[fd].num_blocks = rc16->returned_lba + 1;
iscsi_fd_list[fd].offset = 0; iscsi_fd_list[fd].offset = 0;
iscsi_fd_list[fd].lun = iscsi_url->lun; iscsi_fd_list[fd].lun = iscsi_url->lun;
iscsi_fd_list[fd].mode = mode;
if (getenv("LD_ISCSI_GET_LBA_STATUS") != NULL) {
iscsi_fd_list[fd].get_lba_status = atoi(getenv("LD_ISCSI_GET_LBA_STATUS"));
if (rc16->lbpme == 0){
LD_ISCSI_DPRINTF(1,"Logical unit is fully provisioned. Will skip get_lba_status tasks");
iscsi_fd_list[fd].get_lba_status = 0;
}
}
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
@@ -257,8 +281,9 @@ ssize_t read(int fd, void *buf, size_t count)
{ {
if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) { if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) {
uint64_t offset; uint64_t offset;
uint32_t num_blocks, lba; uint64_t num_blocks, lba;
struct scsi_task *task; struct scsi_task *task;
struct scsi_get_lba_status *lbas;
if (iscsi_fd_list[fd].dup2fd >= 0) { if (iscsi_fd_list[fd].dup2fd >= 0) {
return read(iscsi_fd_list[fd].dup2fd, buf, count); return read(iscsi_fd_list[fd].dup2fd, buf, count);
@@ -278,10 +303,70 @@ ssize_t read(int fd, void *buf, size_t count)
} }
iscsi_fd_list[fd].in_flight = 1; iscsi_fd_list[fd].in_flight = 1;
task = iscsi_read10_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size, 0, 0, 0, 0, 0); if (iscsi_fd_list[fd].get_lba_status != 0) {
if (iscsi_fd_list[fd].lbasd_cache_valid==1) {
LD_ISCSI_DPRINTF(5,"cached get_lba_status_descriptor is lba %lu, num_blocks %d, provisioning %d",iscsi_fd_list[fd].lbasd_cached.lba,iscsi_fd_list[fd].lbasd_cached.num_blocks,iscsi_fd_list[fd].lbasd_cached.provisioning);
if (iscsi_fd_list[fd].lbasd_cached.provisioning != 0x00 && lba >= iscsi_fd_list[fd].lbasd_cached.lba && lba+num_blocks < iscsi_fd_list[fd].lbasd_cached.lba+iscsi_fd_list[fd].lbasd_cached.num_blocks)
{
LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
memset(buf, 0x00, count);
iscsi_fd_list[fd].offset += count;
iscsi_fd_list[fd].in_flight = 0;
return count;
}
}
LD_ISCSI_DPRINTF(4,"get_lba_status_sync: lun %d, lba %lu, num_blocks: %lu",iscsi_fd_list[fd].lun,lba,num_blocks);
task = iscsi_get_lba_status_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, 8+16);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
LD_ISCSI_DPRINTF(0,"failed to send get_lba_status command");
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
lbas = scsi_datain_unmarshall(task);
if (lbas == NULL) {
LD_ISCSI_DPRINTF(0,"failed to unmarshall get_lba_status data");
scsi_free_scsi_task(task);
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
u_int32_t i;
LD_ISCSI_DPRINTF(5,"get_lba_status: num_descriptors: %d",lbas->num_descriptors);
u_int32_t _num_allocated=0;
u_int32_t _num_blocks=0;
for (i=0;i<lbas->num_descriptors;i++) {
struct scsi_lba_status_descriptor *lbasd = &lbas->descriptors[i];
LD_ISCSI_DPRINTF(5,"get_lba_status_descriptor %d, lba %lu, num_blocks %d, provisioning %d",i,lbasd->lba,lbasd->num_blocks,lbasd->provisioning);
if (lbasd->lba != _num_blocks+lba) {
LD_ISCSI_DPRINTF(0,"get_lba_status response is non-continuous");
scsi_free_scsi_task(task);
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
_num_allocated+=(lbasd->provisioning==0x00)?lbasd->num_blocks:0;
_num_blocks+=lbasd->num_blocks;
iscsi_fd_list[fd].lbasd_cached=lbas->descriptors[i];
iscsi_fd_list[fd].lbasd_cache_valid=1;
}
scsi_free_scsi_task(task);
if (_num_allocated == 0 && _num_blocks >= num_blocks) {
LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
memset(buf, 0x00, count);
iscsi_fd_list[fd].offset += count;
iscsi_fd_list[fd].in_flight = 0;
return count;
}
}
LD_ISCSI_DPRINTF(4,"read16_sync: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
task = iscsi_read16_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size, 0, 0, 0, 0, 0);
iscsi_fd_list[fd].in_flight = 0; iscsi_fd_list[fd].in_flight = 0;
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr, "ld-iscsi: failed to send read10 command\n"); LD_ISCSI_DPRINTF(0,"failed to send read16 command");
errno = EIO; errno = EIO;
return -1; return -1;
} }
@@ -381,59 +466,63 @@ static void __attribute__((constructor)) _init(void)
iscsi_fd_list[i].dup2fd = -1; iscsi_fd_list[i].dup2fd = -1;
} }
if (getenv("LD_ISCSI_DEBUG") != NULL) {
debug = atoi(getenv("LD_ISCSI_DEBUG"));
}
real_open = dlsym(RTLD_NEXT, "open"); real_open = dlsym(RTLD_NEXT, "open");
if (real_open == NULL) { if (real_open == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(open)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(open)");
exit(10); exit(10);
} }
real_close = dlsym(RTLD_NEXT, "close"); real_close = dlsym(RTLD_NEXT, "close");
if (real_close == NULL) { if (real_close == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(close)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(close)");
exit(10); exit(10);
} }
real_fxstat = dlsym(RTLD_NEXT, "__fxstat"); real_fxstat = dlsym(RTLD_NEXT, "__fxstat");
if (real_fxstat == NULL) { if (real_fxstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__fxstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__fxstat)");
exit(10); exit(10);
} }
real_lxstat = dlsym(RTLD_NEXT, "__lxstat"); real_lxstat = dlsym(RTLD_NEXT, "__lxstat");
if (real_lxstat == NULL) { if (real_lxstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__lxstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__lxstat)");
exit(10); exit(10);
} }
real_xstat = dlsym(RTLD_NEXT, "__xstat"); real_xstat = dlsym(RTLD_NEXT, "__xstat");
if (real_xstat == NULL) { if (real_xstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__xstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__xstat)");
exit(10); exit(10);
} }
real_read = dlsym(RTLD_NEXT, "read"); real_read = dlsym(RTLD_NEXT, "read");
if (real_read == NULL) { if (real_read == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(read)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(read)");
exit(10); exit(10);
} }
real_dup2 = dlsym(RTLD_NEXT, "dup2"); real_dup2 = dlsym(RTLD_NEXT, "dup2");
if (real_dup2 == NULL) { if (real_dup2 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(dup2)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(dup2)");
exit(10); exit(10);
} }
real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64"); real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64");
if (real_fxstat64 == NULL) { if (real_fxstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__fxstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__fxstat64)");
} }
real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64"); real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
if (real_lxstat64 == NULL) { if (real_lxstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(_lxstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(_lxstat64)");
} }
real_xstat64 = dlsym(RTLD_NEXT, "__xstat64"); real_xstat64 = dlsym(RTLD_NEXT, "__xstat64");
if (real_xstat64 == NULL) { if (real_xstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__xstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__xstat64)");
} }
} }