Merge branch 'tst'

This commit is contained in:
Ronnie Sahlberg
2025-04-26 11:30:58 +10:00
37 changed files with 1971 additions and 500 deletions

View File

@@ -29,5 +29,5 @@ pkgconfig_DATA = libiscsi.pc
iscsi_includedir = $(includedir)/iscsi
dist_iscsi_include_HEADERS = include/iscsi.h include/scsi-lowlevel.h
dist_noinst_HEADERS = include/iscsi-private.h include/md5.h include/slist.h \
include/iser-private.h include/utils.h
include/iser-private.h include/iscsi-multithreading.h include/utils.h

View File

@@ -56,6 +56,13 @@ Example:
iscsi://server/iqn.ronnie.test/1
MULTITHREADING
==============
Multithreading is supported both on Linux, using pthreads, and Windows, using native API.
By default libicsi will start with multithreading disabled and you will need
to activate once connected to the LUN.
There are examples of multithreading in the examples directory.
CHAP Authentication
===================
CHAP authentication can be specified two ways. Either via the URL itself

View File

@@ -216,6 +216,20 @@ AM_CONDITIONAL([HAVE_LINUX_ISER], [test $libiscsi_cv_HAVE_LINUX_ISER = yes])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <rdma/rdma_cma.h>]], [[return RDMA_OPTION_ID_ACK_TIMEOUT;]])],[AC_DEFINE([HAVE_RDMA_ACK_TIMEOUT],[1],[Define to 1 if you have RDMA ack timeout support])],[])
# check for stdatomic.h
dnl Check for stdatomic.h
AC_CHECK_HEADERS([stdatomic.h])
# check for pthread
AC_CACHE_CHECK([for pthread support],libiscsi_cv_HAVE_PTHREAD,[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <pthread.h>]], [[pthread_t thread1, thread2;]])],[libiscsi_cv_HAVE_PTHREAD=yes],[libiscsi_cv_HAVE_PTHREAD=no])])
if test x"$libiscsi_cv_HAVE_PTHREAD" = x"yes"; then
AC_DEFINE(HAVE_PTHREAD,1,[Whether we have pthread support])
AC_DEFINE(HAVE_MULTITHREADING,1,[Whether we have multithreading support])
fi
AM_CONDITIONAL([HAVE_PTHREAD], [test x$libiscsi_cv_HAVE_PTHREAD = xyes])
AC_CACHE_CHECK([whether libcunit is available],
[ac_cv_have_cunit],
[ac_save_CFLAGS="$CFLAGS"

View File

@@ -3,4 +3,4 @@ AM_CFLAGS=$(WARN_CFLAGS)
AM_LDFLAGS=-no-undefined
LIBS=../lib/libiscsi.la
noinst_PROGRAMS = iscsiclient iscsi-dd
noinst_PROGRAMS = iscsiclient iscsi-dd iscsi-pthreads-inq iscsi-pthreads-readloop iscsi-pthreads-readloop-async

View File

@@ -0,0 +1,343 @@
/*
Copyright (C) 2025 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-inq";
void inquiry_block_limits(struct scsi_inquiry_block_limits *inq)
{
printf("wsnz:%d\n", inq->wsnz);
printf("maximum compare and write length:%" PRIu8 "\n", inq->max_cmp);
printf("optimal transfer length granularity:%" PRIu16 "\n", inq->opt_gran);
printf("maximum transfer length:%" PRIu32 "\n", inq->max_xfer_len);
printf("optimal transfer length:%" PRIu32 "\n",inq->opt_xfer_len);
printf("maximum prefetch xdread xdwrite transfer length:%" PRIu32 "\n", inq->max_prefetch);
printf("maximum unmap lba count:%" PRIu32 "\n", inq->max_unmap);
printf("maximum unmap block descriptor count:%" PRIu32 "\n", inq->max_unmap_bdc);
printf("optimal unmap granularity:%" PRIu32 "\n", inq->opt_unmap_gran);
printf("ugavalid:%d\n", inq->ugavalid);
printf("unmap granularity alignment:%" PRIu32 "\n", inq->unmap_gran_align);
printf("maximum write same length:%" PRIu64 "\n", inq->max_ws_len);
}
void inquiry_logical_block_provisioning(struct scsi_inquiry_logical_block_provisioning *inq)
{
printf("Threshold Exponent:%d\n", inq->threshold_exponent);
printf("lbpu:%d\n", inq->lbpu);
printf("lbpws:%d\n", inq->lbpws);
printf("lbpws10:%d\n", inq->lbpws10);
printf("lbprz:%d\n", inq->lbprz);
printf("anc_sup:%d\n", inq->anc_sup);
printf("dp:%d\n", inq->dp);
printf("provisioning type:%d\n", inq->provisioning_type);
}
void inquiry_block_device_characteristics(struct scsi_inquiry_block_device_characteristics *inq)
{
printf("Medium Rotation Rate:%dRPM\n", inq->medium_rotation_rate);
}
void inquiry_device_identification(struct scsi_inquiry_device_identification *inq)
{
struct scsi_inquiry_device_designator *dev;
int i;
printf("Peripheral Qualifier:%s\n",
scsi_devqualifier_to_str(inq->qualifier));
printf("Peripheral Device Type:%s\n",
scsi_devtype_to_str(inq->device_type));
printf("Page Code:(0x%02x) %s\n",
inq->pagecode, scsi_inquiry_pagecode_to_str(inq->pagecode));
for (i=0, dev = inq->designators; dev; i++, dev = dev->next) {
printf("DEVICE DESIGNATOR #%d\n", i);
if (dev->piv != 0) {
printf("Device Protocol Identifier:(%d) %s\n", dev->protocol_identifier, scsi_protocol_identifier_to_str(dev->protocol_identifier));
}
printf("Code Set:(%d) %s\n", dev->code_set, scsi_codeset_to_str(dev->code_set));
printf("PIV:%d\n", dev->piv);
printf("Association:(%d) %s\n", dev->association, scsi_association_to_str(dev->association));
printf("Designator Type:(%d) %s\n", dev->designator_type, scsi_designator_type_to_str(dev->designator_type));
printf("Designator:[%s]\n", dev->designator);
}
}
void inquiry_unit_serial_number(struct scsi_inquiry_unit_serial_number *inq)
{
printf("Unit Serial Number:[%s]\n", inq->usn);
}
void inquiry_supported_pages(struct scsi_inquiry_supported_pages *inq)
{
int i;
for (i = 0; i < inq->num_pages; i++) {
printf("Page:0x%02x %s\n", inq->pages[i], scsi_inquiry_pagecode_to_str(inq->pages[i]));
}
}
void inquiry_standard(struct scsi_inquiry_standard *inq)
{
int i;
printf("Peripheral Qualifier:%s\n",
scsi_devqualifier_to_str(inq->qualifier));
printf("Peripheral Device Type:%s\n",
scsi_devtype_to_str(inq->device_type));
printf("Removable:%d\n", inq->rmb);
printf("Version:%d %s\n", inq->version, scsi_version_to_str(inq->version));
printf("NormACA:%d\n", inq->normaca);
printf("HiSup:%d\n", inq->hisup);
printf("ReponseDataFormat:%d\n", inq->response_data_format);
printf("SCCS:%d\n", inq->sccs);
printf("ACC:%d\n", inq->acc);
printf("TPGS:%d\n", inq->tpgs);
printf("3PC:%d\n", inq->threepc);
printf("Protect:%d\n", inq->protect);
printf("EncServ:%d\n", inq->encserv);
printf("MultiP:%d\n", inq->multip);
printf("SYNC:%d\n", inq->sync);
printf("CmdQue:%d\n", inq->cmdque);
printf("Vendor:%s\n", inq->vendor_identification);
printf("Product:%s\n", inq->product_identification);
printf("Revision:%s\n", inq->product_revision_level);
for (i = 0; i < 8; i++) {
if (inq->version_descriptor[i] == 0) {
continue;
}
printf("Version Descriptor:%04x %s\n",
inq->version_descriptor[i],
scsi_version_descriptor_to_str(
inq->version_descriptor[i]));
}
}
void do_inquiry(struct iscsi_context *iscsi, int lun, int evpd, int pc)
{
struct scsi_task *task;
int full_size;
void *inq;
/* See how big this inquiry data is */
task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi));
exit(10);
}
full_size = scsi_datain_getfullsize(task);
if (full_size > task->datain.size) {
scsi_free_scsi_task(task);
/* we need more data for the full list */
if ((task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, full_size)) == NULL) {
fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi));
exit(10);
}
}
inq = scsi_datain_unmarshall(task);
if (inq == NULL) {
fprintf(stderr, "failed to unmarshall inquiry datain blob\n");
exit(10);
}
if (evpd == 0) {
inquiry_standard(inq);
} else {
switch (pc) {
case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
inquiry_supported_pages(inq);
break;
case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
inquiry_unit_serial_number(inq);
break;
case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
inquiry_device_identification(inq);
break;
case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
inquiry_block_limits(inq);
break;
case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
inquiry_block_device_characteristics(inq);
break;
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
inquiry_logical_block_provisioning(inq);
break;
default:
fprintf(stderr, "Usupported pagecode:0x%02x\n", pc);
}
}
scsi_free_scsi_task(task);
}
void print_usage(void)
{
fprintf(stderr, "Usage: iscsi-inq [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n"
"\t\t[-e|--evpd=integer] [-c|--pagecode=integer] <iscsi-url>\n");
}
void print_help(void)
{
fprintf(stderr, "Usage: iscsi-inq [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -e, --evpd=integer evpd\n");
fprintf(stderr, " -c, --pagecode=integer page code\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n");
fprintf(stderr, " --usage Display brief usage message\n");
fprintf(stderr, "\n");
fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX);
fprintf(stderr, "\n");
fprintf(stderr, "<host> is either of:\n");
fprintf(stderr, " \"hostname\" iscsi.example\n");
fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n");
fprintf(stderr, " \"ipv6-address\" [fce0::1]\n");
}
int main(int argc, char *argv[])
{
struct iscsi_context *iscsi;
char *url = NULL;
struct iscsi_url *iscsi_url = NULL;
int evpd = 0, pagecode = 0;
int show_help = 0, show_usage = 0, debug = 0;
int c;
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"usage", no_argument, NULL, 'u'},
{"debug", required_argument, NULL, 'd'},
{"initiator-name", required_argument, NULL, 'i'},
{"evpd", required_argument, NULL, 'e'},
{"pagecode", required_argument, NULL, 'c'},
{0, 0, 0, 0}
};
int option_index;
while ((c = getopt_long(argc, argv, "h?ud:i:e:c:", long_options,
&option_index)) != -1) {
switch (c) {
case 'h':
case '?':
show_help = 1;
break;
case 'u':
show_usage = 1;
break;
case 'd':
debug = strtol(optarg, NULL, 0);
break;
case 'i':
initiator = optarg;
break;
case 'e':
evpd = strtol(optarg, NULL, 0);
break;
case 'c':
pagecode = strtol(optarg, NULL, 0);
break;
default:
fprintf(stderr, "Unrecognized option '%c'\n\n", c);
print_help();
exit(0);
}
}
if (show_help != 0) {
print_help();
exit(0);
}
if (show_usage != 0) {
print_usage();
exit(0);
}
iscsi = iscsi_create_context(initiator);
if (iscsi == NULL) {
fprintf(stderr, "Failed to create context\n");
exit(10);
}
if (debug > 0) {
iscsi_set_log_level(iscsi, debug);
iscsi_set_log_fn(iscsi, iscsi_log_to_stderr);
}
if (argv[optind] != NULL) {
url = strdup(argv[optind]);
}
if (url == NULL) {
fprintf(stderr, "You must specify the URL\n");
print_usage();
exit(10);
}
iscsi_url = iscsi_parse_full_url(iscsi, url);
free(url);
if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n",
iscsi_get_error(iscsi));
exit(10);
}
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi);
exit(10);
}
if (iscsi_mt_service_thread_start(iscsi)) {
fprintf(stderr, "failed to start service thread\n");
exit(10);
}
do_inquiry(iscsi, iscsi_url->lun, evpd, pagecode);
iscsi_destroy_url(iscsi_url);
iscsi_mt_service_thread_stop(iscsi);
iscsi_logout_sync(iscsi);
iscsi_destroy_context(iscsi);
return 0;
}

View File

