[stgt] RHEL 5.3

FUJITA Tomonori fujita.tomonori at lab.ntt.co.jp
Wed Mar 11 11:12:51 CET 2009


On Wed, 11 Mar 2009 09:01:50 +0100
Tomasz Chmielewski <mangoo at wpkg.org> wrote:

> FUJITA Tomonori schrieb:
> > RHEL 5.3 release note says (I think that some of you guys already know
> > this):
> > 
> > =
> > iSCSI target capability
> > 
> > The iSCSI target capability, delivered as part of the Linux Target
> > (tgt) framework, moves from Technology Preview to full support in Red
> 
> (...)
> 
> > http://www.redhat.com/docs/manuals/enterprise/
> > 
> > 
> > We need to be more serious. :) Hopefully, this would attract more
> > users to tgt.
> > 
> > Feel feel to post what features you want, what areas need to be fixed,
> > etc.
> 
> The only thing that bothers me is target/lun limit, caused by libc 
> pthread limit. I thought it only affects 32 bit targets, but now I see 
> it happens also with 64 bits.
> 
> I understand it's a major design problem - do you think it could be 
> addressed? I.e., use prefork model used by Apache and just launch more 
> tgtd processes?

I'm not sure Apache uses such model, 'client per process with
preforking) because it sucks (I guess it used the model):

http://www.kegel.com/c10k.html


The only reason we have to use pthread is that Linux AIO is
broken. I've been waiting for the new AIO mechanism:

http://lwn.net/Articles/316193/

It would improve the performance too.


Anyway, the target/lun limit problem is bad. So here's a patch to fix
it. I've not tested it much. So let me know how it works.

=
From: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
Subject: [PATCH] add async threads

Signed-off-by: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
---
 usr/Makefile    |    2 +-
 usr/async.c     |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 usr/async.h     |   18 +++
 usr/bs.c        |  245 +++++++++++++++++++++++-------------------
 usr/scsi_cmnd.h |    4 +
 usr/tgtd.c      |    7 ++
 6 files changed, 481 insertions(+), 113 deletions(-)
 create mode 100644 usr/async.c
 create mode 100644 usr/async.h

diff --git a/usr/Makefile b/usr/Makefile
index 3fc848e..743a2b6 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -61,7 +61,7 @@ LIBS += -lpthread
 
 PROGRAMS += tgtd tgtadm tgtimg
 SCRIPTS += ../scripts/tgt-setup-lun ../scripts/tgt-admin
-TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o work.o \
+TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o work.o async.o \
 		parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o \
 		ssc.o bs_ssc.o libssc.o \
 		bs_null.o bs_sg.o bs.o libcrc32c.o
