X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=block%2Fiscsi.c;h=6d0035d4b981bfeeb6f756be36fb15b2bc684f77;hb=cc9743c236cce8a35449e3ef67140287b68bb705;hp=b5f7a228b97ff513155bf0fb6e076b02c0350edb;hpb=84e3d0725b06bdf8c6985788caa7776d6b7353ce;p=qmiga%2Fqemu.git diff --git a/block/iscsi.c b/block/iscsi.c index b5f7a228b9..6d0035d4b9 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2,7 +2,7 @@ * QEMU Block driver for iSCSI images * * Copyright (c) 2010-2011 Ronnie Sahlberg - * Copyright (c) 2012-2016 Peter Lieven + * Copyright (c) 2012-2017 Peter Lieven * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,21 +28,28 @@ #include #include #include -#include "qemu-common.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/bitops.h" #include "qemu/bitmap.h" #include "block/block_int.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "qemu/iov.h" +#include "qemu/option.h" #include "qemu/uuid.h" -#include "qmp-commands.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" #include "crypto/secret.h" +#include "scsi/utils.h" +/* Conflict between scsi/utils.h and libiscsi! :( */ +#define SCSI_XFER_NONE ISCSI_XFER_NONE #include #include +#undef SCSI_XFER_NONE +QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE); #ifdef __linux__ #include @@ -61,6 +68,7 @@ typedef struct IscsiLun { QemuMutex mutex; struct scsi_inquiry_logical_block_provisioning lbp; struct scsi_inquiry_block_limits bl; + struct scsi_inquiry_device_designator *dd; unsigned char *zeroblock; /* The allocmap tracks which clusters (pages) on the iSCSI target are * allocated and which are not. In case a target returns zeros for @@ -79,7 +87,7 @@ typedef struct IscsiLun { unsigned long *allocmap; unsigned long *allocmap_valid; long allocmap_size; - int cluster_sectors; + int cluster_size; bool use_16_for_rw; bool write_protected; bool lbpme; @@ -99,6 +107,7 @@ typedef struct IscsiTask { IscsiLun *iscsilun; QEMUTimer retry_timer; int err_code; + char *err_str; } IscsiTask; typedef struct IscsiAIOCB { @@ -209,47 +218,9 @@ static inline unsigned exp_random(double mean) static int iscsi_translate_sense(struct scsi_sense *sense) { - int ret; - - switch (sense->key) { - case SCSI_SENSE_NOT_READY: - return -EBUSY; - case SCSI_SENSE_DATA_PROTECTION: - return -EACCES; - case SCSI_SENSE_COMMAND_ABORTED: - return -ECANCELED; - case SCSI_SENSE_ILLEGAL_REQUEST: - /* Parse ASCQ */ - break; - default: - return -EIO; - } - switch (sense->ascq) { - case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR: - case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE: - case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB: - case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST: - ret = -EINVAL; - break; - case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE: - ret = -ENOSPC; - break; - case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED: - ret = -ENOTSUP; - break; - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT: - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED: - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN: - ret = -ENOMEDIUM; - break; - case SCSI_SENSE_ASCQ_WRITE_PROTECTED: - ret = -EACCES; - break; - default: - ret = -EIO; - break; - } - return ret; + return - scsi_sense_to_errno(sense->key, + (sense->ascq & 0xFF00) >> 8, + sense->ascq & 0xFF); } /* Called (via iscsi_service) with QemuMutex held. */ @@ -298,7 +269,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, } } iTask->err_code = iscsi_translate_sense(&task->sense); - error_report("iSCSI Failure: %s", iscsi_get_error(iscsi)); + iTask->err_str = g_strdup(iscsi_get_error(iscsi)); } out: @@ -460,9 +431,10 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags) { iscsi_allocmap_free(iscsilun); + assert(iscsilun->cluster_size); iscsilun->allocmap_size = - DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks, iscsilun), - iscsilun->cluster_sectors); + DIV_ROUND_UP(iscsilun->num_blocks * iscsilun->block_size, + iscsilun->cluster_size); iscsilun->allocmap = bitmap_try_new(iscsilun->allocmap_size); if (!iscsilun->allocmap) { @@ -470,7 +442,7 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags) } if (open_flags & BDRV_O_NOCACHE) { - /* in case that cache.direct = on all allocmap entries are + /* when cache.direct = on all allocmap entries are * treated as invalid to force a relookup of the block * status on every read request */ return 0; @@ -487,8 +459,8 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags) } static void -iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num, - int nb_sectors, bool allocated, bool valid) +iscsi_allocmap_update(IscsiLun *iscsilun, int64_t offset, + int64_t bytes, bool allocated, bool valid) { int64_t cl_num_expanded, nb_cls_expanded, cl_num_shrunk, nb_cls_shrunk; @@ -496,13 +468,13 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num, return; } /* expand to entirely contain all affected clusters */ - cl_num_expanded = sector_num / iscsilun->cluster_sectors; - nb_cls_expanded = DIV_ROUND_UP(sector_num + nb_sectors, - iscsilun->cluster_sectors) - cl_num_expanded; + assert(iscsilun->cluster_size); + cl_num_expanded = offset / iscsilun->cluster_size; + nb_cls_expanded = DIV_ROUND_UP(offset + bytes, + iscsilun->cluster_size) - cl_num_expanded; /* shrink to touch only completely contained clusters */ - cl_num_shrunk = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors); - nb_cls_shrunk = (sector_num + nb_sectors) / iscsilun->cluster_sectors - - cl_num_shrunk; + cl_num_shrunk = DIV_ROUND_UP(offset, iscsilun->cluster_size); + nb_cls_shrunk = (offset + bytes) / iscsilun->cluster_size - cl_num_shrunk; if (allocated) { bitmap_set(iscsilun->allocmap, cl_num_expanded, nb_cls_expanded); } else { @@ -525,26 +497,26 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num, } static void -iscsi_allocmap_set_allocated(IscsiLun *iscsilun, int64_t sector_num, - int nb_sectors) +iscsi_allocmap_set_allocated(IscsiLun *iscsilun, int64_t offset, + int64_t bytes) { - iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, true, true); + iscsi_allocmap_update(iscsilun, offset, bytes, true, true); } static void -iscsi_allocmap_set_unallocated(IscsiLun *iscsilun, int64_t sector_num, - int nb_sectors) +iscsi_allocmap_set_unallocated(IscsiLun *iscsilun, int64_t offset, + int64_t bytes) { /* Note: if cache.direct=on the fifth argument to iscsi_allocmap_update * is ignored, so this will in effect be an iscsi_allocmap_set_invalid. */ - iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, false, true); + iscsi_allocmap_update(iscsilun, offset, bytes, false, true); } -static void iscsi_allocmap_set_invalid(IscsiLun *iscsilun, int64_t sector_num, - int nb_sectors) +static void iscsi_allocmap_set_invalid(IscsiLun *iscsilun, int64_t offset, + int64_t bytes) { - iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, false, false); + iscsi_allocmap_update(iscsilun, offset, bytes, false, false); } static void iscsi_allocmap_invalidate(IscsiLun *iscsilun) @@ -558,33 +530,35 @@ static void iscsi_allocmap_invalidate(IscsiLun *iscsilun) } static inline bool -iscsi_allocmap_is_allocated(IscsiLun *iscsilun, int64_t sector_num, - int nb_sectors) +iscsi_allocmap_is_allocated(IscsiLun *iscsilun, int64_t offset, + int64_t bytes) { unsigned long size; if (iscsilun->allocmap == NULL) { return true; } - size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors); + assert(iscsilun->cluster_size); + size = DIV_ROUND_UP(offset + bytes, iscsilun->cluster_size); return !(find_next_bit(iscsilun->allocmap, size, - sector_num / iscsilun->cluster_sectors) == size); + offset / iscsilun->cluster_size) == size); } static inline bool iscsi_allocmap_is_valid(IscsiLun *iscsilun, - int64_t sector_num, int nb_sectors) + int64_t offset, int64_t bytes) { unsigned long size; if (iscsilun->allocmap_valid == NULL) { return false; } - size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors); + assert(iscsilun->cluster_size); + size = DIV_ROUND_UP(offset + bytes, iscsilun->cluster_size); return (find_next_zero_bit(iscsilun->allocmap_valid, size, - sector_num / iscsilun->cluster_sectors) == size); + offset / iscsilun->cluster_size) == size); } static int coroutine_fn -iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors, - QEMUIOVector *iov, int flags) +iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + QEMUIOVector *iov, int flags) { IscsiLun *iscsilun = bs->opaque; struct IscsiTask iTask; @@ -661,53 +635,60 @@ retry: } if (iTask.status != SCSI_STATUS_GOOD) { - iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors); + iscsi_allocmap_set_invalid(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba, + iTask.err_str); r = iTask.err_code; goto out_unlock; } - iscsi_allocmap_set_allocated(iscsilun, sector_num, nb_sectors); + iscsi_allocmap_set_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } -static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, - int64_t sector_num, - int nb_sectors, int *pnum, - BlockDriverState **file) +static int coroutine_fn iscsi_co_block_status(BlockDriverState *bs, + bool want_zero, int64_t offset, + int64_t bytes, int64_t *pnum, + int64_t *map, + BlockDriverState **file) { IscsiLun *iscsilun = bs->opaque; struct scsi_get_lba_status *lbas = NULL; struct scsi_lba_status_descriptor *lbasd = NULL; struct IscsiTask iTask; - int64_t ret; + uint64_t lba; + int ret; iscsi_co_init_iscsitask(iscsilun, &iTask); - if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { - ret = -EINVAL; - goto out; - } + assert(QEMU_IS_ALIGNED(offset | bytes, iscsilun->block_size)); /* default to all sectors allocated */ - ret = BDRV_BLOCK_DATA; - ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID; - *pnum = nb_sectors; + ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; + if (map) { + *map = offset; + } + *pnum = bytes; /* LUN does not support logical block provisioning */ if (!iscsilun->lbpme) { goto out; } + lba = offset / iscsilun->block_size; + qemu_mutex_lock(&iscsilun->mutex); retry: if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun, - sector_qemu2lun(sector_num, iscsilun), - 8 + 16, iscsi_co_generic_cb, + lba, 8 + 16, iscsi_co_generic_cb, &iTask) == NULL) { ret = -ENOMEM; goto out_unlock; @@ -734,6 +715,8 @@ retry: * because the device is busy or the cmd is not * supported) we pretend all blocks are allocated * for backwards compatibility */ + error_report("iSCSI GET_LBA_STATUS failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); goto out_unlock; } @@ -745,12 +728,12 @@ retry: lbasd = &lbas->descriptors[0]; - if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) { + if (lba != lbasd->lba) { ret = -EIO; goto out_unlock; } - *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun); + *pnum = lbasd->num_blocks * iscsilun->block_size; if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED || lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) { @@ -761,21 +744,22 @@ retry: } if (ret & BDRV_BLOCK_ZERO) { - iscsi_allocmap_set_unallocated(iscsilun, sector_num, *pnum); + iscsi_allocmap_set_unallocated(iscsilun, offset, *pnum); } else { - iscsi_allocmap_set_allocated(iscsilun, sector_num, *pnum); + iscsi_allocmap_set_allocated(iscsilun, offset, *pnum); } - if (*pnum > nb_sectors) { - *pnum = nb_sectors; + if (*pnum > bytes) { + *pnum = bytes; } out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); out: if (iTask.task != NULL) { scsi_free_scsi_task(iTask.task); } - if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) { + if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID && file) { *file = bs; } return ret; @@ -789,6 +773,7 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, struct IscsiTask iTask; uint64_t lba; uint32_t num_sectors; + int r = 0; if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { return -EINVAL; @@ -801,29 +786,37 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, /* if cache.direct is off and we have a valid entry in our allocation map * we can skip checking the block status and directly return zeroes if * the request falls within an unallocated area */ - if (iscsi_allocmap_is_valid(iscsilun, sector_num, nb_sectors) && - !iscsi_allocmap_is_allocated(iscsilun, sector_num, nb_sectors)) { + if (iscsi_allocmap_is_valid(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE) && + !iscsi_allocmap_is_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE)) { qemu_iovec_memset(iov, 0, 0x00, iov->size); return 0; } if (nb_sectors >= ISCSI_CHECKALLOC_THRES && - !iscsi_allocmap_is_valid(iscsilun, sector_num, nb_sectors) && - !iscsi_allocmap_is_allocated(iscsilun, sector_num, nb_sectors)) { - int pnum; - BlockDriverState *file; + !iscsi_allocmap_is_valid(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE) && + !iscsi_allocmap_is_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE)) { + int64_t pnum; /* check the block status from the beginning of the cluster * containing the start sector */ - int64_t ret = iscsi_co_get_block_status(bs, - sector_num - sector_num % iscsilun->cluster_sectors, - BDRV_REQUEST_MAX_SECTORS, &pnum, &file); + int64_t head; + int ret; + + assert(iscsilun->cluster_size); + head = (sector_num * BDRV_SECTOR_SIZE) % iscsilun->cluster_size; + ret = iscsi_co_block_status(bs, true, + sector_num * BDRV_SECTOR_SIZE - head, + BDRV_REQUEST_MAX_BYTES, &pnum, NULL, NULL); if (ret < 0) { return ret; } /* if the whole request falls into an unallocated area we can avoid - * to read and directly return zeroes instead */ + * reading and directly return zeroes instead */ if (ret & BDRV_BLOCK_ZERO && - pnum >= nb_sectors + sector_num % iscsilun->cluster_sectors) { + pnum >= nb_sectors * BDRV_SECTOR_SIZE + head) { qemu_iovec_memset(iov, 0, 0x00, iov->size); return 0; } @@ -886,19 +879,23 @@ retry: iTask.complete = 0; goto retry; } - qemu_mutex_unlock(&iscsilun->mutex); if (iTask.status != SCSI_STATUS_GOOD) { - return iTask.err_code; + error_report("iSCSI READ10/16 failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); + r = iTask.err_code; } - return 0; + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; } static int coroutine_fn iscsi_co_flush(BlockDriverState *bs) { IscsiLun *iscsilun = bs->opaque; struct IscsiTask iTask; + int r = 0; iscsi_co_init_iscsitask(iscsilun, &iTask); qemu_mutex_lock(&iscsilun->mutex); @@ -925,13 +922,15 @@ retry: iTask.complete = 0; goto retry; } - qemu_mutex_unlock(&iscsilun->mutex); if (iTask.status != SCSI_STATUS_GOOD) { - return iTask.err_code; + error_report("iSCSI SYNCHRONIZECACHE10 failed: %s", iTask.err_str); + r = iTask.err_code; } - return 0; + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; } #ifdef __linux__ @@ -1116,14 +1115,14 @@ iscsi_getlength(BlockDriverState *bs) } static int -coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) +coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes) { IscsiLun *iscsilun = bs->opaque; struct IscsiTask iTask; struct unmap_list list; int r = 0; - if (!is_byte_request_lun_aligned(offset, count, iscsilun)) { + if (!is_byte_request_lun_aligned(offset, bytes, iscsilun)) { return -ENOTSUP; } @@ -1133,7 +1132,7 @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) } list.lba = offset / iscsilun->block_size; - list.num = count / iscsilun->block_size; + list.num = bytes / iscsilun->block_size; iscsi_co_init_iscsitask(iscsilun, &iTask); qemu_mutex_lock(&iscsilun->mutex); @@ -1161,6 +1160,8 @@ retry: goto retry; } + iscsi_allocmap_set_invalid(iscsilun, offset, bytes); + if (iTask.status == SCSI_STATUS_CHECK_CONDITION) { /* the target might fail with a check condition if it is not happy with the alignment of the UNMAP request @@ -1169,21 +1170,21 @@ retry: } if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI UNMAP failed at lba %" PRIu64 ": %s", + list.lba, iTask.err_str); r = iTask.err_code; goto out_unlock; } - iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); - out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } static int coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - int count, BdrvRequestFlags flags) + int bytes, BdrvRequestFlags flags) { IscsiLun *iscsilun = bs->opaque; struct IscsiTask iTask; @@ -1192,7 +1193,7 @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, bool use_16_for_ws = iscsilun->use_16_for_rw; int r = 0; - if (!is_byte_request_lun_aligned(offset, count, iscsilun)) { + if (!is_byte_request_lun_aligned(offset, bytes, iscsilun)) { return -ENOTSUP; } @@ -1215,7 +1216,7 @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, } lba = offset / iscsilun->block_size; - nb_blocks = count / iscsilun->block_size; + nb_blocks = bytes / iscsilun->block_size; if (iscsilun->zeroblock == NULL) { iscsilun->zeroblock = g_try_malloc0(iscsilun->block_size); @@ -1272,22 +1273,22 @@ retry: } if (iTask.status != SCSI_STATUS_GOOD) { - iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); + iscsi_allocmap_set_invalid(iscsilun, offset, bytes); + error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); r = iTask.err_code; goto out_unlock; } if (flags & BDRV_REQ_MAY_UNMAP) { - iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); + iscsi_allocmap_set_invalid(iscsilun, offset, bytes); } else { - iscsi_allocmap_set_allocated(iscsilun, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); + iscsi_allocmap_set_allocated(iscsilun, offset, bytes); } out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } @@ -1740,6 +1741,30 @@ static QemuOptsList runtime_opts = { }, }; +static void iscsi_save_designator(IscsiLun *lun, + struct scsi_inquiry_device_identification *inq_di) +{ + struct scsi_inquiry_device_designator *desig, *copy = NULL; + + for (desig = inq_di->designators; desig; desig = desig->next) { + if (desig->association || + desig->designator_type > SCSI_DESIGNATOR_TYPE_NAA) { + continue; + } + /* NAA works better than T10 vendor ID based designator. */ + if (!copy || copy->designator_type < desig->designator_type) { + copy = desig; + } + } + if (copy) { + lun->dd = g_new(struct scsi_inquiry_device_designator, 1); + *lun->dd = *copy; + lun->dd->next = NULL; + lun->dd->designator = g_malloc(copy->designator_length); + memcpy(lun->dd->designator, copy->designator, copy->designator_length); + } +} + static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -1761,9 +1786,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, * filename encoded options */ filename = qdict_get_try_str(options, "filename"); if (filename) { - error_report("Warning: 'filename' option specified. " - "This is an unsupported option, and may be deprecated " - "in the future"); + warn_report("'filename' option specified. " + "This is an unsupported option, and may be deprecated " + "in the future"); iscsi_parse_filename(filename, options, &local_err); if (local_err) { ret = -EINVAL; @@ -1886,7 +1911,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, if (iscsilun->dpofua) { bs->supported_write_flags = BDRV_REQ_FUA; } - bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP; /* Check the write protect flag of the LUN if we want to write */ if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && @@ -1923,6 +1947,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, struct scsi_task *inq_task; struct scsi_inquiry_logical_block_provisioning *inq_lbp; struct scsi_inquiry_block_limits *inq_bl; + struct scsi_inquiry_device_identification *inq_di; switch (inq_vpd->pages[i]) { case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, @@ -1948,6 +1973,17 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, sizeof(struct scsi_inquiry_block_limits)); scsi_free_scsi_task(inq_task); break; + case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: + inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, + SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, + (void **) &inq_di, errp); + if (inq_task == NULL) { + ret = -EINVAL; + goto out; + } + iscsi_save_designator(iscsilun, inq_di); + scsi_free_scsi_task(inq_task); + break; default: break; } @@ -1963,13 +1999,17 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, * reasonable size */ if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 && iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) { - iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran * - iscsilun->block_size) >> BDRV_SECTOR_BITS; + iscsilun->cluster_size = iscsilun->bl.opt_unmap_gran * + iscsilun->block_size; if (iscsilun->lbprz) { ret = iscsi_allocmap_init(iscsilun, bs->open_flags); } } + if (iscsilun->lbprz && iscsilun->lbp.lbpws) { + bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP; + } + out: qemu_opts_del(opts); g_free(initiator_name); @@ -2000,6 +2040,10 @@ static void iscsi_close(BlockDriverState *bs) iscsi_logout_sync(iscsi); } iscsi_destroy_context(iscsi); + if (iscsilun->dd) { + g_free(iscsilun->dd->designator); + g_free(iscsilun->dd); + } g_free(iscsilun->zeroblock); iscsi_allocmap_free(iscsilun); qemu_mutex_destroy(&iscsilun->mutex); @@ -2079,11 +2123,18 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state) } } -static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp) +static int iscsi_truncate(BlockDriverState *bs, int64_t offset, + PreallocMode prealloc, Error **errp) { IscsiLun *iscsilun = bs->opaque; Error *local_err = NULL; + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_str(prealloc)); + return -ENOTSUP; + } + if (iscsilun->type != TYPE_DISK) { error_setg(errp, "Cannot resize non-disk iSCSI devices"); return -ENOTSUP; @@ -2107,7 +2158,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp) return 0; } -static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp) +static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts, + Error **errp) { int ret = 0; int64_t total_size = 0; @@ -2132,7 +2184,7 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp) } else { ret = iscsi_open(bs, bs_options, 0, NULL); } - QDECREF(bs_options); + qobject_unref(bs_options); if (ret != 0) { goto out; @@ -2162,13 +2214,12 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { IscsiLun *iscsilun = bs->opaque; bdi->unallocated_blocks_are_zero = iscsilun->lbprz; - bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws; - bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE; + bdi->cluster_size = iscsilun->cluster_size; return 0; } -static void iscsi_invalidate_cache(BlockDriverState *bs, - Error **errp) +static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs, + Error **errp) { IscsiLun *iscsilun = bs->opaque; iscsi_allocmap_invalidate(iscsilun); @@ -2195,22 +2246,22 @@ static BlockDriver bdrv_iscsi = { .bdrv_parse_filename = iscsi_parse_filename, .bdrv_file_open = iscsi_open, .bdrv_close = iscsi_close, - .bdrv_create = iscsi_create, + .bdrv_co_create_opts = iscsi_co_create_opts, .create_opts = &iscsi_create_opts, .bdrv_reopen_prepare = iscsi_reopen_prepare, .bdrv_reopen_commit = iscsi_reopen_commit, - .bdrv_invalidate_cache = iscsi_invalidate_cache, + .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, .bdrv_getlength = iscsi_getlength, .bdrv_get_info = iscsi_get_info, .bdrv_truncate = iscsi_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, - .bdrv_co_get_block_status = iscsi_co_get_block_status, + .bdrv_co_block_status = iscsi_co_block_status, .bdrv_co_pdiscard = iscsi_co_pdiscard, .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes, .bdrv_co_readv = iscsi_co_readv, - .bdrv_co_writev_flags = iscsi_co_writev_flags, + .bdrv_co_writev = iscsi_co_writev, .bdrv_co_flush_to_disk = iscsi_co_flush, #ifdef __linux__ @@ -2230,22 +2281,22 @@ static BlockDriver bdrv_iser = { .bdrv_parse_filename = iscsi_parse_filename, .bdrv_file_open = iscsi_open, .bdrv_close = iscsi_close, - .bdrv_create = iscsi_create, + .bdrv_co_create_opts = iscsi_co_create_opts, .create_opts = &iscsi_create_opts, .bdrv_reopen_prepare = iscsi_reopen_prepare, .bdrv_reopen_commit = iscsi_reopen_commit, - .bdrv_invalidate_cache = iscsi_invalidate_cache, + .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, .bdrv_getlength = iscsi_getlength, .bdrv_get_info = iscsi_get_info, .bdrv_truncate = iscsi_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, - .bdrv_co_get_block_status = iscsi_co_get_block_status, + .bdrv_co_block_status = iscsi_co_block_status, .bdrv_co_pdiscard = iscsi_co_pdiscard, .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes, .bdrv_co_readv = iscsi_co_readv, - .bdrv_co_writev_flags = iscsi_co_writev_flags, + .bdrv_co_writev = iscsi_co_writev, .bdrv_co_flush_to_disk = iscsi_co_flush, #ifdef __linux__