[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCHv4] iscsi: add iscsi_truncate support
From: |
Peter Lieven |
Subject: |
[Qemu-devel] [PATCHv4] iscsi: add iscsi_truncate support |
Date: |
Mon, 18 Feb 2013 14:50:46 +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.
v4:
- factor out complete readcapacity logic into a separate function
- handle capacity change check condition in readcapacity function
(this happens if the block_resize cmd is the first iscsi task
executed after a resize on the storage)
v3:
- remove switch statement in iscsi_open
- create separate patch for brdv_drain_all() in bdrv_truncate()
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/iscsi.c | 133 +++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 87 insertions(+), 46 deletions(-)
diff --git a/block/iscsi.c b/block/iscsi.c
index deb3b68..1ea290e 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -823,6 +823,70 @@ static void iscsi_nop_timed_event(void *opaque)
}
#endif
+static int iscsi_readcapacity_sync(IscsiLun *iscsilun) {
+ struct scsi_task *task = NULL;
+ struct scsi_readcapacity10 *rc10 = NULL;
+ struct scsi_readcapacity16 *rc16 = NULL;
+ int ret = 0;
+
+try_again:
+ switch (iscsilun->type) {
+ case TYPE_DISK:
+ task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun);
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
+ /* Capacity data has changed */
+ if (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
+ && task->sense.key == SCSI_SENSE_UNIT_ATTENTION
+ && task->sense.ascq == 0x2a09) {
+ scsi_free_scsi_task(task);
+ goto try_again;
+ }
+ error_report("iSCSI: failed to send readcapacity16 command.");
+ ret = -EINVAL;
+ 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(iscsilun->iscsi, iscsilun->lun, 0, 0);
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
+ error_report("iSCSI: failed to send readcapacity10 command.");
+ ret = -EINVAL;
+ goto out;
+ }
+ rc10 = scsi_datain_unmarshall(task);
+ if (rc10 == NULL) {
+ error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
+ ret = -EINVAL;
+ goto out;
+ }
+ iscsilun->block_size = rc10->block_size;
+ if (rc10->lba == 0) {
+ /* blank disk loaded */
+ iscsilun->num_blocks = 0;
+ } else {
+ iscsilun->num_blocks = rc10->lba + 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+out:
+ if (task) {
+ scsi_free_scsi_task(task);
+ }
+
+ return ret;
+}
+
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -834,8 +898,6 @@ static int iscsi_open(BlockDriverState *bs, const char
*filename, int flags)
struct iscsi_url *iscsi_url = NULL;
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;
@@ -925,48 +987,8 @@ static int iscsi_open(BlockDriverState *bs, const char
*filename, int flags)
iscsilun->type = inq->periperal_device_type;
- scsi_free_scsi_task(task);
-
- 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;
- 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);
- if (task == NULL || task->status != SCSI_STATUS_GOOD) {
- error_report("iSCSI: failed to send readcapacity10 command.");
- ret = -EINVAL;
- goto out;
- }
- rc10 = scsi_datain_unmarshall(task);
- if (rc10 == NULL) {
- error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
- ret = -EINVAL;
- goto out;
- }
- iscsilun->block_size = rc10->block_size;
- if (rc10->lba == 0) {
- /* blank disk loaded */
- iscsilun->num_blocks = 0;
- } else {
- iscsilun->num_blocks = rc10->lba + 1;
- }
- break;
- default:
- break;
+ if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
+ goto out;
}
bs->total_sectors = iscsilun->num_blocks *
@@ -981,8 +1003,6 @@ static int iscsi_open(BlockDriverState *bs, const char
*filename, int flags)
bs->sg = 1;
}
- ret = 0;
-
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event,
iscsilun);
@@ -1023,6 +1043,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_readcapacity_sync(iscsilun)) != 0) {
+ return ret;
+ }
+
+ if (offset > iscsi_getlength(bs)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int iscsi_has_zero_init(BlockDriverState *bs)
{
return 0;
@@ -1093,6 +1133,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
- [Qemu-devel] [PATCHv2] iscsi: add iscsi_truncate support, (continued)
- [Qemu-devel] [PATCHv2] iscsi: add iscsi_truncate support, Peter Lieven, 2013/02/15
- Re: [Qemu-devel] [PATCHv2] iscsi: add iscsi_truncate support, Paolo Bonzini, 2013/02/15
- [Qemu-devel] [PATCH] block: complete all IOs before .bdrv_truncate, Peter Lieven, 2013/02/18
- Re: [Qemu-devel] [PATCH] block: complete all IOs before .bdrv_truncate, Paolo Bonzini, 2013/02/18
- Re: [Qemu-devel] [PATCH] block: complete all IOs before .bdrv_truncate, Kevin Wolf, 2013/02/20
- Re: [Qemu-devel] [PATCH] block: complete all IOs before .bdrv_truncate, Eric Blake, 2013/02/18
- [Qemu-devel] [PATCHv3] iscsi: add iscsi_truncate support, Peter Lieven, 2013/02/18
- Re: [Qemu-devel] [PATCHv3] iscsi: add iscsi_truncate support, Paolo Bonzini, 2013/02/18
- Re: [Qemu-devel] [PATCHv3] iscsi: add iscsi_truncate support, Peter Lieven, 2013/02/18
- Re: [Qemu-devel] [PATCHv3] iscsi: add iscsi_truncate support, Paolo Bonzini, 2013/02/18
- [Qemu-devel] [PATCHv4] iscsi: add iscsi_truncate support,
Peter Lieven <=
- Re: [Qemu-devel] [PATCHv4] iscsi: add iscsi_truncate support, Paolo Bonzini, 2013/02/25