[Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Peter Lieven

this patch adds iscsi_truncate which effectively allows for online
resizing of iscsi volumes. for this to work you have to resize
the volume on your storage and then call block_resize command
in qemu which will issue a readcapacity16 to update the capacity.

Signed-off-by: Peter Lieven p...@kamp.de
---
 block/iscsi.c |   74 +
 1 file changed, 74 insertions(+)

diff --git a/block/iscsi.c b/block/iscsi.c
index deb3b68..37f12b3 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -67,6 +67,12 @@ typedef struct IscsiAIOCB {
 #endif
 } IscsiAIOCB;

+struct IscsiTask {
+IscsiLun *iscsilun;
+int status;
+int complete;
+};
+
 #define NOP_INTERVAL 5000
 #define MAX_NOP_FAILURES 3

@@ -700,6 +706,73 @@ iscsi_getlength(BlockDriverState *bs)
 return len;
 }

+static void
+iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
+void *command_data, void *opaque)
+{
+struct IscsiTask *itask = opaque;
+struct scsi_readcapacity16 *rc16;
+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;
+}
+
+rc16 = scsi_datain_unmarshall(task);
+if (rc16 == NULL) {
+error_report(iSCSI: Failed to unmarshall readcapacity16 data.);
+itask-status   = 1;
+itask-complete = 1;
+scsi_free_scsi_task(task);
+return;
+}
+
+itask-iscsilun-block_size = rc16-block_length;
+itask-iscsilun-num_blocks = rc16-returned_lba + 1;
+
+itask-status   = 0;
+itask-complete = 1;
+scsi_free_scsi_task(task);
+}
+
+static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+{
+IscsiLun *iscsilun = bs-opaque;
+struct IscsiTask itask;
+struct scsi_task *task = NULL;
+
+if (iscsilun-type != TYPE_DISK) {
+return -ENOTSUP;
+}
+
+itask.iscsilun = iscsilun;
+itask.status = 0;
+itask.complete = 0;
+
+task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
+ iscsi_readcapacity16_cb, itask);
+if (task == NULL) {
+ error_report(iSCSI: failed to send readcapacity16 command.);
+ return -EINVAL;
+}
+
+while (!itask.complete) {
+iscsi_set_events(iscsilun);
+qemu_aio_wait();
+}
+
+if (offset  iscsi_getlength(bs)) {
+return -EINVAL;
+}
+
+return 0;
+}
+
 static int parse_chap(struct iscsi_context *iscsi, const char *target)
 {
 QemuOptsList *list;
@@ -1093,6 +1166,7 @@ static BlockDriver bdrv_iscsi = {
 .create_options  = iscsi_create_options,

 .bdrv_getlength  = iscsi_getlength,
+.bdrv_truncate   = iscsi_truncate,

 .bdrv_aio_readv  = iscsi_aio_readv,
 .bdrv_aio_writev = iscsi_aio_writev,
--
1.7.9.5




Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Paolo Bonzini
Il 15/02/2013 11:58, Peter Lieven ha scritto:
 this patch adds iscsi_truncate which effectively allows for online
 resizing of iscsi volumes. for this to work you have to resize
 the volume on your storage and then call block_resize command
 in qemu which will issue a readcapacity16 to update the capacity.
 
 Signed-off-by: Peter Lieven p...@kamp.de
 ---
  block/iscsi.c |   74
 +
  1 file changed, 74 insertions(+)
 
 diff --git a/block/iscsi.c b/block/iscsi.c
 index deb3b68..37f12b3 100644
 --- a/block/iscsi.c
 +++ b/block/iscsi.c
 @@ -67,6 +67,12 @@ typedef struct IscsiAIOCB {
  #endif
  } IscsiAIOCB;
 
 +struct IscsiTask {
 +IscsiLun *iscsilun;
 +int status;
 +int complete;
 +};
 +
  #define NOP_INTERVAL 5000
  #define MAX_NOP_FAILURES 3
 
 @@ -700,6 +706,73 @@ iscsi_getlength(BlockDriverState *bs)
  return len;
  }
 
 +static void
 +iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
 +void *command_data, void *opaque)
 +{
 +struct IscsiTask *itask = opaque;
 +struct scsi_readcapacity16 *rc16;
 +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;
 +}
 +
 +rc16 = scsi_datain_unmarshall(task);
 +if (rc16 == NULL) {
 +error_report(iSCSI: Failed to unmarshall readcapacity16 data.);
 +itask-status   = 1;
 +itask-complete = 1;
 +scsi_free_scsi_task(task);
 +return;
 +}
 +
 +itask-iscsilun-block_size = rc16-block_length;
 +itask-iscsilun-num_blocks = rc16-returned_lba + 1;
 +
 +itask-status   = 0;
 +itask-complete = 1;
 +scsi_free_scsi_task(task);
 +}
 +
 +static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
 +{
 +IscsiLun *iscsilun = bs-opaque;
 +struct IscsiTask itask;
 +struct scsi_task *task = NULL;
 +
 +if (iscsilun-type != TYPE_DISK) {
 +return -ENOTSUP;
 +}
 +
 +itask.iscsilun = iscsilun;
 +itask.status = 0;
 +itask.complete = 0;
 +
 +task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
 + iscsi_readcapacity16_cb, itask);

