Commit 0748b352 authored by Stefan Hajnoczi's avatar Stefan Hajnoczi

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: 's avatarStefan Hajnoczi <stefanha@redhat.com>
parents 697e42de 42a48128
......@@ -163,11 +163,16 @@ void path_combine(char *dest, int dest_size,
if (path_is_absolute(filename)) {
pstrcpy(dest, dest_size, filename);
} else {
p = strchr(base_path, ':');
if (p)
p++;
else
p = base_path;
const char *protocol_stripped = NULL;
if (path_has_protocol(base_path)) {
protocol_stripped = strchr(base_path, ':');
if (protocol_stripped) {
protocol_stripped++;
}
}
p = protocol_stripped ?: base_path;
p1 = strrchr(base_path, '/');
#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
* return false and writing to the image file is still not possible because the
* image is inactivated. */
......
......@@ -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,
Error **errp)
{
/* The filename does not have to be prefixed by the protocol name, since
* "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);
bdrv_parse_filename_strip_prefix(filename, "file:", options);
}
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,
Error **errp)
{
/* The prefix is optional, just as for "file". */
strstart(filename, "host_device:", &filename);
qdict_put_str(options, "filename", filename);
bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
}
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,
Error **errp)
{
/* The prefix is optional, just as for "file". */
strstart(filename, "host_cdrom:", &filename);
qdict_put_str(options, "filename", filename);
bdrv_parse_filename_strip_prefix(filename, "host_cdrom:", options);
}
#endif
......
......@@ -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,
Error **errp)
{
/* The filename does not have to be prefixed by the protocol name, since
* "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);
bdrv_parse_filename_strip_prefix(filename, "file:", options);
}
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,
Error **errp)
{
/* The prefix is optional, just as for "file". */
strstart(filename, "host_device:", &filename);
qdict_put_str(options, "filename", filename);
bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
}
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
......
......@@ -514,7 +514,12 @@ static void mirror_exit(BlockJob *job, void *opaque)
/* 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
* 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);
s->target = NULL;
......
......@@ -1797,7 +1797,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
}
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 ", L2 index: %#x)", offset,
l2_offset, j);
......
......@@ -3222,7 +3222,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
if (s->refcount_bits != refcount_bits) {
int refcount_order = ctz32(refcount_bits);
Error *local_error = NULL;
if (new_version < 3 && refcount_bits != 16) {
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;
ret = qcow2_change_refcount_order(bs, refcount_order,
&qcow2_amend_helper_cb,
&helper_cb_info, &local_error);
&helper_cb_info, &local_err);
if (ret < 0) {
error_report_err(local_error);
error_report_err(local_err);
return ret;
}
}
......
......@@ -280,6 +280,6 @@ void stream_start(const char *job_id, BlockDriverState *bs,
fail:
if (orig_bs_flags != bdrv_get_flags(bs)) {
bdrv_reopen(bs, s->bs_flags, NULL);
bdrv_reopen(bs, orig_bs_flags, NULL);
}
}
......@@ -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/
*/
......@@ -17,7 +17,11 @@
/**
* Usage: add options:
* -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"
......@@ -34,6 +38,16 @@
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)
{
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))) {
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);
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)
{
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_MPSMAX(n->bar.cap, 4);
n->bar.vs = 0x00010100;
n->bar.vs = 0x00010200;
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++) {
NvmeNamespace *ns = &n->namespaces[i];
NvmeIdNs *id_ns = &ns->id_ns;
......@@ -964,12 +1026,17 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->namespaces);
g_free(n->cq);
g_free(n->sq);
if (n->cmbsz) {
memory_region_unref(&n->ctrl_mem);
}
msix_uninit_exclusive_bar(pci_dev);
}
static Property nvme_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
DEFINE_PROP_END_OF_LIST(),
};
......
......@@ -14,6 +14,8 @@ typedef struct NvmeBar {
uint32_t aqa;
uint64_t asq;
uint64_t acq;
uint32_t cmbloc;
uint32_t cmbsz;
} NvmeBar;
enum NvmeCapShift {
......@@ -138,6 +140,72 @@ enum NvmeAqaMask {
#define NVME_AQA_ASQS(aqa) ((aqa >> AQA_ASQS_SHIFT) & AQA_ASQS_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 {
uint8_t opcode;
uint8_t fuse;
......@@ -688,6 +756,7 @@ typedef struct NvmeNamespace {
typedef struct NvmeCtrl {
PCIDevice parent_obj;
MemoryRegion iomem;
MemoryRegion ctrl_mem;
NvmeBar bar;
BlockConf conf;
......@@ -701,6 +770,10 @@ typedef struct NvmeCtrl {
uint32_t num_queues;
uint32_t max_q_ents;
uint64_t ns_size;
uint32_t cmb_size_mb;
uint32_t cmbsz;
uint32_t cmbloc;
uint8_t *cmbuf;
char *serial;
NvmeNamespace *namespaces;
......
......@@ -682,6 +682,9 @@ int get_tmp_filename(char *filename, int size);
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
const char *filename);
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options);
/**
* bdrv_add_before_write_notifier:
......
......@@ -40,9 +40,9 @@ STEXI
ETEXI
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
@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
DEF("dd", img_dd,
......
This diff is collapsed.
......@@ -45,9 +45,17 @@ keys.
@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
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
is the disk image format. It is guessed automatically in most cases. See below
......
......@@ -147,6 +147,10 @@ class TestSingleDrive(iotests.QMPTestCase):
result = self.vm.qmp('block-stream', device='nonexistent')
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):
num_ops = 4 # Number of parallel block-stream operations
......
......................
.......................
----------------------------------------------------------------------
Ran 22 tests
Ran 23 tests
OK
......@@ -143,7 +143,7 @@ read failed: Input/output error
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 65536/65536 bytes at offset 0
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
=== Testing unaligned reftable entry ===
......
......@@ -147,6 +147,13 @@ class BuiltinNBD(NBDBlockdevAddBase):
self._server_down()
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',
'data': {
'host': '::1',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment