Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into s…
Browse files Browse the repository at this point in the history
…taging

Block layer patches:

- block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options()
- block: Fix option inheritance after stream/commit job graph changes
- qemu-img: Fix memory leak and typo in error message
- nvme: Fixes for lockups and crashes
- scsi-disk: Fix crash if underlying host file or disk returns error
- Several qemu-iotests fixes and improvements

# gpg: Signature made Thu 22 Nov 2018 18:38:30 GMT
# gpg:                using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <[email protected]>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  block: Update BlockDriverState.inherits_from on bdrv_drop_intermediate()
  block: Update BlockDriverState.inherits_from on bdrv_set_backing_hd()
  iotests: Enhance 223 to cover multiple bitmap granularities
  nvme: fix bug with PCI IRQ pins on teardown
  nvme: fix CMB endianness confusion
  Revert "nvme: fix oob access issue(CVE-2018-16847)"
  nvme: fix out-of-bounds access to the CMB
  nvme: call blk_drain in NVMe reset code to avoid lockups
  iotests: fix nbd test 233 to work correctly with raw images
  block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options()
  scsi-disk: Fix crash if underlying host file or disk returns error
  qemu-img: Fix leak
  qemu-img: Fix typo
  iotests: Skip 233 if certtool not installed
  iotests: Replace assertEquals() with assertEqual()
  iotests: Replace time.clock() with Timeout

Signed-off-by: Peter Maydell <[email protected]>
  • Loading branch information
pm215 committed Nov 23, 2018
2 parents ebfd621 + 6bd858b commit 5298f4d
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 63 deletions.
41 changes: 38 additions & 3 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)

static void update_flags_from_options(int *flags, QemuOpts *opts)
{
*flags &= ~BDRV_O_CACHE_MASK;
*flags &= ~(BDRV_O_CACHE_MASK | BDRV_O_RDWR | BDRV_O_AUTO_RDONLY);

assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
Expand All @@ -1149,8 +1149,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
*flags |= BDRV_O_NOCACHE;
}

*flags &= ~BDRV_O_RDWR;

assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
if (!qemu_opt_get_bool_del(opts, BDRV_OPT_READ_ONLY, false)) {
*flags |= BDRV_O_RDWR;
Expand Down Expand Up @@ -2262,13 +2260,28 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load)
}
}

/* Return true if you can reach parent going through child->inherits_from
* recursively. If parent or child are NULL, return false */
static bool bdrv_inherits_from_recursive(BlockDriverState *child,
BlockDriverState *parent)
{
while (child && child != parent) {
child = child->inherits_from;
}

return child != NULL;
}

/*
* Sets the backing file link of a BDS. A new reference is created; callers
* which don't need their own reference any more must call bdrv_unref().
*/
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp)
{
bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) &&
bdrv_inherits_from_recursive(backing_hd, bs);

if (backing_hd) {
bdrv_ref(backing_hd);
}
Expand All @@ -2284,6 +2297,12 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,

bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
errp);
/* If backing_hd was already part of bs's backing chain, and
* inherits_from pointed recursively to bs then let's update it to
* point directly to bs (else it will become NULL). */
if (update_inherits_from) {
backing_hd->inherits_from = bs;
}
if (!bs->backing) {
bdrv_unref(backing_hd);
}
Expand Down Expand Up @@ -3836,6 +3855,8 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
const char *backing_file_str)
{
BlockDriverState *explicit_top = top;
bool update_inherits_from;
BdrvChild *c, *next;
Error *local_err = NULL;
int ret = -EIO;
Expand All @@ -3851,6 +3872,16 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
goto exit;
}

/* If 'base' recursively inherits from 'top' then we should set
* base->inherits_from to top->inherits_from after 'top' and all
* other intermediate nodes have been dropped.
* If 'top' is an implicit node (e.g. "commit_top") we should skip
* it because no one inherits from it. We use explicit_top for that. */
while (explicit_top && explicit_top->implicit) {
explicit_top = backing_bs(explicit_top);
}
update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top);

/* success - we can delete the intermediate states, and link top->base */
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
* we've figured out how they should work. */
Expand Down Expand Up @@ -3886,6 +3917,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
bdrv_unref(top);
}

if (update_inherits_from) {
base->inherits_from = explicit_top->inherits_from;
}

ret = 0;
exit:
bdrv_unref(top);
Expand Down
19 changes: 6 additions & 13 deletions hw/block/nvme.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
trace_nvme_err_invalid_del_cq_notempty(qid);
return NVME_INVALID_QUEUE_DEL;
}
nvme_irq_deassert(n, cq);
trace_nvme_del_cq(qid);
nvme_free_cq(cq, n);
return NVME_SUCCESS;
Expand Down Expand Up @@ -797,6 +798,8 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
{
int i;

blk_drain(n->conf.blk);

for (i = 0; i < n->num_queues; i++) {
if (n->sq[i] != NULL) {
nvme_free_sq(n->sq[i], n);
Expand Down Expand Up @@ -1175,31 +1178,21 @@ static void nvme_cmb_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
NvmeCtrl *n = (NvmeCtrl *)opaque;

if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) {
return;
}
memcpy(&n->cmbuf[addr], &data, size);
stn_le_p(&n->cmbuf[addr], size, data);
}

static uint64_t nvme_cmb_read(void *opaque, hwaddr addr, unsigned size)
{
uint64_t val;
NvmeCtrl *n = (NvmeCtrl *)opaque;

if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) {
return 0;
}
memcpy(&val, &n->cmbuf[addr], size);
return val;
return ldn_le_p(&n->cmbuf[addr], size);
}