You can use iscsi_readcapacity16_sync.  In fact, you probably should
extract code from iscsi_open and reuse it here.

Paolo

 +if (task == NULL) {
 + error_report(iSCSI: failed to send readcapacity16 command.);
 + return -EINVAL;
 +}
 +
 +while (!itask.complete) {
 +iscsi_set_events(iscsilun);
 +qemu_aio_wait();
 +}
 +
 +if (offset  iscsi_getlength(bs)) {
 +return -EINVAL;
 +}
 +
 +return 0;
 +}
 +
  static int parse_chap(struct iscsi_context *iscsi, const char *target)
  {
  QemuOptsList *list;
 @@ -1093,6 +1166,7 @@ static BlockDriver bdrv_iscsi = {
  .create_options  = iscsi_create_options,
 
  .bdrv_getlength  = iscsi_getlength,
 +.bdrv_truncate   = iscsi_truncate,
 
  .bdrv_aio_readv  = iscsi_aio_readv,
  .bdrv_aio_writev = iscsi_aio_writev,




Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Peter Lieven

On 15.02.2013 12:09, Paolo Bonzini wrote:

Il 15/02/2013 11:58, Peter Lieven ha scritto:

this patch adds iscsi_truncate which effectively allows for online
resizing of iscsi volumes. for this to work you have to resize
the volume on your storage and then call block_resize command
in qemu which will issue a readcapacity16 to update the capacity.

Signed-off-by: Peter Lieven p...@kamp.de
---
  block/iscsi.c |   74
+
  1 file changed, 74 insertions(+)

diff --git a/block/iscsi.c b/block/iscsi.c
index deb3b68..37f12b3 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -67,6 +67,12 @@ typedef struct IscsiAIOCB {
  #endif
  } IscsiAIOCB;

+struct IscsiTask {
+IscsiLun *iscsilun;
+int status;
+int complete;
+};
+
  #define NOP_INTERVAL 5000
  #define MAX_NOP_FAILURES 3

@@ -700,6 +706,73 @@ iscsi_getlength(BlockDriverState *bs)
  return len;
  }

+static void
+iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
+void *command_data, void *opaque)
+{
+struct IscsiTask *itask = opaque;
+struct scsi_readcapacity16 *rc16;
+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;
+}
+
+rc16 = scsi_datain_unmarshall(task);
+if (rc16 == NULL) {
+error_report(iSCSI: Failed to unmarshall readcapacity16 data.);
+itask-status   = 1;
+itask-complete = 1;
+scsi_free_scsi_task(task);
+return;
+}
+
+itask-iscsilun-block_size = rc16-block_length;
+itask-iscsilun-num_blocks = rc16-returned_lba + 1;
+
+itask-status   = 0;
+itask-complete = 1;
+scsi_free_scsi_task(task);
+}
+
+static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+{
+IscsiLun *iscsilun = bs-opaque;
+struct IscsiTask itask;
+struct scsi_task *task = NULL;
+
+if (iscsilun-type != TYPE_DISK) {
+return -ENOTSUP;
+}
+
+itask.iscsilun = iscsilun;
+itask.status = 0;
+itask.complete = 0;
+
+task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
+ iscsi_readcapacity16_cb, itask);


You can use iscsi_readcapacity16_sync.  In fact, you probably should
extract code from iscsi_open and reuse it here.


Thats not possible afaik. Mixing sync and async commands in libiscsi is
a very bad thing. It will leed to nested event loops.

Peter




Paolo


