iscsi/qemu-img/block-migration enhancements
v3 cover iscsi/qemu-img/block-migration enhancements
this series adds logical block provisioning functions to the iscsi layer. it also is the first step to the change of migration to coroutines in block/iscsi.
the changes to qemu-img and block migration have been split and will follow in separte patches later.
changes in v3:
- merge both block provision inquiries into one patch. explitely free the iscsi tasks after the inquiry. limit the unmap to 128k blocks if the target returns max_unmap = 0xffffffff;
- in the coroutine framework free the scsi task in the caller not in the callback. also change the iTask init as Kevin suggested.
- in iscsi_co_is_allocated() return unallocated only for ANCHORED and UNALLOACTED to avoid a wrong return value if a new provisioning status is introduced.
- added new patch adding .bdrv_co_discard
- build .bdrv_co_write_zeroes on top of .bdrv_co_discard
- fixed a bug for -ENOSPC in iscsi_create() spotted by Kevin.
- remove support for misaligned nb_sectors in aio_readv
- add log message in error case to lun alignment checks
Peter Lieven (10):
iscsi: add logical block provisioning information to iscsilun
iscsi: add .bdrv_co_is_allocated
iscsi: add .bdrv_co_discard
iscsi: add .bdrv_write_zeroes
block: add bdrv_write_zeroes()
block/raw: add bdrv_co_write_zeroes
iscsi: fix -ENOSPC in iscsi_create()
iscsi: factor out sector conversions
iscsi: remove support for misaligned nb_sectors in aio_readv
iscsi: assert that sectors are aligned to LUN blocksize
block.c | 27 ++- block/iscsi.c | 433 +++++++++++++++++++++++++++++++++++++------------ block/raw.c | 8 + include/block/block.h | 2 + 4 files changed, 358 insertions(+), 112 deletions(-)
Signature · 1 line
1.7.9.5
PATCH v3 1/10 iscsi: add logical block provisioning information to iscsilun
--- block/iscsi.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+)
block/iscsi.c +83 -0
@@ -49,6 +49,12 @@ typedef struct IscsiLun {uint64_t num_blocks;int events;QEMUTimer *nop_timer; +uint8_t lbpme; +uint8_t lbprz; +uint8_t lbpu; +uint8_t lbpws; +uint8_t lbpws10; +uint32_t max_unmap; } IscsiLun; typedef struct IscsiAIOCB {
@@ -73,6 +79,7 @@ typedef struct IscsiAIOCB {#define NOP_INTERVAL 5000#define MAX_NOP_FAILURES 3#define ISCSI_CMD_RETRIES 5 +#define ISCSI_MAX_UNMAP 131072static void iscsi_bh_cb (void *p)
@@ -948,6 +955,8 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun) }else { iscsilun->block_size = rc16->block_length; iscsilun->num_blocks = rc16->returned_lba +1 ; + iscsilun->lbpme = rc16->lbpme; + iscsilun->lbprz = rc16->lbprz; } }break ;
@@ -1000,6 +1009,37 @@ static QemuOptsList runtime_opts = { }, }; +static struct scsi_task *iscsi_do_inquiry (struct iscsi_context *iscsi, +int lun,int evpd,int pc) { +int full_size; +struct scsi_task *task =NULL ; + task =iscsi_inquiry_sync (iscsi, lun, evpd, pc,64 ); +if (task ==NULL || task->status !=SCSI_STATUS_GOOD ) { + goto fail; + } + full_size =scsi_datain_getfullsize (task); +if (full_size > task->datain.size) { +scsi_free_scsi_task (task); + +/* we need more data for the full list */ + task =iscsi_inquiry_sync (iscsi, lun, evpd, pc, full_size); +if (task ==NULL || task->status !=SCSI_STATUS_GOOD ) { + goto fail; + } + } + +return task; + +fail: +error_report ("iSCSI: Inquiry command failed : %s" , +iscsi_get_error (iscsi)); +if (task) { +scsi_free_scsi_task (task); +return NULL ; + } +return NULL ; +} +/* * We support iscsi url's on the form * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -1130,6 +1170,49 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags) bs->sg =1 ; } +if (iscsilun->lbpme) { +struct scsi_inquiry_logical_block_provisioning *inq_lbp; + task =iscsi_do_inquiry (iscsilun->iscsi, iscsilun->lun,1 , +SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING ); +if (task ==NULL ) { + ret = -EINVAL ; + goto out; + } + inq_lbp =scsi_datain_unmarshall (task); +if (inq_lbp ==NULL ) { +error_report ("iSCSI: failed to unmarshall inquiry datain blob" ); + ret = -EINVAL ; + goto out; + } + iscsilun->lbpu = inq_lbp->lbpu; + iscsilun->lbpws = inq_lbp->lbpws; + iscsilun->lbpws10 = inq_lbp->lbpws10; +scsi_free_scsi_task (task); + task =NULL ; + } + +if (iscsilun->lbpu) { +struct scsi_inquiry_block_limits *inq_bl; + task =iscsi_do_inquiry (iscsilun->iscsi, iscsilun->lun,1 , +SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS ); +if (task ==NULL ) { + ret = -EINVAL ; + goto out; + } + inq_bl =scsi_datain_unmarshall (task); +if (inq_bl ==NULL ) { +error_report ("iSCSI: failed to unmarshall inquiry datain blob" ); + ret = -EINVAL ; + goto out; + } + iscsilun->max_unmap = inq_bl->max_unmap; +if (iscsilun->max_unmap ==0xffffffff ) { + iscsilun->max_unmap =ISCSI_MAX_UNMAP ; + } +scsi_free_scsi_task (task); + task =NULL ; + } +#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);
Signature · 1 line
1.7.9.5
PATCH v3 2/10 iscsi: add .bdrv_co_is_allocated
In reply to Peter Lieventhis patch adds a coroutine for .bdrv_co_is_allocated as well as a generic framework that can be used to build coroutines in block/iscsi.
--- block/iscsi.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+)
block/iscsi.c +130 -0
@@ -57,6 +57,15 @@ typedef struct IscsiLun {uint32_t max_unmap; } IscsiLun; +typedef struct IscsiTask { +int status; +int complete; +int retries; +int do_retry; +struct scsi_task *task; +Coroutine *co; +}IscsiTask ; + typedef struct IscsiAIOCB { BlockDriverAIOCB common; QEMUIOVector *qiov;
@@ -113,6 +122,41 @@ iscsi_schedule_bh(IscsiAIOCB *acb)qemu_bh_schedule (acb->bh); } +static void +iscsi_co_generic_cb (struct iscsi_context *iscsi,int status, +void *command_data,void *opaque) +{ +struct IscsiTask *iTask = opaque; +struct scsi_task *task = command_data; + + iTask->complete =1 ; + iTask->status = status; + iTask->do_retry =0 ; + iTask->task = task; + +if (iTask->retries-- >0 && status ==SCSI_STATUS_CHECK_CONDITION + && task->sense.key ==SCSI_SENSE_UNIT_ATTENTION ) { + iTask->do_retry =1 ; + goto out; + } + +if (status !=SCSI_STATUS_GOOD ) { +error_report ("iSCSI: Failure. %s" ,iscsi_get_error (iscsi)); + } + +out: +if (iTask->co) { +qemu_coroutine_enter (iTask->co,NULL ); + } +} + +static void iscsi_co_init_iscsitask (IscsiLun *iscsilun,struct IscsiTask *iTask) +{ + *iTask = (struct IscsiTask ) { + .co =qemu_coroutine_self (), + .retries =ISCSI_CMD_RETRIES , + }; +} static void iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
@@ -807,6 +851,90 @@ iscsi_getlength(BlockDriverState *bs)return len; } +static int coroutine_fn iscsi_co_is_allocated(BlockDriverState *bs, +int64_t sector_num, +int nb_sectors,int *pnum) +{ +IscsiLun *iscsilun = bs->opaque; +struct scsi_get_lba_status *lbas =NULL ; +struct scsi_lba_status_descriptor *lbasd =NULL ; +struct IscsiTask iTask; +int ret; + +/* default to all sectors allocated */ + ret =1 ; + *pnum = nb_sectors; + +/* LUN does not support logical block provisioning */ +if (iscsilun->lbpme ==0 ) { + goto out; + } + +iscsi_co_init_iscsitask (iscsilun, &iTask); + +retry: +if (iscsi_get_lba_status_task (iscsilun->iscsi, iscsilun->lun, +sector_qemu2lun (sector_num, iscsilun), +8 +16 , iscsi_co_generic_cb, + &iTask) ==NULL ) { + ret =0 ; + *pnum =0 ; + goto out; + } + +while (!iTask.complete) { +iscsi_set_events (iscsilun); +qemu_coroutine_yield (); + } + +if (iTask.do_retry) { +if (iTask.task !=NULL ) { +scsi_free_scsi_task (iTask.task); + iTask.task =NULL ; + } + goto retry; + } + +if (iTask.status !=SCSI_STATUS_GOOD ) { +/* in case the get_lba_status_callout fails (i.e. +* because the device is busy or the cmd is not +* supported) we pretend all blocks are allocated +* for backwards compatiblity */ + goto out; + } + + lbas =scsi_datain_unmarshall (iTask.task); +if (lbas ==NULL ) { + ret =0 ; + *pnum =0 ; + goto out; + } + + lbasd = &lbas->descriptors[0 ]; + +if (sector_qemu2lun (sector_num, iscsilun) != lbasd->lba) { + ret =0 ; + *pnum =0 ; + goto out; + } + + *pnum = lbasd->num_blocks * (iscsilun->block_size /BDRV_SECTOR_SIZE ); +if (*pnum > nb_sectors) { + *pnum = nb_sectors; + } + +if (lbasd->provisioning ==SCSI_PROVISIONING_TYPE_DEALLOCATED || + lbasd->provisioning ==SCSI_PROVISIONING_TYPE_ANCHORED ) { + ret =0 ; + } + +out: +if (iTask.task !=NULL ) { +scsi_free_scsi_task (iTask.task); + } +return ret; +} +static int parse_chap (struct iscsi_context *iscsi,const char *target) {QemuOptsList *list;
@@ -1351,6 +1479,8 @@ static BlockDriver bdrv_iscsi = { .bdrv_getlength = iscsi_getlength, .bdrv_truncate = iscsi_truncate, + .bdrv_co_is_allocated = iscsi_co_is_allocated, + .bdrv_aio_readv = iscsi_aio_readv, .bdrv_aio_writev = iscsi_aio_writev, .bdrv_aio_flush = iscsi_aio_flush,
Signature · 1 line
1.7.9.5
PATCH v3 3/10 iscsi: add .bdrv_co_discard
In reply to Peter Lieventhis patch changes bdrv_discard to a co routine. it honours max_unmap information and splits requests if necessary. if unmap is unsupported by the target the request is silently discarded.
--- block/iscsi.c | 137 +++++++++++++++++++++++---------------------------------- 1 file changed, 54 insertions(+), 83 deletions(-)
block/iscsi.c +54 -83
@@ -613,88 +613,6 @@ iscsi_aio_flush(BlockDriverState *bs,return &acb->common; } -static int iscsi_aio_discard_acb (IscsiAIOCB *acb); - -static void -iscsi_unmap_cb (struct iscsi_context *iscsi,int status, -void *command_data,void *opaque) -{ -IscsiAIOCB *acb = opaque; - -if (acb->canceled !=0 ) { -return ; - } - - acb->status =0 ; -if (status !=0 ) { -if (status ==SCSI_STATUS_CHECK_CONDITION - && acb->task->sense.key ==SCSI_SENSE_UNIT_ATTENTION - && acb->retries-- >0 ) { -scsi_free_scsi_task (acb->task); - acb->task =NULL ; -if (iscsi_aio_discard_acb (acb) ==0 ) { -iscsi_set_events (acb->iscsilun); -return ; - } - } -error_report ("Failed to unmap data on iSCSI lun. %s" , -iscsi_get_error (iscsi)); - acb->status = -EIO ; - } - -iscsi_schedule_bh (acb); -} - -static int iscsi_aio_discard_acb (IscsiAIOCB *acb) { -struct iscsi_context *iscsi = acb->iscsilun->iscsi; -struct unmap_list list[1 ]; - - acb->canceled =0 ; - acb->bh =NULL ; - acb->status = -EINPROGRESS ; - acb->buf =NULL ; - - list[0 ].lba =sector_qemu2lun (acb->sector_num, acb->iscsilun); - list[0 ].num = acb->nb_sectors *BDRV_SECTOR_SIZE / acb->iscsilun->block_size; - - acb->task =iscsi_unmap_task (iscsi, acb->iscsilun->lun, -0 ,0 , &list[0 ],1 , - iscsi_unmap_cb, - acb); -if (acb->task ==NULL ) { -error_report ("iSCSI: Failed to send unmap command. %s" , -iscsi_get_error (iscsi)); -return -1 ; - } - -return 0 ; -} - -static BlockDriverAIOCB * -iscsi_aio_discard (BlockDriverState *bs, -int64_t sector_num,int nb_sectors, -BlockDriverCompletionFunc *cb,void *opaque) -{ -IscsiLun *iscsilun = bs->opaque; -IscsiAIOCB *acb; - - acb =qemu_aio_get (&iscsi_aiocb_info, bs, cb, opaque); - - acb->iscsilun = iscsilun; - acb->nb_sectors = nb_sectors; - acb->sector_num = sector_num; - acb->retries =ISCSI_CMD_RETRIES ; - -if (iscsi_aio_discard_acb (acb) !=0 ) { -qemu_aio_release (acb); -return NULL ; - } - -iscsi_set_events (iscsilun); - -return &acb->common; -} -#ifdef __linux__ static void iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
@@ -935,6 +853,59 @@ out:return ret; } +static int +coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num, +int nb_sectors) +{ +IscsiLun *iscsilun = bs->opaque; +struct IscsiTask iTask; +struct unmap_list list; +uint32_t nb_blocks; + +if (!iscsilun->lbpu) { +return 0 ; + } + + list.lba =sector_qemu2lun (sector_num, iscsilun); + nb_blocks =sector_qemu2lun (nb_sectors, iscsilun); + +while (nb_blocks >0 ) { +iscsi_co_init_iscsitask (iscsilun, &iTask); + list.num = nb_blocks; +if (list.num > iscsilun->max_unmap) { + list.num = iscsilun->max_unmap; + } +retry: +if (iscsi_unmap_task (iscsilun->iscsi, iscsilun->lun,0 ,0 , &list,1 , + iscsi_co_generic_cb, &iTask) ==NULL ) { +return -EIO ; + } + +while (!iTask.complete) { +iscsi_set_events (iscsilun); +qemu_coroutine_yield (); + } + +if (iTask.task !=NULL ) { +scsi_free_scsi_task (iTask.task); + iTask.task =NULL ; + } + +if (iTask.do_retry) { + goto retry; + } + +if (iTask.status !=SCSI_STATUS_GOOD ) { +return -EIO ; + } + + list.lba += list.num; + nb_blocks -= list.num; + } + +return 0 ; +} +static int parse_chap (struct iscsi_context *iscsi,const char *target) {QemuOptsList *list;
@@ -1480,12 +1451,12 @@ static BlockDriver bdrv_iscsi = { .bdrv_truncate = iscsi_truncate, .bdrv_co_is_allocated = iscsi_co_is_allocated, + .bdrv_co_discard = iscsi_co_discard, .bdrv_aio_readv = iscsi_aio_readv, .bdrv_aio_writev = iscsi_aio_writev, .bdrv_aio_flush = iscsi_aio_flush, - .bdrv_aio_discard = iscsi_aio_discard, .bdrv_has_zero_init = iscsi_has_zero_init, #ifdef __linux__
Signature · 1 line
1.7.9.5
PATCH v3 4/10 iscsi: add .bdrv_write_zeroes
In reply to Peter Lieven--- block/iscsi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
block/iscsi.c +16 -0
@@ -906,6 +906,21 @@ retry:return 0 ; } +static int +coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, +int nb_sectors) +{ +IscsiLun *iscsilun = bs->opaque; + +if (!iscsilun->lbprz || !iscsilun->lbpu || + !(bs->open_flags &BDRV_O_UNMAP )) { +/* fall back to writev */ +return -ENOTSUP ; + } + +return iscsi_co_discard (bs, sector_num, nb_sectors); +} +static int parse_chap (struct iscsi_context *iscsi,const char *target) {QemuOptsList *list;
@@ -1452,6 +1467,7 @@ static BlockDriver bdrv_iscsi = { .bdrv_co_is_allocated = iscsi_co_is_allocated, .bdrv_co_discard = iscsi_co_discard, + .bdrv_co_write_zeroes = iscsi_co_write_zeroes, .bdrv_aio_readv = iscsi_aio_readv, .bdrv_aio_writev = iscsi_aio_writev,
Signature · 1 line
1.7.9.5
PATCH v3 5/10 block: add bdrv_write_zeroes()
In reply to Peter Lieven--- block.c | 27 +++++++++++++++++++-------- include/block/block.h | 2 ++ 2 files changed, 21 insertions(+), 8 deletions(-)
block.c +19 -8
@@ -2155,6 +2155,7 @@ typedef struct RwCo {QEMUIOVector *qiov;bool is_write;int ret; +BdrvRequestFlags flags; } RwCo; static void coroutine_fn bdrv_rw_co_entry(void *opaque)
@@ -2163,10 +2164,12 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)if (!rwco->is_write) { rwco->ret =bdrv_co_do_readv (rwco->bs, rwco->sector_num, - rwco->nb_sectors, rwco->qiov,0 ); + rwco->nb_sectors, rwco->qiov, + rwco->flags); }else { rwco->ret =bdrv_co_do_writev (rwco->bs, rwco->sector_num, - rwco->nb_sectors, rwco->qiov,0 ); + rwco->nb_sectors, rwco->qiov, + rwco->flags); } }
@@ -2174,7 +2177,8 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)* Process a vectored synchronous request using coroutines */ static int bdrv_rwv_co (BlockDriverState *bs,int64_t sector_num, -QEMUIOVector *qiov,bool is_write) +QEMUIOVector *qiov,bool is_write, +BdrvRequestFlags flags) {Coroutine *co;RwCo rwco = {
@@ -2184,6 +2188,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num, .qiov = qiov, .is_write = is_write, .ret = NOT_DONE, + .flags = flags, };assert ((qiov->size & (BDRV_SECTOR_SIZE -1 )) ==0 );
@@ -2215,7 +2220,7 @@ static int bdrv_rwv_co(BlockDriverState *bs, int64_t sector_num,* Process a synchronous request using coroutines */ static int bdrv_rw_co (BlockDriverState *bs,int64_t sector_num,uint8_t *buf, -int nb_sectors,bool is_write) +int nb_sectors,bool is_write,BdrvRequestFlags flags) {QEMUIOVector qiov;struct iovec iov = {
@@ -2224,14 +2229,14 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, };qemu_iovec_init_external (&qiov, &iov,1 ); -return bdrv_rwv_co (bs, sector_num, &qiov, is_write); +return bdrv_rwv_co (bs, sector_num, &qiov, is_write, flags); }/* return < 0 if error. See bdrv_write() for the return codes */ int bdrv_read (BlockDriverState *bs,int64_t sector_num,uint8_t *buf,int nb_sectors) { -return bdrv_rw_co (bs, sector_num, buf, nb_sectors, false); +return bdrv_rw_co (bs, sector_num, buf, nb_sectors, false,0 ); }/* Just like bdrv_read(), but with I/O throttling temporarily disabled */
@@ -2257,12 +2262,18 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,int bdrv_write (BlockDriverState *bs,int64_t sector_num,const uint8_t *buf,int nb_sectors) { -return bdrv_rw_co (bs, sector_num, (uint8_t *)buf, nb_sectors, true); +return bdrv_rw_co (bs, sector_num, (uint8_t *)buf, nb_sectors, true,0 ); }int bdrv_writev (BlockDriverState *bs,int64_t sector_num,QEMUIOVector *qiov) { -return bdrv_rwv_co (bs, sector_num, qiov, true); +return bdrv_rwv_co (bs, sector_num, qiov, true,0 ); +} + +int bdrv_write_zeroes (BlockDriverState *bs,int64_t sector_num,int nb_sectors) +{ +return bdrv_rw_co (bs, sector_num,NULL , nb_sectors, true, +BDRV_REQ_ZERO_WRITE ); } int bdrv_pread(BlockDriverState *bs, int64_t offset,
include/block/block.h +2 -0
@@ -156,6 +156,8 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors);int bdrv_write (BlockDriverState *bs,int64_t sector_num,const uint8_t *buf,int nb_sectors); +int bdrv_write_zeroes (BlockDriverState *bs,int64_t sector_num, +int nb_sectors);int bdrv_writev (BlockDriverState *bs,int64_t sector_num,QEMUIOVector *qiov);int bdrv_pread (BlockDriverState *bs,int64_t offset,void *buf,int count);
Signature · 1 line
1.7.9.5
PATCH v3 6/10 block/raw: add bdrv_co_write_zeroes
In reply to Peter Lieven--- block/raw.c | 8 ++++++++ 1 file changed, 8 insertions(+)
block/raw.c +8 -0
@@ -42,6 +42,13 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,return bdrv_co_is_allocated (bs->file, sector_num, nb_sectors, pnum); } +static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs, +int64_t sector_num, +int nb_sectors) +{ +return bdrv_co_write_zeroes (bs->file, sector_num, nb_sectors); +} +static int64_t raw_getlength (BlockDriverState *bs) {return bdrv_getlength (bs->file);
@@ -128,6 +135,7 @@ static BlockDriver bdrv_raw = { .bdrv_co_readv = raw_co_readv, .bdrv_co_writev = raw_co_writev, .bdrv_co_is_allocated = raw_co_is_allocated, + .bdrv_co_write_zeroes = raw_co_write_zeroes, .bdrv_co_discard = raw_co_discard, .bdrv_probe = raw_probe,
Signature · 1 line
1.7.9.5
PATCH v3 7/10 iscsi: fix -ENOSPC in iscsi_create()
In reply to Peter Lieventhe -ENOPSC case did not work due to the missing goto.
--- block/iscsi.c | 1 + 1 file changed, 1 insertion(+)
block/iscsi.c +1 -0
@@ -1432,6 +1432,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) }if (bs.total_sectors < total_size) { ret = -ENOSPC ; + goto out; } ret =0 ;
Signature · 1 line
1.7.9.5
PATCH v3 8/10 iscsi: factor out sector conversions
In reply to Peter Lieven--- block/iscsi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
block/iscsi.c +8 -4
@@ -289,6 +289,11 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)return sector *BDRV_SECTOR_SIZE / iscsilun->block_size; } +static int64_t sector_lun2qemu (int64_t sector,IscsiLun *iscsilun) +{ +return sector * iscsilun->block_size /BDRV_SECTOR_SIZE ; +} +static int iscsi_aio_writev_acb (IscsiAIOCB *acb) {
@@ -336,7 +341,7 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb) lba =sector_qemu2lun (acb->sector_num, acb->iscsilun); *(uint32_t *)&acb->task->cdb[2 ] =htonl (lba >>32 ); *(uint32_t *)&acb->task->cdb[6 ] =htonl (lba &0xffffffff ); - num_sectors = size / acb->iscsilun->block_size; + num_sectors =sector_qemu2lun (acb->nb_sectors, acb->iscsilun); *(uint32_t *)&acb->task->cdb[10 ] =htonl (num_sectors); acb->task->expxferlen = size;
@@ -836,7 +841,7 @@ retry: goto out; } - *pnum = lbasd->num_blocks * (iscsilun->block_size /BDRV_SECTOR_SIZE ); + *pnum =sector_lun2qemu (lbasd->num_blocks, iscsilun);if (*pnum > nb_sectors) { *pnum = nb_sectors; }
@@ -1272,8 +1277,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)if ((ret =iscsi_readcapacity_sync (iscsilun)) !=0 ) { goto out; } - bs->total_sectors = iscsilun->num_blocks * - iscsilun->block_size /BDRV_SECTOR_SIZE ; + bs->total_sectors =sector_lun2qemu (iscsilun->num_blocks, iscsilun);/* Medium changer or tape. We dont have any emulation for this so this must * be sg ioctl compatible. We force it to be sg, otherwise qemu will try
Signature · 1 line
1.7.9.5
PATCH v3 9/10 iscsi: remove support for misaligned nb_sectors in aio_readv
In reply to Peter Lieventhis hask is not working (anymore). support for misaligned offsets should be handled at the block layer.
--- block/iscsi.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-)
block/iscsi.c +4 -18
@@ -76,8 +76,6 @@ typedef struct IscsiAIOCB {int status;int canceled;int retries; -size_t read_size; -size_t read_offset;int64_t sector_num;int nb_sectors;#ifdef __linux__
@@ -435,6 +433,7 @@ static int iscsi_aio_readv_acb(IscsiAIOCB *acb) {struct iscsi_context *iscsi = acb->iscsilun->iscsi; +size_t size;uint64_t lba;uint32_t num_sectors;int ret;
@@ -447,20 +446,7 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb) acb->status = -EINPROGRESS ; acb->buf =NULL ; -/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU -* may be misaligned to the LUN, so we may need to read some extra -* data. -*/ - acb->read_offset =0 ; -if (acb->iscsilun->block_size >BDRV_SECTOR_SIZE ) { -uint64_t bdrv_offset =BDRV_SECTOR_SIZE * acb->sector_num; - - acb->read_offset = bdrv_offset % acb->iscsilun->block_size; - } - - num_sectors = (acb->read_size + acb->iscsilun->block_size - + acb->read_offset -1 ) - / acb->iscsilun->block_size; + size = acb->nb_sectors *BDRV_SECTOR_SIZE ; acb->task =malloc (sizeof (struct scsi_task ));if (acb->task ==NULL ) {
@@ -471,8 +457,9 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)memset (acb->task,0 ,sizeof (struct scsi_task )); acb->task->xfer_dir =SCSI_XFER_READ ; + acb->task->expxferlen = size; lba =sector_qemu2lun (acb->sector_num, acb->iscsilun); - acb->task->expxferlen = acb->read_size; + num_sectors =sector_qemu2lun (acb->nb_sectors, acb->iscsilun);switch (acb->iscsilun->type) {case TYPE_DISK :
@@ -527,7 +514,6 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, acb->sector_num = sector_num; acb->iscsilun = iscsilun; acb->qiov = qiov; - acb->read_size =BDRV_SECTOR_SIZE * (size_t )acb->nb_sectors; acb->retries =ISCSI_CMD_RETRIES ;if (iscsi_aio_readv_acb (acb) !=0 ) {
Signature · 1 line
1.7.9.5
PATCH v3 10/10 iscsi: assert that sectors are aligned to LUN blocksize
In reply to Peter Lievenif the blocksize of an iSCSI LUN is bigger than the BDRV_SECTOR_SIZE it is possible that sector_num or nb_sectors are not correctly alligned.
to avoid corruption we fail requests which are misaligned.
--- block/iscsi.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
block/iscsi.c +34 -0
@@ -292,6 +292,18 @@ static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)return sector * iscsilun->block_size /BDRV_SECTOR_SIZE ; } +static bool is_request_lun_aligned (int64_t sector_num,int nb_sectors, +IscsiLun *iscsilun) +{ +if ((sector_num *BDRV_SECTOR_SIZE ) % iscsilun->block_size || + (nb_sectors *BDRV_SECTOR_SIZE ) % iscsilun->block_size) { +error_report ("iSCSI misaligned request: iscsilun->block_size %u, sector_num %ld, nb_sectors %d" , + iscsilun->block_size, sector_num, nb_sectors); +return 0 ; + } +return 1 ; +} +static int iscsi_aio_writev_acb (IscsiAIOCB *acb) {
@@ -376,6 +388,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,IscsiLun *iscsilun = bs->opaque;IscsiAIOCB *acb; +if (!is_request_lun_aligned (sector_num, nb_sectors, iscsilun)) { +return NULL ; + } + acb =qemu_aio_get (&iscsi_aiocb_info, bs, cb, opaque);trace_iscsi_aio_writev (iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
@@ -507,6 +523,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,IscsiLun *iscsilun = bs->opaque;IscsiAIOCB *acb; +if (!is_request_lun_aligned (sector_num, nb_sectors, iscsilun)) { +return NULL ; + } + acb =qemu_aio_get (&iscsi_aiocb_info, bs, cb, opaque);trace_iscsi_aio_readv (iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
@@ -774,6 +794,12 @@ static int coroutine_fn iscsi_co_is_allocated(BlockDriverState *bs, ret =1 ; *pnum = nb_sectors; +if (!is_request_lun_aligned (sector_num, nb_sectors, iscsilun)) { + ret =0 ; + *pnum =0 ; + goto out; + } +/* LUN does not support logical block provisioning */ if (iscsilun->lbpme ==0 ) { goto out;
@@ -853,6 +879,10 @@ coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,struct unmap_list list;uint32_t nb_blocks; +if (!is_request_lun_aligned (sector_num, nb_sectors, iscsilun)) { +return -EINVAL ; + } +if (!iscsilun->lbpu) {return 0 ; }
@@ -903,6 +933,10 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, {IscsiLun *iscsilun = bs->opaque; +if (!is_request_lun_aligned (sector_num, nb_sectors, iscsilun)) { +return -EINVAL ; + } +if (!iscsilun->lbprz || !iscsilun->lbpu || !(bs->open_flags &BDRV_O_UNMAP )) {/* fall back to writev */
Signature · 1 line
1.7.9.5
Il 11/07/2013 14:16, Peter Lieven ha scritto:
Quoted 32 lines
this series adds logical block provisioning functions to the iscsi layer. it also is the first step to the change of migration to coroutines in block/iscsi.
the changes to qemu-img and block migration have been split and will follow in separte patches later.
changes in v3:
- merge both block provision inquiries into one patch. explitely free the iscsi tasks after the inquiry. limit the unmap to 128k blocks if the target returnsmax_unmap=0xffffffff;
- in the coroutine framework free the scsi task in the caller not in the callback. also change the iTask init as Kevin suggested.
- iniscsi_co_is_allocated()return unallocated only for ANCHORED and UNALLOACTED to avoid a wrong return value if a new provisioning status is introduced.
- added new patch adding .bdrv_co_discard
- build .bdrv_co_write_zeroes on top of .bdrv_co_discard
- fixed a bug for-ENOSPCiniscsi_create()spotted by Kevin.
- remove support for misalignednb_sectorsinaio_readv
- add log message in error case to lun alignment checksPeter Lieven (10):
iscsi: add logical block provisioning information to iscsilun
iscsi: add .bdrv_co_is_allocated
iscsi: add .bdrv_co_discard
iscsi: add .bdrv_write_zeroes
block: addbdrv_write_zeroes()
block/raw: addbdrv_co_write_zeroes
iscsi: fix-ENOSPCiniscsi_create()
iscsi: factor out sector conversions
iscsi: remove support for misalignednb_sectorsinaio_readv
iscsi: assert that sectors are aligned to LUN blocksize
Quoted 6 lines
block.c | 27 ++- block/iscsi.c | 433 +++++++++++++++++++++++++++++++++++++------------ block/raw.c | 8 + include/block/block.h | 2 + 4 files changed, 358 insertions(+), 112 deletions(-)
Applied 7-10 to scsi-next, please rebase/resubmit the others (possibly together with the qemu-img convert patches).
Paolo
Quoted 33 lines · Paolo Bonzini
Il 11/07/2013 14:16, Peter Lieven ha scritto:
Quoted 32 lines
this series adds logical block provisioning functions to the iscsi layer. it also is the first step to the change of migration to coroutines in block/iscsi.
the changes to qemu-img and block migration have been split and will follow in separte patches later.
changes in v3:
- merge both block provision inquiries into one patch. explitely free the iscsi tasks afterthe inquiry. limit the unmap to 128k blocks if the target returns max_unmap = 0xffffffff;- in the coroutine framework free the scsi task in the caller not in the callback. also change the iTask init as Kevin suggested.
- iniscsi_co_is_allocated()return unallocated only for ANCHORED and UNALLOACTED to avoid a wrong return value if a new provisioning status is introduced.
- added new patch adding .bdrv_co_discard
- build .bdrv_co_write_zeroes on top of .bdrv_co_discard
- fixed a bug for-ENOSPCiniscsi_create()spotted by Kevin.
- remove support for misalignednb_sectorsinaio_readv
- add log message in error case to lun alignment checksPeter Lieven (10):
iscsi: add logical block provisioning information to iscsilun
iscsi: add .bdrv_co_is_allocated
iscsi: add .bdrv_co_discard
iscsi: add .bdrv_write_zeroes
block: addbdrv_write_zeroes()
block/raw: addbdrv_co_write_zeroes
iscsi: fix-ENOSPCiniscsi_create()
iscsi: factor out sector conversions
iscsi: remove support for misalignednb_sectorsinaio_readv
iscsi: assert that sectors are aligned to LUN blocksize
Quoted 8 lines
Quoted 6 lines
block.c | 27 ++- block/iscsi.c | 433 +++++++++++++++++++++++++++++++++++++------------ block/raw.c | 8 + include/block/block.h | 2 + 4 files changed, 358 insertions(+), 112 deletions(-)Applied 7-10 to scsi-next, please rebase/resubmit the others (possibly together with the qemu-img convert patches).
please consider also pulling
[PATCHv4 1/2] iscsi: add logical block provisioning information to iscsilun [PATCHv4 2/2] iscsi: add .bdrv_co_is_allocated
these patches are unproblematic and keep the number of patches
in the series for the general qemu-img convert/write_zeroes_w_discard approach smaller.
patch 2/2 can also be easily converted to get_block_status even with correct BDRV_BLOCK_ZERO information by evaluating iscsilun->lbprz (which is added in patch 1).
Peter
Stefan Hajnoczi
AppliedQuoted 32 lines · Peter Lieven
this series adds logical block provisioning functions to the iscsi layer. it also is the first step to the change of migration to coroutines in block/iscsi.
the changes to qemu-img and block migration have been split and will follow in separte patches later.
changes in v3:
- merge both block provision inquiries into one patch. explitely free the iscsi tasks after the inquiry. limit the unmap to 128k blocks if the target returnsmax_unmap=0xffffffff;
- in the coroutine framework free the scsi task in the caller not in the callback. also change the iTask init as Kevin suggested.
- iniscsi_co_is_allocated()return unallocated only for ANCHORED and UNALLOACTED to avoid a wrong return value if a new provisioning status is introduced.
- added new patch adding .bdrv_co_discard
- build .bdrv_co_write_zeroes on top of .bdrv_co_discard
- fixed a bug for-ENOSPCiniscsi_create()spotted by Kevin.
- remove support for misalignednb_sectorsinaio_readv
- add log message in error case to lun alignment checksPeter Lieven (10):
iscsi: add logical block provisioning information to iscsilun
iscsi: add .bdrv_co_is_allocated
iscsi: add .bdrv_co_discard
iscsi: add .bdrv_write_zeroes
block: addbdrv_write_zeroes()
block/raw: addbdrv_co_write_zeroes
iscsi: fix-ENOSPCiniscsi_create()
iscsi: factor out sector conversions
iscsi: remove support for misalignednb_sectorsinaio_readv
iscsi: assert that sectors are aligned to LUN blocksize
Quoted 5 lines
block.c | 27 ++- block/iscsi.c | 433 +++++++++++++++++++++++++++++++++++++------------ block/raw.c | 8 + include/block/block.h | 2 + 4 files changed, 358 insertions(+), 112 deletions(-)
Thanks, applied patches 5 & 6 to my block tree:
https://github.com/stefanha/qemu/commits/block
Stefan