@@ -0,0 +1,287 @@
/*
Copyright (C) 2025 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <getopt.h>
#include <inttypes.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
static int finished;
/*
* Number of iscsi connections to the server.
*/
#define NUM_CONTEXTS 1
/*
* Number of threads parallely read device data.
* Usually one thread per context should be sufficient, but here we use more
* threads to demonstrate that multiple threads can very well write to the same
* context.
*/
#define NUM_THREADS 4
/*
* Number of tasks per burst in each thread
*/
#define NUM_TASKS 16
const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-inq";
void print_usage(void)
{
fprintf(stderr, "Usage: iscsi-pthreads-readloop [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n"
"\t\t<iscsi-url>\n");
}
void print_help(void)
{
fprintf(stderr, "Usage: iscsi-pthreads-readloop [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n");
fprintf(stderr, " --usage Display brief usage message\n");
fprintf(stderr, "\n");
fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX);
fprintf(stderr, "\n");
fprintf(stderr, "<host> is either of:\n");
fprintf(stderr, " \"hostname\" iscsi.example\n");
fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n");
fprintf(stderr, " \"ipv6-address\" [fce0::1]\n");
}
struct read_data {
struct iscsi_context *iscsi;
int lun;
int i;
pthread_t thread;
sem_t sem;
};
void read_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data)
{
struct read_data *rd = (struct read_data *)private_data;
struct scsi_task *task = command_data;
if (status == SCSI_STATUS_CHECK_CONDITION) {
fprintf(stderr, "Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq);
scsi_free_scsi_task(task);
exit(10);
}
if (status != SCSI_STATUS_GOOD) {
fprintf(stderr, "Read10/16 failed with %s\n", iscsi_get_error(iscsi));
scsi_free_scsi_task(task);
exit(10);
}
sem_post(&rd->sem);
scsi_free_scsi_task(task);
}
static void *iscsi_read_thread(void *arg)
{
struct read_data *rd = arg;
struct scsi_task *task;
int i;
task = malloc(1024);
printf("iscsi_read_thread %d %p\n", rd->i, task);
free(task);
sem_init(&rd->sem, 0, 0);
while (!finished) {
for (i = 0; i < NUM_TASKS; i++) {
task = iscsi_read10_task(rd->iscsi, rd->lun, 0,
512, 512,
0, 0, 0, 0, 0,
read_cb, rd);
if (task == NULL) {
fprintf(stderr, "Failed to read from lun in thread #%d\n", rd->i);
exit(10);
}
}
for (i = 0; i < NUM_TASKS; i++) {
sem_wait(&rd->sem);
}
}
return NULL;
}
static void sig_alarm(int sig)
{
finished = 1;
}
int main(int argc, char *argv[])
{
struct iscsi_context *iscsi[NUM_CONTEXTS] = {NULL,};
char *url = NULL;
struct iscsi_url *iscsi_url = NULL;
int show_help = 0, show_usage = 0, debug = 0;
int c, i;
struct read_data *rd;
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"usage", no_argument, NULL, 'u'},
{"debug", required_argument, NULL, 'd'},
{"initiator-name", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
int option_index;
while ((c = getopt_long(argc, argv, "h?ud:i:e:c:", long_options,
&option_index)) != -1) {
switch (c) {
case 'h':
case '?':
show_help = 1;
break;
case 'u':
show_usage = 1;
break;
case 'd':
debug = strtol(optarg, NULL, 0);
break;
case 'i':
initiator = optarg;
break;
default:
fprintf(stderr, "Unrecognized option '%c'\n\n", c);
print_help();
exit(0);
}
}
if (show_help != 0) {
print_help();
exit(0);
}
if (show_usage != 0) {
print_usage();
exit(0);
}
for (i = 0; i < NUM_CONTEXTS; i++) {
printf("Creating context #%d\n", i);
iscsi[i] = iscsi_create_context(initiator);
if (iscsi[i] == NULL) {
fprintf(stderr, "Failed to create context\n");
exit(10);
}
if (debug > 0) {
iscsi_set_log_level(iscsi[i], debug);
iscsi_set_log_fn(iscsi[i], iscsi_log_to_stderr);
}
if (i > 0) {
iscsi_destroy_url(iscsi_url);
}
if (argv[optind] != NULL) {
url = strdup(argv[optind]);
}
if (url == NULL) {
fprintf(stderr, "You must specify the URL\n");
print_usage();
exit(10);
}
iscsi_url = iscsi_parse_full_url(iscsi[i], url);
free(url);
if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n",
iscsi_get_error(iscsi[i]));
exit(10);
}
iscsi_set_session_type(iscsi[i], ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi[i], ISCSI_HEADER_DIGEST_NONE_CRC32C);
if (iscsi_full_connect_sync(iscsi[i], iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi[i]));
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi[i]);
exit(10);
}
if (iscsi_mt_service_thread_start(iscsi[i])) {
fprintf(stderr, "failed to start service thread #%d\n", i);
exit(10);
}
}
if ((rd = malloc(sizeof(struct read_data) * NUM_THREADS)) == NULL) {
fprintf(stderr, "Failed to allocated read_data\n");
exit(10);
}
for (i = 0; i < NUM_THREADS; i++) {
rd[i].iscsi = iscsi[i % NUM_CONTEXTS];
rd[i].lun = iscsi_url->lun;
rd[i].i = i;
if (pthread_create(&rd[i].thread, NULL,
&iscsi_read_thread, &rd[i])) {
printf("Failed to create read thread #%d\n", i);
exit(10);
}
}
/* run for 5 seconds */
signal(SIGALRM, sig_alarm);
alarm(5);
/*
* Wait for all threads to complete
*/
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(rd[i].thread, NULL);
}
iscsi_destroy_url(iscsi_url);
for (i = 0; i < NUM_CONTEXTS; i++) {
iscsi_mt_service_thread_stop(iscsi[i]);
iscsi_logout_sync(iscsi[i]);
iscsi_destroy_context(iscsi[i]);
}
printf("finished\n");
return 0;
}

View File

@@ -0,0 +1,253 @@
/*
Copyright (C) 2025 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <getopt.h>
#include <inttypes.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
static int finished;
/*
* Number of iscsi connections to the server.
*/
#define NUM_CONTEXTS 2
/*
* Number of threads parallely read device data.
* Usually one thread per context should be sufficient, but here we use more
* threads to demonstrate that multiple threads can very well write to the same
* context.
*/
#define NUM_THREADS 8
const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-inq";
void print_usage(void)
{
fprintf(stderr, "Usage: iscsi-pthreads-readloop [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n"
"\t\t<iscsi-url>\n");
}
void print_help(void)
{
fprintf(stderr, "Usage: iscsi-pthreads-readloop [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n");
fprintf(stderr, " --usage Display brief usage message\n");
fprintf(stderr, "\n");
fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX);
fprintf(stderr, "\n");
fprintf(stderr, "<host> is either of:\n");
fprintf(stderr, " \"hostname\" iscsi.example\n");
fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n");
fprintf(stderr, " \"ipv6-address\" [fce0::1]\n");
}
struct read_data {
struct iscsi_context *iscsi;
int lun;
int i;
pthread_t thread;
};
static void *iscsi_read_thread(void *arg)
{
struct read_data *rd = arg;
struct scsi_task *task;
task = malloc(1024);
printf("iscsi_read_thread %d %p\n", rd->i, task);
free(task);
while (!finished) {
task = iscsi_read10_sync(rd->iscsi, rd->lun, 0,
512, 512,
0, 0, 0, 0, 0);
printf("task:%p\n", task);
scsi_free_scsi_task(task);
if (task == NULL) {
fprintf(stderr, "Failed to read from lun in thread #%d\n", rd->i);
exit(10);
}
}
return NULL;
}
static void sig_alarm(int sig)
{
finished = 1;
}
int main(int argc, char *argv[])
{
struct iscsi_context *iscsi[NUM_CONTEXTS] = {NULL,};
char *url = NULL;
struct iscsi_url *iscsi_url = NULL;
int show_help = 0, show_usage = 0, debug = 0;
int c, i;
struct read_data *rd;
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"usage", no_argument, NULL, 'u'},
{"debug", required_argument, NULL, 'd'},
{"initiator-name", required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
int option_index;
while ((c = getopt_long(argc, argv, "h?ud:i:e:c:", long_options,
&option_index)) != -1) {
switch (c) {
case 'h':
case '?':
show_help = 1;
break;
case 'u':
show_usage = 1;
break;
case 'd':
debug = strtol(optarg, NULL, 0);
break;
case 'i':
initiator = optarg;
break;
default:
fprintf(stderr, "Unrecognized option '%c'\n\n", c);
print_help();
exit(0);
}
}
if (show_help != 0) {
print_help();
exit(0);
}
if (show_usage != 0) {
print_usage();
exit(0);
}
for (i = 0; i < NUM_CONTEXTS; i++) {
printf("Creating context #%d\n", i);
iscsi[i] = iscsi_create_context(initiator);
if (iscsi[i] == NULL) {
fprintf(stderr, "Failed to create context\n");
exit(10);
}
if (debug > 0) {
iscsi_set_log_level(iscsi[i], debug);
iscsi_set_log_fn(iscsi[i], iscsi_log_to_stderr);
}
if (i > 0) {
iscsi_destroy_url(iscsi_url);
}
if (argv[optind] != NULL) {
url = strdup(argv[optind]);
}
if (url == NULL) {
fprintf(stderr, "You must specify the URL\n");
print_usage();
exit(10);
}
iscsi_url = iscsi_parse_full_url(iscsi[i], url);
free(url);
if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n",
iscsi_get_error(iscsi[i]));
exit(10);
}
iscsi_set_session_type(iscsi[i], ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi[i], ISCSI_HEADER_DIGEST_NONE_CRC32C);
if (iscsi_full_connect_sync(iscsi[i], iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi[i]));
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi[i]);
exit(10);
}
if (iscsi_mt_service_thread_start(iscsi[i])) {
fprintf(stderr, "failed to start service thread #%d\n", i);
exit(10);
}
}
if ((rd = malloc(sizeof(struct read_data) * NUM_THREADS)) == NULL) {
fprintf(stderr, "Failed to allocated read_data\n");
exit(10);
}
for (i = 0; i < NUM_THREADS; i++) {
rd[i].iscsi = iscsi[i % NUM_CONTEXTS];
rd[i].lun = iscsi_url->lun;
rd[i].i = i;
if (pthread_create(&rd[i].thread, NULL,
&iscsi_read_thread, &rd[i])) {
printf("Failed to create read thread #%d\n", i);
exit(10);
}
}
/* run for 5 seconds */
signal(SIGALRM, sig_alarm);
alarm(5);
/*
* Wait for all threads to complete
*/
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(rd[i].thread, NULL);
}
iscsi_destroy_url(iscsi_url);
for (i = 0; i < NUM_CONTEXTS; i++) {
iscsi_mt_service_thread_stop(iscsi[i]);
iscsi_logout_sync(iscsi[i]);
iscsi_destroy_context(iscsi[i]);
}
printf("finished\n");
return 0;
}

View File