+if (task == NULL) {
+ error_report(iSCSI: failed to send readcapacity16 command.);
+ return -EINVAL;
+}
+
+while (!itask.complete) {
+iscsi_set_events(iscsilun);
+qemu_aio_wait();
+}
+
+if (offset  iscsi_getlength(bs)) {
+return -EINVAL;
+}
+
+return 0;
+}
+
  static int parse_chap(struct iscsi_context *iscsi, const char *target)
  {
  QemuOptsList *list;
@@ -1093,6 +1166,7 @@ static BlockDriver bdrv_iscsi = {
  .create_options  = iscsi_create_options,

  .bdrv_getlength  = iscsi_getlength,
+.bdrv_truncate   = iscsi_truncate,

  .bdrv_aio_readv  = iscsi_aio_readv,
  .bdrv_aio_writev = iscsi_aio_writev,







Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Paolo Bonzini
Il 15/02/2013 12:18, Peter Lieven ha scritto:

 +task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
 + iscsi_readcapacity16_cb, itask);

 You can use iscsi_readcapacity16_sync.  In fact, you probably should
 extract code from iscsi_open and reuse it here.
 
 Thats not possible afaik. Mixing sync and async commands in libiscsi is
 a very bad thing. It will leed to nested event loops.

Ah, I thought qmp_block_resize did a bdrv_drain_all before calling
bdrv_truncate.

Maybe it should.  Kevin, what do you think?

Paolo



Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Peter Lieven

Am 15.02.2013 um 12:54 schrieb Paolo Bonzini pbonz...@redhat.com:

 Il 15/02/2013 12:18, Peter Lieven ha scritto:
 
 +task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
 + iscsi_readcapacity16_cb, itask);
 
 You can use iscsi_readcapacity16_sync.  In fact, you probably should
 extract code from iscsi_open and reuse it here.
 
 Thats not possible afaik. Mixing sync and async commands in libiscsi is
 a very bad thing. It will leed to nested event loops.
 
 Ah, I thought qmp_block_resize did a bdrv_drain_all before calling
 bdrv_truncate.

Ah ok. In this special case it might be ok. We should ask Ronnie.
What must not happen is that the sync task loop calls the async callbacks.

Peter

 
 Maybe it should.  Kevin, what do you think?
 
 Paolo




Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Kevin Wolf
On Fri, Feb 15, 2013 at 12:54:51PM +0100, Paolo Bonzini wrote:
 Il 15/02/2013 12:18, Peter Lieven ha scritto:
 
  +task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
  + iscsi_readcapacity16_cb, itask);
 
  You can use iscsi_readcapacity16_sync.  In fact, you probably should
  extract code from iscsi_open and reuse it here.
  
  Thats not possible afaik. Mixing sync and async commands in libiscsi is
  a very bad thing. It will leed to nested event loops.
 
 Ah, I thought qmp_block_resize did a bdrv_drain_all before calling
 bdrv_truncate.
 
 Maybe it should.  Kevin, what do you think?

Probably. bdrv_truncate() invalidates the bdrv_check_request() result for
in-flight requests, so there better be none.

Kevin



Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Peter Lieven

Am 15.02.2013 um 13:18 schrieb Kevin Wolf kw...@redhat.com:

 On Fri, Feb 15, 2013 at 12:54:51PM +0100, Paolo Bonzini wrote:
 Il 15/02/2013 12:18, Peter Lieven ha scritto:
 
 +task = iscsi_readcapacity16_task(iscsilun-iscsi, iscsilun-lun,
 + iscsi_readcapacity16_cb, itask);
 
 You can use iscsi_readcapacity16_sync.  In fact, you probably should
 extract code from iscsi_open and reuse it here.
 
 Thats not possible afaik. Mixing sync and async commands in libiscsi is
 a very bad thing. It will leed to nested event loops.
 
 Ah, I thought qmp_block_resize did a bdrv_drain_all before calling
 bdrv_truncate.
 
 Maybe it should.  Kevin, what do you think?
 
 Probably. bdrv_truncate() invalidates the bdrv_check_request() result for
 in-flight requests, so there better be none.

So you would call brdv_drain_all() before calling brdv_truncate and then
use a sync iscsi call?

Peter


 
 Kevin




Re: [Qemu-devel] [PATCH] iscsi: add iscsi_truncate support

2013-02-15 Thread Paolo Bonzini
Il 15/02/2013 13:36, Peter Lieven ha scritto:
  Ah, I thought qmp_block_resize did a bdrv_drain_all before calling
  bdrv_truncate.
  
  Maybe it should.  Kevin, what do you think?
  
  Probably. bdrv_truncate() invalidates the bdrv_check_request() result for
  in-flight requests, so there better be none.
 So you would call brdv_drain_all() before calling brdv_truncate and then
 use a sync iscsi call?

Yes, please.

Paolo