Il 18/02/2013 14:50, 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. > > 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 <p...@kamp.de>
Applied to scsi-next branch, thanks. Paolo > --- > 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,