@@ -0,0 +1,190 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) 2025 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBISCSI_MULTITHREADING_H_
#define _LIBISCSI_MULTITHREADING_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_MULTITHREADING
#ifdef WIN32
typedef HANDLE libiscsi_thread_t;
typedef HANDLE libiscsi_sem_t;
typedef DWORD iscsi_tid_t;
#elif defined(HAVE_PTHREAD)
#include <pthread.h>
typedef pthread_t libiscsi_thread_t;
#if defined(__APPLE__) && defined(HAVE_DISPATCH_DISPATCH_H)
#include <dispatch/dispatch.h>
typedef dispatch_semaphore_t libiscsi_sem_t;
#else
#include <semaphore.h>
typedef sem_t libiscsi_sem_t;
#endif
#ifdef HAVE_PTHREAD_THREADID_NP
typedef uint64_t iscsi_tid_t;
#else
typedef pid_t iscsi_tid_t;
#endif
#endif /* HAVE_PTHREAD */
iscsi_tid_t iscsi_mt_get_tid(void);
int iscsi_mt_sem_init(libiscsi_sem_t *sem, int value);
int iscsi_mt_sem_destroy(libiscsi_sem_t *sem);
int iscsi_mt_sem_post(libiscsi_sem_t *sem);
int iscsi_mt_sem_wait(libiscsi_sem_t *sem);
#endif /* HAVE_MULTITHREADING */
/*
* We always have access to mutex functions even if multithreading
* is not enabled.
*/
#if defined(HAVE_PTHREAD)
typedef pthread_mutex_t libiscsi_mutex_t;
/*
* If this is enabled we check for the following locking violations, at the
* (slight) cost of performance:
* - Thread holding the lock again tries to lock.
* - Thread not holding the lock tries to unlock.
*
* This is very useful for catching any coding errors.
* The performance hit is not very significant so you can leave it enabled,
* but if you really care then once the code has been vetted, this can be
* undef'ed to get the perf back.
*/
#define DEBUG_PTHREAD_LOCKING_VIOLATIONS
static inline int iscsi_mt_mutex_init(libiscsi_mutex_t *mutex)
{
int ret;
#ifdef DEBUG_PTHREAD_LOCKING_VIOLATIONS
pthread_mutexattr_t attr;
ret = pthread_mutexattr_init(&attr);
if (ret != 0) {
return ret;
}
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
if (ret != 0) {
return ret;
}
ret = pthread_mutex_init(mutex, &attr);
if (ret != 0) {
return ret;
}
#else
ret = pthread_mutex_init(mutex, NULL);
assert(ret == 0);
#endif
return ret;
}
static inline int iscsi_mt_mutex_destroy(libiscsi_mutex_t *mutex)
{
return pthread_mutex_destroy(mutex);
}
static inline int iscsi_mt_mutex_lock(libiscsi_mutex_t *mutex)
{
return pthread_mutex_lock(mutex);
}
static inline int iscsi_mt_mutex_unlock(libiscsi_mutex_t *mutex)
{
return pthread_mutex_unlock(mutex);
}
typedef pthread_spinlock_t libiscsi_spinlock_t;
static inline int iscsi_mt_spin_init(libiscsi_spinlock_t *spinlock, int shared)
{
return pthread_spin_init(spinlock, shared);
}
static inline int iscsi_mt_spin_destroy(libiscsi_spinlock_t *spinlock)
{
return pthread_spin_destroy(spinlock);
}
static inline int iscsi_mt_spin_lock(libiscsi_spinlock_t *spinlock)
{
return pthread_spin_lock(spinlock);
}
static inline int iscsi_mt_spin_unlock(libiscsi_spinlock_t *spinlock)
{
return pthread_spin_unlock(spinlock);
}
#elif defined(WIN32)
typedef HANDLE libiscsi_mutex_t;
static inline int iscsi_mt_mutex_init(libiscsi_mutex_t* mutex)
{
*mutex = CreateSemaphoreA(NULL, 1, 1, NULL);
return 0;
}
static inline int iscsi_mt_mutex_destroy(libiscsi_mutex_t* mutex)
{
CloseHandle(*mutex);
return 0;
}
static inline int iscsi_mt_mutex_lock(libiscsi_mutex_t* mutex)
{
while (WaitForSingleObject(*mutex, INFINITE) != WAIT_OBJECT_0);
return 0;
}
static inline int iscsi_mt_mutex_unlock(libiscsi_mutex_t* mutex)
{
ReleaseSemaphore(*mutex, 1, NULL);
return 0;
}
#else
typedef const int libiscsi_mutex_t;
#define iscsi_mt_mutex_init(x) ;
#define iscsi_mt_mutex_destroy(x) ;
#define iscsi_mt_mutex_lock(x) ;
#define iscsi_mt_mutex_unlock(x) ;
typedef const int libiscsi_spinlock_t;
#define iscsi_mt_spin_init(x) ;
#define iscsi_mt_spin_destroy(x) ;
#define iscsi_mt_spin_lock(x) ;
#define iscsi_mt_spin_unlock(x) ;
#endif /* mutex */
#ifdef __cplusplus
}
#endif
#endif /* !_LIBISCSI_MULTITHREADING_H_ */

View File

