* [Qemu-devel] iSCSI support for QEMU, update
@ 2011-04-21 20:23 ronniesahlberg
2011-04-22 4:08 ` Christoph Hellwig
0 siblings, 1 reply; 8+ messages in thread
From: ronniesahlberg @ 2011-04-21 20:23 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, hch
iSCSI block driver for QEMU
Please find an updated iSCSI patch.
This patch adds setting FUA on all writes when the bit
BDRV_O_CACHE_WB is not set.
regards
ronnie sahlberg
From: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Subject: iSCSI support for QEMU, update
In-Reply-To:
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] iSCSI support for QEMU, update
2011-04-21 20:23 [Qemu-devel] iSCSI support for QEMU, update ronniesahlberg
@ 2011-04-22 4:08 ` Christoph Hellwig
2011-04-22 6:08 ` ronnie sahlberg
0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2011-04-22 4:08 UTC (permalink / raw)
To: ronniesahlberg; +Cc: kwolf, hch, qemu-devel, stefanha
On Fri, Apr 22, 2011 at 06:23:58AM +1000, ronniesahlberg@gmail.com wrote:
> iSCSI block driver for QEMU
>
> Please find an updated iSCSI patch.
> This patch adds setting FUA on all writes when the bit
> BDRV_O_CACHE_WB is not set.
At this point you need to check for BDRV_O_CACHE_WB and BDRV_O_NOCACHE
as they both have writeback cache semantics. I submitted a patch to clean
that up, but it didn't get merged yet.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] iSCSI support for QEMU, update
2011-04-22 4:08 ` Christoph Hellwig
@ 2011-04-22 6:08 ` ronnie sahlberg
2011-04-22 6:13 ` Christoph Hellwig
0 siblings, 1 reply; 8+ messages in thread
From: ronnie sahlberg @ 2011-04-22 6:08 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: kwolf, qemu-devel, stefanha
Thanks,
On Fri, Apr 22, 2011 at 2:08 PM, Christoph Hellwig <hch@lst.de> wrote:
> On Fri, Apr 22, 2011 at 06:23:58AM +1000, ronniesahlberg@gmail.com wrote:
>> iSCSI block driver for QEMU
>>
>> Please find an updated iSCSI patch.
>> This patch adds setting FUA on all writes when the bit
>> BDRV_O_CACHE_WB is not set.
>
> At this point you need to check for BDRV_O_CACHE_WB and BDRV_O_NOCACHE
> as they both have writeback cache semantics. I submitted a patch to clean
> that up, but it didn't get merged yet.
>
So I should set FUA when
BDRV_O_CACHE_WB==0 or BDRV_O_NOCACHE==1
right?
regards
ronnie sahlberg
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] iSCSI support for QEMU, update
2011-04-22 6:08 ` ronnie sahlberg
@ 2011-04-22 6:13 ` Christoph Hellwig
2011-04-22 6:35 ` ronnie sahlberg
0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2011-04-22 6:13 UTC (permalink / raw)
To: ronnie sahlberg; +Cc: kwolf, Christoph Hellwig, stefanha, qemu-devel
On Fri, Apr 22, 2011 at 04:08:57PM +1000, ronnie sahlberg wrote:
> So I should set FUA when
> BDRV_O_CACHE_WB==0 or BDRV_O_NOCACHE==1
> right?
At this point you need to set it if either the BDRV_O_CACHE_WB and
BDRV_O_NOCACHE flags are set. And yes, the naming of the nocache
flag is rather confusing.
Take a look at block.c:bdrv_open_common():
/*
* Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
* write cache to the guest. We do need the fdatasync to flush
* out transactions for block allocations, and we maybe have a
* volatile write cache in our backing device to deal with.
*/
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
bs->enable_write_cache = 1;
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] iSCSI support for QEMU, update
2011-04-22 6:13 ` Christoph Hellwig
@ 2011-04-22 6:35 ` ronnie sahlberg
2011-04-22 6:38 ` Christoph Hellwig
0 siblings, 1 reply; 8+ messages in thread
From: ronnie sahlberg @ 2011-04-22 6:35 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: kwolf, qemu-devel, stefanha
Ok, I am confused
On Fri, Apr 22, 2011 at 4:13 PM, Christoph Hellwig <hch@lst.de> wrote:
> On Fri, Apr 22, 2011 at 04:08:57PM +1000, ronnie sahlberg wrote:
>> So I should set FUA when
>> BDRV_O_CACHE_WB==0 or BDRV_O_NOCACHE==1
>> right?
>
> At this point you need to set it if either the BDRV_O_CACHE_WB and
> BDRV_O_NOCACHE flags are set. And yes, the naming of the nocache
> flag is rather confusing.
>
> Take a look at block.c:bdrv_open_common():
>
> /*
> * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
> * write cache to the guest. We do need the fdatasync to flush
> * out transactions for block allocations, and we maybe have a
> * volatile write cache in our backing device to deal with.
> */
> if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
> bs->enable_write_cache = 1;
>
I have to set FUA if the WB(I guessed this meant write-back) flag is set?
Not the opposite (I assume opposite of write-back is write-through) ?
So that would mean
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
caching is NOT ok, write with FUA=1
else
caching is ok, write with FUA=0
right ?
regards
ronnie sahlberg
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] iSCSI support for QEMU, update
2011-04-22 6:35 ` ronnie sahlberg
@ 2011-04-22 6:38 ` Christoph Hellwig
0 siblings, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2011-04-22 6:38 UTC (permalink / raw)
To: ronnie sahlberg; +Cc: kwolf, Christoph Hellwig, stefanha, qemu-devel
On Fri, Apr 22, 2011 at 04:35:11PM +1000, ronnie sahlberg wrote:
> Ok, I am confused
And this time it's my fault, sorry.
> I have to set FUA if the WB(I guessed this meant write-back) flag is set?
> Not the opposite (I assume opposite of write-back is write-through) ?
Sorry, I meant exactly the opposite. You do not have to set FUA if either
of those two flags is present, so:
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
caching is ok, write with FUA=0
else
caching is NOT ok, write with FUA=1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] iSCSI support for QEMU, update
@ 2011-05-07 6:17 Ronnie Sahlberg
2011-05-07 6:17 ` [Qemu-devel] [PATCH] iSCSI block driver support Ronnie Sahlberg
0 siblings, 1 reply; 8+ messages in thread
From: Ronnie Sahlberg @ 2011-05-07 6:17 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, hch
This is a patch that adds support for iSCSI to QEMU when QEMU is built against libiscsi (https://github.com/sahlberg/libiscsi)
ISCSI devices are specified using a special iSCSI URL:
-drive file=iscsi://10.1.1.1:3260/iqn.ronnie.test/1
This allows a guest to access iscsi devices without exposing these devices to the host. Which is nice if/when you have a very large number of LUNs that are dedicated for virtual guests.
This patch is updated to set FUA for all writes, unless any of the NOCACHE or CACHE_WB flags are set for the device.
Please review and/or apply.
regards
ronnie sahlberg
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH] iSCSI block driver support
2011-05-07 6:17 [Qemu-devel] iSCSI support for QEMU, update Ronnie Sahlberg
@ 2011-05-07 6:17 ` Ronnie Sahlberg
0 siblings, 0 replies; 8+ messages in thread
From: Ronnie Sahlberg @ 2011-05-07 6:17 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, stefanha, Ronnie Sahlberg, hch
This patch adds a new block driver : block.iscsi.c
This driver interfaces with the multiplatform posix library
for iscsi initiator/client access to iscsi devices hosted at
git://github.com/sahlberg/libiscsi.git
The patch adds the driver to interface with the iscsi library.
It also updated the configure script to
* by default, probe is libiscsi is available and if so, build
qemu against libiscsi.
* --enable-libiscsi
Force a build against libiscsi. If libiscsi is not available
the build will fail.
* --disable-libiscsi
Do not link against libiscsi, even if it is available.
When linked with libiscsi, qemu gains support to access iscsi resources
such as disks and cdrom directly, without having to make the devices visible
to the host.
You can specify devices using a iscsi url of the form :
iscsi://[<username>[:<password>@]]<host>[:<port]/<target-iqn-name>/<lun>
When using authentication, the password can optionally be set with
LIBISCSI_CHAP_PASSWORD="password" to avoid it showing up in the process list
Example:
-drive file=iscsi://10.1.1.1:3260/iqn.ronnie.test/1
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
---
Makefile.objs | 1 +
block/iscsi.c | 596 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure | 31 +++
trace-events | 6 +
4 files changed, 634 insertions(+), 0 deletions(-)
create mode 100644 block/iscsi.c
diff --git a/Makefile.objs b/Makefile.objs
index 9d8851e..fd394e0 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -25,6 +25,7 @@ block-nested-y += qed-check.o
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
block-nested-$(CONFIG_POSIX) += raw-posix.o
+block-nested-$(CONFIG_LIBISCSI) += iscsi.o
block-nested-$(CONFIG_CURL) += curl.o
block-nested-$(CONFIG_RBD) += rbd.o
diff --git a/block/iscsi.c b/block/iscsi.c
new file mode 100644
index 0000000..76773db
--- /dev/null
+++ b/block/iscsi.c
@@ -0,0 +1,596 @@
+/*
+ * QEMU Block driver for iSCSI images
+ *
+ * Copyright (c) 2010 Ronnie Sahlberg <ronniesahlberg@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config-host.h"
+
+#include <poll.h>
+#include "sysemu.h"
+#include "qemu-common.h"
+#include "qemu-error.h"
+#include "block_int.h"
+#include "trace.h"
+
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+
+
+typedef struct IscsiLun {
+ struct iscsi_context *iscsi;
+ int lun;
+ int block_size;
+ unsigned long num_blocks;
+} IscsiLun;
+
+typedef struct IscsiAIOCB {
+ BlockDriverAIOCB common;
+ QEMUIOVector *qiov;
+ QEMUBH *bh;
+ IscsiLun *iscsilun;
+ struct scsi_task *task;
+ uint8_t *buf;
+ int canceled;
+ int status;
+ size_t read_size;
+ size_t read_offset;
+} IscsiAIOCB;
+
+struct IscsiTask {
+ IscsiLun *iscsilun;
+ int status;
+ int complete;
+};
+
+static void
+iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
+ void *private_data)
+{
+}
+
+static void
+iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
+ IscsiLun *iscsilun = acb->iscsilun;
+
+ acb->status = -ECANCELED;
+ acb->common.cb(acb->common.opaque, acb->status);
+ acb->canceled = 1;
+
+ iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
+ iscsi_abort_task_cb, NULL);
+}
+
+static AIOPool iscsi_aio_pool = {
+ .aiocb_size = sizeof(IscsiAIOCB),
+ .cancel = iscsi_aio_cancel,
+};
+
+
+static void iscsi_process_read(void *arg);
+static void iscsi_process_write(void *arg);
+
+static int iscsi_process_flush(void *arg)
+{
+ IscsiLun *iscsilun = arg;
+
+ return iscsi_queue_length(iscsilun->iscsi) > 0;
+}
+
+static void
+iscsi_set_events(IscsiLun *iscsilun)
+{
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+
+ qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
+ (iscsi_which_events(iscsi) & POLLOUT)
+ ? iscsi_process_write : NULL,
+ iscsi_process_flush, NULL, iscsilun);
+}
+
+static void
+iscsi_process_read(void *arg)
+{
+ IscsiLun *iscsilun = arg;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+
+ iscsi_service(iscsi, POLLIN);
+ iscsi_set_events(iscsilun);
+}
+
+static void
+iscsi_process_write(void *arg)
+{
+ IscsiLun *iscsilun = arg;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+
+ iscsi_service(iscsi, POLLOUT);
+ iscsi_set_events(iscsilun);
+}
+
+
+static int
+iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
+{
+ acb->bh = qemu_bh_new(cb, acb);
+ if (!acb->bh) {
+ error_report("oom: could not create iscsi bh");
+ return -EIO;
+ }
+
+ qemu_bh_schedule(acb->bh);
+ return 0;
+}
+
+static void
+iscsi_readv_writev_bh_cb(void *p)
+{
+ IscsiAIOCB *acb = p;
+
+ qemu_bh_delete(acb->bh);
+
+ if (acb->status != -ECANCELED) {
+ acb->common.cb(acb->common.opaque, acb->status);
+ }
+
+ qemu_aio_release(acb);
+}
+
+
+static void
+iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
+ void *command_data, void *opaque)
+{
+ IscsiAIOCB *acb = opaque;
+
+ trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
+
+ if (acb->buf != NULL) {
+ free(acb->buf);
+ }
+
+ if (acb->canceled != 0) {
+ qemu_aio_release(acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ return;
+ }
+
+ acb->status = 0;
+ if (status < 0) {
+ error_report("Failed to write10 data to iSCSI lun. %s",
+ iscsi_get_error(iscsi));
+ acb->status = -EIO;
+ }
+
+ iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+}
+
+static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
+{
+ return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+ IscsiAIOCB *acb;
+ size_t size;
+ int fua = 0;
+
+ /* set FUA on writes when cache mode is write through */
+ if (!(bs->open_flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))) {
+ fua = 1;
+ }
+
+ acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+ trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
+ if (!acb) {
+ return NULL;
+ }
+
+ acb->iscsilun = iscsilun;
+ acb->qiov = qiov;
+
+ acb->canceled = 0;
+
+ /* XXX we should pass the iovec to write10 to avoid the extra copy */
+ /* this will allow us to get rid of 'buf' completely */
+ size = nb_sectors * BDRV_SECTOR_SIZE;
+ acb->buf = qemu_malloc(size);
+ qemu_iovec_to_buffer(acb->qiov, acb->buf);
+ acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
+ sector_qemu2lun(sector_num, iscsilun),
+ fua, 0, iscsilun->block_size,
+ iscsi_aio_write10_cb, acb);
+ if (acb->task == NULL) {
+ error_report("iSCSI: Failed to send write10 command. %s",
+ iscsi_get_error(iscsi));
+ qemu_free(acb->buf);
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
+ iscsi_set_events(iscsilun);
+
+ return &acb->common;
+}
+
+static void
+iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
+ void *command_data, void *opaque)
+{
+ IscsiAIOCB *acb = opaque;
+
+ trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
+
+ if (acb->canceled != 0) {
+ qemu_aio_release(acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ return;
+ }
+
+ acb->status = 0;
+ if (status != 0) {
+ error_report("Failed to read10 data from iSCSI lun. %s",
+ iscsi_get_error(iscsi));
+ acb->status = -EIO;
+ }
+
+ iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+ IscsiAIOCB *acb;
+ size_t qemu_read_size, lun_read_size;
+ int i;
+
+ qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
+
+ acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+ trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
+ if (!acb) {
+ return NULL;
+ }
+
+ acb->iscsilun = iscsilun;
+ acb->qiov = qiov;
+
+ acb->canceled = 0;
+ acb->read_size = qemu_read_size;
+ acb->buf = NULL;
+
+ /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
+ * may be misaligned to the LUN, so we may need to read some extra
+ * data.
+ */
+ acb->read_offset = 0;
+ if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
+ uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
+
+ acb->read_offset = bdrv_offset % iscsilun->block_size;
+ }
+
+ lun_read_size = (qemu_read_size + iscsilun->block_size
+ + acb->read_offset - 1)
+ / iscsilun->block_size * iscsilun->block_size;
+ acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
+ sector_qemu2lun(sector_num, iscsilun),
+ lun_read_size, iscsilun->block_size,
+ iscsi_aio_read10_cb, acb);
+ if (acb->task == NULL) {
+ error_report("iSCSI: Failed to send read10 command. %s",
+ iscsi_get_error(iscsi));
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
+ for (i = 0;i < acb->qiov->niov; i++) {
+ scsi_task_add_data_in_buffer(acb->task,
+ acb->qiov->iov[i].iov_len,
+ acb->qiov->iov[i].iov_base);
+ }
+
+ iscsi_set_events(iscsilun);
+
+ return &acb->common;
+}
+
+
+static void
+iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
+ void *command_data, void *opaque)
+{
+ IscsiAIOCB *acb = opaque;
+
+ if (acb->canceled != 0) {
+ qemu_aio_release(acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ return;
+ }
+
+ acb->status = 0;
+ if (status < 0) {
+ error_report("Failed to sync10 data on iSCSI lun. %s",
+ iscsi_get_error(iscsi));
+ acb->status = -EIO;
+ }
+
+ iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+ IscsiAIOCB *acb;
+
+ acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+ if (!acb) {
+ return NULL;
+ }
+
+ acb->iscsilun = iscsilun;
+ acb->canceled = 0;
+
+ acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
+ 0, 0, 0, 0,
+ iscsi_synccache10_cb,
+ acb);
+ if (acb->task == NULL) {
+ error_report("iSCSI: Failed to send synchronizecache10 command. %s",
+ iscsi_get_error(iscsi));
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
+ iscsi_set_events(iscsilun);
+
+ return &acb->common;
+}
+
+static int64_t
+iscsi_getlength(BlockDriverState *bs)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ int64_t len;
+
+ len = iscsilun->num_blocks;
+ len *= iscsilun->block_size;
+
+ return len;
+}
+
+static void
+iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
+ void *command_data, void *opaque)
+{
+ struct IscsiTask *itask = opaque;
+ struct scsi_readcapacity10 *rc10;
+ struct scsi_task *task = command_data;
+
+ if (status != 0) {
+ error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
+ iscsi_get_error(iscsi));
+ itask->status = 1;
+ itask->complete = 1;
+ scsi_free_scsi_task(task);
+ return;
+ }
+
+ rc10 = scsi_datain_unmarshall(task);
+ if (rc10 == NULL) {
+ error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
+ itask->status = 1;
+ itask->complete = 1;
+ scsi_free_scsi_task(task);
+ return;
+ }
+
+ itask->iscsilun->block_size = rc10->block_size;
+ itask->iscsilun->num_blocks = rc10->lba;
+
+ itask->status = 0;
+ itask->complete = 1;
+ scsi_free_scsi_task(task);
+}
+
+
+static void
+iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
+ void *opaque)
+{
+ struct IscsiTask *itask = opaque;
+ struct scsi_task *task;
+
+ if (status != 0) {
+ itask->status = 1;
+ itask->complete = 1;
+ return;
+ }
+
+ task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
+ iscsi_readcapacity10_cb, opaque);
+ if (task == NULL) {
+ error_report("iSCSI: failed to send readcapacity command.");
+ itask->status = 1;
+ itask->complete = 1;
+ return;
+ }
+}
+
+/*
+ * We support iscsi url's on the form
+ * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
+ */
+static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ struct iscsi_context *iscsi = NULL;
+ struct iscsi_url *iscsi_url = NULL;
+ struct IscsiTask task;
+ int ret;
+
+ if ((BDRV_SECTOR_SIZE % 512) != 0) {
+ error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
+ "BDRV_SECTOR_SIZE(%lld) is not a multiple "
+ "of 512", BDRV_SECTOR_SIZE);
+ return -EINVAL;
+ }
+
+ memset(iscsilun, 0, sizeof(IscsiLun));
+
+ /* Should really append the KVM name after the ':' here */
+ iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
+ if (iscsi == NULL) {
+ error_report("iSCSI: Failed to create iSCSI context.");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ iscsi_url = iscsi_parse_full_url(iscsi, filename);
+ if (iscsi_url == NULL) {
+ error_report("Failed to parse URL : %s %s", filename,
+ iscsi_get_error(iscsi));
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
+ error_report("iSCSI: Failed to set target name.");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ if (iscsi_url->user != NULL) {
+ ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
+ iscsi_url->passwd);
+ if (ret != 0) {
+ error_report("Failed to set initiator username and password");
+ ret = -ENOMEM;
+ goto failed;
+ }
+ }
+ if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
+ error_report("iSCSI: Failed to set session type to normal.");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+ task.iscsilun = iscsilun;
+ task.status = 0;
+ task.complete = 0;
+
+ iscsilun->iscsi = iscsi;
+ iscsilun->lun = iscsi_url->lun;
+
+ if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
+ iscsi_connect_cb, &task)
+ != 0) {
+ error_report("iSCSI: Failed to start async connect.");
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ async_context_push();
+ while (!task.complete) {
+ iscsi_set_events(iscsilun);
+ qemu_aio_wait();
+ }
+ async_context_pop();
+ if (task.status != 0) {
+ error_report("iSCSI: Failed to connect to LUN : %s",
+ iscsi_get_error(iscsi));
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ if (iscsi_url != NULL) {
+ iscsi_destroy_url(iscsi_url);
+ }
+ if (iscsi != NULL) {
+ iscsi_destroy_context(iscsi);
+ }
+ memset(iscsilun, 0, sizeof(IscsiLun));
+ return ret;
+}
+
+static void iscsi_close(BlockDriverState *bs)
+{
+ IscsiLun *iscsilun = bs->opaque;
+ struct iscsi_context *iscsi = iscsilun->iscsi;
+
+ qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
+ iscsi_destroy_context(iscsi);
+ memset(iscsilun, 0, sizeof(IscsiLun));
+}
+
+static BlockDriver bdrv_iscsi = {
+ .format_name = "iscsi",
+ .protocol_name = "iscsi",
+
+ .instance_size = sizeof(IscsiLun),
+ .bdrv_file_open = iscsi_open,
+ .bdrv_close = iscsi_close,
+
+ .bdrv_getlength = iscsi_getlength,
+
+ .bdrv_aio_readv = iscsi_aio_readv,
+ .bdrv_aio_writev = iscsi_aio_writev,
+ .bdrv_aio_flush = iscsi_aio_flush,
+};
+
+static void iscsi_block_init(void)
+{
+ bdrv_register(&bdrv_iscsi);
+}
+
+block_init(iscsi_block_init);
+
diff --git a/configure b/configure
index 6f75e2e..e5ff29d 100755
--- a/configure
+++ b/configure
@@ -178,6 +178,7 @@ rbd=""
smartcard=""
smartcard_nss=""
opengl=""
+libiscsi=""
# parse CC options first
for opt do
@@ -632,6 +633,10 @@ for opt do
;;
--enable-spice) spice="yes"
;;
+ --disable-libiscsi) libiscsi="no"
+ ;;
+ --enable-libiscsi) libiscsi="yes"
+ ;;
--enable-profiler) profiler="yes"
;;
--enable-cocoa)
@@ -941,6 +946,8 @@ echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
echo " --enable-spice enable spice"
echo " --enable-rbd enable building the rados block device (rbd)"
+echo " --disable-libiscsi disable iscsi support"
+echo " --enable-libiscsi enable iscsi support"
echo " --disable-smartcard disable smartcard support"
echo " --enable-smartcard enable smartcard support"
echo " --disable-smartcard-nss disable smartcard nss support"
@@ -2290,6 +2297,25 @@ if compile_prog "" "" ; then
fi
##########################################
+# Do we have libiscsi
+if test "$libiscsi" != "no" ; then
+ cat > $TMPC << EOF
+#include <iscsi/iscsi.h>
+int main(void) { iscsi_create_context(""); return 0; }
+EOF
+ if compile_prog "-Werror" "-liscsi" ; then
+ libiscsi="yes"
+ LIBS="$LIBS -liscsi"
+ else
+ if test "$libiscsi" = "yes" ; then
+ feature_not_found "libiscsi"
+ fi
+ libiscsi="no"
+ fi
+fi
+
+
+##########################################
# Do we need librt
cat > $TMPC <<EOF
#include <signal.h>
@@ -2623,6 +2649,7 @@ echo "rbd support $rbd"
echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "OpenGL support $opengl"
+echo "libiscsi support $libiscsi"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2917,6 +2944,10 @@ if test "$opengl" = "yes" ; then
echo "CONFIG_OPENGL=y" >> $config_host_mak
fi
+if test "$libiscsi" = "yes" ; then
+ echo "CONFIG_LIBISCSI=y" >> $config_host_mak
+fi
+
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak
diff --git a/trace-events b/trace-events
index 4f965e2..ad167a8 100644
--- a/trace-events
+++ b/trace-events
@@ -361,3 +361,9 @@ disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
# hw/milkymist-vgafb.c
disable milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
disable milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
+
+# block/iscsi.c
+disable iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+disable iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+disable iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+disable iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
--
1.7.3.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-05-07 6:18 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-07 6:17 [Qemu-devel] iSCSI support for QEMU, update Ronnie Sahlberg
2011-05-07 6:17 ` [Qemu-devel] [PATCH] iSCSI block driver support Ronnie Sahlberg
-- strict thread matches above, loose matches on Subject: below --
2011-04-21 20:23 [Qemu-devel] iSCSI support for QEMU, update ronniesahlberg
2011-04-22 4:08 ` Christoph Hellwig
2011-04-22 6:08 ` ronnie sahlberg
2011-04-22 6:13 ` Christoph Hellwig
2011-04-22 6:35 ` ronnie sahlberg
2011-04-22 6:38 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).