diff --git a/usr/async.c b/usr/async.c
new file mode 100644
index 0000000..85fdbee
--- /dev/null
+++ b/usr/async.c
@@ -0,0 +1,318 @@
+/*
+ * infrastructure to perform synchronous functions asynchronously
+ *
+ * Copyright (C) 2008 FUJITA Tomonori <tomof at acm.org>
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+
+#include "list.h"
+#include "util.h"
+#include "tgtd.h"
+#include "async.h"
+
+#define NR_THREADS 8
+
+struct async_task_info {
+	pthread_t ack_thread;
+	pthread_t worker_thread[NR_THREADS];
+
+	/* protected by pipe */
+	struct list_head ack_list;
+
+	pthread_cond_t finished_cond;
+	pthread_mutex_t finished_lock;
+	struct list_head finished_list;
+
+	/* wokers sleep on this and signaled by tgtd */
+	pthread_cond_t pending_cond;
+	/* locked by tgtd and workers */
+	pthread_mutex_t pending_lock;
+	/* protected by pending_lock */
+	struct list_head pending_list;
+
+	pthread_mutex_t startup_lock;
+
+	int command_fd[2];
+	int done_fd[2];
+
+	int stop;
+};
+
+struct async_task_info *info, __info;
+
+static void *atask_ack_fn(void *arg)
+{
+	struct async_task_info *info = arg;
+	int command, ret, nr;
+	struct atask *task;
+
+retry:
+	ret = read(info->command_fd[0], &command, sizeof(command));
+	if (ret < 0) {
+		eprintf("ack pthread will be dead, %m\n");
+		if (errno == EAGAIN || errno == EINTR)
+			goto retry;
+
+		goto out;
+	}
+
+	if (info->stop)
+		goto out;
+
+	pthread_mutex_lock(&info->finished_lock);
+retest:
+	if (list_empty(&info->finished_list)) {
+		pthread_cond_wait(&info->finished_cond, &info->finished_lock);
+		goto retest;
+	}
+
+	while (!list_empty(&info->finished_list)) {
+		task = list_first_entry(&info->finished_list,
+				 struct atask, at_list);
+
+		list_del(&task->at_list);
+		list_add(&task->at_list, &info->ack_list);
+	}
+
+	pthread_mutex_unlock(&info->finished_lock);
+
+	nr = 1;
+rewrite:
+	ret = write(info->done_fd[1], &nr, sizeof(nr));
+	if (ret < 0) {
+		eprintf("can't ack tgtd, %m\n");
+		if (errno == EAGAIN || errno == EINTR)
+			goto rewrite;
+
+		goto out;
+	}
+
+	goto retry;
+out:
+	pthread_exit(NULL);
+}
+
+static void *bs_thread_worker_fn(void *arg)
+{
+	struct async_task_info *info = arg;
+	struct atask *task;
+
+	pthread_mutex_lock(&info->startup_lock);
+	dprintf("started this thread\n");
+	pthread_mutex_unlock(&info->startup_lock);
+
+	while (!info->stop) {
+		pthread_mutex_lock(&info->pending_lock);
+	retest:
+		if (list_empty(&info->pending_list)) {
+			pthread_cond_wait(&info->pending_cond, &info->pending_lock);
+			if (info->stop) {
+				pthread_mutex_unlock(&info->pending_lock);
+				pthread_exit(NULL);
+			}
+			goto retest;
+		}
+
+		task = list_first_entry(&info->pending_list,
+					struct atask, at_list);
+
+
+		list_del(&task->at_list);
+		pthread_mutex_unlock(&info->pending_lock);
+
+		task->fn(task);
+
+		pthread_mutex_lock(&info->finished_lock);
+		list_add(&task->at_list, &info->finished_list);
+		pthread_mutex_unlock(&info->finished_lock);
+
+		pthread_cond_signal(&info->finished_cond);
+	}
+
+	pthread_exit(NULL);
+}
+
+static void atask_done_fn(int fd, int events, void *data)
+{
+	struct async_task_info *info = data;
+	struct atask *task;
+	int nr_events, ret;
+
+	ret = read(info->done_fd[0], &nr_events, sizeof(nr_events));
+	if (ret < 0) {
+		eprintf("wrong wakeup\n");
+		return;
+	}
+
+	while (!list_empty(&info->ack_list)) {
+		task = list_first_entry(&info->ack_list,
+					struct atask, at_list);
+
+		list_del(&task->at_list);
+		task->done(task);
+	}
+
+rewrite:
+	ret = write(info->command_fd[1], &nr_events, sizeof(nr_events));
+	if (ret < 0) {
+		eprintf("can't write done, %m\n");
+		if (errno == EAGAIN || errno == EINTR)
+			goto rewrite;
+
+		return;
+	}
+}
+
+int init_async(void)
+{
+	int i, ret;
+
+	info = &__info;
+
+	INIT_LIST_HEAD(&info->ack_list);
+	INIT_LIST_HEAD(&info->finished_list);
+	INIT_LIST_HEAD(&info->pending_list);
+
+	pthread_cond_init(&info->finished_cond, NULL);
+	pthread_cond_init(&info->pending_cond, NULL);
+
+	pthread_mutex_init(&info->finished_lock, NULL);
+	pthread_mutex_init(&info->pending_lock, NULL);
+	pthread_mutex_init(&info->startup_lock, NULL);
+
+	ret = pipe(info->command_fd);
+	if (ret) {
+		eprintf("failed to create command pipe, %m\n");
+		goto destroy_cond_mutex;
+	}
+
+	ret = pipe(info->done_fd);
+	if (ret) {
+		eprintf("failed to done command pipe, %m\n");
+		goto close_command_fd;
+	}
+
+	ret = tgt_event_add(info->done_fd[0], EPOLLIN, atask_done_fn, info);
+	if (ret) {
+		eprintf("failed to add epoll event\n");
+		goto close_done_fd;
+	}
+
+	ret = pthread_create(&info->ack_thread, NULL, atask_ack_fn, info);
+	if (ret) {
+		eprintf("failed to create an ack thread, %s\n", strerror(ret));
+		goto event_del;
+	}
+
+	pthread_mutex_lock(&info->startup_lock);
+	for (i = 0; i < ARRAY_SIZE(info->worker_thread); i++) {
+		ret = pthread_create(&info->worker_thread[i], NULL,
+				     bs_thread_worker_fn, info);
+
+		if (ret) {
+			eprintf("failed to create a worker thread, %d %s\n",
+				i, strerror(ret));
+			if (ret)
+				goto destroy_threads;
+		}
+	}
+	pthread_mutex_unlock(&info->startup_lock);
+rewrite:
+	ret = write(info->command_fd[1], &ret, sizeof(ret));
+	if (ret < 0) {
+		eprintf("can't write done, %m\n");
+		if (errno == EAGAIN || errno == EINTR)
+			goto rewrite;
+	}
+
+	return 0;
+destroy_threads:
+	info->stop = 1;
+	write(info->command_fd[1], &ret, sizeof(ret));
+	pthread_join(info->ack_thread, NULL);
+
+	eprintf("stopped the ack thread\n");
+
+	pthread_mutex_unlock(&info->startup_lock);
+	for (; i > 0; i--) {
+		pthread_join(info->worker_thread[i - 1], NULL);
+		eprintf("stopped the worker thread %d\n", i - 1);
+	}
+event_del:
+	tgt_event_del(info->done_fd[0]);
+close_done_fd:
+	close(info->done_fd[0]);
+	close(info->done_fd[1]);
+close_command_fd:
+	close(info->command_fd[0]);
+	close(info->command_fd[1]);
+destroy_cond_mutex:
+	pthread_cond_destroy(&info->finished_cond);
+	pthread_cond_destroy(&info->pending_cond);
+	pthread_mutex_destroy(&info->finished_lock);
+	pthread_mutex_destroy(&info->pending_lock);
+	pthread_mutex_destroy(&info->startup_lock);
+
+	return 1;
+}
+
+void exit_async(void)
+{
+	int i;
+
+	pthread_cancel(info->ack_thread);
+	pthread_join(info->ack_thread, NULL);
+
+	info->stop = 1;
+	pthread_cond_broadcast(&info->pending_cond);
+
+	for (i = 0; info->worker_thread[i] &&
+		     i < ARRAY_SIZE(info->worker_thread); i++)
+		pthread_join(info->worker_thread[i], NULL);
+
+	pthread_cond_destroy(&info->finished_cond);
+	pthread_cond_destroy(&info->pending_cond);
+	pthread_mutex_destroy(&info->finished_lock);
+	pthread_mutex_destroy(&info->pending_lock);
+	pthread_mutex_destroy(&info->startup_lock);
+
+	tgt_event_del(info->done_fd[0]);
+
+	close(info->done_fd[0]);
+	close(info->done_fd[1]);
+
+	close(info->command_fd[0]);
+	close(info->command_fd[1]);
+
+	info->stop = 0;
+}
+
+void async_submit(struct atask *task)
+{
+	pthread_mutex_lock(&info->pending_lock);
+
+	list_add(&task->at_list, &info->pending_list);
+
+	pthread_mutex_unlock(&info->pending_lock);
+
+	pthread_cond_signal(&info->pending_cond);
+}
diff --git a/usr/async.h b/usr/async.h
new file mode 100644
index 0000000..0a0960d
--- /dev/null
+++ b/usr/async.h
@@ -0,0 +1,18 @@
+#ifndef __ASYNC_H__
+#define __ASYNC_H__
+
+struct atask;
+
+typedef void (async_task_func_t) (struct atask *);
+
+struct atask {
+	struct list_head at_list;
+	async_task_func_t *fn;
+	async_task_func_t *done;
+};
+
+int init_async(void);
+void exit_async(void);
+void async_submit(struct atask *task);
+
+#endif
diff --git a/usr/bs.c b/usr/bs.c
index cd19b86..3876188 100644
--- a/usr/bs.c
+++ b/usr/bs.c
@@ -30,6 +30,7 @@
 #include "tgtadm_error.h"
 #include "util.h"
 #include "bs_thread.h"