@@ -28,6 +28,32 @@
#include "iscsi.h"
#ifdef HAVE_MULTITHREADING
#ifdef HAVE_STDATOMIC_H
#include <stdatomic.h>
#define ATOMIC_INC(rpc, x) \
atomic_fetch_add_explicit(&x, 1, memory_order_relaxed)
#define ATOMIC_DEC(rpc, x) \
atomic_fetch_sub_explicit(&x, 1, memory_order_relaxed)
#else /* HAVE_STDATOMIC_H */
#define ATOMIC_INC(rpc, x) \
iscs_mt_mutex_lock(&iscs->atomic_int_mutex); \
} \
x++; \
iscsi_mt_mutex_unlock(&iscsi->atomic_int_mutex);
#define ATOMIC_DEC(rpc, x) \
nfs_mt_mutex_lock(&rpc->atomic_int_mutex); \
x--; \
nfs_mt_mutex_unlock(&rpc->atomic_int_mutex);
#endif /* HAVE_STDATOMIC_H */
#else /* HAVE_MULTITHREADING */
/* no multithreading support, no need to protect the increment */
#define ATOMIC_INC(rpc, x) x++
#define ATOMIC_DEC(rpc, x) x--
#endif /* HAVE_MULTITHREADING */
#include "iscsi-multithreading.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -105,12 +131,12 @@ struct iscsi_context {
enum iscsi_session_type session_type;
unsigned char isid[6];
uint8_t rdma_ack_timeout;
uint32_t itt;
uint32_t cmdsn;
uint32_t min_cmdsn_waiting;
uint32_t expcmdsn;
uint32_t maxcmdsn;
uint32_t statsn;
uint32_t itt; /* Protected by iscsi_lock */
uint32_t cmdsn; /* Protected by iscsi_lock */
uint32_t min_cmdsn_waiting; /* Protected by iscsi_lock */
uint32_t expcmdsn; /* Protected by iscsi_lock */
uint32_t maxcmdsn; /* Protected by iscsi_lock */
uint32_t statsn; /* Protected by iscsi_lock */
enum iscsi_header_digest want_header_digest;
enum iscsi_header_digest header_digest;
enum iscsi_data_digest want_data_digest;
@@ -144,11 +170,10 @@ struct iscsi_context {
iscsi_command_cb socket_status_cb;
void *connect_data;
struct iscsi_pdu *outqueue;
struct iscsi_pdu *outqueue_current;
struct iscsi_pdu *waitpdu;
struct iscsi_in_pdu *incoming;
struct iscsi_pdu *outqueue; /* Protected by iscsi_lock */
struct iscsi_pdu *outqueue_current; /* Protected by iscsi_lock */
struct iscsi_pdu *waitpdu; /* Protected by iscsi_lock */
struct iscsi_in_pdu *incoming; /* Protected by iscsi_lock */
uint32_t max_burst_length;
uint32_t first_burst_length;
@@ -168,14 +193,10 @@ struct iscsi_context {
int log_level;
iscsi_log_fn log_fn;
int mallocs;
int reallocs;
int frees;
int smallocs;
void* smalloc_ptrs[SMALL_ALLOC_MAX_FREE];
int smalloc_free;
size_t smalloc_size;
int cache_allocations;
int mallocs; //needs protection?
int reallocs; //needs protection?
int frees; //needs protection?
int cache_allocations; //needs ptotection?
time_t next_reconnect;
int scsi_timeout;
@@ -184,6 +205,17 @@ struct iscsi_context {
int no_ua_on_reconnect;
void (*fd_dup_cb)(struct iscsi_context *iscsi, void *opaque);
void *fd_dup_opaque;
#ifdef HAVE_MULTITHREADING
int multithreading_enabled;
libiscsi_spinlock_t iscsi_lock;
libiscsi_mutex_t iscsi_mutex;
libiscsi_thread_t service_thread;
int poll_timeout;
#ifndef HAVE_STDATOMIC_H
libiscsi_mutex_t atomic_int_mutex;
#endif /* HAVE_STDATOMIC_H */
#endif /* HAVE_MULTITHREADING */
};
#define ISCSI_PDU_IMMEDIATE 0x40
@@ -308,10 +340,11 @@ void iscsi_cancel_pdus(struct iscsi_context *iscsi);
void iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun);
int iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *dptr, int dsize);
int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
void iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data,
const unsigned char *dptr, int dsize, int pdualignment);
void iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
struct scsi_task;
void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task);
@@ -358,9 +391,6 @@ void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size);
void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size);
void iscsi_free(struct iscsi_context *iscsi, void* ptr);
char* iscsi_strdup(struct iscsi_context *iscsi, const char* str);
void* iscsi_smalloc(struct iscsi_context *iscsi, size_t size);
void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size);
void iscsi_sfree(struct iscsi_context *iscsi, void* ptr);
uint32_t crc32c(uint8_t *buf, int len);
void crc32c_init(uint32_t *crc_ptr);
@@ -381,9 +411,6 @@ void iscsi_decrement_iface_rr(void);
void __attribute__((format(printf, 3, 4)))
iscsi_log_message(struct iscsi_context *iscsi, int level, const char *format, ...);
void
iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
int iscsi_serial32_compare(uint32_t s1, uint32_t s2);
uint32_t iscsi_itt_post_increment(struct iscsi_context *iscsi);
@@ -407,7 +434,7 @@ union socket_address;
typedef struct iscsi_transport {
int (*connect)(struct iscsi_context *iscsi, union socket_address *sa, int ai_family);
int (*queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
void (*queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
struct iscsi_pdu* (*new_pdu)(struct iscsi_context *iscsi, size_t size);
int (*disconnect)(struct iscsi_context *iscsi);
void (*free_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);

View File

@@ -1704,6 +1704,18 @@ iscsi_set_fd_dup_cb(struct iscsi_context *iscsi,
void (*cb)(struct iscsi_context *iscsi, void *opaque),
void *opaque);
/*
* MULTITHREADING
*/
/*
* This function starts a separate service thread for multithreading support.
*/
EXTERN int iscsi_mt_service_thread_start(struct iscsi_context *iscsi);
/*
* Shutdown multithreading support.
*/
EXTERN void iscsi_mt_service_thread_stop(struct iscsi_context *iscsi);
#ifdef __cplusplus
}
#endif

View File

@@ -5,6 +5,7 @@ noinst_LTLIBRARIES = libiscsipriv.la
libiscsipriv_la_SOURCES = \
connect.c crc32c.c discovery.c init.c \
login.c nop.c pdu.c iscsi-command.c \
multithreading.c \
scsi-lowlevel.c socket.c sync.c task_mgmt.c \
logging.c utils.c sha1.c sha224-256.c sha3.c

View File

@@ -280,7 +280,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *private_data)
{
struct iscsi_context *old_iscsi;
int i;
struct iscsi_pdu *tmp = NULL;
if (status != SCSI_STATUS_GOOD) {
int backoff = ++iscsi->old_iscsi->retry_cnt;
@@ -305,16 +305,20 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
old_iscsi = iscsi->old_iscsi;
iscsi->old_iscsi = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
while (old_iscsi->outqueue) {
struct iscsi_pdu *pdu = old_iscsi->outqueue;
ISCSI_LIST_REMOVE(&old_iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&old_iscsi->waitpdu, pdu);
}
tmp = old_iscsi->waitpdu;
old_iscsi->waitpdu = NULL;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
while (old_iscsi->waitpdu) {
struct iscsi_pdu *pdu = old_iscsi->waitpdu;
while (tmp) {
struct iscsi_pdu *pdu = tmp;
ISCSI_LIST_REMOVE(&old_iscsi->waitpdu, pdu);
ISCSI_LIST_REMOVE(&tmp, pdu);
if (pdu->itt == 0xffffffff) {
iscsi->drv->free_pdu(old_iscsi, pdu);
continue;
@@ -351,6 +355,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
iscsi->drv->free_pdu(old_iscsi, pdu);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (old_iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(old_iscsi, old_iscsi->incoming);
}
@@ -358,13 +363,10 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
if (old_iscsi->outqueue_current != NULL && old_iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
iscsi->drv->free_pdu(old_iscsi, old_iscsi->outqueue_current);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_free(old_iscsi, old_iscsi->opaque);
for (i = 0; i < old_iscsi->smalloc_free; i++) {
iscsi_free(old_iscsi, old_iscsi->smalloc_ptrs[i]);
}
iscsi->mallocs += old_iscsi->mallocs;
iscsi->frees += old_iscsi->frees;
@@ -461,10 +463,6 @@ static int reconnect(struct iscsi_context *iscsi, int force)
tmp_iscsi->reconnect_max_retries = iscsi->reconnect_max_retries;
if (iscsi->old_iscsi) {
int i;
for (i = 0; i < iscsi->smalloc_free; i++) {
iscsi_free(iscsi, iscsi->smalloc_ptrs[i]);
}
iscsi_free(iscsi, iscsi->opaque);
iscsi->old_iscsi->mallocs += iscsi->mallocs;

View File

@@ -73,12 +73,7 @@ iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
pdu->callback = cb;
pdu->private_data = private_data;
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi "
"text pdu.");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi_queue_pdu(iscsi, pdu);
return 0;
}

View File

@@ -115,51 +115,14 @@ char* iscsi_strdup(struct iscsi_context *iscsi, const char* str) {
return str2;
}
void* iscsi_smalloc(struct iscsi_context *iscsi, size_t size) {
void *ptr;
if (size > iscsi->smalloc_size) return NULL;
if (iscsi->smalloc_free > 0) {
ptr = iscsi->smalloc_ptrs[--iscsi->smalloc_free];
iscsi->smallocs++;
} else {
ptr = iscsi_malloc(iscsi, iscsi->smalloc_size);
}
return ptr;
}
void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size) {
void *ptr = iscsi_smalloc(iscsi, size);
if (ptr) {
memset(ptr, 0, size);
}
return ptr;
}
void iscsi_sfree(struct iscsi_context *iscsi, void* ptr) {
if (ptr == NULL) {
return;
}
if (!iscsi->cache_allocations) {
iscsi_free(iscsi, ptr);
} else if (iscsi->smalloc_free == SMALL_ALLOC_MAX_FREE) {
/* SMALL_ALLOC_MAX_FREE should be adjusted that this */
/* happens rarely */
ISCSI_LOG(iscsi, 6, "smalloc free == SMALLOC_MAX_FREE");
iscsi_free(iscsi, ptr);
} else {
iscsi->smalloc_ptrs[iscsi->smalloc_free++] = ptr;
}
}
static bool rd_set = false;
static pthread_mutex_t rd_mutex = PTHREAD_MUTEX_INITIALIZER;
static void
iscsi_srand_init(struct iscsi_context *iscsi) {
unsigned int seed;
int urand_fd;
ssize_t rc;
int err;
static bool rd_set = false;
static pthread_mutex_t rd_mutex = PTHREAD_MUTEX_INITIALIZER;
if (rd_set) {
/* fast case, seed has been set */
@@ -202,7 +165,6 @@ struct iscsi_context *
iscsi_create_context(const char *initiator_name)
{
struct iscsi_context *iscsi;
size_t required = ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE;
char *ca;
if (!initiator_name[0]) {
@@ -216,6 +178,10 @@ iscsi_create_context(const char *initiator_name)
memset(iscsi, 0, sizeof(struct iscsi_context));
iscsi_mt_spin_init(&iscsi->iscsi_lock, PTHREAD_PROCESS_PRIVATE);
iscsi_mt_mutex_init(&iscsi->iscsi_mutex);
iscsi->poll_timeout = 100;
/* initalize transport of context */
if (iscsi_init_transport(iscsi, TCP_TRANSPORT)) {
free(iscsi);
@@ -286,18 +252,6 @@ iscsi_create_context(const char *initiator_name)
iscsi->rdma_ack_timeout = atoi(getenv("LIBISCSI_RDMA_ACK_TIMEOUT"));
}
/* iscsi->smalloc_size is the size for small allocations. this should be
max(ISCSI_HEADER_SIZE, sizeof(struct iscsi_pdu), sizeof(struct iscsi_in_pdu))
rounded up to the next power of 2. */
required = MAX(required, sizeof(struct iscsi_pdu));
required = MAX(required, sizeof(struct iscsi_in_pdu));
iscsi->smalloc_size = 1;
while (iscsi->smalloc_size < required) {
iscsi->smalloc_size <<= 1;
}
ISCSI_LOG(iscsi, 5, "small allocation size is %u byte",
(uint32_t)iscsi->smalloc_size);
ca = getenv("LIBISCSI_CACHE_ALLOCATIONS");
if (!ca || atoi(ca) != 0) {
iscsi->cache_allocations = 1;
@@ -394,8 +348,6 @@ iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
int
iscsi_destroy_context(struct iscsi_context *iscsi)
{
int i;
if (iscsi == NULL) {
return 0;
}
@@ -404,6 +356,7 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
iscsi_cancel_pdus(iscsi);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current != NULL && iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
iscsi->drv->free_pdu(iscsi, iscsi->outqueue_current);
}
@@ -411,19 +364,16 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
if (iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(iscsi, iscsi->incoming);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->connect_data = NULL;
for (i=0;i<iscsi->smalloc_free;i++) {
iscsi_free(iscsi, iscsi->smalloc_ptrs[i]);
}
iscsi_free(iscsi, iscsi->opaque);
if (iscsi->mallocs != iscsi->frees) {
ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s), %d free(s) and %d reused small allocations",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees,iscsi->smallocs);
ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s), %d free(s)",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees);
} else {
ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s), %d free(s) and %d reused small allocations",iscsi->mallocs,iscsi->reallocs,iscsi->frees,iscsi->smallocs);
ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s), %d free(s)",iscsi->mallocs,iscsi->reallocs,iscsi->frees);
}
if (iscsi->old_iscsi) {
@@ -431,6 +381,9 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
iscsi_destroy_context(iscsi->old_iscsi);
}
iscsi_mt_spin_destroy(&iscsi->iscsi_lock);
iscsi_mt_mutex_destroy(&iscsi->iscsi_mutex);
memset(iscsi, 0, sizeof(struct iscsi_context));
free(iscsi);

View File

@@ -128,12 +128,7 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu,
/* update data segment length */
scsi_set_uint32(&pdu->outdata.data[4], pdu->payload_len);
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi "
"scsi pdu.");
iscsi->drv->free_pdu(iscsi, pdu);
goto error;
}
iscsi_queue_pdu(iscsi, pdu);
tot_len -= len;
offset += len;
@@ -141,8 +136,10 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu,
return 0;
error:
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->outqueue, cmd_pdu);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, cmd_pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (cmd_pdu->callback) {
cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
cmd_pdu->private_data);
@@ -264,6 +261,9 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
}
iscsi_pdu_set_pduflags(pdu, flags);
pdu->callback = iscsi_scsi_response_cb;
pdu->private_data = &pdu->scsi_cbdata;
/* lun */
iscsi_pdu_set_lun(pdu, lun);
pdu->lun = lun;
@@ -272,21 +272,14 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
iscsi_pdu_set_expxferlen(pdu, task->expxferlen);
/* cmdsn */
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
/* cdb */
iscsi_pdu_set_cdb(pdu, task);
pdu->callback = iscsi_scsi_response_cb;
pdu->private_data = &pdu->scsi_cbdata;
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi "
"scsi pdu.");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi->cmdsn++;
iscsi_queue_pdu(iscsi, pdu);
/* The F flag is not set. This means we haven't sent all the unsolicited
* data yet. Sent as much as we are allowed as a train of DATA-OUT PDUs.
@@ -2416,11 +2409,13 @@ iscsi_get_scsi_task_iovector_in(struct iscsi_context *iscsi, struct iscsi_in_pdu
}
itt = scsi_get_uint32(&in->hdr[16]);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
return NULL;
@@ -2679,11 +2674,14 @@ int iscsi_scsi_is_task_in_outqueue(struct iscsi_context *iscsi, struct scsi_task
{
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
if (pdu->itt == task->itt) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 1;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 0;
}
@@ -2692,13 +2690,15 @@ int
iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
struct scsi_task *task)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
int ret = -1;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == task->itt) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
@@ -2708,6 +2708,8 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
return 0;
}
}
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -2717,22 +2719,29 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
if (pdu->itt == task->itt) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
ISCSI_LIST_ADD_END(&tmp, pdu);
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
pdu->private_data);
}
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
cmdsn_gap++;
}
iscsi->drv->free_pdu(iscsi, pdu);
ret = 0;
if (!cmdsn_gap) {
break;
}
}
}
}
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi->cmdsn--;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
cmdsn_gap++;
}
iscsi->drv->free_pdu(iscsi, pdu);
ret = 0;
if (!cmdsn_gap) {
break;
}
}
if (iscsi->old_iscsi) {
return iscsi_scsi_cancel_task(iscsi->old_iscsi, task);

View File

@@ -334,6 +334,7 @@ iser_free_queued_pdu_tx_desc(struct iscsi_context *iscsi)
struct iscsi_pdu *pdu;
struct iser_pdu *iser_pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
iser_pdu = container_of(pdu, struct iser_pdu, iscsi_pdu);
if (iser_pdu->desc) {
@@ -349,6 +350,7 @@ iser_free_queued_pdu_tx_desc(struct iscsi_context *iscsi)
iser_pdu->desc = NULL;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
}
/*
@@ -537,7 +539,7 @@ iscsi_iser_new_pdu(struct iscsi_context *iscsi, __attribute__((unused))size_t si
struct iscsi_pdu *pdu;
struct iser_pdu *iser_pdu;
iser_pdu = iscsi_szmalloc(iscsi, sizeof(*iser_pdu));
iser_pdu = iscsi_zmalloc(iscsi, sizeof(*iser_pdu));
pdu = &iser_pdu->iscsi_pdu;
pdu->indata.data = NULL;
@@ -561,26 +563,19 @@ iscsi_iser_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
iser_pdu->desc = NULL;
}
if (pdu->outdata.size <= iscsi->smalloc_size) {
iscsi_sfree(iscsi, pdu->outdata.data);
} else {
iscsi_free(iscsi, pdu->outdata.data);
}
iscsi_free(iscsi, pdu->outdata.data);
pdu->outdata.data = NULL;
if (pdu->indata.size <= iscsi->smalloc_size) {
iscsi_sfree(iscsi, pdu->indata.data);
} else {
iscsi_free(iscsi, pdu->indata.data);
}
iscsi_free(iscsi, pdu->indata.data);
pdu->indata.data = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current == pdu) {
iscsi->outqueue_current = NULL;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_sfree(iscsi, iser_pdu);
iscsi_free(iscsi, iser_pdu);
}
/**
@@ -770,11 +765,7 @@ iser_prepare_read_cmd(struct iser_conn *iser_conn,struct iser_pdu *iser_pdu)
if (data_size > 0) {
if (task->iovector_in.iov == NULL) {
if (data_size <= iscsi->smalloc_size) {
iser_pdu->iscsi_pdu.indata.data = iscsi_smalloc(iscsi, data_size);
} else {
iser_pdu->iscsi_pdu.indata.data = iscsi_malloc(iscsi, data_size);
}
iser_pdu->iscsi_pdu.indata.data = iscsi_malloc(iscsi, data_size);
if (iser_pdu->iscsi_pdu.indata.data == NULL) {
iscsi_set_error(iscsi, "Failed to aloocate data buffer");
return -1;
@@ -920,8 +911,10 @@ iscsi_iser_send_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) {
iser_pdu = container_of(pdu, struct iser_pdu, iscsi_pdu);
opcode = pdu->outdata.data[0];
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi_pdu_set_expstatsn(pdu, iscsi->statsn + 1);
ISCSI_LIST_ADD_END(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
/*
* because of async reconnection, before reconnecting successfully,
@@ -954,16 +947,20 @@ static int
iscsi_iser_revive_queued_pdus(struct iscsi_context *iscsi) {
struct iscsi_pdu *pdu;
while (iscsi->outqueue != NULL) {
while (iscsi->outqueue) {
if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0) {
break;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
pdu = iscsi->outqueue;
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (iscsi_iser_send_pdu(iscsi, pdu) < 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_ADD(&iscsi->outqueue, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return -1;
}
}
@@ -982,27 +979,27 @@ iscsi_iser_revive_queued_pdus(struct iscsi_context *iscsi) {
* Need to be compatible to TCP which has real queue,
* in iSER pdus with cmdsn not exceeds maxcmdsn are already sent.
*/
static int
static void
iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) {
if (pdu == NULL) {
iscsi_set_error(iscsi, "trying to queue NULL pdu");
return -1;
return;
}
if (pdu->outdata.data[0] == ISCSI_PDU_NOP_OUT &&
iscsi_iser_cm_event(iscsi) != 0) {
iscsi_service_reconnect_if_loggedin(iscsi);
return -1;
return;
}
if (iscsi->outqueue != NULL ||
if (iscsi->outqueue ||
(iscsi_serial32_compare(pdu->cmdsn, iscsi->maxcmdsn) > 0
&& !(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) {
iscsi_add_to_outqueue(iscsi, pdu);
return 0;
return;
}
return iscsi_iser_send_pdu(iscsi, pdu);
iscsi_iser_send_pdu(iscsi, pdu);
}
@@ -1308,6 +1305,8 @@ iser_rcv_completion(struct iser_rx_desc *rx_desc,
struct iscsi_in_pdu in;
int empty, err;
struct iscsi_context *iscsi = iser_conn->cma_id->context;
struct iscsi_pdu *iscsi_pdu;
struct iser_pdu *iser_pdu;
in.hdr = (unsigned char*)rx_desc->iscsi_header;
in.data_pos = iscsi_get_pdu_data_size(&in.hdr[0]);
@@ -1322,12 +1321,12 @@ iser_rcv_completion(struct iser_rx_desc *rx_desc,
if (opcode == ISCSI_PDU_ASYNC_MSG)
goto no_waitpdu;
struct iscsi_pdu *iscsi_pdu;
struct iser_pdu *iser_pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (iscsi_pdu = iscsi->waitpdu ; iscsi_pdu ; iscsi_pdu = iscsi_pdu->next) {
if(iscsi_pdu->itt == itt)
break;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iser_pdu = container_of(iscsi_pdu, struct iser_pdu, iscsi_pdu);
@@ -1731,11 +1730,6 @@ void iscsi_init_iser_transport(struct iscsi_context *iscsi)
/* Update iSCSI params as per iSER transport */
iscsi->initiator_max_recv_data_segment_length = ISCSI_DEF_MAX_RECV_SEG_LEN;
iscsi->target_max_recv_data_segment_length = ISCSI_DEF_MAX_RECV_SEG_LEN;
/* ensure smalloc_size is enough for iser_pdu */
while (iscsi->smalloc_size < sizeof(struct iser_pdu)) {
iscsi->smalloc_size <<= 1;
}
}
#endif

View File

@@ -38,6 +38,8 @@ iscsi_modesense6_sync
iscsi_modesense6_task
iscsi_modesense10_sync
iscsi_modesense10_task
iscsi_mt_service_thread_start
iscsi_mt_service_thread_stop
iscsi_nop_out_async
iscsi_parse_full_url
iscsi_parse_portal_url

View File

@@ -41,6 +41,8 @@ iscsi_modesense10_sync
iscsi_modesense10_task
iscsi_modesense6_sync
iscsi_modesense6_task
iscsi_mt_service_thread_start
iscsi_mt_service_thread_stop
iscsi_nop_out_async
iscsi_orwrite_iov_sync
iscsi_orwrite_iov_task

View File

@@ -1236,12 +1236,7 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
pdu->callback = cb;
pdu->private_data = private_data;
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi "
"pdu.");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi_queue_pdu(iscsi, pdu);
return 0;
}
@@ -1587,12 +1582,7 @@ iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
pdu->callback = cb;
pdu->private_data = private_data;
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi "
"logout pdu.");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi_queue_pdu(iscsi, pdu);
return 0;
}

279
lib/multithreading.c Normal file
View File

@@ -0,0 +1,279 @@
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
/*
Copyright (C) 2025 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32/win32_compat.h"
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <string.h>
#include "iscsi.h"
#include "iscsi-private.h"
#ifdef HAVE_MULTITHREADING
#ifdef WIN32
iscsi_tid_t iscsi_mt_get_tid(void)
{
return GetCurrentThreadId();
}
static void* iscsi_mt_service_thread(void* arg)
{
struct iscsi_context* iscsi = (struct iscsi_context*)arg;
struct pollfd pfd;
int revents;
int ret;
iscsi->multithreading_enabled = 1;
while (iscsi->multithreading_enabled) {
pfd.fd = iscsi_get_fd(iscsi);
pfd.events = iscsi_which_events(iscsi);
pfd.revents = 0;
ret = poll(&pfd, 1, 0);
if (ret < 0) {
iscsi_set_error(iscsi, "Poll failed");
revents = -1;
}
else {
revents = pfd.revents;
}
if (iscsi_service(iscsi, revents) < 0) {
if (revents != -1)
iscsi_set_error(iscsi, "iscsi_service failed");
}
}
return NULL;
}
static DWORD WINAPI service_thread_init(LPVOID lpParam)
{
HANDLE hStdout;
struct iscsi_context* iscsi;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdout == INVALID_HANDLE_VALUE) {
return 1;
}
iscsi = (struct iscsi_context *)lpParam;
iscsi_mt_service_thread(iscsi);
return 0;
}
int iscsi_mt_service_thread_start(struct iscsi_context* iscsi)
{
iscsi->iscsii->service_thread = CreateThread(NULL, 1024*1024, service_thread_init, iscsi, 0, NULL);
if (iscsi->iscsii->service_thread == NULL) {
iscsi_set_error(iscsi, "Failed to start service thread");
return -1;
}
while (iscsi->multithreading_enabled == 0) {
Sleep(100);
}
return 0;
}
void iscsi_mt_service_thread_stop(struct iscsi_context* iscsi)
{
iscsi->multithreading_enabled = 0;
while (WaitForSingleObject(iscsi->iscsii->service_thread, INFINITE) != WAIT_OBJECT_0);
}
int iscsi_mt_sem_init(libiscsi_sem_t* sem, int value)
{
*sem = CreateSemaphoreA(NULL, 0, 16, NULL);
return 0;
}
int iscsi_mt_sem_destroy(libiscsi_sem_t* sem)
{
CloseHandle(*sem);
return 0;
}
int iscsi_mt_sem_post(libiscsi_sem_t* sem)
{
ReleaseSemaphore(*sem, 1, NULL);
return 0;
}
int iscsi_mt_sem_wait(libiscsi_sem_t* sem)
{
while (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0);
return 0;
}
#elif defined(HAVE_PTHREAD) /* WIN32 */
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
iscsi_tid_t iscsi_mt_get_tid(void)
{
#ifdef HAVE_PTHREAD_THREADID_NP
iscsi_tid_t tid;
pthread_threadid_np(NULL, &tid);
return tid;
#elif defined(SYS_gettid)
pid_t tid = syscall(SYS_gettid);
return tid;
#else
#error "SYS_gettid unavailable on this system"
#endif
}
static void on_sigusr1(int _unused)
{
}
static void *iscsi_mt_service_thread(void *arg)
{
struct iscsi_context *iscsi = (struct iscsi_context *)arg;
struct pollfd pfd;
int revents;
int ret;
/* set signal to break poll when we need to send more data */
signal(SIGUSR1, on_sigusr1);
iscsi->multithreading_enabled = 1;
/* TODO: add timeout scanning */
while (iscsi->multithreading_enabled) {
pfd.fd = iscsi_get_fd(iscsi);
pfd.events = iscsi_which_events(iscsi);
pfd.revents = 0;
ret = poll(&pfd, 1, iscsi->poll_timeout);
if (ret < 0 && errno == EINTR) {
/*
* Got a signal. Assume it is because we need to start writing new PDUs
* to the socket.
*/
revents = POLLOUT;
goto call_service;
}
if (ret < 0) {
iscsi_set_error(iscsi, "Poll failed");
revents = -1;
} else {
revents = pfd.revents;
}
call_service:
if (iscsi_service(iscsi, revents) < 0) {
if (revents != -1)
iscsi_set_error(iscsi, "iscsi_service failed");
}
}
return NULL;
}
int iscsi_mt_service_thread_start(struct iscsi_context *iscsi)
{
if (pthread_create(&iscsi->service_thread, NULL,
&iscsi_mt_service_thread, iscsi)) {
iscsi_set_error(iscsi, "Failed to start service thread");
return -1;
}
while (iscsi->multithreading_enabled == 0) {
struct timespec ts = {0, 1000000};
nanosleep(&ts, NULL);
}
return 0;
}
void iscsi_mt_service_thread_stop(struct iscsi_context *iscsi)
{
iscsi->multithreading_enabled = 0;
pthread_join(iscsi->service_thread, NULL);
}
#if defined(__APPLE__) && defined(HAVE_DISPATCH_DISPATCH_H)
int iscsi_mt_sem_init(libiscsi_sem_t *sem, int value)
{
if ((*sem = dispatch_semaphore_create(value)) != NULL)
return 0;
return -1;
}
int iscsi_mt_sem_destroy(libiscsi_sem_t *sem)
{
dispatch_release(*sem);
return 0;
}
int iscsi_mt_sem_post(libiscsi_sem_t *sem)
{
dispatch_semaphore_signal(*sem);
return 0;
}
int iscsi_mt_sem_wait(libiscsi_sem_t *sem)
{
dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER);
return 0;
}
#else
int iscsi_mt_sem_init(libiscsi_sem_t *sem, int value)
{
return sem_init(sem, 0, value);
}
int iscsi_mt_sem_destroy(libiscsi_sem_t *sem)
{
return sem_destroy(sem);
}
int iscsi_mt_sem_post(libiscsi_sem_t *sem)
{
return sem_post(sem);
}
int iscsi_mt_sem_wait(libiscsi_sem_t *sem)
{
return sem_wait(sem);
}
#endif
#endif /* HAVE_PTHREAD */
#endif /* HAVE_MULTITHREADING */

View File

@@ -54,6 +54,9 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
return -1;
}
pdu->callback = cb;
pdu->private_data = private_data;
/* flags */
iscsi_pdu_set_pduflags(pdu, 0x80);
@@ -64,26 +67,22 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
iscsi_pdu_set_lun(pdu, 0);
/* cmdsn */
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
pdu->callback = cb;
pdu->private_data = private_data;
if (data != NULL && len > 0) {
if (iscsi_pdu_add_data(iscsi, pdu, data, len) != 0) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_set_error(iscsi, "Failed to add outdata to nop-out");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
}
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi->cmdsn++;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_queue_pdu(iscsi, pdu);
iscsi->nops_in_flight++;
ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
"NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)",
@@ -122,11 +121,7 @@ iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt, uint32_t lu
/* cmdsn is not increased if Immediate delivery*/
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi_queue_pdu(iscsi, pdu);
ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
"NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, pdu->lun %8x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)",
@@ -141,6 +136,7 @@ iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
{
struct iscsi_data data;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
"NOP-In received (pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)",
pdu->itt, 0xffffffff, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn);
@@ -155,6 +151,7 @@ iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
iscsi->nops_in_flight = 0;
}
iscsi->min_cmdsn_waiting = iscsi->waitpdu->cmdsn;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu->callback == NULL) {
return 0;

349
lib/pdu.c
View File

@@ -70,12 +70,15 @@ iscsi_serial32_compare(uint32_t s1, uint32_t s2) {
uint32_t
iscsi_itt_post_increment(struct iscsi_context *iscsi) {
uint32_t old_itt = iscsi->itt;
iscsi->itt++;
uint32_t old_itt;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
old_itt = iscsi->itt++;
/* 0xffffffff is a reserved value */
if (iscsi->itt == 0xffffffff) {
iscsi->itt = 0;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return old_itt;
}
@@ -184,7 +187,7 @@ void iscsi_dump_pdu_header(struct iscsi_context *iscsi, unsigned char *data) {
struct iscsi_pdu*
iscsi_tcp_new_pdu(struct iscsi_context *iscsi, size_t size)
{
return iscsi_szmalloc(iscsi, size);
return iscsi_zmalloc(iscsi, size);
}
struct iscsi_pdu *
@@ -201,7 +204,7 @@ iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode,
}
pdu->outdata.size = ISCSI_HEADER_SIZE(iscsi->header_digest);
pdu->outdata.data = iscsi_szmalloc(iscsi, pdu->outdata.size);
pdu->outdata.data = iscsi_zmalloc(iscsi, pdu->outdata.size);
if (pdu->outdata.data == NULL) {
iscsi_set_error(iscsi, "failed to allocate pdu header");
@@ -239,25 +242,17 @@ iscsi_tcp_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
return;
}
if (pdu->outdata.size <= iscsi->smalloc_size) {
iscsi_sfree(iscsi, pdu->outdata.data);
} else {
iscsi_free(iscsi, pdu->outdata.data);
}
iscsi_free(iscsi, pdu->outdata.data);
pdu->outdata.data = NULL;
if (pdu->indata.size <= iscsi->smalloc_size) {
iscsi_sfree(iscsi, pdu->indata.data);
} else {
iscsi_free(iscsi, pdu->indata.data);
}
iscsi_free(iscsi, pdu->indata.data);
pdu->indata.data = NULL;
if (iscsi->outqueue_current == pdu) {
iscsi->outqueue_current = NULL;
}
iscsi_sfree(iscsi, pdu);
iscsi_free(iscsi, pdu);
}
int
@@ -280,15 +275,9 @@ iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data,
}
if (data->size == 0) {
if (aligned <= iscsi->smalloc_size) {
data->data = iscsi_szmalloc(iscsi, aligned);
} else {
data->data = iscsi_malloc(iscsi, aligned);
}
data->data = iscsi_malloc(iscsi, aligned);
} else {
if (aligned > iscsi->smalloc_size) {
data->data = iscsi_realloc(iscsi, data->data, aligned);
}
data->data = iscsi_realloc(iscsi, data->data, aligned);
}
if (data->data == NULL) {
iscsi_set_error(iscsi, "failed to allocate buffer for %d "
@@ -458,11 +447,13 @@ int iscsi_process_reject(struct iscsi_context *iscsi,
iscsi_dump_pdu_header(iscsi, in->data);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
iscsi_set_error(iscsi, "Can not match REJECT with"
@@ -476,7 +467,9 @@ int iscsi_process_reject(struct iscsi_context *iscsi,
pdu->private_data);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
return 0;
}
@@ -496,6 +489,7 @@ static void iscsi_process_pdu_serials(struct iscsi_context *iscsi, struct iscsi_
return;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi_serial32_compare(maxcmdsn, iscsi->maxcmdsn) > 0) {
iscsi->maxcmdsn = maxcmdsn;
}
@@ -506,6 +500,7 @@ static void iscsi_process_pdu_serials(struct iscsi_context *iscsi, struct iscsi_
/* RFC3720 10.7.3 (StatSN is invalid if S bit unset in flags) */
if (opcode == ISCSI_PDU_DATA_IN &&
!(flags & ISCSI_PDU_DATA_CONTAINS_STATUS)) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return;
}
@@ -516,6 +511,7 @@ static void iscsi_process_pdu_serials(struct iscsi_context *iscsi, struct iscsi_
if (iscsi_serial32_compare(statsn, iscsi->statsn) > 0) {
iscsi->statsn = statsn;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
}
int
@@ -525,6 +521,8 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
uint8_t ahslen = in->hdr[4];
struct iscsi_pdu *pdu;
enum iscsi_opcode expected_response;
int is_finished = 1;
/* verify header checksum */
if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) {
@@ -623,125 +621,148 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
return 0;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
enum iscsi_opcode expected_response = pdu->response_opcode;
int is_finished = 1;
if (pdu->itt != itt) {
continue;
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
iscsi_set_error(iscsi, "Got unsolicited response with "
"itt:%d",
itt);
return -1;
}
/* we have a special case with scsi-command opcodes,
* they are replied to by either a scsi-response
* or a data-in, or a combination of both.
*/
expected_response = pdu->response_opcode;
if (opcode == ISCSI_PDU_DATA_IN
&& expected_response == ISCSI_PDU_SCSI_RESPONSE) {
expected_response = ISCSI_PDU_DATA_IN;
}
/* we have a special case with scsi-command opcodes,
* they are replied to by either a scsi-response
* or a data-in, or a combination of both.
*/
if (opcode == ISCSI_PDU_DATA_IN
&& expected_response == ISCSI_PDU_SCSI_RESPONSE) {
expected_response = ISCSI_PDU_DATA_IN;
}
/* Another special case is if we get a R2T.
* In this case we should find the original request and just send an additional
* DATAOUT segment for this task.
*/
if (opcode == ISCSI_PDU_R2T) {
expected_response = ISCSI_PDU_R2T;
}
/* Another special case is if we get a R2T.
* In this case we should find the original request and just send an additional
* DATAOUT segment for this task.
*/
if (opcode == ISCSI_PDU_R2T) {
expected_response = ISCSI_PDU_R2T;
}
if (opcode != expected_response) {
iscsi_set_error(iscsi, "Got wrong opcode back for "
"itt:%d got:%d expected %d",
itt, opcode, pdu->response_opcode);
return -1;
}
switch (opcode) {
case ISCSI_PDU_LOGIN_RESPONSE:
if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi login reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_TEXT_RESPONSE:
if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi text reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_LOGOUT_RESPONSE:
if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi logout reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_RESPONSE:
if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi response reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_DATA_IN:
if (iscsi_process_scsi_data_in(iscsi, pdu, in,
&is_finished) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi data in "
"failed");
return -1;
}
break;
case ISCSI_PDU_NOP_IN:
if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi nop-in failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
if (iscsi_process_task_mgmt_reply(iscsi, pdu,
in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi task-mgmt failed");
return -1;
}
break;
case ISCSI_PDU_R2T:
if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi r2t "
"failed");
return -1;
}
is_finished = 0;
break;
default:
iscsi_set_error(iscsi, "Don't know how to handle "
"opcode 0x%02x", opcode);
return -1;
}
if (opcode != expected_response) {
iscsi_set_error(iscsi, "Got wrong opcode back for "
"itt:%d got:%d expected %d",
itt, opcode, pdu->response_opcode);
return -1;
}
switch (opcode) {
case ISCSI_PDU_LOGIN_RESPONSE:
if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi login reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_TEXT_RESPONSE:
if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi text reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_LOGOUT_RESPONSE:
if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi logout reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_RESPONSE:
if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi response reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_DATA_IN:
if (iscsi_process_scsi_data_in(iscsi, pdu, in,
&is_finished) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi data in "
"failed");
return -1;
}
break;
case ISCSI_PDU_NOP_IN:
if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi nop-in failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
if (iscsi_process_task_mgmt_reply(iscsi, pdu,
in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi task-mgmt failed");
return -1;
}
break;
case ISCSI_PDU_R2T:
if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi r2t "
"failed");
return -1;
}
is_finished = 0;
break;
default:
iscsi_set_error(iscsi, "Don't know how to handle "
"opcode 0x%02x", opcode);
return -1;
}
if (is_finished && iscsi->waitpdu != NULL) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
}
return 0;
}
return 0;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (is_finished && iscsi->waitpdu != NULL) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 0;
}
void
@@ -842,7 +863,8 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
{
struct iscsi_pdu *tmp_pdu, *next_pdu;
enum scsi_opcode opcode = pdu->outdata.data[32];
int ret = 1;
/* only care DATA OUT command here */
if ((pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_SCSI_REQUEST) {
return 0;
@@ -857,9 +879,10 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
return 0;
};
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
/* current outgoing one is part of the PDU? */
if (iscsi->outqueue_current && (iscsi->outqueue_current->scsi_cbdata.task == pdu->scsi_cbdata.task)) {
return 1;
goto finished;
}
/* any child DATAOUT PDU in outqueue? */
@@ -867,21 +890,26 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
next_pdu = tmp_pdu->next;
if (tmp_pdu->scsi_cbdata.task == pdu->scsi_cbdata.task) {
return 1;
goto finished;
}
}
return 0;
ret = 0;
finished:
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return ret;
}
void
iscsi_timeout_scan(struct iscsi_context *iscsi)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
time_t t = time(NULL);
uint32_t cmdsn_gap = 0;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -904,6 +932,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
continue;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command timed out from outqueue");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
if (pdu->callback) {
@@ -912,6 +945,9 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
}
iscsi->drv->free_pdu(iscsi, pdu);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->waitpdu; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -927,6 +963,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
continue;
}
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command timed out from waitqueue");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
if (pdu->callback) {
@@ -937,17 +978,18 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
}
}
int
void
iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
return iscsi->drv->queue_pdu(iscsi, pdu);
iscsi->drv->queue_pdu(iscsi, pdu);
}
void
iscsi_cancel_pdus(struct iscsi_context *iscsi)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
while ((pdu = iscsi->outqueue)) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
if (pdu->callback) {
@@ -960,8 +1002,12 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
}
iscsi->drv->free_pdu(iscsi, pdu);
}
while ((pdu = iscsi->waitpdu)) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
tmp = iscsi->waitpdu;
iscsi->waitpdu = NULL;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
while ((pdu = tmp)) {
ISCSI_LIST_REMOVE(&tmp, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
NULL, pdu->private_data);
@@ -973,11 +1019,13 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
void
iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
struct scsi_task * task = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
task = iscsi_scsi_get_task_from_pdu(pdu);
@@ -994,6 +1042,11 @@ iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun)
cmdsn_gap++;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command cancelled");
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED,

