Block layer patches

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJZLDGTAAoJEH8JsnLIjy/WjY0P/jtXF+SQKs9H695Uy+U+EUr5
 9w+lYTfjHXTUx9F5AKT4OAMww/uWSG5ywG8FZD8AJZyt1B8piDrSA7sW5YYgWCV4
 XD1HMzN6pasVGrchzgfBSW/K9BgUlvBEjqFrLCNVii0osa68J7vX3uJsLyRA+yPo
 ijFseJaB/b0KnAPG9JqHXc4DVQgU2IhZH3ZsgE6Utb+KUrm8/veiORhWQboBbfCW
 eyTF+YWee/rI+up4nKn9+Le57EUXWr3Y50BBxFZw1/4wQbv0WEhOIbl/Z4ggxNRR
 VoyXGMqOIZFlGQ7bGxDawuEwGKfcOFFEHj3rhPrs7RPnod/6X8Vxm0rAr2GNZoOW
 9tLMQKe4HLo3kVwX65AhzWd/WMukAd0MC/0oaULOjiAEdlWjflyEhx9H9uYefl5x
 kn77ZqQqIEL4aCYRBLJn9oJV3CIZbSd6cuKC9UPuXAwD8XDWTXUzT/aDMJUnfij7
 vhS1qks1Wyk37wIjTuuERwrr0K6y8e3De30NeU6LqQuzXvJ1MYSp49BA1FCgHfmT
 x5RWbTSjLdjZiIo7biE2dSwdOtsxsnuxX19utqfGqOmegNU7LykRtu6mFh9kJhNe
 5ladt1Mu//puZLQ/q4RH/J0pwkuS/OVrS3LBobcggPGHhUIiHhdNUI73bb7BK0+9
 ME5DGLm4/c/REB3Lidr9
 =kkU0
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'kwolf/tags/for-upstream' into staging

Block layer patches

# gpg: Signature made Mon 29 May 2017 03:34:59 PM BST
# gpg:                using RSA key 0x7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* kwolf/tags/for-upstream:
  block/file-*: *_parse_filename() and colons
  block: Fix backing paths for filenames with colons
  block: Tweak error message related to qemu-img amend
  qemu-img: Fix leakage of options on error
  qemu-img: copy *key-secret opts when opening newly created files
  qemu-img: introduce --target-image-opts for 'convert' command
  qemu-img: fix --image-opts usage with dd command
  qemu-img: add support for --object with 'dd' command
  qemu-img: Fix documentation of convert
  qcow2: remove extra local_error variable
  mirror: Drop permissions on s->target on completion
  nvme: Add support for Controller Memory Buffers
  iotests: 147: Don't test inet6 if not available
  qemu-iotests: Test streaming with missing job ID
  stream: fix crash in stream_start() when block_job_create() fails

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2017-05-30 14:15:15 +01:00
commit 0748b3526e
17 changed files with 352 additions and 78 deletions

50
block.c
View File

