Merge remote-tracking branch 'bonzini/scsi-next' into staging
# By Peter Lieven (4) and Ronnie Sahlberg (1) # Via Paolo Bonzini * bonzini/scsi-next: iscsi: factor out sector conversions iscsi: assert that sectors are aligned to LUN blocksize iscsi: remove support for misaligned nb_sectors in aio_readv iscsi: fix -ENOSPC in iscsi_create() Fix iSCSI crash on SG_IO with an iovector Message-id: 1374073524-8469-1-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
commit
5ab4dba4da
@ -32,6 +32,7 @@
|
|||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "block/scsi.h"
|
#include "block/scsi.h"
|
||||||
|
#include "qemu/iov.h"
|
||||||
|
|
||||||
#include <iscsi/iscsi.h>
|
#include <iscsi/iscsi.h>
|
||||||
#include <iscsi/scsi-lowlevel.h>
|
#include <iscsi/scsi-lowlevel.h>
|
||||||
@ -61,8 +62,6 @@ typedef struct IscsiAIOCB {
|
|||||||
int status;
|
int status;
|
||||||
int canceled;
|
int canceled;
|
||||||
int retries;
|
int retries;
|
||||||
size_t read_size;
|
|
||||||
size_t read_offset;
|
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
int nb_sectors;
|
int nb_sectors;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -233,11 +232,28 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
|
|||||||
iscsi_schedule_bh(acb);
|
iscsi_schedule_bh(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
|
||||||
|
{
|
||||||
|
return sector * iscsilun->block_size / BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
|
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
|
||||||
{
|
{
|
||||||
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
|
return sector * BDRV_SECTOR_SIZE / iscsilun->block_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
|
static int
|
||||||
iscsi_aio_writev_acb(IscsiAIOCB *acb)
|
iscsi_aio_writev_acb(IscsiAIOCB *acb)
|
||||||
{
|
{
|
||||||
@ -285,7 +301,7 @@ iscsi_aio_writev_acb(IscsiAIOCB *acb)
|
|||||||
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
|
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
|
||||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
||||||
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
|
*(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);
|
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||||
acb->task->expxferlen = size;
|
acb->task->expxferlen = size;
|
||||||
|
|
||||||
@ -322,6 +338,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
IscsiAIOCB *acb;
|
IscsiAIOCB *acb;
|
||||||
|
|
||||||
|
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||||
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
|
trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
|
||||||
|
|
||||||
@ -379,6 +399,7 @@ static int
|
|||||||
iscsi_aio_readv_acb(IscsiAIOCB *acb)
|
iscsi_aio_readv_acb(IscsiAIOCB *acb)
|
||||||
{
|
{
|
||||||
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
|
struct iscsi_context *iscsi = acb->iscsilun->iscsi;
|
||||||
|
size_t size;
|
||||||
uint64_t lba;
|
uint64_t lba;
|
||||||
uint32_t num_sectors;
|
uint32_t num_sectors;
|
||||||
int ret;
|
int ret;
|
||||||
@ -391,20 +412,7 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
|
|||||||
acb->status = -EINPROGRESS;
|
acb->status = -EINPROGRESS;
|
||||||
acb->buf = NULL;
|
acb->buf = NULL;
|
||||||
|
|
||||||
/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
|
size = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
* 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;
|
|
||||||
|
|
||||||
acb->task = malloc(sizeof(struct scsi_task));
|
acb->task = malloc(sizeof(struct scsi_task));
|
||||||
if (acb->task == NULL) {
|
if (acb->task == NULL) {
|
||||||
@ -415,8 +423,9 @@ iscsi_aio_readv_acb(IscsiAIOCB *acb)
|
|||||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||||
|
|
||||||
acb->task->xfer_dir = SCSI_XFER_READ;
|
acb->task->xfer_dir = SCSI_XFER_READ;
|
||||||
|
acb->task->expxferlen = size;
|
||||||
lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
|
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) {
|
switch (acb->iscsilun->type) {
|
||||||
case TYPE_DISK:
|
case TYPE_DISK:
|
||||||
@ -464,6 +473,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
IscsiAIOCB *acb;
|
IscsiAIOCB *acb;
|
||||||
|
|
||||||
|
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||||
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
|
trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
|
||||||
|
|
||||||
@ -471,7 +484,6 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
acb->sector_num = sector_num;
|
acb->sector_num = sector_num;
|
||||||
acb->iscsilun = iscsilun;
|
acb->iscsilun = iscsilun;
|
||||||
acb->qiov = qiov;
|
acb->qiov = qiov;
|
||||||
acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors;
|
|
||||||
acb->retries = ISCSI_CMD_RETRIES;
|
acb->retries = ISCSI_CMD_RETRIES;
|
||||||
|
|
||||||
if (iscsi_aio_readv_acb(acb) != 0) {
|
if (iscsi_aio_readv_acb(acb) != 0) {
|
||||||
@ -651,6 +663,9 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
|
|||||||
{
|
{
|
||||||
IscsiAIOCB *acb = opaque;
|
IscsiAIOCB *acb = opaque;
|
||||||
|
|
||||||
|
g_free(acb->buf);
|
||||||
|
acb->buf = NULL;
|
||||||
|
|
||||||
if (acb->canceled != 0) {
|
if (acb->canceled != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -727,14 +742,30 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
memcpy(&acb->task->cdb[0], acb->ioh->cmdp, acb->ioh->cmd_len);
|
memcpy(&acb->task->cdb[0], acb->ioh->cmdp, acb->ioh->cmd_len);
|
||||||
acb->task->expxferlen = acb->ioh->dxfer_len;
|
acb->task->expxferlen = acb->ioh->dxfer_len;
|
||||||
|
|
||||||
|
data.size = 0;
|
||||||
if (acb->task->xfer_dir == SCSI_XFER_WRITE) {
|
if (acb->task->xfer_dir == SCSI_XFER_WRITE) {
|
||||||
|
if (acb->ioh->iovec_count == 0) {
|
||||||
data.data = acb->ioh->dxferp;
|
data.data = acb->ioh->dxferp;
|
||||||
data.size = acb->ioh->dxfer_len;
|
data.size = acb->ioh->dxfer_len;
|
||||||
|
} else {
|
||||||
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
|
scsi_task_set_iov_out(acb->task,
|
||||||
|
(struct scsi_iovec *) acb->ioh->dxferp,
|
||||||
|
acb->ioh->iovec_count);
|
||||||
|
#else
|
||||||
|
struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
|
||||||
|
|
||||||
|
acb->buf = g_malloc(acb->ioh->dxfer_len);
|
||||||
|
data.data = acb->buf;
|
||||||
|
data.size = iov_to_buf(iov, acb->ioh->iovec_count, 0,
|
||||||
|
acb->buf, acb->ioh->dxfer_len);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||||
iscsi_aio_ioctl_cb,
|
iscsi_aio_ioctl_cb,
|
||||||
(acb->task->xfer_dir == SCSI_XFER_WRITE) ?
|
(data.size > 0) ? &data : NULL,
|
||||||
&data : NULL,
|
|
||||||
acb) != 0) {
|
acb) != 0) {
|
||||||
scsi_free_scsi_task(acb->task);
|
scsi_free_scsi_task(acb->task);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_release(acb);
|
||||||
@ -743,9 +774,26 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* tell libiscsi to read straight into the buffer we got from ioctl */
|
/* tell libiscsi to read straight into the buffer we got from ioctl */
|
||||||
if (acb->task->xfer_dir == SCSI_XFER_READ) {
|
if (acb->task->xfer_dir == SCSI_XFER_READ) {
|
||||||
|
if (acb->ioh->iovec_count == 0) {
|
||||||
scsi_task_add_data_in_buffer(acb->task,
|
scsi_task_add_data_in_buffer(acb->task,
|
||||||
acb->ioh->dxfer_len,
|
acb->ioh->dxfer_len,
|
||||||
acb->ioh->dxferp);
|
acb->ioh->dxferp);
|
||||||
|
} else {
|
||||||
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
|
scsi_task_set_iov_in(acb->task,
|
||||||
|
(struct scsi_iovec *) acb->ioh->dxferp,
|
||||||
|
acb->ioh->iovec_count);
|
||||||
|
#else
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < acb->ioh->iovec_count; i++) {
|
||||||
|
struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
|
||||||
|
|
||||||
|
scsi_task_add_data_in_buffer(acb->task,
|
||||||
|
iov[i].iov_len,
|
||||||
|
iov[i].iov_base);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iscsi_set_events(iscsilun);
|
iscsi_set_events(iscsilun);
|
||||||
@ -1118,8 +1166,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
|
|||||||
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs->total_sectors = iscsilun->num_blocks *
|
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||||
iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
|
||||||
|
|
||||||
/* Medium changer or tape. We dont have any emulation for this so this must
|
/* 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
|
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||||||
@ -1235,6 +1282,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
|
|||||||
}
|
}
|
||||||
if (bs.total_sectors < total_size) {
|
if (bs.total_sectors < total_size) {
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user