View File

@@ -62,6 +62,10 @@
#include <sys/uio.h>
#endif
#ifdef HAVE_PTHREAD
#include <signal.h>
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -88,7 +92,7 @@ union socket_address {
void
iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
struct iscsi_pdu *current = iscsi->outqueue;
struct iscsi_pdu *current;
struct iscsi_pdu *last = NULL;
if (iscsi->scsi_timeout > 0) {
@@ -97,12 +101,15 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
pdu->scsi_timeout = 0;
}
if (iscsi->outqueue == NULL) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
current = iscsi->outqueue;
if (iscsi->outqueue == NULL) {
iscsi->outqueue = pdu;
pdu->next = NULL;
return;
goto finished;
}
/* queue pdus in ascending order of CmdSN.
* ensure that pakets with the same CmdSN are kept in FIFO order.
* immediate PDUs are queued in front of queue with the CmdSN
@@ -126,22 +133,37 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE && !(current->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) {
/* insert PDU before the current */
if (last != NULL) {
last->next=pdu;
last->next = pdu;
} else {
iscsi->outqueue=pdu;
iscsi->outqueue = pdu;
}
pdu->next = current;
return;
goto finished;
}
last=current;
current=current->next;
last = current;
current = current->next;
} while (current != NULL);
last->next = pdu;
pdu->next = NULL;
finished:
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
/* TODO QQQ need to immediately send for the non multithreading case too
* and for the Windows API too */
#if defined(HAVE_MULTITHREADING) && defined(HAVE_PTHREAD)
if(iscsi->multithreading_enabled) {
if (current == NULL && pdu == iscsi->outqueue) {
pthread_kill(iscsi->service_thread, SIGUSR1);
}
}
#endif
return;
}
void iscsi_decrement_iface_rr() {
/* TODO QQQ use an atomic here */
iface_rr--;
}
@@ -484,14 +506,16 @@ iscsi_tcp_which_events(struct iscsi_context *iscsi)
return 0;
}
if (iscsi->outqueue_current != NULL ||
(iscsi->outqueue != NULL && !iscsi->is_corked &&
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current ||
(iscsi->outqueue && !iscsi->is_corked &&
(iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0 ||
iscsi->outqueue->outdata.data[0] & ISCSI_PDU_IMMEDIATE)
)
) {
events |= POLLOUT;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return events;
}
@@ -507,6 +531,7 @@ iscsi_queue_length(struct iscsi_context *iscsi)
int i = 0;
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
i++;
}
@@ -516,6 +541,7 @@ iscsi_queue_length(struct iscsi_context *iscsi)
if (iscsi->is_connected == 0) {
i++;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return i;
}
@@ -526,9 +552,11 @@ iscsi_out_queue_length(struct iscsi_context *iscsi)
int i = 0;
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
i++;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return i;
}
@@ -653,20 +681,23 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
struct iscsi_in_pdu *in;
ssize_t hdr_size, data_size, count, padding_size;
bool do_data_digest = (iscsi->data_digest != ISCSI_DATA_DIGEST_NONE);
int ret = -1;
do {
hdr_size = ISCSI_HEADER_SIZE(iscsi->header_digest);
if (iscsi->incoming == NULL) {
iscsi->incoming = iscsi_szmalloc(iscsi, sizeof(struct iscsi_in_pdu));
iscsi->incoming = iscsi_zmalloc(iscsi, sizeof(struct iscsi_in_pdu));
if (iscsi->incoming == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu");
return -1;
goto finished;
}
}
if (iscsi->incoming->hdr == NULL) {
crc32c_init(&(iscsi->incoming->calculated_data_digest));
iscsi->incoming->hdr = iscsi_smalloc(iscsi, hdr_size);
iscsi->incoming->hdr = iscsi_malloc(iscsi, hdr_size);
if (iscsi->incoming->hdr == NULL) {
iscsi_set_error(iscsi, "Out-of-memory");
return -1;
goto finished;
}
}
in = iscsi->incoming;
@@ -681,7 +712,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
count, 0);
if (count == 0) {
/* remote side has closed the socket. */
return -1;
goto finished;
}
if (count < 0) {
if (errno == EINTR || errno == EAGAIN) {
@@ -689,7 +720,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
}
iscsi_set_error(iscsi, "read from socket failed, "
"errno:%d", errno);
return -1;
goto finished;
}
in->hdr_pos += count;
}
@@ -704,7 +735,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
if (data_size < 0 || data_size > (ssize_t)iscsi->initiator_max_recv_data_segment_length) {
iscsi_set_error(iscsi, "Invalid data size received from target (%d)", (int)data_size);
return -1;
goto finished;
}
if (data_size != 0) {
unsigned char padding_buf[3];
@@ -724,7 +755,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
in->data = iscsi_malloc(iscsi, data_size);
if (in->data == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu->data(%d)", (int)data_size);
return -1;
goto finished;
}
}
buf = &in->data[in->data_pos];
@@ -735,13 +766,13 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
}
if (count == 0) {
/* remote side has closed the socket. */
return -1;
goto finished;
}
if (count < 0) {
if (errno == EINTR || errno == EAGAIN) {
break;
}
return -1;
goto finished;
}
in->data_pos += count;
}
@@ -757,13 +788,13 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
count = recv(iscsi->fd, (void *)(in->data_digest_buf + in->received_data_digest_bytes), ISCSI_DIGEST_SIZE - in->received_data_digest_bytes, 0);
if (count == 0) {
/* remote side has closed the socket. */
return -1;
goto finished;
}
if (count < 0) {
if (errno == EINTR || errno == EAGAIN) {
break;
}
return -1;
goto finished;
}
in->received_data_digest_bytes += count;
@@ -772,15 +803,17 @@ iscsi_read_from_socket(struct iscsi_context *iscsi)
}
}
iscsi->incoming = NULL;
iscsi->incoming = NULL;
if (iscsi_process_pdu(iscsi, in) != 0) {
iscsi_free_iscsi_in_pdu(iscsi, in);
return -1;
goto finished;
}
iscsi_free_iscsi_in_pdu(iscsi, in);
} while (iscsi->tcp_nonblocking && iscsi->waitpdu && iscsi->is_loggedin);
} while (iscsi->tcp_nonblocking && iscsi->waitpdu && iscsi->is_loggedin); //QQQ break the loop
return 0;
ret = 0;
finished:
return ret;
}
static int iscsi_pdu_update_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
@@ -823,7 +856,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
return -1;
}
while (iscsi->outqueue != NULL || iscsi->outqueue_current != NULL) {
while (iscsi->outqueue || iscsi->outqueue_current) {
if (iscsi->outqueue_current == NULL) {
if (iscsi->is_corked) {
/* connection is corked we are not allowed to send
@@ -848,6 +881,8 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
iscsi->outqueue->cmdsn, iscsi->expcmdsn, iscsi->outqueue->outdata.data[0] & 0x3f);
return -1;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi->outqueue_current = iscsi->outqueue;
/* set exp statsn */
@@ -856,6 +891,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
/* calculate header checksum */
if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE &&
iscsi_pdu_update_headerdigest(iscsi, iscsi->outqueue_current) != 0) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return -1;
}
@@ -867,6 +903,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
cmd PDU the R2T might get lost otherwise. */
ISCSI_LIST_ADD_END(&iscsi->waitpdu, iscsi->outqueue_current);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
}
pdu = iscsi->outqueue_current;
@@ -1109,6 +1146,7 @@ iscsi_tcp_service(struct iscsi_context *iscsi, int revents)
return iscsi_service_reconnect_if_loggedin(iscsi);
}
}
if (revents & POLLOUT) {
if (iscsi_write_to_socket(iscsi) != 0) {
ISCSI_LOG(iscsi, 1, "%s", iscsi_get_error(iscsi));
@@ -1132,26 +1170,19 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
return iscsi->drv->service(iscsi, revents);
}
static int iscsi_tcp_queue_pdu(struct iscsi_context *iscsi,
static void iscsi_tcp_queue_pdu(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu)
{
if (pdu == NULL) {
iscsi_set_error(iscsi, "trying to queue NULL pdu");
return -1;
}
iscsi_add_to_outqueue(iscsi, pdu);
return 0;
}
void
iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
{
iscsi_sfree(iscsi, in->hdr);
iscsi_free(iscsi, in->hdr);
iscsi_free(iscsi, in->data);
in->data=NULL;
iscsi_sfree(iscsi, in);
iscsi_free(iscsi, in);
in=NULL;
}

View File

@@ -48,6 +48,9 @@ struct iscsi_sync_state {
int status;
void *ptr;
struct scsi_task *task;
#ifdef HAVE_MULTITHREADING
libiscsi_sem_t wait_sem;
#endif /* HAVE_MULTITHREADING */
};
static void
@@ -58,12 +61,21 @@ event_loop(struct iscsi_context *iscsi, struct iscsi_sync_state *state)
int ret;
time_t t;
#ifdef HAVE_MULTITHREADING
if(iscsi->multithreading_enabled) {
/* TODO QQQ Must make sure the service thread event loop handle timeouts properly */
iscsi_mt_sem_wait(&state->wait_sem);
iscsi_mt_sem_destroy(&state->wait_sem);
return;
}
#endif
if (iscsi->scsi_timeout) {
scsi_timeout = time(NULL) + iscsi->scsi_timeout;
} else {
scsi_timeout = 0;
}
while (state->finished == 0) {
short revents;
@@ -118,6 +130,27 @@ iscsi_sync_cb(struct iscsi_context *iscsi, int status,
state->status = status;
state->finished = 1;
#ifdef HAVE_MULTITHREADING
if(iscsi->multithreading_enabled) {
iscsi_mt_sem_post(&state->wait_sem);
}
#endif
}
static void
iscsi_init_sync_state(struct iscsi_context *iscsi, struct iscsi_sync_state *state)
{
memset(state, 0, sizeof(*state));
#ifdef HAVE_MULTITHREADING
if(iscsi->multithreading_enabled) {
/*
* Create a semaphore and initialize it to zero. So that we
* can wait for it and immetiately block until the service thread
* has received the reply.
*/
iscsi_mt_sem_init(&state->wait_sem, 0);
}
#endif /* HAVE_MULTITHREADING */
}
int
@@ -125,7 +158,7 @@ iscsi_connect_sync(struct iscsi_context *iscsi, const char *portal)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_connect_async(iscsi, portal,
iscsi_sync_cb, &state) != 0) {
@@ -154,7 +187,7 @@ iscsi_full_connect_sync(struct iscsi_context *iscsi,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_full_connect_async(iscsi, portal, lun,
iscsi_sync_cb, &state) != 0) {
@@ -178,7 +211,7 @@ int iscsi_login_sync(struct iscsi_context *iscsi)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_login_async(iscsi, iscsi_sync_cb, &state) != 0) {
iscsi_set_error(iscsi, "Failed to login. %s",
@@ -195,7 +228,7 @@ int iscsi_logout_sync(struct iscsi_context *iscsi)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_logout_async(iscsi, iscsi_sync_cb, &state) != 0) {
iscsi_set_error(iscsi, "Failed to start logout() %s",
@@ -243,7 +276,7 @@ int iscsi_reconnect_sync(struct iscsi_context *iscsi)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_reconnect(iscsi) != 0) {
iscsi_set_error(iscsi, "Failed to reconnect. %s", iscsi_get_error(iscsi));
@@ -259,7 +292,7 @@ int iscsi_force_reconnect_sync(struct iscsi_context *iscsi)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_force_reconnect(iscsi) != 0) {
iscsi_set_error(iscsi, "Failed to reconnect. %s", iscsi_get_error(iscsi));
@@ -313,7 +346,7 @@ iscsi_task_mgmt_sync(struct iscsi_context *iscsi,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_task_mgmt_async(iscsi, lun, function,
ritt, rcmdsn,
@@ -396,6 +429,11 @@ scsi_sync_cb(struct iscsi_context *iscsi, int status, void *command_data,
state->status = status;
state->finished = 1;
state->task = task;
#ifdef HAVE_MULTITHREADING
if(iscsi->multithreading_enabled) {
iscsi_mt_sem_post(&state->wait_sem);
}
#endif
}
struct scsi_task *
@@ -404,7 +442,7 @@ iscsi_reportluns_sync(struct iscsi_context *iscsi, int report_type,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_reportluns_task(iscsi, report_type, alloc_len,
scsi_sync_cb, &state) == NULL) {
@@ -423,7 +461,7 @@ iscsi_testunitready_sync(struct iscsi_context *iscsi, int lun)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_testunitready_task(iscsi, lun,
scsi_sync_cb, &state) == NULL) {
@@ -443,7 +481,7 @@ iscsi_inquiry_sync(struct iscsi_context *iscsi, int lun, int evpd,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_inquiry_task(iscsi, lun, evpd, page_code, maxsize,
scsi_sync_cb, &state) == NULL) {
@@ -462,7 +500,7 @@ iscsi_read6_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read6_task(iscsi, lun, lba, datalen, blocksize,
scsi_sync_cb, &state) == NULL) {
@@ -482,7 +520,7 @@ iscsi_read6_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read6_iov_task(iscsi, lun, lba, datalen, blocksize,
scsi_sync_cb, &state, iov, niov) == NULL) {
@@ -503,7 +541,7 @@ iscsi_read10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read10_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -526,7 +564,7 @@ iscsi_read10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read10_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -548,7 +586,7 @@ iscsi_read12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read12_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -571,7 +609,7 @@ iscsi_read12_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read12_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -593,7 +631,7 @@ iscsi_read16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read16_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -616,7 +654,7 @@ iscsi_read16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_read16_iov_task(iscsi, lun, lba, datalen, blocksize, rdprotect,
dpo, fua, fua_nv, group_number,
@@ -637,7 +675,7 @@ iscsi_readcapacity10_sync(struct iscsi_context *iscsi, int lun, int lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_readcapacity10_task(iscsi, lun, lba, pmi,
scsi_sync_cb, &state) == NULL) {
@@ -656,7 +694,7 @@ iscsi_readcapacity16_sync(struct iscsi_context *iscsi, int lun)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_readcapacity16_task(iscsi, lun,
scsi_sync_cb, &state) == NULL) {
@@ -677,7 +715,7 @@ iscsi_readdefectdata10_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_readdefectdata10_task(iscsi, lun,
req_plist, req_glist,
@@ -702,7 +740,7 @@ iscsi_readdefectdata12_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_readdefectdata12_task(iscsi, lun,
req_plist, req_glist,
@@ -726,7 +764,7 @@ iscsi_sanitize_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_sanitize_task(iscsi, lun,
immed, ause, sa, param_len, data,
@@ -747,7 +785,7 @@ iscsi_sanitize_block_erase_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_sanitize_block_erase_task(iscsi, lun,
immed, ause,
@@ -768,7 +806,7 @@ iscsi_sanitize_crypto_erase_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_sanitize_crypto_erase_task(iscsi, lun,
immed, ause,
@@ -789,7 +827,7 @@ iscsi_sanitize_exit_failure_mode_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_sanitize_exit_failure_mode_task(iscsi, lun,
immed, ause,
@@ -809,7 +847,7 @@ iscsi_get_lba_status_sync(struct iscsi_context *iscsi, int lun, uint64_t startin
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_get_lba_status_task(iscsi, lun, starting_lba, alloc_len,
scsi_sync_cb, &state) == NULL) {
@@ -829,7 +867,7 @@ iscsi_synchronizecache10_sync(struct iscsi_context *iscsi, int lun, int lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_synchronizecache10_task(iscsi, lun, lba, num_blocks,
syncnv, immed,
@@ -851,7 +889,7 @@ iscsi_startstopunit_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_startstopunit_task(iscsi, lun, immed, pcm, pc,
no_flush, loej, start,
@@ -872,7 +910,7 @@ iscsi_preventallow_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_preventallow_task(iscsi, lun, prevent,
scsi_sync_cb, &state) == NULL) {
@@ -892,7 +930,7 @@ iscsi_synchronizecache16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_synchronizecache16_task(iscsi, lun, lba, num_blocks,
syncnv, immed,
@@ -913,7 +951,7 @@ iscsi_prefetch10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_prefetch10_task(iscsi, lun, lba, num_blocks,
immed, group,
@@ -934,7 +972,7 @@ iscsi_prefetch16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_prefetch16_task(iscsi, lun, lba, num_blocks,
immed, group,
@@ -956,7 +994,7 @@ iscsi_write10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write10_task(iscsi, lun, lba, data, datalen, blocksize,
wrprotect, dpo, fua, fua_nv, group_number,
@@ -979,7 +1017,7 @@ iscsi_write10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write10_iov_task(iscsi, lun, lba, data, datalen, blocksize,
wrprotect, dpo, fua, fua_nv, group_number,
@@ -1001,7 +1039,7 @@ iscsi_write12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write12_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1025,7 +1063,7 @@ iscsi_write12_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write12_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1048,7 +1086,7 @@ iscsi_write16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write16_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1072,7 +1110,7 @@ iscsi_write16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_write16_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1095,7 +1133,7 @@ iscsi_writeatomic16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeatomic16_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1119,7 +1157,7 @@ iscsi_writeatomic16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeatomic16_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1142,7 +1180,7 @@ iscsi_orwrite_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_orwrite_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1166,7 +1204,7 @@ iscsi_orwrite_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_orwrite_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1189,7 +1227,7 @@ iscsi_compareandwrite_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_compareandwrite_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1213,7 +1251,7 @@ iscsi_compareandwrite_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lb
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_compareandwrite_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1236,7 +1274,7 @@ iscsi_writeverify10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify10_task(iscsi, lun, lba, data, datalen, blocksize,
wrprotect, dpo, bytchk, group_number,
@@ -1259,7 +1297,7 @@ iscsi_writeverify10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify10_iov_task(iscsi, lun, lba, data, datalen, blocksize,
wrprotect, dpo, bytchk, group_number,
@@ -1281,7 +1319,7 @@ iscsi_writeverify12_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify12_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1305,7 +1343,7 @@ iscsi_writeverify12_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify12_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1328,7 +1366,7 @@ iscsi_writeverify16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify16_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1352,7 +1390,7 @@ iscsi_writeverify16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writeverify16_iov_task(iscsi, lun, lba,
data, datalen, blocksize, wrprotect,
@@ -1374,7 +1412,7 @@ iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, u
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify10_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state) == NULL) {
@@ -1394,7 +1432,7 @@ iscsi_verify10_iov_sync(struct iscsi_context *iscsi, int lun, unsigned char *dat
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify10_iov_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state, iov, niov) == NULL) {
@@ -1415,7 +1453,7 @@ iscsi_verify12_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, u
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify12_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state) == NULL) {
@@ -1435,7 +1473,7 @@ iscsi_verify12_iov_sync(struct iscsi_context *iscsi, int lun, unsigned char *dat
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify12_iov_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state, iov, niov) == NULL) {
@@ -1455,7 +1493,7 @@ iscsi_verify16_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, u
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify16_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state) == NULL) {
@@ -1475,7 +1513,7 @@ iscsi_verify16_iov_sync(struct iscsi_context *iscsi, int lun, unsigned char *dat
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_verify16_iov_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state, iov, niov) == NULL) {
@@ -1497,7 +1535,7 @@ iscsi_writesame10_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writesame10_task(iscsi, lun, lba,
data, datalen, num_blocks,
@@ -1522,7 +1560,7 @@ iscsi_writesame10_iov_sync(struct iscsi_context *iscsi, int lun, uint32_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writesame10_iov_task(iscsi, lun, lba,
data, datalen, num_blocks,
@@ -1546,7 +1584,7 @@ iscsi_writesame16_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writesame16_task(iscsi, lun, lba,
data, datalen, num_blocks,
@@ -1571,7 +1609,7 @@ iscsi_writesame16_iov_sync(struct iscsi_context *iscsi, int lun, uint64_t lba,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_writesame16_iov_task(iscsi, lun, lba,
data, datalen, num_blocks,
@@ -1593,7 +1631,7 @@ iscsi_persistent_reserve_in_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_persistent_reserve_in_task(iscsi, lun, sa, xferlen,
scsi_sync_cb, &state) == NULL) {
@@ -1613,7 +1651,7 @@ iscsi_persistent_reserve_out_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_persistent_reserve_out_task(iscsi, lun,
sa, scope, type, param,
@@ -1634,7 +1672,7 @@ iscsi_unmap_sync(struct iscsi_context *iscsi, int lun, int anchor, int group,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_unmap_task(iscsi, lun, anchor, group, list, list_len,
scsi_sync_cb, &state) == NULL) {
@@ -1654,7 +1692,7 @@ iscsi_readtoc_sync(struct iscsi_context *iscsi, int lun, int msf, int format,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_readtoc_task(iscsi, lun, msf, format, track_session,
maxsize, scsi_sync_cb, &state) == NULL) {
@@ -1672,7 +1710,7 @@ iscsi_reserve6_sync(struct iscsi_context *iscsi, int lun)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_reserve6_task(iscsi, lun, scsi_sync_cb, &state) == NULL) {
iscsi_set_error(iscsi, "Failed to send RESERVE6 command");
@@ -1689,7 +1727,7 @@ iscsi_release6_sync(struct iscsi_context *iscsi, int lun)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_release6_task(iscsi, lun, scsi_sync_cb, &state) == NULL) {
iscsi_set_error(iscsi, "Failed to send RELEASE6 command");
@@ -1709,7 +1747,7 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_report_supported_opcodes_task(iscsi, lun, rctd, options, opcode, sa, alloc_len, scsi_sync_cb, &state) == NULL) {
iscsi_set_error(iscsi, "Failed to send MaintenanceIn:"
@@ -1728,7 +1766,7 @@ iscsi_receive_copy_results_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_receive_copy_results_task(iscsi, lun, sa, list_id, alloc_len,
scsi_sync_cb, &state) == NULL) {
@@ -1748,7 +1786,7 @@ iscsi_extended_copy_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_extended_copy_task(iscsi, lun, param_data,
scsi_sync_cb, &state) == NULL) {
@@ -1768,7 +1806,7 @@ iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_scsi_command_async(iscsi, lun, task,
scsi_sync_cb, data, &state) != 0) {
@@ -1788,7 +1826,7 @@ iscsi_modeselect6_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_modeselect6_task(iscsi, lun, pf, sp, mp,
scsi_sync_cb, &state) == NULL) {
@@ -1808,7 +1846,7 @@ iscsi_modeselect10_sync(struct iscsi_context *iscsi, int lun,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_modeselect10_task(iscsi, lun, pf, sp, mp,
scsi_sync_cb, &state) == NULL) {
@@ -1829,7 +1867,7 @@ iscsi_modesense6_sync(struct iscsi_context *iscsi, int lun, int dbd,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_modesense6_task(iscsi, lun, dbd, pc, page_code, sub_page_code, alloc_len,
scsi_sync_cb, &state) == NULL) {
@@ -1850,7 +1888,7 @@ iscsi_modesense10_sync(struct iscsi_context *iscsi, int lun, int llbaa, int dbd,
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_modesense10_task(iscsi, lun, llbaa, dbd, pc,
page_code, sub_page_code, alloc_len,
@@ -1924,12 +1962,11 @@ iscsi_discovery_sync(struct iscsi_context *iscsi)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
iscsi_init_sync_state(iscsi, &state);
if (iscsi_discovery_async(iscsi, iscsi_discovery_cb, &state) != 0) {
iscsi_set_error(iscsi, "Failed to run discovery. %s",
iscsi_get_error(iscsi));
printf("async discovery call failed\n");
return NULL;
}

View File

@@ -80,11 +80,7 @@ iscsi_task_mgmt_async(struct iscsi_context *iscsi,
pdu->callback = cb;
pdu->private_data = private_data;
if (iscsi_queue_pdu(iscsi, pdu) != 0) {
iscsi_set_error(iscsi, "failed to queue iscsi taskmgmt pdu");
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi_queue_pdu(iscsi, pdu);
return 0;
}

View File

@@ -561,6 +561,7 @@ wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *
state->finished = 1;
state->status = SCSI_STATUS_CANCELLED;
state->task->status = SCSI_STATUS_CANCELLED;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
/* this may leak memory since we don't free the pdu */
while ((pdu = iscsi->outqueue)) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
@@ -568,6 +569,7 @@ wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *
while ((pdu = iscsi->waitpdu)) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return;
}
continue;

View File

@@ -739,7 +739,7 @@ static struct test_family families[] = {
*/
struct scsi_task *task;
unsigned char *read_write_buf;
int (*orig_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
void (*orig_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu);
static void
print_usage(void)

View File

@@ -35,8 +35,8 @@
/* globals between setup, tests, and teardown */
extern struct scsi_task *task;
extern unsigned char *read_write_buf;
extern int (*orig_queue_pdu)(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu);
extern void (*orig_queue_pdu)(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu);
#ifndef HAVE_CU_SUITEINFO_PSETUPFUNC
/* libcunit version 1 */

View File

@@ -28,13 +28,13 @@
static int new_nlb = -1;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
if (pdu->outdata.data[0] != ISCSI_PDU_SCSI_REQUEST && new_nlb >= 0) {
/* change NUMBER OF LOGICAL BLOCKS to new_nlb */
pdu->outdata.data[32 + 13] = new_nlb;
}
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void

View File

@@ -77,7 +77,7 @@ test_iscsi_strip_tag(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
return 0;
}
static int
static void
chap_mod_strip_replace_queue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const char *new_chap_a)
{
@@ -93,41 +93,41 @@ chap_mod_strip_replace_queue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
goto out;
}
if (ret < 0) {
return ret;
return;
}
ret = iscsi_pdu_add_data(iscsi, pdu, (const unsigned char *)new_chap_a,
strlen(new_chap_a) + 1);
if (ret < 0) {
return ret;
return;
}
logging(LOG_VERBOSE, "replaced Login PDU CHAP_A setting with %s", new_chap_a);
out:
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
static int
static void
chap_mod_many_types_queue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
return chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=5,6,7,8");
chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=5,6,7,8");
}
static int
static void
chap_mod_no_type_queue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
return chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=");
chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=");
}
static int
static void
chap_mod_bad_type_queue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
/* value starts with '5', to catch targets that only check one byte */
return chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=56");
chap_mod_strip_replace_queue(iscsi, pdu, "CHAP_A=56");
}
static int
test_iscsi_chap_login(int (*test_queue_pdu)(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu))
test_iscsi_chap_login(void (*test_queue_pdu)(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu))
{
struct iscsi_context *iscsi;
struct iscsi_url *iscsi_url;

View File

@@ -26,7 +26,7 @@
static int change_cmdsn;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
switch (change_cmdsn) {
case 1:
@@ -45,7 +45,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
}
change_cmdsn = 0;
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_iscsi_cmdsn_toohigh(void)

View File

@@ -26,7 +26,7 @@
static int change_cmdsn;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
switch (change_cmdsn) {
case 1:
@@ -45,7 +45,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
}
change_cmdsn = 0;
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_iscsi_cmdsn_toolow(void)

View File

@@ -26,7 +26,7 @@
static int change_datasn;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
uint32_t datasn;
@@ -57,7 +57,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
break;
}
out:
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_iscsi_datasn_invalid(void)

View File

@@ -148,8 +148,7 @@ test_iscsi_text_req_queue(struct iscsi_context *iscsi,
pdu->callback = cb;
pdu->private_data = state;
ret = iscsi_queue_pdu(iscsi, pdu);
CU_ASSERT_EQUAL_FATAL(ret, 0);
iscsi_queue_pdu(iscsi, pdu);
state->dispatched++;
logging(LOG_VERBOSE, "queued Text request %d with %s",
state->dispatched, kv_data);

View File

@@ -26,7 +26,7 @@
static int change_num;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
switch (change_num) {
case 1:
@@ -44,7 +44,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
}
change_num = 0;
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_sanitize_block_erase_reserved(void)

View File

@@ -26,7 +26,7 @@
static int change_num;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
switch (change_num) {
case 1:
@@ -44,7 +44,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
}
change_num = 0;
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_sanitize_crypto_erase_reserved(void)

View File

@@ -27,7 +27,7 @@
static int change_num;
static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
static void my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
switch (change_num) {
case 1:
@@ -45,7 +45,7 @@ static int my_iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu
}
change_num = 0;
return orig_queue_pdu(iscsi, pdu);
orig_queue_pdu(iscsi, pdu);
}
void test_sanitize_overwrite_reserved(void)