@ -163,11 +163,16 @@ void path_combine(char *dest, int dest_size,
if (path_is_absolute(filename)) { if (path_is_absolute(filename)) {
pstrcpy(dest, dest_size, filename); pstrcpy(dest, dest_size, filename);
} else { } else {
p = strchr(base_path, ':'); const char *protocol_stripped = NULL;
if (p)
p++; if (path_has_protocol(base_path)) {
else protocol_stripped = strchr(base_path, ':');
p = base_path; if (protocol_stripped) {
protocol_stripped++;
}
}
p = protocol_stripped ?: base_path;
p1 = strrchr(base_path, '/'); p1 = strrchr(base_path, '/');
#ifdef _WIN32 #ifdef _WIN32
{ {
@ -192,6 +197,41 @@ void path_combine(char *dest, int dest_size,
} }
} }
/*
* Helper function for bdrv_parse_filename() implementations to remove optional
* protocol prefixes (especially "file:") from a filename and for putting the
* stripped filename into the options QDict if there is such a prefix.
*/
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options)
{
if (strstart(filename, prefix, &filename)) {
/* Stripping the explicit protocol prefix may result in a protocol
* prefix being (wrongly) detected (if the filename contains a colon) */
if (path_has_protocol(filename)) {
QString *fat_filename;
/* This means there is some colon before the first slash; therefore,
* this cannot be an absolute path */
assert(!path_is_absolute(filename));
/* And we can thus fix the protocol detection issue by prefixing it
* by "./" */
fat_filename = qstring_from_str("./");
qstring_append(fat_filename, filename);
assert(!path_has_protocol(qstring_get_str(fat_filename)));
qdict_put(options, "filename", fat_filename);
} else {
/* If no protocol prefix was detected, we can use the shortened
* filename as-is */
qdict_put_str(options, "filename", filename);
}
}
}
/* Returns whether the image file is opened as read-only. Note that this can /* Returns whether the image file is opened as read-only. Note that this can
* return false and writing to the image file is still not possible because the * return false and writing to the image file is still not possible because the
* image is inactivated. */ * image is inactivated. */

View File

@ -381,12 +381,7 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags)
static void raw_parse_filename(const char *filename, QDict *options, static void raw_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
/* The filename does not have to be prefixed by the protocol name, since bdrv_parse_filename_strip_prefix(filename, "file:", options);
* "file" is the default protocol; therefore, the return value of this
* function call can be ignored. */
strstart(filename, "file:", &filename);
qdict_put_str(options, "filename", filename);
} }
static QemuOptsList raw_runtime_opts = { static QemuOptsList raw_runtime_opts = {
@ -2395,10 +2390,7 @@ static int check_hdev_writable(BDRVRawState *s)
static void hdev_parse_filename(const char *filename, QDict *options, static void hdev_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
/* The prefix is optional, just as for "file". */ bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
strstart(filename, "host_device:", &filename);
qdict_put_str(options, "filename", filename);
} }
static bool hdev_is_sg(BlockDriverState *bs) static bool hdev_is_sg(BlockDriverState *bs)
@ -2697,10 +2689,7 @@ static BlockDriver bdrv_host_device = {
static void cdrom_parse_filename(const char *filename, QDict *options, static void cdrom_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
/* The prefix is optional, just as for "file". */ bdrv_parse_filename_strip_prefix(filename, "host_cdrom:", options);
strstart(filename, "host_cdrom:", &filename);
qdict_put_str(options, "filename", filename);
} }
#endif #endif

View File

@ -276,12 +276,7 @@ static void raw_parse_flags(int flags, bool use_aio, int *access_flags,
static void raw_parse_filename(const char *filename, QDict *options, static void raw_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
/* The filename does not have to be prefixed by the protocol name, since bdrv_parse_filename_strip_prefix(filename, "file:", options);
* "file" is the default protocol; therefore, the return value of this
* function call can be ignored. */
strstart(filename, "file:", &filename);
qdict_put_str(options, "filename", filename);
} }
static QemuOptsList raw_runtime_opts = { static QemuOptsList raw_runtime_opts = {
@ -671,10 +666,7 @@ static int hdev_probe_device(const char *filename)
static void hdev_parse_filename(const char *filename, QDict *options, static void hdev_parse_filename(const char *filename, QDict *options,
Error **errp) Error **errp)
{ {
/* The prefix is optional, just as for "file". */ bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
strstart(filename, "host_device:", &filename);
qdict_put_str(options, "filename", filename);
} }
static int hdev_open(BlockDriverState *bs, QDict *options, int flags, static int hdev_open(BlockDriverState *bs, QDict *options, int flags,

View File

@ -514,7 +514,12 @@ static void mirror_exit(BlockJob *job, void *opaque)
/* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before /* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
* inserting target_bs at s->to_replace, where we might not be able to get * inserting target_bs at s->to_replace, where we might not be able to get
* these permissions. */ * these permissions.
*
* Note that blk_unref() alone doesn't necessarily drop permissions because
* we might be running nested inside mirror_drain(), which takes an extra
* reference, so use an explicit blk_set_perm() first. */
blk_set_perm(s->target, 0, BLK_PERM_ALL, &error_abort);
blk_unref(s->target); blk_unref(s->target);
s->target = NULL; s->target = NULL;

View File

@ -1797,7 +1797,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
} }
if (offset_into_cluster(s, offset)) { if (offset_into_cluster(s, offset)) {
qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset " qcow2_signal_corruption(bs, true, -1, -1,
"Cluster allocation offset "
"%#" PRIx64 " unaligned (L2 offset: %#" "%#" PRIx64 " unaligned (L2 offset: %#"
PRIx64 ", L2 index: %#x)", offset, PRIx64 ", L2 index: %#x)", offset,
l2_offset, j); l2_offset, j);

View File

@ -3222,7 +3222,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
if (s->refcount_bits != refcount_bits) { if (s->refcount_bits != refcount_bits) {
int refcount_order = ctz32(refcount_bits); int refcount_order = ctz32(refcount_bits);
Error *local_error = NULL;
if (new_version < 3 && refcount_bits != 16) { if (new_version < 3 && refcount_bits != 16) {
error_report("Different refcount widths than 16 bits require " error_report("Different refcount widths than 16 bits require "
@ -3234,9 +3233,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER; helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER;
ret = qcow2_change_refcount_order(bs, refcount_order, ret = qcow2_change_refcount_order(bs, refcount_order,
&qcow2_amend_helper_cb, &qcow2_amend_helper_cb,
&helper_cb_info, &local_error); &helper_cb_info, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_error); error_report_err(local_err);
return ret; return ret;
} }
} }

View File

@ -280,6 +280,6 @@ void stream_start(const char *job_id, BlockDriverState *bs,
fail: fail:
if (orig_bs_flags != bdrv_get_flags(bs)) { if (orig_bs_flags != bdrv_get_flags(bs)) {
bdrv_reopen(bs, s->bs_flags, NULL); bdrv_reopen(bs, orig_bs_flags, NULL);
} }
} }

View File

@ -9,7 +9,7 @@
*/ */
/** /**
* Reference Specs: http://www.nvmexpress.org, 1.1, 1.0e * Reference Specs: http://www.nvmexpress.org, 1.2, 1.1, 1.0e
* *
* http://www.nvmexpress.org/resources/ * http://www.nvmexpress.org/resources/
*/ */
@ -17,7 +17,11 @@
/** /**
* Usage: add options: * Usage: add options:
* -drive file=<file>,if=none,id=<drive_id> * -drive file=<file>,if=none,id=<drive_id>
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]> * -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
* cmb_size_mb=<cmb_size_mb[optional]>
*
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
* offset 0 in BAR2 and supports SQS only for now.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
@ -34,6 +38,16 @@
static void nvme_process_sq(void *opaque); static void nvme_process_sq(void *opaque);
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
{
if (n->cmbsz && addr >= n->ctrl_mem.addr &&
addr < (n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size))) {
memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size);
} else {
pci_dma_read(&n->parent_obj, addr, buf, size);
}
}
static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid)
{ {
return sqid < n->num_queues && n->sq[sqid] != NULL ? 0 : -1; return sqid < n->num_queues && n->sq[sqid] != NULL ? 0 : -1;
@ -637,7 +651,7 @@ static void nvme_process_sq(void *opaque)
while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) { while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
addr = sq->dma_addr + sq->head * n->sqe_size; addr = sq->dma_addr + sq->head * n->sqe_size;
pci_dma_read(&n->parent_obj, addr, (void *)&cmd, sizeof(cmd)); nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd));
nvme_inc_sq_head(sq); nvme_inc_sq_head(sq);
req = QTAILQ_FIRST(&sq->req_list); req = QTAILQ_FIRST(&sq->req_list);
@ -852,6 +866,32 @@ static const MemoryRegionOps nvme_mmio_ops = {
}, },
}; };
static void nvme_cmb_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
NvmeCtrl *n = (NvmeCtrl *)opaque;
memcpy(&n->cmbuf[addr], &data, size);
}
static uint64_t nvme_cmb_read(void *opaque, hwaddr addr, unsigned size)
{
uint64_t val;
NvmeCtrl *n = (NvmeCtrl *)opaque;
memcpy(&val, &n->cmbuf[addr], size);
return val;
}
static const MemoryRegionOps nvme_cmb_ops = {
.read = nvme_cmb_read,
.write = nvme_cmb_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 2,
.max_access_size = 8,
},
};
static int nvme_init(PCIDevice *pci_dev) static int nvme_init(PCIDevice *pci_dev)
{ {
NvmeCtrl *n = NVME(pci_dev); NvmeCtrl *n = NVME(pci_dev);
@ -936,9 +976,31 @@ static int nvme_init(PCIDevice *pci_dev)
NVME_CAP_SET_CSS(n->bar.cap, 1); NVME_CAP_SET_CSS(n->bar.cap, 1);
NVME_CAP_SET_MPSMAX(n->bar.cap, 4); NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
n->bar.vs = 0x00010100; n->bar.vs = 0x00010200;
n->bar.intmc = n->bar.intms = 0; n->bar.intmc = n->bar.intms = 0;
if (n->cmb_size_mb) {
NVME_CMBLOC_SET_BIR(n->bar.cmbloc, 2);
NVME_CMBLOC_SET_OFST(n->bar.cmbloc, 0);
NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1);
NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0);
NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 0);
NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 0);
NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 0);
NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */
NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->cmb_size_mb);
n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n,
"nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
pci_register_bar(&n->parent_obj, NVME_CMBLOC_BIR(n->bar.cmbloc),
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
}
for (i = 0; i < n->num_namespaces; i++) { for (i = 0; i < n->num_namespaces; i++) {
NvmeNamespace *ns = &n->namespaces[i]; NvmeNamespace *ns = &n->namespaces[i];
NvmeIdNs *id_ns = &ns->id_ns; NvmeIdNs *id_ns = &ns->id_ns;
@ -964,12 +1026,17 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->namespaces); g_free(n->namespaces);
g_free(n->cq); g_free(n->cq);
g_free(n->sq); g_free(n->sq);
if (n->cmbsz) {
memory_region_unref(&n->ctrl_mem);
}
msix_uninit_exclusive_bar(pci_dev); msix_uninit_exclusive_bar(pci_dev);
} }
static Property nvme_props[] = { static Property nvme_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
DEFINE_PROP_STRING("serial", NvmeCtrl, serial), DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -14,6 +14,8 @@ typedef struct NvmeBar {
uint32_t aqa; uint32_t aqa;
uint64_t asq; uint64_t asq;
uint64_t acq; uint64_t acq;
uint32_t cmbloc;
uint32_t cmbsz;
} NvmeBar; } NvmeBar;
enum NvmeCapShift { enum NvmeCapShift {
@ -138,6 +140,72 @@ enum NvmeAqaMask {
#define NVME_AQA_ASQS(aqa) ((aqa >> AQA_ASQS_SHIFT) & AQA_ASQS_MASK) #define NVME_AQA_ASQS(aqa) ((aqa >> AQA_ASQS_SHIFT) & AQA_ASQS_MASK)
#define NVME_AQA_ACQS(aqa) ((aqa >> AQA_ACQS_SHIFT) & AQA_ACQS_MASK) #define NVME_AQA_ACQS(aqa) ((aqa >> AQA_ACQS_SHIFT) & AQA_ACQS_MASK)
enum NvmeCmblocShift {
CMBLOC_BIR_SHIFT = 0,
CMBLOC_OFST_SHIFT = 12,
};
enum NvmeCmblocMask {
CMBLOC_BIR_MASK = 0x7,
CMBLOC_OFST_MASK = 0xfffff,
};
#define NVME_CMBLOC_BIR(cmbloc) ((cmbloc >> CMBLOC_BIR_SHIFT) & \
CMBLOC_BIR_MASK)
#define NVME_CMBLOC_OFST(cmbloc)((cmbloc >> CMBLOC_OFST_SHIFT) & \
CMBLOC_OFST_MASK)
#define NVME_CMBLOC_SET_BIR(cmbloc, val) \
(cmbloc |= (uint64_t)(val & CMBLOC_BIR_MASK) << CMBLOC_BIR_SHIFT)
#define NVME_CMBLOC_SET_OFST(cmbloc, val) \
(cmbloc |= (uint64_t)(val & CMBLOC_OFST_MASK) << CMBLOC_OFST_SHIFT)
enum NvmeCmbszShift {
CMBSZ_SQS_SHIFT = 0,
CMBSZ_CQS_SHIFT = 1,
CMBSZ_LISTS_SHIFT = 2,
CMBSZ_RDS_SHIFT = 3,
CMBSZ_WDS_SHIFT = 4,
CMBSZ_SZU_SHIFT = 8,
CMBSZ_SZ_SHIFT = 12,
};
enum NvmeCmbszMask {
CMBSZ_SQS_MASK = 0x1,
CMBSZ_CQS_MASK = 0x1,
CMBSZ_LISTS_MASK = 0x1,
CMBSZ_RDS_MASK = 0x1,
CMBSZ_WDS_MASK = 0x1,
CMBSZ_SZU_MASK = 0xf,
CMBSZ_SZ_MASK = 0xfffff,
};
#define NVME_CMBSZ_SQS(cmbsz) ((cmbsz >> CMBSZ_SQS_SHIFT) & CMBSZ_SQS_MASK)
#define NVME_CMBSZ_CQS(cmbsz) ((cmbsz >> CMBSZ_CQS_SHIFT) & CMBSZ_CQS_MASK)
#define NVME_CMBSZ_LISTS(cmbsz)((cmbsz >> CMBSZ_LISTS_SHIFT) & CMBSZ_LISTS_MASK)
#define NVME_CMBSZ_RDS(cmbsz) ((cmbsz >> CMBSZ_RDS_SHIFT) & CMBSZ_RDS_MASK)
#define NVME_CMBSZ_WDS(cmbsz) ((cmbsz >> CMBSZ_WDS_SHIFT) & CMBSZ_WDS_MASK)
#define NVME_CMBSZ_SZU(cmbsz) ((cmbsz >> CMBSZ_SZU_SHIFT) & CMBSZ_SZU_MASK)
#define NVME_CMBSZ_SZ(cmbsz) ((cmbsz >> CMBSZ_SZ_SHIFT) & CMBSZ_SZ_MASK)
#define NVME_CMBSZ_SET_SQS(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_SQS_MASK) << CMBSZ_SQS_SHIFT)
#define NVME_CMBSZ_SET_CQS(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_CQS_MASK) << CMBSZ_CQS_SHIFT)
#define NVME_CMBSZ_SET_LISTS(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_LISTS_MASK) << CMBSZ_LISTS_SHIFT)
#define NVME_CMBSZ_SET_RDS(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_RDS_MASK) << CMBSZ_RDS_SHIFT)
#define NVME_CMBSZ_SET_WDS(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_WDS_MASK) << CMBSZ_WDS_SHIFT)
#define NVME_CMBSZ_SET_SZU(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_SZU_MASK) << CMBSZ_SZU_SHIFT)
#define NVME_CMBSZ_SET_SZ(cmbsz, val) \
(cmbsz |= (uint64_t)(val & CMBSZ_SZ_MASK) << CMBSZ_SZ_SHIFT)
#define NVME_CMBSZ_GETSIZE(cmbsz) \
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
typedef struct NvmeCmd { typedef struct NvmeCmd {
uint8_t opcode; uint8_t opcode;
uint8_t fuse; uint8_t fuse;
@ -688,6 +756,7 @@ typedef struct NvmeNamespace {
typedef struct NvmeCtrl { typedef struct NvmeCtrl {
PCIDevice parent_obj; PCIDevice parent_obj;
MemoryRegion iomem; MemoryRegion iomem;
MemoryRegion ctrl_mem;
NvmeBar bar; NvmeBar bar;
BlockConf conf; BlockConf conf;
@ -701,6 +770,10 @@ typedef struct NvmeCtrl {
uint32_t num_queues; uint32_t num_queues;
uint32_t max_q_ents; uint32_t max_q_ents;
uint64_t ns_size; uint64_t ns_size;
uint32_t cmb_size_mb;
uint32_t cmbsz;
uint32_t cmbloc;
uint8_t *cmbuf;
char *serial; char *serial;
NvmeNamespace *namespaces; NvmeNamespace *namespaces;

View File

@ -682,6 +682,9 @@ int get_tmp_filename(char *filename, int size);
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
const char *filename); const char *filename);
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options);
/** /**
* bdrv_add_before_write_notifier: * bdrv_add_before_write_notifier:

View File

@ -40,9 +40,9 @@ STEXI
ETEXI ETEXI
DEF("convert", img_convert, DEF("convert", img_convert,
"convert [--object objectdef] [--image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
STEXI STEXI
@item convert [--object @var{objectdef}] [--image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename} @item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI ETEXI
DEF("dd", img_dd, DEF("dd", img_dd,

View File

@ -60,6 +60,7 @@ enum {
OPTION_PATTERN = 260, OPTION_PATTERN = 260,
OPTION_FLUSH_INTERVAL = 261, OPTION_FLUSH_INTERVAL = 261,
OPTION_NO_DRAIN = 262, OPTION_NO_DRAIN = 262,
OPTION_TARGET_IMAGE_OPTS = 263,
}; };
typedef enum OutputFormat { typedef enum OutputFormat {
@ -294,6 +295,7 @@ static BlockBackend *img_open_opts(const char *optstr,
if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE) if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
&& !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) { && !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) {
error_report("--force-share/-U conflicts with image options"); error_report("--force-share/-U conflicts with image options");
QDECREF(options);
return NULL; return NULL;
} }
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
@ -313,14 +315,17 @@ static BlockBackend *img_open_opts(const char *optstr,
} }
static BlockBackend *img_open_file(const char *filename, static BlockBackend *img_open_file(const char *filename,
QDict *options,
const char *fmt, int flags, const char *fmt, int flags,
bool writethrough, bool quiet, bool writethrough, bool quiet,
bool force_share) bool force_share)
{ {
BlockBackend *blk; BlockBackend *blk;
Error *local_err = NULL; Error *local_err = NULL;
QDict *options = qdict_new();
if (!options) {
options = qdict_new();
}
if (fmt) { if (fmt) {
qdict_put_str(options, "driver", fmt); qdict_put_str(options, "driver", fmt);
} }
@ -343,6 +348,35 @@ static BlockBackend *img_open_file(const char *filename,
} }
static int img_add_key_secrets(void *opaque,
const char *name, const char *value,
Error **errp)
{
QDict *options = opaque;
if (g_str_has_suffix(name, "key-secret")) {
qdict_put(options, name, qstring_from_str(value));
}
return 0;
}
static BlockBackend *img_open_new_file(const char *filename,
QemuOpts *create_opts,
const char *fmt, int flags,
bool writethrough, bool quiet,
bool force_share)
{
QDict *options = NULL;
options = qdict_new();
qemu_opt_foreach(create_opts, img_add_key_secrets, options, &error_abort);
return img_open_file(filename, options, fmt, flags, writethrough, quiet,
force_share);
}
static BlockBackend *img_open(bool image_opts, static BlockBackend *img_open(bool image_opts,
const char *filename, const char *filename,
const char *fmt, int flags, bool writethrough, const char *fmt, int flags, bool writethrough,
@ -363,7 +397,7 @@ static BlockBackend *img_open(bool image_opts,
blk = img_open_opts(filename, opts, flags, writethrough, quiet, blk = img_open_opts(filename, opts, flags, writethrough, quiet,
force_share); force_share);
} else { } else {
blk = img_open_file(filename, fmt, flags, writethrough, quiet, blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet,
force_share); force_share);
} }
return blk; return blk;
@ -1913,10 +1947,10 @@ static int convert_do_copy(ImgConvertState *s)
static int img_convert(int argc, char **argv) static int img_convert(int argc, char **argv)
{ {
int c, bs_i, flags, src_flags = 0; int c, bs_i, flags, src_flags = 0;
const char *fmt = NULL, *out_fmt = "raw", *cache = "unsafe", const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL, *src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
*out_filename, *out_baseimg_param, *snapshot_name = NULL; *out_filename, *out_baseimg_param, *snapshot_name = NULL;
BlockDriver *drv, *proto_drv; BlockDriver *drv = NULL, *proto_drv = NULL;
BlockDriverInfo bdi; BlockDriverInfo bdi;
BlockDriverState *out_bs; BlockDriverState *out_bs;
QemuOpts *opts = NULL, *sn_opts = NULL; QemuOpts *opts = NULL, *sn_opts = NULL;
@ -1924,7 +1958,7 @@ static int img_convert(int argc, char **argv)
char *options = NULL; char *options = NULL;
Error *local_err = NULL; Error *local_err = NULL;
bool writethrough, src_writethrough, quiet = false, image_opts = false, bool writethrough, src_writethrough, quiet = false, image_opts = false,
skip_create = false, progress = false; skip_create = false, progress = false, tgt_image_opts = false;
int64_t ret = -EINVAL; int64_t ret = -EINVAL;
bool force_share = false; bool force_share = false;
@ -1942,6 +1976,7 @@ static int img_convert(int argc, char **argv)
{"object", required_argument, 0, OPTION_OBJECT}, {"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"force-share", no_argument, 0, 'U'}, {"force-share", no_argument, 0, 'U'},
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:WU", c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:WU",
@ -2062,9 +2097,16 @@ static int img_convert(int argc, char **argv)
case OPTION_IMAGE_OPTS: case OPTION_IMAGE_OPTS:
image_opts = true; image_opts = true;
break; break;
case OPTION_TARGET_IMAGE_OPTS:
tgt_image_opts = true;
break;
} }
} }
if (!out_fmt && !tgt_image_opts) {
out_fmt = "raw";
}
if (qemu_opts_foreach(&qemu_object_opts, if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach, user_creatable_add_opts_foreach,
NULL, NULL)) { NULL, NULL)) {
@ -2076,12 +2118,22 @@ static int img_convert(int argc, char **argv)
goto fail_getopt; goto fail_getopt;
} }
if (tgt_image_opts && !skip_create) {
error_report("--target-image-opts requires use of -n flag");
goto fail_getopt;
}
s.src_num = argc - optind - 1; s.src_num = argc - optind - 1;
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL; out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
if (options && has_help_option(options)) { if (options && has_help_option(options)) {
ret = print_block_option_help(out_filename, out_fmt); if (out_fmt) {
goto fail_getopt; ret = print_block_option_help(out_filename, out_fmt);
goto fail_getopt;
} else {
error_report("Option help requires a format be specified");
goto fail_getopt;
}
} }
if (s.src_num < 1) { if (s.src_num < 1) {
@ -2146,22 +2198,22 @@ static int img_convert(int argc, char **argv)
goto out; goto out;
} }
/* Find driver and parse its options */
drv = bdrv_find_format(out_fmt);
if (!drv) {
error_report("Unknown file format '%s'", out_fmt);
ret = -1;
goto out;
}
proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
if (!proto_drv) {
error_report_err(local_err);
ret = -1;
goto out;
}
if (!skip_create) { if (!skip_create) {
/* Find driver and parse its options */
drv = bdrv_find_format(out_fmt);
if (!drv) {
error_report("Unknown file format '%s'", out_fmt);
ret = -1;
goto out;
}
proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
if (!proto_drv) {
error_report_err(local_err);
ret = -1;
goto out;
}
if (!drv->create_opts) { if (!drv->create_opts) {
error_report("Format driver '%s' does not support image creation", error_report("Format driver '%s' does not support image creation",
drv->format_name); drv->format_name);
@ -2218,7 +2270,7 @@ static int img_convert(int argc, char **argv)
const char *preallocation = const char *preallocation =
qemu_opt_get(opts, BLOCK_OPT_PREALLOC); qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
if (!drv->bdrv_co_pwritev_compressed) { if (drv && !drv->bdrv_co_pwritev_compressed) {
error_report("Compression not supported for this file format"); error_report("Compression not supported for this file format");
ret = -1; ret = -1;
goto out; goto out;
@ -2258,19 +2310,30 @@ static int img_convert(int argc, char **argv)
goto out; goto out;
} }
/* XXX we should allow --image-opts to trigger use of if (skip_create) {
* img_open() here, but then we have trouble with s.target = img_open(tgt_image_opts, out_filename, out_fmt,
* the bdrv_create() call which takes different params. flags, writethrough, quiet, false);
* Not critical right now, so fix can wait... } else {
*/ /* TODO ultimately we should allow --target-image-opts
s.target = img_open_file(out_filename, out_fmt, flags, writethrough, quiet, * to be used even when -n is not given.
false); * That has to wait for bdrv_create to be improved
* to allow filenames in option syntax
*/
s.target = img_open_new_file(out_filename, opts, out_fmt,
flags, writethrough, quiet, false);
}
if (!s.target) { if (!s.target) {
ret = -1; ret = -1;
goto out; goto out;
} }
out_bs = blk_bs(s.target); out_bs = blk_bs(s.target);
if (s.compressed && !out_bs->drv->bdrv_co_pwritev_compressed) {
error_report("Compression not supported for this file format");
ret = -1;
goto out;
}
/* increase bufsectors from the default 4096 (2M) if opt_transfer /* increase bufsectors from the default 4096 (2M) if opt_transfer
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB) * or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
* as maximum. */ * as maximum. */
@ -4157,6 +4220,7 @@ static int img_dd(int argc, char **argv)
}; };
const struct option long_options[] = { const struct option long_options[] = {
{ "help", no_argument, 0, 'h'}, { "help", no_argument, 0, 'h'},
{ "object", required_argument, 0, OPTION_OBJECT},
{ "image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, { "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{ "force-share", no_argument, 0, 'U'}, { "force-share", no_argument, 0, 'U'},
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
@ -4185,6 +4249,15 @@ static int img_dd(int argc, char **argv)
case 'U': case 'U':
force_share = true; force_share = true;
break; break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
ret = -1;
goto out;
}
} break;
case OPTION_IMAGE_OPTS: case OPTION_IMAGE_OPTS:
image_opts = true; image_opts = true;
break; break;
@ -4229,6 +4302,14 @@ static int img_dd(int argc, char **argv)
ret = -1; ret = -1;
goto out; goto out;
} }
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
ret = -1;
goto out;
}
blk1 = img_open(image_opts, in.filename, fmt, 0, false, false, blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
force_share); force_share);
@ -4297,8 +4378,13 @@ static int img_dd(int argc, char **argv)
goto out; goto out;
} }
blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, /* TODO, we can't honour --image-opts for the target,
false, false, false); * since it needs to be given in a format compatible
* with the bdrv_create() call above which does not
* support image-opts style.
*/
blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
false, false, false);
if (!blk2) { if (!blk2) {
ret = -1; ret = -1;

View File

@ -45,9 +45,17 @@ keys.
@item --image-opts @item --image-opts
Indicates that the @var{filename} parameter is to be interpreted as a Indicates that the source @var{filename} parameter is to be interpreted as a
full option string, not a plain filename. This parameter is mutually full option string, not a plain filename. This parameter is mutually
exclusive with the @var{-f} and @var{-F} parameters. exclusive with the @var{-f} parameter.
@item --target-image-opts
Indicates that the @var{output_filename} parameter(s) are to be interpreted as
a full option string, not a plain filename. This parameter is mutually
exclusive with the @var{-O} parameters. It is currently required to also use
the @var{-n} parameter to skip image creation. This restriction may be relaxed
in a future release.
@item fmt @item fmt
is the disk image format. It is guessed automatically in most cases. See below is the disk image format. It is guessed automatically in most cases. See below

View File

@ -147,6 +147,10 @@ class TestSingleDrive(iotests.QMPTestCase):
result = self.vm.qmp('block-stream', device='nonexistent') result = self.vm.qmp('block-stream', device='nonexistent')
self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/class', 'GenericError')
def test_job_id_missing(self):
result = self.vm.qmp('block-stream', device='mid')
self.assert_qmp(result, 'error/class', 'GenericError')
class TestParallelOps(iotests.QMPTestCase): class TestParallelOps(iotests.QMPTestCase):
num_ops = 4 # Number of parallel block-stream operations num_ops = 4 # Number of parallel block-stream operations

View File

@ -1,5 +1,5 @@
...................... .......................
---------------------------------------------------------------------- ----------------------------------------------------------------------
Ran 22 tests Ran 23 tests
OK OK

View File

@ -143,7 +143,7 @@ read failed: Input/output error
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 65536/65536 bytes at offset 0 wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qcow2: Marking image as corrupt: Data cluster offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed qcow2: Marking image as corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed
qemu-img: Error while amending options: Input/output error qemu-img: Error while amending options: Input/output error
=== Testing unaligned reftable entry === === Testing unaligned reftable entry ===

View File

@ -147,6 +147,13 @@ class BuiltinNBD(NBDBlockdevAddBase):
self._server_down() self._server_down()
def test_inet6(self): def test_inet6(self):
try:
socket.getaddrinfo("::0", "0", socket.AF_INET6,
socket.SOCK_STREAM, socket.IPPROTO_TCP,
socket.AI_ADDRCONFIG | socket.AI_CANONNAME)
except socket.gaierror:
# IPv6 not available, skip
return
address = { 'type': 'inet', address = { 'type': 'inet',
'data': { 'data': {
'host': '::1', 'host': '::1',