提交 063c3378 编写于 作者: P Peter Lieven 提交者: Paolo Bonzini

block/iscsi: introduce bdrv_co_{readv, writev, flush_to_disk}

this converts read, write and flush functions from aio to coroutines
eliminating almost 200 lines of code.

The requirement for libiscsi is bumped to version 1.4.0 which was
released in may 2012.
Signed-off-by: NPeter Lieven <pl@kamp.de>
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
上级 d97e7730
...@@ -239,44 +239,6 @@ iscsi_process_write(void *arg) ...@@ -239,44 +239,6 @@ iscsi_process_write(void *arg)
iscsi_set_events(iscsilun); iscsi_set_events(iscsilun);
} }
static int
iscsi_aio_writev_acb(IscsiAIOCB *acb);
static void
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
g_free(acb->buf);
acb->buf = NULL;
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_writev_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to write16 data to iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
}
iscsi_schedule_bh(acb);
}
static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun) static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
{ {
return sector * iscsilun->block_size / BDRV_SECTOR_SIZE; return sector * iscsilun->block_size / BDRV_SECTOR_SIZE;
...@@ -301,324 +263,172 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors, ...@@ -301,324 +263,172 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
return 1; return 1;
} }
static int static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
iscsi_aio_writev_acb(IscsiAIOCB *acb) int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{ {
struct iscsi_context *iscsi = acb->iscsilun->iscsi; IscsiLun *iscsilun = bs->opaque;
size_t size; struct IscsiTask iTask;
uint32_t num_sectors;
uint64_t lba; uint64_t lba;
#if !defined(LIBISCSI_FEATURE_IOVECTOR) uint32_t num_sectors;
struct iscsi_data data; uint8_t *data = NULL;
#endif uint8_t *buf = NULL;
int ret;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
/* this will allow us to get rid of 'buf' completely */ if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
size = acb->nb_sectors * BDRV_SECTOR_SIZE; return -EINVAL;
}
lba = sector_qemu2lun(sector_num, iscsilun);
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
#if !defined(LIBISCSI_FEATURE_IOVECTOR) #if !defined(LIBISCSI_FEATURE_IOVECTOR)
data.size = MIN(size, acb->qiov->size);
/* if the iovec only contains one buffer we can pass it directly */ /* if the iovec only contains one buffer we can pass it directly */
if (acb->qiov->niov == 1) { if (iov->niov == 1) {
data.data = acb->qiov->iov[0].iov_base; data = iov->iov[0].iov_base;
} else { } else {
acb->buf = g_malloc(data.size); size_t size = MIN(nb_sectors * BDRV_SECTOR_SIZE, iov->size);
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size); buf = g_malloc(size);
data.data = acb->buf; qemu_iovec_to_buf(iov, 0, buf, size);
data = buf;
} }
#endif #endif
iscsi_co_init_iscsitask(iscsilun, &iTask);
acb->task = malloc(sizeof(struct scsi_task)); retry:
if (acb->task == NULL) { iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
error_report("iSCSI: Failed to allocate task for scsi WRITE16 " data, num_sectors * iscsilun->block_size,
"command. %s", iscsi_get_error(iscsi)); iscsilun->block_size, 0, 0, 0, 0, 0,
return -1; iscsi_co_generic_cb, &iTask);
if (iTask.task == NULL) {
g_free(buf);
return -EIO;
} }
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_WRITE;
acb->task->cdb_size = 16;
acb->task->cdb[0] = 0x8a;
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 = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
acb->task->expxferlen = size;
#if defined(LIBISCSI_FEATURE_IOVECTOR) #if defined(LIBISCSI_FEATURE_IOVECTOR)
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
iscsi_aio_write16_cb, iov->niov);
NULL,
acb);
#else
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
iscsi_aio_write16_cb,
&data,
acb);
#endif #endif
if (ret != 0) { while (!iTask.complete) {
scsi_free_scsi_task(acb->task); iscsi_set_events(iscsilun);
g_free(acb->buf); qemu_coroutine_yield();
return -1;
} }
#if defined(LIBISCSI_FEATURE_IOVECTOR) if (iTask.task != NULL) {
scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov); scsi_free_scsi_task(iTask.task);
#endif iTask.task = NULL;
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
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); if (iTask.do_retry) {
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb); goto retry;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_writev_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
} }
iscsi_set_events(iscsilun); g_free(buf);
return &acb->common;
}
static int
iscsi_aio_readv_acb(IscsiAIOCB *acb);
static void
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
if (acb->canceled != 0) {
return;
}
acb->status = 0; if (iTask.status != SCSI_STATUS_GOOD) {
if (status != 0) { return -EIO;
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_readv_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to read16 data from iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
} }
iscsi_schedule_bh(acb); return 0;
} }
static int static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
iscsi_aio_readv_acb(IscsiAIOCB *acb) int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{ {
struct iscsi_context *iscsi = acb->iscsilun->iscsi; IscsiLun *iscsilun = bs->opaque;
size_t size; struct IscsiTask iTask;
uint64_t lba; uint64_t lba;
uint32_t num_sectors; uint32_t num_sectors;
int ret;
#if !defined(LIBISCSI_FEATURE_IOVECTOR) #if !defined(LIBISCSI_FEATURE_IOVECTOR)
int i; int i;
#endif #endif
acb->canceled = 0; if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
acb->bh = NULL; return -EINVAL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
size = acb->nb_sectors * BDRV_SECTOR_SIZE;
acb->task = malloc(sizeof(struct scsi_task));
if (acb->task == NULL) {
error_report("iSCSI: Failed to allocate task for scsi READ16 "
"command. %s", iscsi_get_error(iscsi));
return -1;
} }
memset(acb->task, 0, sizeof(struct scsi_task));
acb->task->xfer_dir = SCSI_XFER_READ; lba = sector_qemu2lun(sector_num, iscsilun);
acb->task->expxferlen = size; num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
num_sectors = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
switch (acb->iscsilun->type) { iscsi_co_init_iscsitask(iscsilun, &iTask);
retry:
switch (iscsilun->type) {
case TYPE_DISK: case TYPE_DISK:
acb->task->cdb_size = 16; iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
acb->task->cdb[0] = 0x88; num_sectors * iscsilun->block_size,
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32); iscsilun->block_size, 0, 0, 0, 0, 0,
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff); iscsi_co_generic_cb, &iTask);
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
break; break;
default: default:
acb->task->cdb_size = 10; iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba,
acb->task->cdb[0] = 0x28; num_sectors * iscsilun->block_size,
*(uint32_t *)&acb->task->cdb[2] = htonl(lba); iscsilun->block_size, 0, 0, 0, 0, 0,
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors); iscsi_co_generic_cb, &iTask);
break; break;
} }
if (iTask.task == NULL) {
ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, return -EIO;
iscsi_aio_read16_cb,
NULL,
acb);
if (ret != 0) {
scsi_free_scsi_task(acb->task);
return -1;
} }
#if defined(LIBISCSI_FEATURE_IOVECTOR) #if defined(LIBISCSI_FEATURE_IOVECTOR)
scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov); scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
#else #else
for (i = 0; i < acb->qiov->niov; i++) { for (i = 0; i < iov->niov; i++) {
scsi_task_add_data_in_buffer(acb->task, scsi_task_add_data_in_buffer(iTask.task,
acb->qiov->iov[i].iov_len, iov->iov[i].iov_len,
acb->qiov->iov[i].iov_base); iov->iov[i].iov_base);
} }
#endif #endif
return 0;
}
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
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); while (!iTask.complete) {
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb); iscsi_set_events(iscsilun);
qemu_coroutine_yield();
acb->nb_sectors = nb_sectors;
acb->sector_num = sector_num;
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->retries = ISCSI_CMD_RETRIES;
if (iscsi_aio_readv_acb(acb) != 0) {
qemu_aio_release(acb);
return NULL;
} }
iscsi_set_events(iscsilun); if (iTask.task != NULL) {
return &acb->common; scsi_free_scsi_task(iTask.task);
} iTask.task = NULL;
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb);
static void
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
if (acb->canceled != 0) {
return;
} }
acb->status = 0; if (iTask.do_retry) {
if (status != 0) { goto retry;
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_flush_acb(acb) == 0) {
iscsi_set_events(acb->iscsilun);
return;
}
}
error_report("Failed to sync10 data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
} }
iscsi_schedule_bh(acb); if (iTask.status != SCSI_STATUS_GOOD) {
} return -EIO;
static int
iscsi_aio_flush_acb(IscsiAIOCB *acb)
{
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
acb->canceled = 0;
acb->bh = NULL;
acb->status = -EINPROGRESS;
acb->buf = NULL;
acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun,
0, 0, 0, 0,
iscsi_synccache10_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send synchronizecache10 command. %s",
iscsi_get_error(iscsi));
return -1;
} }
return 0; return 0;
} }
static BlockDriverAIOCB * static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{ {
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
struct IscsiTask iTask;
IscsiAIOCB *acb; iscsi_co_init_iscsitask(iscsilun, &iTask);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); retry:
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
0, iscsi_co_generic_cb, &iTask) == NULL) {
return -EIO;
}
acb->iscsilun = iscsilun; while (!iTask.complete) {
acb->retries = ISCSI_CMD_RETRIES; iscsi_set_events(iscsilun);
qemu_coroutine_yield();
}
if (iscsi_aio_flush_acb(acb) != 0) { if (iTask.task != NULL) {
qemu_aio_release(acb); scsi_free_scsi_task(iTask.task);
return NULL; iTask.task = NULL;
} }
iscsi_set_events(iscsilun); if (iTask.do_retry) {
goto retry;
}
return &acb->common; if (iTask.status != SCSI_STATUS_GOOD) {
return -EIO;
}
return 0;
} }
#ifdef __linux__ #ifdef __linux__
...@@ -1624,10 +1434,9 @@ static BlockDriver bdrv_iscsi = { ...@@ -1624,10 +1434,9 @@ static BlockDriver bdrv_iscsi = {
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED) #if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
.bdrv_co_write_zeroes = iscsi_co_write_zeroes, .bdrv_co_write_zeroes = iscsi_co_write_zeroes,
#endif #endif
.bdrv_co_readv = iscsi_co_readv,
.bdrv_aio_readv = iscsi_aio_readv, .bdrv_co_writev = iscsi_co_writev,
.bdrv_aio_writev = iscsi_aio_writev, .bdrv_co_flush_to_disk = iscsi_co_flush,
.bdrv_aio_flush = iscsi_aio_flush,
#ifdef __linux__ #ifdef __linux__
.bdrv_ioctl = iscsi_ioctl, .bdrv_ioctl = iscsi_ioctl,
......
...@@ -3025,13 +3025,13 @@ fi ...@@ -3025,13 +3025,13 @@ fi
########################################## ##########################################
# Do we have libiscsi # Do we have libiscsi
# We check for iscsi_unmap_sync() to make sure we have a # We check for iscsi_write16_sync() to make sure we have a
# recent enough version of libiscsi. # at least version 1.4.0 of libiscsi.
if test "$libiscsi" != "no" ; then if test "$libiscsi" != "no" ; then
cat > $TMPC << EOF cat > $TMPC << EOF
#include <stdio.h> #include <stdio.h>
#include <iscsi/iscsi.h> #include <iscsi/iscsi.h>
int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; } int main(void) { iscsi_write16_sync(NULL,0,0,NULL,0,0,0,0,0,0,0); return 0; }
EOF EOF
if $pkg_config --atleast-version=1.7.0 libiscsi; then if $pkg_config --atleast-version=1.7.0 libiscsi; then
libiscsi="yes" libiscsi="yes"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册