mirror of https://gitee.com/openkylin/qemu.git
nbd patches for 2017-08-15
- Eric Blake: nbd: Fix trace message for disconnect - Stefan Hajnoczi: qemu-iotests: step clock after each test iteration - Fam Zheng: 0/4 block: Fix non-shared storage migration - Eric Blake: nbd-client: Fix regression when server sends garbage -----BEGIN PGP SIGNATURE----- Comment: Public key at http://people.redhat.com/eblake/eblake.gpg iQEcBAABCAAGBQJZkw3aAAoJEKeha0olJ0NqoNgH/j5/97f5MVsWWS+dV1KxKnpD gCeOi3uk9Rvyx+cQafm6THK4FwVVRVbSV3DeJDPXa0Bsr7n7HklXEdERB7iR6K7m NhvrwDd/3WCJp2GZoC8l4ywu+zWtxIJXKM52lNfUxd//zvzGfs+cvVsw1rgD10UR Kl1cyEJJ66fIoTKCkKmveCX+knhgH1JaJnxW7dHBxIBwKs0EuW25hrEi4abd0tvF erpgePK6ikLwuSfK/Ni8xroooRy392pzVFRyWY/0xuVT+Ap6bfC/DeKFg6WkAx/9 G9jKBsy5ZucHAWk8Qn/7dxzD0E540RiEDTkoLfSuCfxo59R89Rv4Wl3PD9YyocQ= =M36z -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2017-08-15' into staging nbd patches for 2017-08-15 - Eric Blake: nbd: Fix trace message for disconnect - Stefan Hajnoczi: qemu-iotests: step clock after each test iteration - Fam Zheng: 0/4 block: Fix non-shared storage migration - Eric Blake: nbd-client: Fix regression when server sends garbage # gpg: Signature made Tue 15 Aug 2017 16:06:02 BST # gpg: using RSA key 0xA7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" # gpg: aka "[jpeg image of size 6874]" # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-nbd-2017-08-15: nbd-client: Fix regression when server sends garbage iotests: Add non-shared storage migration case 192 block-backend: Defer shared_perm tightening migration completion nbd: Fix order of bdrv_set_perm and bdrv_invalidate_cache stubs: Add vm state change handler stubs qemu-iotests: step clock after each test iteration nbd: Fix trace message for disconnect Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
09920c5354
|
@ -20,6 +20,7 @@
|
||||||
#include "qapi-event.h"
|
#include "qapi-event.h"
|
||||||
#include "qemu/id.h"
|
#include "qemu/id.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "migration/misc.h"
|
||||||
|
|
||||||
/* Number of coroutines to reserve per attached device model */
|
/* Number of coroutines to reserve per attached device model */
|
||||||
#define COROUTINE_POOL_RESERVATION 64
|
#define COROUTINE_POOL_RESERVATION 64
|
||||||
|
@ -68,6 +69,7 @@ struct BlockBackend {
|
||||||
NotifierList remove_bs_notifiers, insert_bs_notifiers;
|
NotifierList remove_bs_notifiers, insert_bs_notifiers;
|
||||||
|
|
||||||
int quiesce_counter;
|
int quiesce_counter;
|
||||||
|
VMChangeStateEntry *vmsh;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BlockBackendAIOCB {
|
typedef struct BlockBackendAIOCB {
|
||||||
|
@ -129,6 +131,23 @@ static const char *blk_root_get_name(BdrvChild *child)
|
||||||
return blk_name(child->opaque);
|
return blk_name(child->opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void blk_vm_state_changed(void *opaque, int running, RunState state)
|
||||||
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
|
BlockBackend *blk = opaque;
|
||||||
|
|
||||||
|
if (state == RUN_STATE_INMIGRATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_del_vm_change_state_handler(blk->vmsh);
|
||||||
|
blk->vmsh = NULL;
|
||||||
|
blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report_err(local_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notifies the user of the BlockBackend that migration has completed. qdev
|
* Notifies the user of the BlockBackend that migration has completed. qdev
|
||||||
* devices can tighten their permissions in response (specifically revoke
|
* devices can tighten their permissions in response (specifically revoke
|
||||||
|
@ -147,6 +166,24 @@ static void blk_root_activate(BdrvChild *child, Error **errp)
|
||||||
|
|
||||||
blk->disable_perm = false;
|
blk->disable_perm = false;
|
||||||
|
|
||||||
|
blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
blk->disable_perm = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||||
|
/* Activation can happen when migration process is still active, for
|
||||||
|
* example when nbd_server_add is called during non-shared storage
|
||||||
|
* migration. Defer the shared_perm update to migration completion. */
|
||||||
|
if (!blk->vmsh) {
|
||||||
|
blk->vmsh = qemu_add_vm_change_state_handler(blk_vm_state_changed,
|
||||||
|
blk);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
|
blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
@ -291,6 +328,10 @@ static void blk_delete(BlockBackend *blk)
|
||||||
if (blk->root) {
|
if (blk->root) {
|
||||||
blk_remove_bs(blk);
|
blk_remove_bs(blk);
|
||||||
}
|
}
|
||||||
|
if (blk->vmsh) {
|
||||||
|
qemu_del_vm_change_state_handler(blk->vmsh);
|
||||||
|
blk->vmsh = NULL;
|
||||||
|
}
|
||||||
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
|
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
|
||||||
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
|
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
|
||||||
QTAILQ_REMOVE(&block_backends, blk, link);
|
QTAILQ_REMOVE(&block_backends, blk, link);
|
||||||
|
|
|
@ -73,7 +73,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||||
int ret;
|
int ret;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
for (;;) {
|
while (!s->quit) {
|
||||||
assert(s->reply.handle == 0);
|
assert(s->reply.handle == 0);
|
||||||
ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
|
ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -107,6 +107,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
s->quit = true;
|
||||||
|
}
|
||||||
nbd_recv_coroutines_enter_all(s);
|
nbd_recv_coroutines_enter_all(s);
|
||||||
s->read_reply_co = NULL;
|
s->read_reply_co = NULL;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +138,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||||
assert(i < MAX_NBD_REQUESTS);
|
assert(i < MAX_NBD_REQUESTS);
|
||||||
request->handle = INDEX_TO_HANDLE(s, i);
|
request->handle = INDEX_TO_HANDLE(s, i);
|
||||||
|
|
||||||
|
if (s->quit) {
|
||||||
|
qemu_co_mutex_unlock(&s->send_mutex);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
if (!s->ioc) {
|
if (!s->ioc) {
|
||||||
qemu_co_mutex_unlock(&s->send_mutex);
|
qemu_co_mutex_unlock(&s->send_mutex);
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
|
@ -143,7 +150,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||||
if (qiov) {
|
if (qiov) {
|
||||||
qio_channel_set_cork(s->ioc, true);
|
qio_channel_set_cork(s->ioc, true);
|
||||||
rc = nbd_send_request(s->ioc, request);
|
rc = nbd_send_request(s->ioc, request);
|
||||||
if (rc >= 0) {
|
if (rc >= 0 && !s->quit) {
|
||||||
ret = nbd_rwv(s->ioc, qiov->iov, qiov->niov, request->len, false,
|
ret = nbd_rwv(s->ioc, qiov->iov, qiov->niov, request->len, false,
|
||||||
NULL);
|
NULL);
|
||||||
if (ret != request->len) {
|
if (ret != request->len) {
|
||||||
|
@ -154,6 +161,9 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||||
} else {
|
} else {
|
||||||
rc = nbd_send_request(s->ioc, request);
|
rc = nbd_send_request(s->ioc, request);
|
||||||
}
|
}
|
||||||
|
if (rc < 0) {
|
||||||
|
s->quit = true;
|
||||||
|
}
|
||||||
qemu_co_mutex_unlock(&s->send_mutex);
|
qemu_co_mutex_unlock(&s->send_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -168,8 +178,7 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||||
/* Wait until we're woken up by nbd_read_reply_entry. */
|
/* Wait until we're woken up by nbd_read_reply_entry. */
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
*reply = s->reply;
|
*reply = s->reply;
|
||||||
if (reply->handle != request->handle ||
|
if (reply->handle != request->handle || !s->ioc || s->quit) {
|
||||||
!s->ioc) {
|
|
||||||
reply->error = EIO;
|
reply->error = EIO;
|
||||||
} else {
|
} else {
|
||||||
if (qiov && reply->error == 0) {
|
if (qiov && reply->error == 0) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ typedef struct NBDClientSession {
|
||||||
|
|
||||||
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
||||||
NBDReply reply;
|
NBDReply reply;
|
||||||
|
bool quit;
|
||||||
} NBDClientSession;
|
} NBDClientSession;
|
||||||
|
|
||||||
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
||||||
|
|
|
@ -182,7 +182,7 @@ const char *nbd_cmd_lookup(uint16_t cmd)
|
||||||
case NBD_CMD_WRITE:
|
case NBD_CMD_WRITE:
|
||||||
return "write";
|
return "write";
|
||||||
case NBD_CMD_DISC:
|
case NBD_CMD_DISC:
|
||||||
return "discard";
|
return "disconnect";
|
||||||
case NBD_CMD_FLUSH:
|
case NBD_CMD_FLUSH:
|
||||||
return "flush";
|
return "flush";
|
||||||
case NBD_CMD_TRIM:
|
case NBD_CMD_TRIM:
|
||||||
|
|
20
nbd/server.c
20
nbd/server.c
|
@ -1045,11 +1045,22 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
|
||||||
bool writethrough, BlockBackend *on_eject_blk,
|
bool writethrough, BlockBackend *on_eject_blk,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
AioContext *ctx;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
NBDExport *exp = g_malloc0(sizeof(NBDExport));
|
NBDExport *exp = g_malloc0(sizeof(NBDExport));
|
||||||
uint64_t perm;
|
uint64_t perm;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NBD exports are used for non-shared storage migration. Make sure
|
||||||
|
* that BDRV_O_INACTIVE is cleared and the image is ready for write
|
||||||
|
* access since the export could be available before migration handover.
|
||||||
|
*/
|
||||||
|
ctx = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(ctx);
|
||||||
|
bdrv_invalidate_cache(bs, NULL);
|
||||||
|
aio_context_release(ctx);
|
||||||
|
|
||||||
/* Don't allow resize while the NBD server is running, otherwise we don't
|
/* Don't allow resize while the NBD server is running, otherwise we don't
|
||||||
* care what happens with the node. */
|
* care what happens with the node. */
|
||||||
perm = BLK_PERM_CONSISTENT_READ;
|
perm = BLK_PERM_CONSISTENT_READ;
|
||||||
|
@ -1087,15 +1098,6 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
|
||||||
exp->eject_notifier.notify = nbd_eject_notifier;
|
exp->eject_notifier.notify = nbd_eject_notifier;
|
||||||
blk_add_remove_bs_notifier(on_eject_blk, &exp->eject_notifier);
|
blk_add_remove_bs_notifier(on_eject_blk, &exp->eject_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* NBD exports are used for non-shared storage migration. Make sure
|
|
||||||
* that BDRV_O_INACTIVE is cleared and the image is ready for write
|
|
||||||
* access since the export could be available before migration handover.
|
|
||||||
*/
|
|
||||||
aio_context_acquire(exp->ctx);
|
|
||||||
blk_invalidate_cache(blk, NULL);
|
|
||||||
aio_context_release(exp->ctx);
|
|
||||||
return exp;
|
return exp;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -19,6 +19,7 @@ stub-obj-y += is-daemonized.o
|
||||||
stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||||
stub-obj-y += machine-init-done.o
|
stub-obj-y += machine-init-done.o
|
||||||
stub-obj-y += migr-blocker.o
|
stub-obj-y += migr-blocker.o
|
||||||
|
stub-obj-y += change-state-handler.o
|
||||||
stub-obj-y += monitor.o
|
stub-obj-y += monitor.o
|
||||||
stub-obj-y += notify-event.o
|
stub-obj-y += notify-event.o
|
||||||
stub-obj-y += qtest.o
|
stub-obj-y += qtest.o
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
|
VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
|
||||||
|
{
|
||||||
|
/* Nothing to do. */
|
||||||
|
}
|
|
@ -133,6 +133,10 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
||||||
self.assertTrue(check_limit(params['iops_rd'], rd_iops))
|
self.assertTrue(check_limit(params['iops_rd'], rd_iops))
|
||||||
self.assertTrue(check_limit(params['iops_wr'], wr_iops))
|
self.assertTrue(check_limit(params['iops_wr'], wr_iops))
|
||||||
|
|
||||||
|
# Allow remaining requests to finish. We submitted twice as many to
|
||||||
|
# ensure the throttle limit is reached.
|
||||||
|
self.vm.qtest("clock_step %d" % ns)
|
||||||
|
|
||||||
# Connect N drives to a VM and test I/O in all of them
|
# Connect N drives to a VM and test I/O in all of them
|
||||||
def test_all(self):
|
def test_all(self):
|
||||||
params = {"bps": 4096,
|
params = {"bps": 4096,
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test NBD export with -incoming (non-shared storage migration use case from
|
||||||
|
# libvirt)
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# creator
|
||||||
|
owner=famz@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
_supported_fmt generic
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
|
||||||
|
_notrun "Requires a PC machine"
|
||||||
|
fi
|
||||||
|
|
||||||
|
size=64M
|
||||||
|
_make_test_img $size
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "nbd_server_start unix:$TEST_DIR/nbd"
|
||||||
|
echo "nbd_server_add -w drive0"
|
||||||
|
echo "q"
|
||||||
|
} | $QEMU -nodefaults -display none -monitor stdio \
|
||||||
|
-drive format=$IMGFMT,file=$TEST_IMG,if=ide,id=drive0 \
|
||||||
|
-incoming defer 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,7 @@
|
||||||
|
QA output created by 192
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
|
(qemu) nbd_server_start unix:TEST_DIR/nbd
|
||||||
|
(qemu) nbd_server_add -w drive0
|
||||||
|
(qemu) q
|
||||||
|
*** done
|
|
@ -186,3 +186,4 @@
|
||||||
188 rw auto quick
|
188 rw auto quick
|
||||||
189 rw auto
|
189 rw auto
|
||||||
190 rw auto quick
|
190 rw auto quick
|
||||||
|
192 rw auto quick
|
||||||
|
|
Loading…
Reference in New Issue