static const MemoryRegionOps nvme_cmb_ops = {
.read = nvme_cmb_read,
.write = nvme_cmb_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 2,
.min_access_size = 1,
.max_access_size = 8,
},
};
Expand Down
2 changes: 1 addition & 1 deletion hw/scsi/scsi-disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
if (action == BLOCK_ERROR_ACTION_STOP) {
scsi_req_retry(&r->req);
}
return false;
return true;
}

static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
Expand Down
3 changes: 2 additions & 1 deletion qemu-img.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,9 @@ static int print_block_option_help(const char *filename, const char *fmt)
return 1;
}
if (!proto_drv->create_opts) {
error_report("Protocal driver '%s' does not support image creation",
error_report("Protocol driver '%s' does not support image creation",
proto_drv->format_name);
qemu_opts_free(create_opts);
return 1;
}
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
Expand Down
2 changes: 1 addition & 1 deletion tests/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ tests/test-hmp$(EXESUF): tests/test-hmp.o
tests/machine-none-test$(EXESUF): tests/machine-none-test.o
tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
tests/nvme-test$(EXESUF): tests/nvme-test.o
tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
tests/ac97-test$(EXESUF): tests/ac97-test.o
Expand Down
68 changes: 58 additions & 10 deletions tests/nvme-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,73 @@
*/

#include "qemu/osdep.h"
#include "qemu/units.h"
#include "libqtest.h"
#include "libqos/libqos-pc.h"

static QOSState *qnvme_start(const char *extra_opts)
{
QOSState *qs;
const char *arch = qtest_get_arch();
const char *cmd = "-drive id=drv0,if=none,file=null-co://,format=raw "
"-device nvme,addr=0x4.0,serial=foo,drive=drv0 %s";

if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
qs = qtest_pc_boot(cmd, extra_opts ? : "");
global_qtest = qs->qts;
return qs;
}

g_printerr("nvme tests are only available on x86\n");
exit(EXIT_FAILURE);
}

static void qnvme_stop(QOSState *qs)
{
qtest_shutdown(qs);
}

/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
{
QOSState *qs;

qs = qnvme_start(NULL);
qnvme_stop(qs);
}

int main(int argc, char **argv)
static void nvmetest_cmb_test(void)
{
int ret;
const int cmb_bar_size = 2 * MiB;
QOSState *qs;
QPCIDevice *pdev;
QPCIBar bar;

g_test_init(&argc, &argv, NULL);
qtest_add_func("/nvme/nop", nop);
qs = qnvme_start("-global nvme.cmb_size_mb=2");
pdev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4,0));
g_assert(pdev != NULL);

qpci_device_enable(pdev);
bar = qpci_iomap(pdev, 2, NULL);

qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);

/* Test partially out-of-bounds accesses. */
qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
g_free(pdev);

qtest_start("-drive id=drv0,if=none,file=null-co://,format=raw "
"-device nvme,drive=drv0,serial=foo");
ret = g_test_run();
qnvme_stop(qs);
}

qtest_end();
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
qtest_add_func("/nvme/nop", nop);
qtest_add_func("/nvme/cmb_test", nvmetest_cmb_test);

return ret;
return g_test_run();
}
6 changes: 3 additions & 3 deletions tests/qemu-iotests/041
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ new_state = "1"
self.assert_qmp(event, 'data/id', 'drive0')
event = self.vm.get_qmp_event(wait=True)

self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assertEqual(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'read')
result = self.vm.qmp('query-block-jobs')
Expand All @@ -494,7 +494,7 @@ new_state = "1"
self.assert_qmp(event, 'data/id', 'drive0')
event = self.vm.get_qmp_event(wait=True)

self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assertEqual(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'read')
result = self.vm.qmp('query-block-jobs')
Expand Down Expand Up @@ -625,7 +625,7 @@ new_state = "1"
self.assert_qmp(result, 'return', {})

event = self.vm.event_wait(name='BLOCK_JOB_ERROR')
self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assertEqual(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'write')
result = self.vm.qmp('query-block-jobs')
Expand Down
20 changes: 8 additions & 12 deletions tests/qemu-iotests/118
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,17 @@ class ChangeBaseClass(iotests.QMPTestCase):
if not self.has_real_tray:
return

timeout = time.clock() + 3
while not self.has_opened and time.clock() < timeout:
self.process_events()
if not self.has_opened:
self.fail('Timeout while waiting for the tray to open')
with iotests.Timeout(3, 'Timeout while waiting for the tray to open'):
while not self.has_opened:
self.process_events()

def wait_for_close(self):
if not self.has_real_tray:
return

timeout = time.clock() + 3
while not self.has_closed and time.clock() < timeout:
self.process_events()
if not self.has_opened:
self.fail('Timeout while waiting for the tray to close')
with iotests.Timeout(3, 'Timeout while waiting for the tray to close'):
while not self.has_closed:
self.process_events()

class GeneralChangeTestsBaseClass(ChangeBaseClass):

Expand Down Expand Up @@ -265,7 +261,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
# Should be a no-op
self.assert_qmp(result, 'return', {})
self.assertEquals(self.vm.get_qmp_events(wait=False), [])
self.assertEqual(self.vm.get_qmp_events(wait=False), [])

def test_remove_on_closed(self):
if not self.has_real_tray:
Expand Down Expand Up @@ -452,7 +448,7 @@ class TestChangeReadOnly(ChangeBaseClass):
read_only_mode='retain')
self.assert_qmp(result, 'error/class', 'GenericError')

self.assertEquals(self.vm.get_qmp_events(wait=False), [])
self.assertEqual(self.vm.get_qmp_events(wait=False), [])

result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/ro', False)
Expand Down
Loading

0 comments on commit 5298f4d

Please sign in to comment.