+#include "async.h"
 
 static LIST_HEAD(bst_list);
 
@@ -184,145 +185,165 @@ static void *bs_thread_worker_fn(void *arg)
 int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn,
 		   int nr_threads)
 {
-	int i, ret;
+/* 	int i, ret; */
 
 	info->request_fn = rfn;
 
-	INIT_LIST_HEAD(&info->ack_list);
-	INIT_LIST_HEAD(&info->finished_list);
-	INIT_LIST_HEAD(&info->pending_list);
+/* 	INIT_LIST_HEAD(&info->ack_list); */
+/* 	INIT_LIST_HEAD(&info->finished_list); */
+/* 	INIT_LIST_HEAD(&info->pending_list); */
+
+/* 	pthread_cond_init(&info->finished_cond, NULL); */
+/* 	pthread_cond_init(&info->pending_cond, NULL); */
+
+/* 	pthread_mutex_init(&info->finished_lock, NULL); */
+/* 	pthread_mutex_init(&info->pending_lock, NULL); */
+/* 	pthread_mutex_init(&info->startup_lock, NULL); */
+
+/* 	ret = pipe(info->command_fd); */
+/* 	if (ret) { */
+/* 		eprintf("failed to create command pipe, %m\n"); */
+/* 		goto destroy_cond_mutex; */
+/* 	} */
+
+/* 	ret = pipe(info->done_fd); */
+/* 	if (ret) { */
+/* 		eprintf("failed to done command pipe, %m\n"); */
+/* 		goto close_command_fd; */
+/* 	} */
+
+/* 	ret = tgt_event_add(info->done_fd[0], EPOLLIN, bs_thread_request_done, info); */
+/* 	if (ret) { */
+/* 		eprintf("failed to add epoll event\n"); */
+/* 		goto close_done_fd; */
+/* 	} */
+
+/* 	ret = pthread_create(&info->ack_thread, NULL, bs_thread_ack_fn, info); */
+/* 	if (ret) { */
+/* 		eprintf("failed to create an ack thread, %s\n", strerror(ret)); */
+/* 		goto event_del; */
+/* 	} */
+
+/* 	if (nr_threads > ARRAY_SIZE(info->worker_thread)) { */
+/* 		eprintf("too many threads %d\n", nr_threads); */
+/* 		nr_threads = ARRAY_SIZE(info->worker_thread); */
+/* 	} */
+
+/* 	pthread_mutex_lock(&info->startup_lock); */
+/* 	for (i = 0; i < nr_threads; i++) { */
+/* 		ret = pthread_create(&info->worker_thread[i], NULL, */
+/* 				     bs_thread_worker_fn, info); */
+
+/* 		if (ret) { */
+/* 			eprintf("failed to create a worker thread, %d %s\n", */
+/* 				i, strerror(ret)); */
+/* 			if (ret) */
+/* 				goto destroy_threads; */
+/* 		} */
+/* 	} */
+/* 	pthread_mutex_unlock(&info->startup_lock); */
+/* rewrite: */
+/* 	ret = write(info->command_fd[1], &ret, sizeof(ret)); */
+/* 	if (ret < 0) { */
+/* 		eprintf("can't write done, %m\n"); */
+/* 		if (errno == EAGAIN || errno == EINTR) */
+/* 			goto rewrite; */
+/* 	} */
 
-	pthread_cond_init(&info->finished_cond, NULL);
-	pthread_cond_init(&info->pending_cond, NULL);
+	return 0;
+/* destroy_threads: */
+/* 	info->stop = 1; */
+/* 	write(info->command_fd[1], &ret, sizeof(ret)); */
+/* 	pthread_join(info->ack_thread, NULL); */
+
+/* 	eprintf("stopped the ack thread\n"); */
+
+/* 	pthread_mutex_unlock(&info->startup_lock); */
+/* 	for (; i > 0; i--) { */
+/* 		pthread_join(info->worker_thread[i - 1], NULL); */
+/* 		eprintf("stopped the worker thread %d\n", i - 1); */
+/* 	} */
+/* event_del: */
+/* 	tgt_event_del(info->done_fd[0]); */
+/* close_done_fd: */
+/* 	close(info->done_fd[0]); */
+/* 	close(info->done_fd[1]); */
+/* close_command_fd: */
+/* 	close(info->command_fd[0]); */
+/* 	close(info->command_fd[1]); */
+/* destroy_cond_mutex: */
+/* 	pthread_cond_destroy(&info->finished_cond); */
+/* 	pthread_cond_destroy(&info->pending_cond); */
+/* 	pthread_mutex_destroy(&info->finished_lock); */
+/* 	pthread_mutex_destroy(&info->pending_lock); */
+/* 	pthread_mutex_destroy(&info->startup_lock); */
+
+/* 	return TGTADM_NOMEM; */
+}
 
