From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:43144) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RJjxD-0008Ny-J5 for qemu-devel@nongnu.org; Fri, 28 Oct 2011 06:46:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RJjx9-0006gX-8l for qemu-devel@nongnu.org; Fri, 28 Oct 2011 06:46:27 -0400 Received: from mail-vx0-f173.google.com ([209.85.220.173]:62845) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RJjx9-0006gT-1l for qemu-devel@nongnu.org; Fri, 28 Oct 2011 06:46:23 -0400 Received: by vcbfl17 with SMTP id fl17so3725076vcb.4 for ; Fri, 28 Oct 2011 03:46:22 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1316597875-30463-2-git-send-email-ronniesahlberg@gmail.com> References: <1316597875-30463-1-git-send-email-ronniesahlberg@gmail.com> <1316597875-30463-2-git-send-email-ronniesahlberg@gmail.com> Date: Fri, 28 Oct 2011 18:46:22 +0800 Message-ID: From: Zhi Yong Wu Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH] This patch adds a new block driver : iSCSI List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Ronnie Sahlberg Cc: kwolf@redhat.com, stefanha@linux.vnet.ibm.com, dlaor@redhat.com, qemu-devel@nongnu.org, fujita.tomonori@lab.ntt.co.jp, owasserm@redhat.com, pbonzini@redhat.com, hch@lst.de On Wed, Sep 21, 2011 at 5:37 PM, Ronnie Sahlberg wrote: > This provides built-in support for iSCSI to QEMU. > This has the advantage that the iSCSI devices need not be made visible to= the host, which is useful if you have very many virtual machines and very = many iscsi devices. > It also has the benefit that non-root users of QEMU can access iSCSI devi= ces across the network without requiring root privilege on the host. > > This driver interfaces with the multiplatform posix library for iscsi ini= tiator/client access to iscsi devices hosted at > =A0 =A0git://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 > =A0qemu against libiscsi. > * --enable-libiscsi > =A0Force a build against libiscsi. If libiscsi is not available > =A0the build will fail. > * --disable-libiscsi > =A0Do not link against libiscsi, even if it is available. > > When linked with libiscsi, qemu gains support to access iscsi resources s= uch 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://[[:@]][:/ > When using authentication, the password can optionally be set with > LIBISCSI_CHAP_PASSWORD=3D"password" to avoid it showing up in the process= list > > Signed-off-by: Ronnie Sahlberg > --- > =A0Makefile.objs | =A0 =A01 + > =A0block/iscsi.c | =A0596 +++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++ > =A0configure =A0 =A0 | =A0 31 +++ > =A0trace-events =A0| =A0 =A07 + > =A04 files changed, 635 insertions(+), 0 deletions(-) > =A0create mode 100644 block/iscsi.c > > diff --git a/Makefile.objs b/Makefile.objs > index a529a11..8c8e420 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -36,6 +36,7 @@ block-nested-y +=3D qed-check.o > =A0block-nested-y +=3D parallels.o nbd.o blkdebug.o sheepdog.o blkverify.= o > =A0block-nested-$(CONFIG_WIN32) +=3D raw-win32.o > =A0block-nested-$(CONFIG_POSIX) +=3D raw-posix.o > +block-nested-$(CONFIG_LIBISCSI) +=3D iscsi.o > =A0block-nested-$(CONFIG_CURL) +=3D curl.o > =A0block-nested-$(CONFIG_RBD) +=3D rbd.o > > diff --git a/block/iscsi.c b/block/iscsi.c > new file mode 100644 > index 0000000..6517576 > --- /dev/null > +++ b/block/iscsi.c > @@ -0,0 +1,596 @@ > +/* > + * QEMU Block driver for iSCSI images > + * > + * Copyright (c) 2010-2011 Ronnie Sahlberg > + * > + * 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 includ= ed in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI= TY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR = OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI= NG FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING= S IN > + * THE SOFTWARE. > + */ > + > +#include "config-host.h" > + > +#include > +#include "sysemu.h" > +#include "qemu-common.h" > +#include "qemu-error.h" > +#include "block_int.h" > +#include "trace.h" > + > +#include > +#include > + > + > +typedef struct IscsiLun { > + =A0 =A0struct iscsi_context *iscsi; > + =A0 =A0int lun; > + =A0 =A0int block_size; > + =A0 =A0unsigned long num_blocks; > +} IscsiLun; > + > +typedef struct IscsiAIOCB { > + =A0 =A0BlockDriverAIOCB common; > + =A0 =A0QEMUIOVector *qiov; > + =A0 =A0QEMUBH *bh; > + =A0 =A0IscsiLun *iscsilun; > + =A0 =A0struct scsi_task *task; > + =A0 =A0uint8_t *buf; > + =A0 =A0int canceled; > + =A0 =A0int status; > + =A0 =A0size_t read_size; > + =A0 =A0size_t read_offset; > +} IscsiAIOCB; > + > +struct IscsiTask { > + =A0 =A0IscsiLun *iscsilun; > + =A0 =A0int status; > + =A0 =A0int complete; > +}; > + > +static void > +iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *comma= nd_data, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *private_data) > +{ > +} > + > +static void > +iscsi_aio_cancel(BlockDriverAIOCB *blockacb) > +{ > + =A0 =A0IscsiAIOCB *acb =3D (IscsiAIOCB *)blockacb; > + =A0 =A0IscsiLun *iscsilun =3D acb->iscsilun; > + > + =A0 =A0acb->status =3D -ECANCELED; > + =A0 =A0acb->common.cb(acb->common.opaque, acb->status); > + =A0 =A0acb->canceled =3D 1; > + > + =A0 =A0/* send a task mgmt call to the target to cancel the task on the= target */ > + =A0 =A0iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= iscsi_abort_task_cb, NULL); > + > + =A0 =A0/* then also cancel the task locally in libiscsi */ > + =A0 =A0iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task); > +} > + > +static AIOPool iscsi_aio_pool =3D { > + =A0 =A0.aiocb_size =A0 =A0 =A0 =A0 =3D sizeof(IscsiAIOCB), > + =A0 =A0.cancel =A0 =A0 =A0 =A0 =A0 =A0 =3D iscsi_aio_cancel, > +}; > + > + > +static void iscsi_process_read(void *arg); > +static void iscsi_process_write(void *arg); > + > +static int iscsi_process_flush(void *arg) > +{ > + =A0 =A0IscsiLun *iscsilun =3D arg; > + > + =A0 =A0return iscsi_queue_length(iscsilun->iscsi) > 0; > +} > + > +static void > +iscsi_set_events(IscsiLun *iscsilun) > +{ > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =A0 =A0qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (iscsi_which_events= (iscsi) & POLLOUT) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ? iscsi_process_wri= te : NULL, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_process_flush= , NULL, iscsilun); > +} > + > +static void > +iscsi_process_read(void *arg) > +{ > + =A0 =A0IscsiLun *iscsilun =3D arg; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =A0 =A0iscsi_service(iscsi, POLLIN); > + =A0 =A0iscsi_set_events(iscsilun); > +} > + > +static void > +iscsi_process_write(void *arg) > +{ > + =A0 =A0IscsiLun *iscsilun =3D arg; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =A0 =A0iscsi_service(iscsi, POLLOUT); > + =A0 =A0iscsi_set_events(iscsilun); > +} > + > + > +static int > +iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb) > +{ > + =A0 =A0acb->bh =3D qemu_bh_new(cb, acb); > + =A0 =A0if (!acb->bh) { > + =A0 =A0 =A0 =A0error_report("oom: could not create iscsi bh"); > + =A0 =A0 =A0 =A0return -EIO; > + =A0 =A0} > + > + =A0 =A0qemu_bh_schedule(acb->bh); > + =A0 =A0return 0; > +} > + > +static void > +iscsi_readv_writev_bh_cb(void *p) > +{ > + =A0 =A0IscsiAIOCB *acb =3D p; > + > + =A0 =A0qemu_bh_delete(acb->bh); > + > + =A0 =A0if (acb->status !=3D -ECANCELED) { > + =A0 =A0 =A0 =A0acb->common.cb(acb->common.opaque, acb->status); > + =A0 =A0} > + > + =A0 =A0qemu_aio_release(acb); > +} > + > + > +static void > +iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *command_data, void *opaqu= e) > +{ > + =A0 =A0IscsiAIOCB *acb =3D opaque; > + > + =A0 =A0trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled); > + > + =A0 =A0g_free(acb->buf); > + > + =A0 =A0if (acb->canceled !=3D 0) { > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0 =A0 =A0acb->task =3D NULL; > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0acb->status =3D 0; > + =A0 =A0if (status < 0) { > + =A0 =A0 =A0 =A0error_report("Failed to write10 data to iSCSI lun. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0acb->status =3D -EIO; > + =A0 =A0} > + > + =A0 =A0iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); > + =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0acb->task =3D NULL; > +} > + > +static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun) > +{ > + =A0 =A0return sector * BDRV_SECTOR_SIZE / iscsilun->block_size; > +} > + > +static BlockDriverAIOCB * > +iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 QEMUIOVector *qiov, int nb_sectors, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 BlockDriverCompletionFunc *cb, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *opaque) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =A0 =A0IscsiAIOCB *acb; > + =A0 =A0size_t size; > + =A0 =A0int fua =3D 0; > + > + =A0 =A0/* set FUA on writes when cache mode is write through */ > + =A0 =A0if (!(bs->open_flags & BDRV_O_CACHE_WB)) { > + =A0 =A0 =A0 =A0fua =3D 1; > + =A0 =A0} > + > + =A0 =A0acb =3D qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); > + =A0 =A0trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, ac= b); > + =A0 =A0if (!acb) { > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0acb->iscsilun =3D iscsilun; > + =A0 =A0acb->qiov =A0 =A0 =3D qiov; > + > + =A0 =A0acb->canceled =A0 =3D 0; > + > + =A0 =A0/* XXX we should pass the iovec to write10 to avoid the extra co= py */ > + =A0 =A0/* this will allow us to get rid of 'buf' completely */ > + =A0 =A0size =3D nb_sectors * BDRV_SECTOR_SIZE; > + =A0 =A0acb->buf =3D g_malloc(size); > + =A0 =A0qemu_iovec_to_buffer(acb->qiov, acb->buf); > + =A0 =A0acb->task =3D iscsi_write10_task(iscsi, iscsilun->lun, acb->buf,= size, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sector_qemu2= lun(sector_num, iscsilun), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fua, 0, iscs= ilun->block_size, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0iscsi_aio_wr= ite10_cb, acb); > + =A0 =A0if (acb->task =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to send write10 command. %s"= , > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0g_free(acb->buf); > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0iscsi_set_events(iscsilun); > + > + =A0 =A0return &acb->common; > +} > + > +static void > +iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *command_data, void *opaque= ) > +{ > + =A0 =A0IscsiAIOCB *acb =3D opaque; > + > + =A0 =A0trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled); > + > + =A0 =A0if (acb->canceled !=3D 0) { > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0 =A0 =A0acb->task =3D NULL; > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0acb->status =3D 0; > + =A0 =A0if (status !=3D 0) { > + =A0 =A0 =A0 =A0error_report("Failed to read10 data from iSCSI lun. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0acb->status =3D -EIO; > + =A0 =A0} > + > + =A0 =A0iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); > + =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0acb->task =3D NULL; > +} > + > +static BlockDriverAIOCB * > +iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0QEMUIOVector *qiov, int nb_sectors, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0BlockDriverCompletionFunc *cb, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *opaque) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =A0 =A0IscsiAIOCB *acb; > + =A0 =A0size_t qemu_read_size, lun_read_size; > + =A0 =A0int i; > + > + =A0 =A0qemu_read_size =3D BDRV_SECTOR_SIZE * (size_t)nb_sectors; > + > + =A0 =A0acb =3D qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); > + =A0 =A0trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb= ); > + =A0 =A0if (!acb) { > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0acb->iscsilun =3D iscsilun; > + =A0 =A0acb->qiov =A0 =A0 =3D qiov; > + > + =A0 =A0acb->canceled =A0 =A0=3D 0; > + =A0 =A0acb->read_size =A0 =3D qemu_read_size; > + =A0 =A0acb->buf =A0 =A0 =A0 =A0 =3D NULL; > + > + =A0 =A0/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from Q= EMU > + =A0 =A0 * may be misaligned to the LUN, so we may need to read some ext= ra > + =A0 =A0 * data. > + =A0 =A0 */ > + =A0 =A0acb->read_offset =3D 0; > + =A0 =A0if (iscsilun->block_size > BDRV_SECTOR_SIZE) { > + =A0 =A0 =A0 =A0uint64_t bdrv_offset =3D BDRV_SECTOR_SIZE * sector_num; > + > + =A0 =A0 =A0 =A0acb->read_offset =A0=3D bdrv_offset % iscsilun->block_si= ze; > + =A0 =A0} > + > + =A0 =A0lun_read_size =A0=3D (qemu_read_size + iscsilun->block_size > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 + acb->read_offset - 1) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 / iscsilun->block_size * iscsil= un->block_size; > + =A0 =A0acb->task =3D iscsi_read10_task(iscsi, iscsilun->lun, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sector_qemu2lun= (sector_num, iscsilun), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 lun_read_size, = iscsilun->block_size, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_aio_read1= 0_cb, acb); > + =A0 =A0if (acb->task =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to send read10 command. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0for (i =3D 0; i < acb->qiov->niov; i++) { > + =A0 =A0 =A0 =A0scsi_task_add_data_in_buffer(acb->task, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0acb->qiov->iov[i].iov_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0acb->qiov->iov[i].iov_base); > + =A0 =A0} > + > + =A0 =A0iscsi_set_events(iscsilun); > + > + =A0 =A0return &acb->common; > +} > + > + > +static void > +iscsi_synccache10_cb(struct iscsi_context *iscsi, int status, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *command_data, void *opaqu= e) > +{ > + =A0 =A0IscsiAIOCB *acb =3D opaque; > + > + =A0 =A0if (acb->canceled !=3D 0) { > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0 =A0 =A0acb->task =3D NULL; > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0acb->status =3D 0; > + =A0 =A0if (status < 0) { > + =A0 =A0 =A0 =A0error_report("Failed to sync10 data on iSCSI lun. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0acb->status =3D -EIO; > + =A0 =A0} > + > + =A0 =A0iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); > + =A0 =A0scsi_free_scsi_task(acb->task); > + =A0 =A0acb->task =3D NULL; > +} > + > +static BlockDriverAIOCB * > +iscsi_aio_flush(BlockDriverState *bs, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0BlockDriverCompletionFunc *cb, void *opa= que) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =A0 =A0IscsiAIOCB *acb; > + > + =A0 =A0acb =3D qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); > + =A0 =A0if (!acb) { > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0acb->iscsilun =3D iscsilun; > + =A0 =A0acb->canceled =A0 =3D 0; > + > + =A0 =A0acb->task =3D iscsi_synchronizecache10_task(iscsi, iscsilun->lun= , > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 0, 0, 0, 0, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 iscsi_synccache10_cb, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 acb); > + =A0 =A0if (acb->task =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to send synchronizecache10 c= ommand. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0qemu_aio_release(acb); > + =A0 =A0 =A0 =A0return NULL; > + =A0 =A0} > + > + =A0 =A0iscsi_set_events(iscsilun); > + > + =A0 =A0return &acb->common; > +} > + > +static int64_t > +iscsi_getlength(BlockDriverState *bs) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0int64_t len; > + > + =A0 =A0len =A0=3D iscsilun->num_blocks; > + =A0 =A0len *=3D iscsilun->block_size; > + > + =A0 =A0return len; > +} > + > +static void > +iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *command_data, void= *opaque) > +{ > + =A0 =A0struct IscsiTask *itask =3D opaque; > + =A0 =A0struct scsi_readcapacity10 *rc10; > + =A0 =A0struct scsi_task *task =3D command_data; > + > + =A0 =A0if (status !=3D 0) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to read capacity of iSCSI lu= n. %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0itask->status =A0 =3D 1; > + =A0 =A0 =A0 =A0itask->complete =3D 1; > + =A0 =A0 =A0 =A0scsi_free_scsi_task(task); > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0rc10 =3D scsi_datain_unmarshall(task); > + =A0 =A0if (rc10 =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to unmarshall readcapacity10= data."); > + =A0 =A0 =A0 =A0itask->status =A0 =3D 1; > + =A0 =A0 =A0 =A0itask->complete =3D 1; > + =A0 =A0 =A0 =A0scsi_free_scsi_task(task); > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0itask->iscsilun->block_size =3D rc10->block_size; > + =A0 =A0itask->iscsilun->num_blocks =3D rc10->lba; > + > + =A0 =A0itask->status =A0 =3D 0; > + =A0 =A0itask->complete =3D 1; > + =A0 =A0scsi_free_scsi_task(task); > +} > + > + > +static void > +iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_= data, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *opaque) > +{ > + =A0 =A0struct IscsiTask *itask =3D opaque; > + =A0 =A0struct scsi_task *task; > + > + =A0 =A0if (status !=3D 0) { > + =A0 =A0 =A0 =A0itask->status =A0 =3D 1; > + =A0 =A0 =A0 =A0itask->complete =3D 1; > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > + > + =A0 =A0task =3D iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, = 0, 0, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 isc= si_readcapacity10_cb, opaque); > + =A0 =A0if (task =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: failed to send readcapacity command= ."); > + =A0 =A0 =A0 =A0itask->status =A0 =3D 1; > + =A0 =A0 =A0 =A0itask->complete =3D 1; > + =A0 =A0 =A0 =A0return; > + =A0 =A0} > +} > + > +/* > + * We support iscsi url's on the form > + * iscsi://[%@][:]// > + */ > +static int iscsi_open(BlockDriverState *bs, const char *filename, int fl= ags) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0struct iscsi_context *iscsi =3D NULL; > + =A0 =A0struct iscsi_url *iscsi_url =3D NULL; > + =A0 =A0struct IscsiTask task; > + =A0 =A0int ret; > + > + =A0 =A0if ((BDRV_SECTOR_SIZE % 512) !=3D 0) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "BDRV_SECTOR_SIZE(%lld) is not = a multiple " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "of 512", BDRV_SECTOR_SIZE); > + =A0 =A0 =A0 =A0return -EINVAL; > + =A0 =A0} > + > + =A0 =A0memset(iscsilun, 0, sizeof(IscsiLun)); > + > + =A0 =A0/* Should really append the KVM name after the ':' here */ > + =A0 =A0iscsi =3D iscsi_create_context("iqn.2008-11.org.linux-kvm:"); > + =A0 =A0if (iscsi =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to create iSCSI context."); > + =A0 =A0 =A0 =A0ret =3D -ENOMEM; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0iscsi_url =3D iscsi_parse_full_url(iscsi, filename); > + =A0 =A0if (iscsi_url =3D=3D NULL) { > + =A0 =A0 =A0 =A0error_report("Failed to parse URL : %s %s", filename, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0if (iscsi_set_targetname(iscsi, iscsi_url->target)) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to set target name."); > + =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0if (iscsi_url->user !=3D NULL) { > + =A0 =A0 =A0 =A0ret =3D iscsi_set_initiator_username_pwd(iscsi, iscsi_ur= l->user, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0iscsi_url->passwd); > + =A0 =A0 =A0 =A0if (ret !=3D 0) { > + =A0 =A0 =A0 =A0 =A0 =A0error_report("Failed to set initiator username a= nd password"); > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0 =A0 =A0goto failed; > + =A0 =A0 =A0 =A0} > + =A0 =A0} > + =A0 =A0if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) !=3D 0) = { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to set session type to norma= l."); > + =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); > + > + =A0 =A0task.iscsilun =3D iscsilun; > + =A0 =A0task.status =3D 0; > + =A0 =A0task.complete =3D 0; > + > + =A0 =A0iscsilun->iscsi =3D iscsi; > + =A0 =A0iscsilun->lun =A0 =3D iscsi_url->lun; > + > + =A0 =A0if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url= ->lun, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_c= onnect_cb, &task) > + =A0 =A0 =A0 =A0!=3D 0) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to start async connect."); > + =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0while (!task.complete) { > + =A0 =A0 =A0 =A0iscsi_set_events(iscsilun); > + =A0 =A0 =A0 =A0qemu_aio_wait(); > + =A0 =A0} Why need this use "while" ? I thought that iscsi_set_events only need to be called once, right? > + =A0 =A0if (task.status !=3D 0) { > + =A0 =A0 =A0 =A0error_report("iSCSI: Failed to connect to LUN : %s", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iscsi_get_error(iscsi)); > + =A0 =A0 =A0 =A0ret =3D -EINVAL; > + =A0 =A0 =A0 =A0goto failed; > + =A0 =A0} > + > + =A0 =A0return 0; > + > +failed: > + =A0 =A0if (iscsi_url !=3D NULL) { > + =A0 =A0 =A0 =A0iscsi_destroy_url(iscsi_url); > + =A0 =A0} > + =A0 =A0if (iscsi !=3D NULL) { > + =A0 =A0 =A0 =A0iscsi_destroy_context(iscsi); > + =A0 =A0} > + =A0 =A0memset(iscsilun, 0, sizeof(IscsiLun)); > + =A0 =A0return ret; > +} > + > +static void iscsi_close(BlockDriverState *bs) > +{ > + =A0 =A0IscsiLun *iscsilun =3D bs->opaque; > + =A0 =A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =A0 =A0qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, N= ULL, NULL); > + =A0 =A0iscsi_destroy_context(iscsi); > + =A0 =A0memset(iscsilun, 0, sizeof(IscsiLun)); > +} > + > +static BlockDriver bdrv_iscsi =3D { > + =A0 =A0.format_name =A0 =A0 =3D "iscsi", > + =A0 =A0.protocol_name =A0 =3D "iscsi", > + > + =A0 =A0.instance_size =A0 =3D sizeof(IscsiLun), > + =A0 =A0.bdrv_file_open =A0=3D iscsi_open, > + =A0 =A0.bdrv_close =A0 =A0 =A0=3D iscsi_close, > + > + =A0 =A0.bdrv_getlength =A0=3D iscsi_getlength, > + > + =A0 =A0.bdrv_aio_readv =A0=3D iscsi_aio_readv, > + =A0 =A0.bdrv_aio_writev =3D iscsi_aio_writev, > + =A0 =A0.bdrv_aio_flush =A0=3D iscsi_aio_flush, > +}; > + > +static void iscsi_block_init(void) > +{ > + =A0 =A0bdrv_register(&bdrv_iscsi); > +} > + > +block_init(iscsi_block_init); > + > diff --git a/configure b/configure > index 348f36a..a2c30e1 100755 > --- a/configure > +++ b/configure > @@ -182,6 +182,7 @@ usb_redir=3D"" > =A0opengl=3D"" > =A0zlib=3D"yes" > =A0guest_agent=3D"yes" > +libiscsi=3D"" > > =A0# parse CC options first > =A0for opt do > @@ -651,6 +652,10 @@ for opt do > =A0 ;; > =A0 --enable-spice) spice=3D"yes" > =A0 ;; > + =A0--disable-libiscsi) libiscsi=3D"no" > + =A0;; > + =A0--enable-libiscsi) libiscsi=3D"yes" > + =A0;; > =A0 --enable-profiler) profiler=3D"yes" > =A0 ;; > =A0 --enable-cocoa) > @@ -1037,6 +1042,8 @@ echo " =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 Default:trace-" > =A0echo " =A0--disable-spice =A0 =A0 =A0 =A0 =A0disable spice" > =A0echo " =A0--enable-spice =A0 =A0 =A0 =A0 =A0 enable spice" > =A0echo " =A0--enable-rbd =A0 =A0 =A0 =A0 =A0 =A0 enable building the rad= os block device (rbd)" > +echo " =A0--disable-libiscsi =A0 =A0 =A0 disable iscsi support" > +echo " =A0--enable-libiscsi =A0 =A0 =A0 =A0enable iscsi support" > =A0echo " =A0--disable-smartcard =A0 =A0 =A0disable smartcard support" > =A0echo " =A0--enable-smartcard =A0 =A0 =A0 enable smartcard support" > =A0echo " =A0--disable-smartcard-nss =A0disable smartcard nss support" > @@ -2326,6 +2333,25 @@ if compile_prog "" "" ; then > =A0fi > > =A0########################################## > +# Do we have libiscsi > +if test "$libiscsi" !=3D "no" ; then > + =A0cat > $TMPC << EOF > +#include > +int main(void) { iscsi_create_context(""); return 0; } > +EOF > + =A0if compile_prog "-Werror" "-liscsi" ; then > + =A0 =A0libiscsi=3D"yes" > + =A0 =A0LIBS=3D"$LIBS -liscsi" > + =A0else > + =A0 =A0if test "$libiscsi" =3D "yes" ; then > + =A0 =A0 =A0feature_not_found "libiscsi" > + =A0 =A0fi > + =A0 =A0libiscsi=3D"no" > + =A0fi > +fi > + > + > +########################################## > =A0# Do we need librt > =A0cat > $TMPC < =A0#include > @@ -2727,6 +2753,7 @@ echo "xfsctl support =A0 =A0$xfs" > =A0echo "nss used =A0 =A0 =A0 =A0 =A0$smartcard_nss" > =A0echo "usb net redir =A0 =A0 $usb_redir" > =A0echo "OpenGL support =A0 =A0$opengl" > +echo "libiscsi support =A0$libiscsi" > =A0echo "build guest agent $guest_agent" > > =A0if test "$sdl_too_old" =3D "yes"; then > @@ -3028,6 +3055,10 @@ if test "$opengl" =3D "yes" ; then > =A0 echo "CONFIG_OPENGL=3Dy" >> $config_host_mak > =A0fi > > +if test "$libiscsi" =3D "yes" ; then > + =A0echo "CONFIG_LIBISCSI=3Dy" >> $config_host_mak > +fi > + > =A0# XXX: suppress that > =A0if [ "$bsd" =3D "yes" ] ; then > =A0 echo "CONFIG_BSD=3Dy" >> $config_host_mak > diff --git a/trace-events b/trace-events > index 3fdd60f..ce68516 100644 > --- a/trace-events > +++ b/trace-events > @@ -494,3 +494,10 @@ escc_sunkbd_event_in(int ch) "Untranslated keycode %= 2.2x" > =A0escc_sunkbd_event_out(int ch) "Translated keycode %2.2x" > =A0escc_kbd_command(int val) "Command %d" > =A0escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=3D%d dy=3D%= d buttons=3D%01x" > + > +# block/iscsi.c > +iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "= iscsi %p status %d acb %p canceled %d" > +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 a= cb %p" > +iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "i= scsi %p status %d acb %p canceled %d" > +iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *o= paque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p ac= b %p" > + > -- > 1.7.3.1 > > > --=20 Regards, Zhi Yong Wu