qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


From: Peter Lieven
Subject: [Qemu-devel] [PATCHv2] iscsi: add iscsi_truncate support
Date: Fri, 15 Feb 2013 15:35:36 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130106 Thunderbird/17.0.2

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.

v2:
 - add a general bdrv_drain_all() before bdrv_truncate() to avoid
   in-flight AIOs while the device is truncated
 - since no AIOs are in flight we can use a sync libiscsi call
   to re-read the capacity
 - factor out the readcapacity16 logic as it is redundant
   to iscsi_open() and iscsi_truncate().

Signed-off-by: Peter Lieven <address@hidden>
---
 block.c       |    4 ++++
 block/iscsi.c |   65 +++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/block.c b/block.c
index 50dab8e..d8880e3 100644
--- a/block.c
+++ b/block.c
@@ -2427,6 +2427,10 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
         return -EACCES;
     if (bdrv_in_use(bs))
         return -EBUSY;
+
+    /* there should be better no AIOs in flight when we truncate the device */
+    bdrv_drain_all();
+
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
diff --git a/block/iscsi.c b/block/iscsi.c
index deb3b68..dd41943 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -823,6 +823,35 @@ static void iscsi_nop_timed_event(void *opaque)
 }
 #endif

+static int iscsi_disk_readcapacity16_sync(IscsiLun *iscsilun) {
+    struct scsi_task *task = NULL;
+    struct scsi_readcapacity16 *rc16 = NULL;
+
+    task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun);
+    if (task == NULL) {
+        error_report("iSCSI: failed to send readcapacity16 command.");
+        return -EINVAL;
+    }
+    if (task->status != SCSI_STATUS_GOOD) {
+        error_report("iSCSI: failed to send readcapacity16 command.");
+        scsi_free_scsi_task(task);
+        return -EINVAL;
+    }
+    rc16 = scsi_datain_unmarshall(task);
+    if (rc16 == NULL) {
+        error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
+        scsi_free_scsi_task(task);
+        return -EINVAL;
+    }
+
+    iscsilun->block_size = rc16->block_length;
+    iscsilun->num_blocks = rc16->returned_lba + 1;
+
+    scsi_free_scsi_task(task);
+
+    return 0;
+}
+
 /*
  * We support iscsi url's on the form
  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -835,7 +864,6 @@ static int iscsi_open(BlockDriverState *bs, const char 
*filename, int flags)
     struct scsi_task *task = NULL;
     struct scsi_inquiry_standard *inq = NULL;
     struct scsi_readcapacity10 *rc10 = NULL;
-    struct scsi_readcapacity16 *rc16 = NULL;
     char *initiator_name = NULL;
     int ret;

@@ -926,23 +954,13 @@ static int iscsi_open(BlockDriverState *bs, const char 
*filename, int flags)
     iscsilun->type = inq->periperal_device_type;

     scsi_free_scsi_task(task);
+    task = NULL;

     switch (iscsilun->type) {
     case TYPE_DISK:
-        task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
-        if (task == NULL || task->status != SCSI_STATUS_GOOD) {
-            error_report("iSCSI: failed to send readcapacity16 command.");
-            ret = -EINVAL;
+        if ((ret = iscsi_disk_readcapacity16_sync(iscsilun))) {
             goto out;
         }
-        rc16 = scsi_datain_unmarshall(task);
-        if (rc16 == NULL) {
-            error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
-            ret = -EINVAL;
-            goto out;
-        }
-        iscsilun->block_size = rc16->block_length;
-        iscsilun->num_blocks = rc16->returned_lba + 1;
         break;
     case TYPE_ROM:
         task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
@@ -1023,6 +1041,26 @@ static void iscsi_close(BlockDriverState *bs)
     memset(iscsilun, 0, sizeof(IscsiLun));
 }

+static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    int ret = 0;
+
+    if (iscsilun->type != TYPE_DISK) {
+        return -ENOTSUP;
+    }
+
+    if ((ret = iscsi_disk_readcapacity16_sync(iscsilun))) {
+        return ret;
+    }
+
+    if (offset > iscsi_getlength(bs)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
 static int iscsi_has_zero_init(BlockDriverState *bs)
 {
     return 0;
@@ -1093,6 +1131,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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]