-	pthread_mutex_init(&info->finished_lock, NULL);
-	pthread_mutex_init(&info->pending_lock, NULL);
-	pthread_mutex_init(&info->startup_lock, NULL);
+void bs_thread_close(struct bs_thread_info *info)
+{
+/* 	int i; */
 
-	ret = pipe(info->command_fd);
-	if (ret) {
-		eprintf("failed to create command pipe, %m\n");
-		goto destroy_cond_mutex;
-	}
+/* 	pthread_cancel(info->ack_thread); */
+/* 	pthread_join(info->ack_thread, NULL); */
 
-	ret = pipe(info->done_fd);
-	if (ret) {
-		eprintf("failed to done command pipe, %m\n");
-		goto close_command_fd;
-	}
+/* 	info->stop = 1; */
+/* 	pthread_cond_broadcast(&info->pending_cond); */
 
-	ret = tgt_event_add(info->done_fd[0], EPOLLIN, bs_thread_request_done, info);
-	if (ret) {
-		eprintf("failed to add epoll event\n");
-		goto close_done_fd;
-	}
+/* 	for (i = 0; info->worker_thread[i] && */
+/* 		     i < ARRAY_SIZE(info->worker_thread); i++) */
+/* 		pthread_join(info->worker_thread[i], NULL); */
 
-	ret = pthread_create(&info->ack_thread, NULL, bs_thread_ack_fn, info);
-	if (ret) {
-		eprintf("failed to create an ack thread, %s\n", strerror(ret));
-		goto event_del;
-	}
+/* 	pthread_cond_destroy(&info->finished_cond); */
+/* 	pthread_cond_destroy(&info->pending_cond); */
+/* 	pthread_mutex_destroy(&info->finished_lock); */
+/* 	pthread_mutex_destroy(&info->pending_lock); */
+/* 	pthread_mutex_destroy(&info->startup_lock); */
 
-	if (nr_threads > ARRAY_SIZE(info->worker_thread)) {
-		eprintf("too many threads %d\n", nr_threads);
-		nr_threads = ARRAY_SIZE(info->worker_thread);
-	}
+/* 	tgt_event_del(info->done_fd[0]); */
 
-	pthread_mutex_lock(&info->startup_lock);
-	for (i = 0; i < nr_threads; i++) {
-		ret = pthread_create(&info->worker_thread[i], NULL,
-				     bs_thread_worker_fn, info);
-
-		if (ret) {
-			eprintf("failed to create a worker thread, %d %s\n",
-				i, strerror(ret));
-			if (ret)
-				goto destroy_threads;
-		}
-	}
-	pthread_mutex_unlock(&info->startup_lock);
-rewrite:
-	ret = write(info->command_fd[1], &ret, sizeof(ret));
-	if (ret < 0) {
-		eprintf("can't write done, %m\n");
-		if (errno == EAGAIN || errno == EINTR)
-			goto rewrite;
-	}
+/* 	close(info->done_fd[0]); */
+/* 	close(info->done_fd[1]); */
 
-	return 0;
-destroy_threads:
-	info->stop = 1;
-	write(info->command_fd[1], &ret, sizeof(ret));
-	pthread_join(info->ack_thread, NULL);
-
-	eprintf("stopped the ack thread\n");
+/* 	close(info->command_fd[0]); */
+/* 	close(info->command_fd[1]); */
 
-	pthread_mutex_unlock(&info->startup_lock);
-	for (; i > 0; i--) {
-		pthread_join(info->worker_thread[i - 1], NULL);
-		eprintf("stopped the worker thread %d\n", i - 1);
-	}
-event_del:
-	tgt_event_del(info->done_fd[0]);
-close_done_fd:
-	close(info->done_fd[0]);
-	close(info->done_fd[1]);
-close_command_fd:
-	close(info->command_fd[0]);
-	close(info->command_fd[1]);
-destroy_cond_mutex:
-	pthread_cond_destroy(&info->finished_cond);
-	pthread_cond_destroy(&info->pending_cond);
-	pthread_mutex_destroy(&info->finished_lock);
-	pthread_mutex_destroy(&info->pending_lock);
-	pthread_mutex_destroy(&info->startup_lock);
-
-	return TGTADM_NOMEM;
+/* 	info->stop = 0; */
 }
 
