Il 27/06/2013 15:11, Peter Lieven ha scritto: > if the device supports unmapping and unmapped blocks read as > zero ensure that the whole device is unmapped and report > .has_zero_init = 1 in this case to speed up qemu-img convert.
This can still take several minutes. Do you need any special timeout in libiscsi? Perhaps we can have a new "discard_zeroes" field in bdrv_get_info, and the unmap functionality can be moved up to qemu-img convert? Paolo > > Signed-off-by: Peter Lieven <p...@kamp.de> > --- > block/iscsi.c | 72 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 71 insertions(+), 1 deletion(-) > > diff --git a/block/iscsi.c b/block/iscsi.c > index 92e66a6..621ca40 100644 > --- a/block/iscsi.c > +++ b/block/iscsi.c > @@ -1436,7 +1436,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t > offset) > > static int iscsi_has_zero_init(BlockDriverState *bs) > { > - return 0; > + IscsiLun *iscsilun = bs->opaque; > + return (iscsilun->lbpu && iscsilun->lbprz) ? 1 : 0; > } > > static int iscsi_create(const char *filename, QEMUOptionParameter *options) > @@ -1446,6 +1447,7 @@ static int iscsi_create(const char *filename, > QEMUOptionParameter *options) > BlockDriverState bs; > IscsiLun *iscsilun = NULL; > QDict *bs_options; > + struct scsi_task *task = NULL; > > memset(&bs, 0, sizeof(BlockDriverState)); > > @@ -1481,7 +1483,75 @@ static int iscsi_create(const char *filename, > QEMUOptionParameter *options) > } > > ret = 0; > + > + if (iscsilun->lbpu && iscsilun->lbprz) { > + uint64_t lba = 0; > + while (lba < iscsilun->num_blocks) { > + struct scsi_get_lba_status *lbas = NULL; > + struct scsi_lba_status_descriptor *lbasd = NULL; > + enum scsi_provisioning_type provisioning; > + uint32_t nb_sectors; > + > + task = iscsi_get_lba_status_sync(iscsilun->iscsi, iscsilun->lun, > + lba, 8 + 16); > + if (task == NULL || task->status != SCSI_STATUS_GOOD) { > + error_report("iSCSI: Failed to get_lba_status on iSCSI lun. > %s", > + iscsi_get_error(iscsilun->iscsi)); > + ret = -EINVAL; > + goto out; > + } > + > + lbas = scsi_datain_unmarshall(task); > + if (lbas == NULL) { > + error_report("iSCSI: failed to unmarshall inquiry datain > blob"); > + ret = -EINVAL; > + goto out; > + } > + lbasd = &lbas->descriptors[0]; > + if (lbasd->lba != lba) { > + ret = -EINVAL; > + goto out; > + } > + nb_sectors = lbasd->num_blocks; > + provisioning = lbasd->provisioning; > + scsi_free_scsi_task(task); > + task = NULL; > + > + /* blocks from lba to lba + nb_sectors - 1 are not mapped > + * and read as zero (lbprz==1) so we can skip them */ > + if (provisioning != SCSI_PROVISIONING_TYPE_MAPPED) { > + lba += nb_sectors; > + continue; > + } > + > + uint64_t lba2 = lba + nb_sectors; > + while (lba < lba2) { > + struct unmap_list list[1]; > + list[0].lba = lba; > + list[0].num = iscsilun->max_unmap; > + if (lba + list[0].num > iscsilun->num_blocks) { > + list[0].num = iscsilun->num_blocks - lba; > + } > + task = iscsi_unmap_sync(iscsilun->iscsi, > + iscsilun->lun, > + 0, 0, &list[0], 1); > + if (task == NULL || task->status != SCSI_STATUS_GOOD) { > + error_report("iSCSI: Failed to unmap data on iSCSI lun. > %s", > + iscsi_get_error(iscsilun->iscsi)); > + ret = -EINVAL; > + goto out; > + } > + scsi_free_scsi_task(task); > + task = NULL; > + lba += list[0].num; > + } > + } > + } > + > out: > + if (task) { > + scsi_free_scsi_task(task); > + } > if (iscsilun->iscsi != NULL) { > iscsi_destroy_context(iscsilun->iscsi); > } >