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

@@ -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)
@@ -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

@@ -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)");
} }
} }