-void bs_thread_close(struct bs_thread_info *info)
+static void bs_fn(struct atask *task)
 {
-	int i;
-
-	pthread_cancel(info->ack_thread);
-	pthread_join(info->ack_thread, NULL);
-
-	info->stop = 1;
-	pthread_cond_broadcast(&info->pending_cond);
-
-	for (i = 0; info->worker_thread[i] &&
-		     i < ARRAY_SIZE(info->worker_thread); i++)
-		pthread_join(info->worker_thread[i], NULL);
-
-	pthread_cond_destroy(&info->finished_cond);
-	pthread_cond_destroy(&info->pending_cond);
-	pthread_mutex_destroy(&info->finished_lock);
-	pthread_mutex_destroy(&info->pending_lock);
-	pthread_mutex_destroy(&info->startup_lock);
-
-	tgt_event_del(info->done_fd[0]);
+	struct scsi_cmd *cmd = container_of(task, struct scsi_cmd, at);
+	struct scsi_lu *lu = cmd->dev;
+	struct bs_thread_info *info = BS_THREAD_I(lu);
 
-	close(info->done_fd[0]);
-	close(info->done_fd[1]);
+	info->request_fn(cmd);
+}
 
-	close(info->command_fd[0]);
-	close(info->command_fd[1]);
+static void bs_done(struct atask *task)
+{
+	struct scsi_cmd *cmd = container_of(task, struct scsi_cmd, at);
 
-	info->stop = 0;
+	cmd->scsi_cmd_done(cmd, scsi_get_result(cmd));
 }
 
 int bs_thread_cmd_submit(struct scsi_cmd *cmd)
 {
-	struct scsi_lu *lu = cmd->dev;
-	struct bs_thread_info *info = BS_THREAD_I(lu);
+	struct atask *task = &cmd->at;
+
+	task->fn = bs_fn;
+	task->done = bs_done;
+
+	async_submit(task);
 
-	pthread_mutex_lock(&info->pending_lock);
+/* 	pthread_mutex_lock(&info->pending_lock); */
 
-	list_add(&cmd->bs_list, &info->pending_list);
+/* 	list_add(&cmd->bs_list, &info->pending_list); */
 
-	pthread_mutex_unlock(&info->pending_lock);
+/* 	pthread_mutex_unlock(&info->pending_lock); */
 
-	pthread_cond_signal(&info->pending_cond);
+/* 	pthread_cond_signal(&info->pending_cond); */
 
 	set_cmd_async(cmd);
 
diff --git a/usr/scsi_cmnd.h b/usr/scsi_cmnd.h
index 011f3e6..e496fde 100644
--- a/usr/scsi_cmnd.h
+++ b/usr/scsi_cmnd.h
@@ -1,3 +1,5 @@
+#include "async.h"
+
 struct target;
 struct mgmt_req;
 
@@ -51,6 +53,8 @@ struct scsi_cmd {
 
 	struct it_nexus *it_nexus;
 	struct it_nexus_lu_info *itn_lu_info;
+
+	struct atask at;
 };
 
 #define scsi_cmnd_accessor(field, type)						\
diff --git a/usr/tgtd.c b/usr/tgtd.c
index 8569d41..e57373d 100644
--- a/usr/tgtd.c
+++ b/usr/tgtd.c
@@ -37,6 +37,7 @@
 #include "tgtd.h"
 #include "driver.h"
 #include "work.h"
+#include "async.h"
 #include "util.h"
 
 unsigned long pagesize, pageshift, pagemask;
@@ -388,6 +389,10 @@ int main(int argc, char **argv)
 		}
 	}
 
+	err = init_async();
+	if (err)
+		exit(1);
+
 	event_loop();
 
 	lld_exit();
@@ -396,5 +401,7 @@ int main(int argc, char **argv)
 
 	log_close();
 
+	exit_async();
+
 	return 0;
 }
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list