Xen queue
* Xen PV backend 'qdevification'. Starting with xen_disk. * Performance improvements for xen-block. * Remove of the Xen PV domain builder. * bug fixes. -----BEGIN PGP SIGNATURE----- iQFOBAABCgA4FiEE+AwAYwjiLP2KkueYDPVXL9f7Va8FAlw8krkaHGFudGhvbnku cGVyYXJkQGNpdHJpeC5jb20ACgkQDPVXL9f7Va81vQf/XH0vIHytB0xM9qd06Svi axW6grfLfHipSIjQwdv8xeJjLJUQxZCV3Q1kg8sHDAioj9LVc0jAiJKMMUkQdnHT Ad98PbKrPNdEZJf+dydzFmibuehqD8OHL0Nu4U/k3+PKp/QjWJZvr7SspVxJPvz3 K29n5HTjfA4QntahSEHKndmbQ9sxPd+Pz8+qZEXBLtogOW0xhK6WAVwkPG4XwhFz 6wXySfuruSM0v5F3wkdA7FS1rmcdW/prty81MT7zg6h8hcYLo49pbXrRTuB6Psuz UWsbNhegevYWpxZAZZv9TvCY6d/5X733wDhENCTD8am+GBoDVV4Dh9YljTTjG4S0 tA== =88n2 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/aperard/tags/pull-xen-20190114' into staging Xen queue * Xen PV backend 'qdevification'. Starting with xen_disk. * Performance improvements for xen-block. * Remove of the Xen PV domain builder. * bug fixes. # gpg: Signature made Mon 14 Jan 2019 13:46:33 GMT # gpg: using RSA key 0CF5572FD7FB55AF # gpg: Good signature from "Anthony PERARD <anthony.perard@gmail.com>" # gpg: aka "Anthony PERARD <anthony.perard@citrix.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 5379 2F71 024C 600F 778A 7161 D8D5 7199 DF83 42C8 # Subkey fingerprint: F80C 0063 08E2 2CFD 8A92 E798 0CF5 572F D7FB 55AF * remotes/aperard/tags/pull-xen-20190114: (25 commits) xen-block: avoid repeated memory allocation xen-block: improve response latency xen-block: improve batching behaviour xen: Replace few mentions of xend by libxl Remove broken Xen PV domain builder xen: remove the legacy 'xen_disk' backend MAINTAINERS: add myself as a Xen maintainer xen: automatically create XenBlockDevice-s xen: add a mechanism to automatically create XenDevice-s... xen: add implementations of xen-block connect and disconnect functions... xen: purge 'blk' and 'ioreq' from function names in dataplane/xen-block.c xen: remove 'ioreq' struct/varable/field names from dataplane/xen-block.c xen: remove 'XenBlkDev' and 'blkdev' names from dataplane/xen-block xen: add header and build dataplane/xen-block.c xen: remove unnecessary code from dataplane/xen-block.c xen: duplicate xen_disk.c as basis of dataplane/xen-block.c xen: add event channel interface for XenDevice-s xen: add grant table interface for XenDevice-s xen: add xenstore watcher infrastructure xen: create xenstore areas for XenDevice-s ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c9d18c1c15
|
@ -407,6 +407,7 @@ Guest CPU Cores (Xen):
|
|||
X86
|
||||
M: Stefano Stabellini <sstabellini@kernel.org>
|
||||
M: Anthony Perard <anthony.perard@citrix.com>
|
||||
M: Paul Durrant <paul.durrant@citrix.com>
|
||||
L: xen-devel@lists.xenproject.org
|
||||
S: Supported
|
||||
F: */xen*
|
||||
|
@ -414,10 +415,12 @@ F: hw/9pfs/xen-9p-backend.c
|
|||
F: hw/char/xen_console.c
|
||||
F: hw/display/xenfb.c
|
||||
F: hw/net/xen_nic.c
|
||||
F: hw/block/xen_*
|
||||
F: hw/block/xen*
|
||||
F: hw/block/dataplane/xen*
|
||||
F: hw/xen/
|
||||
F: hw/xenpv/
|
||||
F: hw/i386/xen/
|
||||
F: include/hw/block/dataplane/xen*
|
||||
F: include/hw/xen/
|
||||
F: include/sysemu/xen-mapcache.h
|
||||
|
||||
|
|
17
configure
vendored
17
configure
vendored
|
@ -357,7 +357,6 @@ vnc_png=""
|
|||
xkbcommon=""
|
||||
xen=""
|
||||
xen_ctrl_version=""
|
||||
xen_pv_domain_build="no"
|
||||
xen_pci_passthrough=""
|
||||
linux_aio=""
|
||||
cap_ng=""
|
||||
|
@ -1119,10 +1118,6 @@ for opt do
|
|||
;;
|
||||
--enable-xen-pci-passthrough) xen_pci_passthrough="yes"
|
||||
;;
|
||||
--disable-xen-pv-domain-build) xen_pv_domain_build="no"
|
||||
;;
|
||||
--enable-xen-pv-domain-build) xen_pv_domain_build="yes"
|
||||
;;
|
||||
--disable-brlapi) brlapi="no"
|
||||
;;
|
||||
--enable-brlapi) brlapi="yes"
|
||||
|
@ -1685,8 +1680,6 @@ Advanced options (experts only):
|
|||
--tls-priority default TLS protocol/cipher priority string
|
||||
--enable-gprof QEMU profiling with gprof
|
||||
--enable-profiler profiler support
|
||||
--enable-xen-pv-domain-build
|
||||
xen pv domain builder
|
||||
--enable-debug-stack-usage
|
||||
track the maximum stack usage of stacks created by qemu_alloc_stack
|
||||
|
||||
|
@ -2678,12 +2671,6 @@ if test "$xen_pci_passthrough" != "no"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if test "$xen_pv_domain_build" = "yes" &&
|
||||
test "$xen" != "yes"; then
|
||||
error_exit "User requested Xen PV domain builder support" \
|
||||
"which requires Xen support."
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Windows Hypervisor Platform accelerator (WHPX) check
|
||||
if test "$whpx" != "no" ; then
|
||||
|
@ -6069,7 +6056,6 @@ fi
|
|||
echo "xen support $xen"
|
||||
if test "$xen" = "yes" ; then
|
||||
echo "xen ctrl version $xen_ctrl_version"
|
||||
echo "pv dom build $xen_pv_domain_build"
|
||||
fi
|
||||
echo "brlapi support $brlapi"
|
||||
echo "bluez support $bluez"
|
||||
|
@ -6539,9 +6525,6 @@ fi
|
|||
if test "$xen" = "yes" ; then
|
||||
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
|
||||
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
|
||||
if test "$xen_pv_domain_build" = "yes" ; then
|
||||
echo "CONFIG_XEN_PV_DOMAIN_BUILD=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$linux_aio" = "yes" ; then
|
||||
echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/9pfs/9p.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/9pfs/xen-9pfs.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/config-file.h"
|
||||
|
@ -45,7 +45,7 @@ typedef struct Xen9pfsRing {
|
|||
} Xen9pfsRing;
|
||||
|
||||
typedef struct Xen9pfsDev {
|
||||
struct XenDevice xendev; /* must be first */
|
||||
struct XenLegacyDevice xendev; /* must be first */
|
||||
V9fsState state;
|
||||
char *path;
|
||||
char *security_model;
|
||||
|
@ -56,7 +56,7 @@ typedef struct Xen9pfsDev {
|
|||
Xen9pfsRing *rings;
|
||||
} Xen9pfsDev;
|
||||
|
||||
static void xen_9pfs_disconnect(struct XenDevice *xendev);
|
||||
static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
|
||||
|
||||
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
|
||||
struct iovec *in_sg,
|
||||
|
@ -243,7 +243,7 @@ static const V9fsTransport xen_9p_transport = {
|
|||
.push_and_notify = xen_9pfs_push_and_notify,
|
||||
};
|
||||
|
||||
static int xen_9pfs_init(struct XenDevice *xendev)
|
||||
static int xen_9pfs_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ static void xen_9pfs_evtchn_event(void *opaque)
|
|||
qemu_bh_schedule(ring->bh);
|
||||
}
|
||||
|
||||
static void xen_9pfs_disconnect(struct XenDevice *xendev)
|
||||
static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||
int i;
|
||||
|
@ -321,7 +321,7 @@ static void xen_9pfs_disconnect(struct XenDevice *xendev)
|
|||
}
|
||||
}
|
||||
|
||||
static int xen_9pfs_free(struct XenDevice *xendev)
|
||||
static int xen_9pfs_free(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||
int i;
|
||||
|
@ -354,7 +354,7 @@ static int xen_9pfs_free(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xen_9pfs_connect(struct XenDevice *xendev)
|
||||
static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
@ -467,7 +467,7 @@ out:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void xen_9pfs_alloc(struct XenDevice *xendev)
|
||||
static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
xenstore_write_be_str(xendev, "versions", VERSIONS);
|
||||
xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
|
||||
|
|
|
@ -4,7 +4,7 @@ common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
|
|||
common-obj-$(CONFIG_NAND) += nand.o
|
||||
common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
|
||||
common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
|
||||
common-obj-$(CONFIG_XEN) += xen_disk.o
|
||||
common-obj-$(CONFIG_XEN) += xen-block.o
|
||||
common-obj-$(CONFIG_ECC) += ecc.o
|
||||
common-obj-$(CONFIG_ONENAND) += onenand.o
|
||||
common-obj-$(CONFIG_NVME_PCI) += nvme.o
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
obj-y += virtio-blk.o
|
||||
obj-$(CONFIG_XEN) += xen-block.o
|
||||
|
|
827
hw/block/dataplane/xen-block.c
Normal file
827
hw/block/dataplane/xen-block.c
Normal file
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
* (c) Gerd Hoffmann <kraxel@redhat.com>
|
||||
*
|
||||
* 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; under version 2 of the License.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/block/xen_blkif.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/iothread.h"
|
||||
#include "xen-block.h"
|
||||
|
||||
typedef struct XenBlockRequest {
|
||||
blkif_request_t req;
|
||||
int16_t status;
|
||||
off_t start;
|
||||
QEMUIOVector v;
|
||||
void *buf;
|
||||
size_t size;
|
||||
int presync;
|
||||
int aio_inflight;
|
||||
int aio_errors;
|
||||
XenBlockDataPlane *dataplane;
|
||||
QLIST_ENTRY(XenBlockRequest) list;
|
||||
BlockAcctCookie acct;
|
||||
} XenBlockRequest;
|
||||
|
||||
struct XenBlockDataPlane {
|
||||
XenDevice *xendev;
|
||||
XenEventChannel *event_channel;
|
||||
unsigned int *ring_ref;
|
||||
unsigned int nr_ring_ref;
|
||||
void *sring;
|
||||
int64_t file_blk;
|
||||
int64_t file_size;
|
||||
int protocol;
|
||||
blkif_back_rings_t rings;
|
||||
int more_work;
|
||||
QLIST_HEAD(inflight_head, XenBlockRequest) inflight;
|
||||
QLIST_HEAD(freelist_head, XenBlockRequest) freelist;
|
||||
int requests_total;
|
||||
int requests_inflight;
|
||||
unsigned int max_requests;
|
||||
BlockBackend *blk;
|
||||
QEMUBH *bh;
|
||||
IOThread *iothread;
|
||||
AioContext *ctx;
|
||||
};
|
||||
|
||||
static void reset_request(XenBlockRequest *request)
|
||||
{
|
||||
memset(&request->req, 0, sizeof(request->req));
|
||||
request->status = 0;
|
||||
request->start = 0;
|
||||
request->size = 0;
|
||||
request->presync = 0;
|
||||
|
||||
request->aio_inflight = 0;
|
||||
request->aio_errors = 0;
|
||||
|
||||
request->dataplane = NULL;
|
||||
memset(&request->list, 0, sizeof(request->list));
|
||||
memset(&request->acct, 0, sizeof(request->acct));
|
||||
|
||||
qemu_iovec_reset(&request->v);
|
||||
}
|
||||
|
||||
static XenBlockRequest *xen_block_start_request(XenBlockDataPlane *dataplane)
|
||||
{
|
||||
XenBlockRequest *request = NULL;
|
||||
|
||||
if (QLIST_EMPTY(&dataplane->freelist)) {
|
||||
if (dataplane->requests_total >= dataplane->max_requests) {
|
||||
goto out;
|
||||
}
|
||||
/* allocate new struct */
|
||||
request = g_malloc0(sizeof(*request));
|
||||
request->dataplane = dataplane;
|
||||
/*
|
||||
* We cannot need more pages per requests than this, and since we
|
||||
* re-use requests, allocate the memory once here. It will be freed
|
||||
* xen_block_dataplane_destroy() when the request list is freed.
|
||||
*/
|
||||
request->buf = qemu_memalign(XC_PAGE_SIZE,
|
||||
BLKIF_MAX_SEGMENTS_PER_REQUEST *
|
||||
XC_PAGE_SIZE);
|
||||
dataplane->requests_total++;
|
||||
qemu_iovec_init(&request->v, 1);
|
||||
} else {
|
||||
/* get one from freelist */
|
||||
request = QLIST_FIRST(&dataplane->freelist);
|
||||
QLIST_REMOVE(request, list);
|
||||
}
|
||||
QLIST_INSERT_HEAD(&dataplane->inflight, request, list);
|
||||
dataplane->requests_inflight++;
|
||||
|
||||
out:
|
||||
return request;
|
||||
}
|
||||
|
||||
static void xen_block_finish_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
QLIST_REMOVE(request, list);
|
||||
dataplane->requests_inflight--;
|
||||
}
|
||||
|
||||
static void xen_block_release_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
QLIST_REMOVE(request, list);
|
||||
reset_request(request);
|
||||
request->dataplane = dataplane;
|
||||
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
|
||||
dataplane->requests_inflight--;
|
||||
}
|
||||
|
||||
/*
|
||||
* translate request into iovec + start offset
|
||||
* do sanity checks along the way
|
||||
*/
|
||||
static int xen_block_parse_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_READ:
|
||||
break;
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
request->presync = 1;
|
||||
if (!request->req.nr_segments) {
|
||||
return 0;
|
||||
}
|
||||
/* fall through */
|
||||
case BLKIF_OP_WRITE:
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
return 0;
|
||||
default:
|
||||
error_report("error: unknown operation (%d)", request->req.operation);
|
||||
goto err;
|
||||
};
|
||||
|
||||
if (request->req.operation != BLKIF_OP_READ &&
|
||||
blk_is_read_only(dataplane->blk)) {
|
||||
error_report("error: write req for ro device");
|
||||
goto err;
|
||||
}
|
||||
|
||||
request->start = request->req.sector_number * dataplane->file_blk;
|
||||
for (i = 0; i < request->req.nr_segments; i++) {
|
||||
if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
|
||||
error_report("error: nr_segments too big");
|
||||
goto err;
|
||||
}
|
||||
if (request->req.seg[i].first_sect > request->req.seg[i].last_sect) {
|
||||
error_report("error: first > last sector");
|
||||
goto err;
|
||||
}
|
||||
if (request->req.seg[i].last_sect * dataplane->file_blk >=
|
||||
XC_PAGE_SIZE) {
|
||||
error_report("error: page crossing");
|
||||
goto err;
|
||||
}
|
||||
|
||||
len = (request->req.seg[i].last_sect -
|
||||
request->req.seg[i].first_sect + 1) * dataplane->file_blk;
|
||||
request->size += len;
|
||||
}
|
||||
if (request->start + request->size > dataplane->file_size) {
|
||||
error_report("error: access beyond end of file");
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
request->status = BLKIF_RSP_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int xen_block_copy_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
XenDevice *xendev = dataplane->xendev;
|
||||
XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
int i, count;
|
||||
int64_t file_blk = dataplane->file_blk;
|
||||
bool to_domain = (request->req.operation == BLKIF_OP_READ);
|
||||
void *virt = request->buf;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (request->req.nr_segments == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = request->req.nr_segments;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (to_domain) {
|
||||
segs[i].dest.foreign.ref = request->req.seg[i].gref;
|
||||
segs[i].dest.foreign.offset = request->req.seg[i].first_sect *
|
||||
file_blk;
|
||||
segs[i].source.virt = virt;
|
||||
} else {
|
||||
segs[i].source.foreign.ref = request->req.seg[i].gref;
|
||||
segs[i].source.foreign.offset = request->req.seg[i].first_sect *
|
||||
file_blk;
|
||||
segs[i].dest.virt = virt;
|
||||
}
|
||||
segs[i].len = (request->req.seg[i].last_sect -
|
||||
request->req.seg[i].first_sect + 1) * file_blk;
|
||||
virt += segs[i].len;
|
||||
}
|
||||
|
||||
xen_device_copy_grant_refs(xendev, to_domain, segs, count, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
error_reportf_err(local_err, "failed to copy data: ");
|
||||
|
||||
request->aio_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xen_block_do_aio(XenBlockRequest *request);
|
||||
static int xen_block_send_response(XenBlockRequest *request);
|
||||
|
||||
static void xen_block_complete_aio(void *opaque, int ret)
|
||||
{
|
||||
XenBlockRequest *request = opaque;
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
aio_context_acquire(dataplane->ctx);
|
||||
|
||||
if (ret != 0) {
|
||||
error_report("%s I/O error",
|
||||
request->req.operation == BLKIF_OP_READ ?
|
||||
"read" : "write");
|
||||
request->aio_errors++;
|
||||
}
|
||||
|
||||
request->aio_inflight--;
|
||||
if (request->presync) {
|
||||
request->presync = 0;
|
||||
xen_block_do_aio(request);
|
||||
goto done;
|
||||
}
|
||||
if (request->aio_inflight > 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_READ:
|
||||
/* in case of failure request->aio_errors is increased */
|
||||
if (ret == 0) {
|
||||
xen_block_copy_request(request);
|
||||
}
|
||||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
if (!request->req.nr_segments) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||
xen_block_finish_request(request);
|
||||
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
if (!request->req.nr_segments) {
|
||||
break;
|
||||
}
|
||||
case BLKIF_OP_READ:
|
||||
if (request->status == BLKIF_RSP_OKAY) {
|
||||
block_acct_done(blk_get_stats(dataplane->blk), &request->acct);
|
||||
} else {
|
||||
block_acct_failed(blk_get_stats(dataplane->blk), &request->acct);
|
||||
}
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (xen_block_send_response(request)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_notify_event_channel(dataplane->xendev,
|
||||
dataplane->event_channel,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
xen_block_release_request(request);
|
||||
|
||||
qemu_bh_schedule(dataplane->bh);
|
||||
|
||||
done:
|
||||
aio_context_release(dataplane->ctx);
|
||||
}
|
||||
|
||||
static bool xen_block_split_discard(XenBlockRequest *request,
|
||||
blkif_sector_t sector_number,
|
||||
uint64_t nr_sectors)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
int64_t byte_offset;
|
||||
int byte_chunk;
|
||||
uint64_t byte_remaining, limit;
|
||||
uint64_t sec_start = sector_number;
|
||||
uint64_t sec_count = nr_sectors;
|
||||
|
||||
/* Wrap around, or overflowing byte limit? */
|
||||
if (sec_start + sec_count < sec_count ||
|
||||
sec_start + sec_count > INT64_MAX / dataplane->file_blk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
limit = BDRV_REQUEST_MAX_SECTORS * dataplane->file_blk;
|
||||
byte_offset = sec_start * dataplane->file_blk;
|
||||
byte_remaining = sec_count * dataplane->file_blk;
|
||||
|
||||
do {
|
||||
byte_chunk = byte_remaining > limit ? limit : byte_remaining;
|
||||
request->aio_inflight++;
|
||||
blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk,
|
||||
xen_block_complete_aio, request);
|
||||
byte_remaining -= byte_chunk;
|
||||
byte_offset += byte_chunk;
|
||||
} while (byte_remaining > 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int xen_block_do_aio(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
if (request->req.nr_segments &&
|
||||
(request->req.operation == BLKIF_OP_WRITE ||
|
||||
request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
|
||||
xen_block_copy_request(request)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
request->aio_inflight++;
|
||||
if (request->presync) {
|
||||
blk_aio_flush(request->dataplane->blk, xen_block_complete_aio,
|
||||
request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_READ:
|
||||
qemu_iovec_add(&request->v, request->buf, request->size);
|
||||
block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
|
||||
request->v.size, BLOCK_ACCT_READ);
|
||||
request->aio_inflight++;
|
||||
blk_aio_preadv(dataplane->blk, request->start, &request->v, 0,
|
||||
xen_block_complete_aio, request);
|
||||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
if (!request->req.nr_segments) {
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_iovec_add(&request->v, request->buf, request->size);
|
||||
block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
|
||||
request->v.size,
|
||||
request->req.operation == BLKIF_OP_WRITE ?
|
||||
BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
|
||||
request->aio_inflight++;
|
||||
blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0,
|
||||
xen_block_complete_aio, request);
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
{
|
||||
struct blkif_request_discard *req = (void *)&request->req;
|
||||
if (!xen_block_split_discard(request, req->sector_number,
|
||||
req->nr_sectors)) {
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* unknown operation (shouldn't happen -- parse catches this) */
|
||||
goto err;
|
||||
}
|
||||
|
||||
xen_block_complete_aio(request, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
xen_block_finish_request(request);
|
||||
request->status = BLKIF_RSP_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int xen_block_send_response(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
int send_notify = 0;
|
||||
int have_requests = 0;
|
||||
blkif_response_t *resp;
|
||||
|
||||
/* Place on the response ring for the relevant domain. */
|
||||
switch (dataplane->protocol) {
|
||||
case BLKIF_PROTOCOL_NATIVE:
|
||||
resp = (blkif_response_t *)RING_GET_RESPONSE(
|
||||
&dataplane->rings.native,
|
||||
dataplane->rings.native.rsp_prod_pvt);
|
||||
break;
|
||||
case BLKIF_PROTOCOL_X86_32:
|
||||
resp = (blkif_response_t *)RING_GET_RESPONSE(
|
||||
&dataplane->rings.x86_32_part,
|
||||
dataplane->rings.x86_32_part.rsp_prod_pvt);
|
||||
break;
|
||||
case BLKIF_PROTOCOL_X86_64:
|
||||
resp = (blkif_response_t *)RING_GET_RESPONSE(
|
||||
&dataplane->rings.x86_64_part,
|
||||
dataplane->rings.x86_64_part.rsp_prod_pvt);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
resp->id = request->req.id;
|
||||
resp->operation = request->req.operation;
|
||||
resp->status = request->status;
|
||||
|
||||
dataplane->rings.common.rsp_prod_pvt++;
|
||||
|
||||
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&dataplane->rings.common,
|
||||
send_notify);
|
||||
if (dataplane->rings.common.rsp_prod_pvt ==
|
||||
dataplane->rings.common.req_cons) {
|
||||
/*
|
||||
* Tail check for pending requests. Allows frontend to avoid
|
||||
* notifications if requests are already in flight (lower
|
||||
* overheads and promotes batching).
|
||||
*/
|
||||
RING_FINAL_CHECK_FOR_REQUESTS(&dataplane->rings.common,
|
||||
have_requests);
|
||||
} else if (RING_HAS_UNCONSUMED_REQUESTS(&dataplane->rings.common)) {
|
||||
have_requests = 1;
|
||||
}
|
||||
|
||||
if (have_requests) {
|
||||
dataplane->more_work++;
|
||||
}
|
||||
return send_notify;
|
||||
}
|
||||
|
||||
static int xen_block_get_request(XenBlockDataPlane *dataplane,
|
||||
XenBlockRequest *request, RING_IDX rc)
|
||||
{
|
||||
switch (dataplane->protocol) {
|
||||
case BLKIF_PROTOCOL_NATIVE: {
|
||||
blkif_request_t *req =
|
||||
RING_GET_REQUEST(&dataplane->rings.native, rc);
|
||||
|
||||
memcpy(&request->req, req, sizeof(request->req));
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_32: {
|
||||
blkif_x86_32_request_t *req =
|
||||
RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc);
|
||||
|
||||
blkif_get_x86_32_req(&request->req, req);
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_64: {
|
||||
blkif_x86_64_request_t *req =
|
||||
RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc);
|
||||
|
||||
blkif_get_x86_64_req(&request->req, req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Prevent the compiler from accessing the on-ring fields instead. */
|
||||
barrier();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Threshold of in-flight requests above which we will start using
|
||||
* blk_io_plug()/blk_io_unplug() to batch requests.
|
||||
*/
|
||||
#define IO_PLUG_THRESHOLD 1
|
||||
|
||||
static void xen_block_handle_requests(XenBlockDataPlane *dataplane)
|
||||
{
|
||||
RING_IDX rc, rp;
|
||||
XenBlockRequest *request;
|
||||
int inflight_atstart = dataplane->requests_inflight;
|
||||
int batched = 0;
|
||||
|
||||
dataplane->more_work = 0;
|
||||
|
||||
rc = dataplane->rings.common.req_cons;
|
||||
rp = dataplane->rings.common.sring->req_prod;
|
||||
xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||||
|
||||
/*
|
||||
* If there was more than IO_PLUG_THRESHOLD requests in flight
|
||||
* when we got here, this is an indication that there the bottleneck
|
||||
* is below us, so it's worth beginning to batch up I/O requests
|
||||
* rather than submitting them immediately. The maximum number
|
||||
* of requests we're willing to batch is the number already in
|
||||
* flight, so it can grow up to max_requests when the bottleneck
|
||||
* is below us.
|
||||
*/
|
||||
if (inflight_atstart > IO_PLUG_THRESHOLD) {
|
||||
blk_io_plug(dataplane->blk);
|
||||
}
|
||||
while (rc != rp) {
|
||||
/* pull request from ring */
|
||||
if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) {
|
||||
break;
|
||||
}
|
||||
request = xen_block_start_request(dataplane);
|
||||
if (request == NULL) {
|
||||
dataplane->more_work++;
|
||||
break;
|
||||
}
|
||||
xen_block_get_request(dataplane, request, rc);
|
||||
dataplane->rings.common.req_cons = ++rc;
|
||||
|
||||
/* parse them */
|
||||
if (xen_block_parse_request(request) != 0) {
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_READ:
|
||||
block_acct_invalid(blk_get_stats(dataplane->blk),
|
||||
BLOCK_ACCT_READ);
|
||||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
block_acct_invalid(blk_get_stats(dataplane->blk),
|
||||
BLOCK_ACCT_WRITE);
|
||||
break;
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
block_acct_invalid(blk_get_stats(dataplane->blk),
|
||||
BLOCK_ACCT_FLUSH);
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
if (xen_block_send_response(request)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_notify_event_channel(dataplane->xendev,
|
||||
dataplane->event_channel,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
xen_block_release_request(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inflight_atstart > IO_PLUG_THRESHOLD &&
|
||||
batched >= inflight_atstart) {
|
||||
blk_io_unplug(dataplane->blk);
|
||||
}
|
||||
xen_block_do_aio(request);
|
||||
if (inflight_atstart > IO_PLUG_THRESHOLD) {
|
||||
if (batched >= inflight_atstart) {
|
||||
blk_io_plug(dataplane->blk);
|
||||
batched = 0;
|
||||
} else {
|
||||
batched++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inflight_atstart > IO_PLUG_THRESHOLD) {
|
||||
blk_io_unplug(dataplane->blk);
|
||||
}
|
||||
|
||||
if (dataplane->more_work &&
|
||||
dataplane->requests_inflight < dataplane->max_requests) {
|
||||
qemu_bh_schedule(dataplane->bh);
|
||||
}
|
||||
}
|
||||
|
||||
static void xen_block_dataplane_bh(void *opaque)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = opaque;
|
||||
|
||||
aio_context_acquire(dataplane->ctx);
|
||||
xen_block_handle_requests(dataplane);
|
||||
aio_context_release(dataplane->ctx);
|
||||
}
|
||||
|
||||
static void xen_block_dataplane_event(void *opaque)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = opaque;
|
||||
|
||||
qemu_bh_schedule(dataplane->bh);
|
||||
}
|
||||
|
||||
XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
|
||||
BlockConf *conf,
|
||||
IOThread *iothread)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = g_new0(XenBlockDataPlane, 1);
|
||||
|
||||
dataplane->xendev = xendev;
|
||||
dataplane->file_blk = conf->logical_block_size;
|
||||
dataplane->blk = conf->blk;
|
||||
dataplane->file_size = blk_getlength(dataplane->blk);
|
||||
|
||||
QLIST_INIT(&dataplane->inflight);
|
||||
QLIST_INIT(&dataplane->freelist);
|
||||
|
||||
if (iothread) {
|
||||
dataplane->iothread = iothread;
|
||||
object_ref(OBJECT(dataplane->iothread));
|
||||
dataplane->ctx = iothread_get_aio_context(dataplane->iothread);
|
||||
} else {
|
||||
dataplane->ctx = qemu_get_aio_context();
|
||||
}
|
||||
dataplane->bh = aio_bh_new(dataplane->ctx, xen_block_dataplane_bh,
|
||||
dataplane);
|
||||
|
||||
return dataplane;
|
||||
}
|
||||
|
||||
void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
|
||||
{
|
||||
XenBlockRequest *request;
|
||||
|
||||
if (!dataplane) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!QLIST_EMPTY(&dataplane->freelist)) {
|
||||
request = QLIST_FIRST(&dataplane->freelist);
|
||||
QLIST_REMOVE(request, list);
|
||||
qemu_iovec_destroy(&request->v);
|
||||
qemu_vfree(request->buf);
|
||||
g_free(request);
|
||||
}
|
||||
|
||||
qemu_bh_delete(dataplane->bh);
|
||||
if (dataplane->iothread) {
|
||||
object_unref(OBJECT(dataplane->iothread));
|
||||
}
|
||||
|
||||
g_free(dataplane);
|
||||
}
|
||||
|
||||
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
|
||||
{
|
||||
XenDevice *xendev;
|
||||
|
||||
if (!dataplane) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context_acquire(dataplane->ctx);
|
||||
blk_set_aio_context(dataplane->blk, qemu_get_aio_context());
|
||||
aio_context_release(dataplane->ctx);
|
||||
|
||||
xendev = dataplane->xendev;
|
||||
|
||||
if (dataplane->event_channel) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_unbind_event_channel(xendev, dataplane->event_channel,
|
||||
&local_err);
|
||||
dataplane->event_channel = NULL;
|
||||
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
|
||||
if (dataplane->sring) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_unmap_grant_refs(xendev, dataplane->sring,
|
||||
dataplane->nr_ring_ref, &local_err);
|
||||
dataplane->sring = NULL;
|
||||
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(dataplane->ring_ref);
|
||||
dataplane->ring_ref = NULL;
|
||||
}
|
||||
|
||||
void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
|
||||
const unsigned int ring_ref[],
|
||||
unsigned int nr_ring_ref,
|
||||
unsigned int event_channel,
|
||||
unsigned int protocol,
|
||||
Error **errp)
|
||||
{
|
||||
XenDevice *xendev = dataplane->xendev;
|
||||
Error *local_err = NULL;
|
||||
unsigned int ring_size;
|
||||
unsigned int i;
|
||||
|
||||
dataplane->nr_ring_ref = nr_ring_ref;
|
||||
dataplane->ring_ref = g_new(unsigned int, nr_ring_ref);
|
||||
|
||||
for (i = 0; i < nr_ring_ref; i++) {
|
||||
dataplane->ring_ref[i] = ring_ref[i];
|
||||
}
|
||||
|
||||
dataplane->protocol = protocol;
|
||||
|
||||
ring_size = XC_PAGE_SIZE * dataplane->nr_ring_ref;
|
||||
switch (dataplane->protocol) {
|
||||
case BLKIF_PROTOCOL_NATIVE:
|
||||
{
|
||||
dataplane->max_requests = __CONST_RING_SIZE(blkif, ring_size);
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_32:
|
||||
{
|
||||
dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_64:
|
||||
{
|
||||
dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error_setg(errp, "unknown protocol %u", dataplane->protocol);
|
||||
return;
|
||||
}
|
||||
|
||||
xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto stop;
|
||||
}
|
||||
|
||||
dataplane->sring = xen_device_map_grant_refs(xendev,
|
||||
dataplane->ring_ref,
|
||||
dataplane->nr_ring_ref,
|
||||
PROT_READ | PROT_WRITE,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto stop;
|
||||
}
|
||||
|
||||
switch (dataplane->protocol) {
|
||||
case BLKIF_PROTOCOL_NATIVE:
|
||||
{
|
||||
blkif_sring_t *sring_native = dataplane->sring;
|
||||
|
||||
BACK_RING_INIT(&dataplane->rings.native, sring_native, ring_size);
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_32:
|
||||
{
|
||||
blkif_x86_32_sring_t *sring_x86_32 = dataplane->sring;
|
||||
|
||||
BACK_RING_INIT(&dataplane->rings.x86_32_part, sring_x86_32,
|
||||
ring_size);
|
||||
break;
|
||||
}
|
||||
case BLKIF_PROTOCOL_X86_64:
|
||||
{
|
||||
blkif_x86_64_sring_t *sring_x86_64 = dataplane->sring;
|
||||
|
||||
BACK_RING_INIT(&dataplane->rings.x86_64_part, sring_x86_64,
|
||||
ring_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dataplane->event_channel =
|
||||
xen_device_bind_event_channel(xendev, event_channel,
|
||||
xen_block_dataplane_event, dataplane,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto stop;
|
||||
}
|
||||
|
||||
aio_context_acquire(dataplane->ctx);
|
||||
blk_set_aio_context(dataplane->blk, dataplane->ctx);
|
||||
aio_context_release(dataplane->ctx);
|
||||
return;
|
||||
|
||||
stop:
|
||||
xen_block_dataplane_stop(dataplane);
|
||||
}
|
29
hw/block/dataplane/xen-block.h
Normal file
29
hw/block/dataplane/xen-block.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_BLOCK_DATAPLANE_XEN_BLOCK_H
|
||||
#define HW_BLOCK_DATAPLANE_XEN_BLOCK_H
|
||||
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "sysemu/iothread.h"
|
||||
|
||||
typedef struct XenBlockDataPlane XenBlockDataPlane;
|
||||
|
||||
XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
|
||||
BlockConf *conf,
|
||||
IOThread *iothread);
|
||||
void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane);
|
||||
void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
|
||||
const unsigned int ring_ref[],
|
||||
unsigned int nr_ring_ref,
|
||||
unsigned int event_channel,
|
||||
unsigned int protocol,
|
||||
Error **errp);
|
||||
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane);
|
||||
|
||||
#endif /* HW_BLOCK_DATAPLANE_XEN_BLOCK_H */
|
|
@ -127,3 +127,17 @@ xen_disk_init(char *name) "%s"
|
|||
xen_disk_connect(char *name) "%s"
|
||||
xen_disk_disconnect(char *name) "%s"
|
||||
xen_disk_free(char *name) "%s"
|
||||
|
||||
# hw/block/xen-block.c
|
||||
xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
|
||||
xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
|
||||
xen_block_disconnect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
|
||||
xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
|
||||
xen_disk_realize(void) ""
|
||||
xen_disk_unrealize(void) ""
|
||||
xen_cdrom_realize(void) ""
|
||||
xen_cdrom_unrealize(void) ""
|
||||
xen_block_blockdev_add(char *str) "%s"
|
||||
xen_block_blockdev_del(const char *node_name) "%s"
|
||||
xen_block_device_create(unsigned int number) "%u"
|
||||
xen_block_device_destroy(unsigned int number) "%u"
|
||||
|
|
963
hw/block/xen-block.c
Normal file
963
hw/block/xen-block.c
Normal file
|
@ -0,0 +1,963 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-block-core.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-visit-block-core.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/block/xen_blkif.h"
|
||||
#include "hw/xen/xen-block.h"
|
||||
#include "hw/xen/xen-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/iothread.h"
|
||||
#include "dataplane/xen-block.h"
|
||||
#include "trace.h"
|
||||
|
||||
static char *xen_block_get_name(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
|
||||
return g_strdup_printf("%lu", vdev->number);
|
||||
}
|
||||
|
||||
static void xen_block_disconnect(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
const char *type = object_get_typename(OBJECT(blockdev));
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
|
||||
trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
|
||||
|
||||
xen_block_dataplane_stop(blockdev->dataplane);
|
||||
}
|
||||
|
||||
static void xen_block_connect(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
const char *type = object_get_typename(OBJECT(blockdev));
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
|
||||
char *str;
|
||||
|
||||
trace_xen_block_connect(type, vdev->disk, vdev->partition);
|
||||
|
||||
if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
|
||||
&order) != 1) {
|
||||
nr_ring_ref = 1;
|
||||
ring_ref = g_new(unsigned int, nr_ring_ref);
|
||||
|
||||
if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
|
||||
&ring_ref[0]) != 1) {
|
||||
error_setg(errp, "failed to read ring-ref");
|
||||
g_free(ring_ref);
|
||||
return;
|
||||
}
|
||||
} else if (order <= blockdev->props.max_ring_page_order) {
|
||||
unsigned int i;
|
||||
|
||||
nr_ring_ref = 1 << order;
|
||||
ring_ref = g_new(unsigned int, nr_ring_ref);
|
||||
|
||||
for (i = 0; i < nr_ring_ref; i++) {
|
||||
const char *key = g_strdup_printf("ring-ref%u", i);
|
||||
|
||||
if (xen_device_frontend_scanf(xendev, key, "%u",
|
||||
&ring_ref[i]) != 1) {
|
||||
error_setg(errp, "failed to read %s", key);
|
||||
g_free((gpointer)key);
|
||||
g_free(ring_ref);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free((gpointer)key);
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "invalid ring-page-order (%d)", order);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
|
||||
&event_channel) != 1) {
|
||||
error_setg(errp, "failed to read event-channel");
|
||||
g_free(ring_ref);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
|
||||
&str) != 1) {
|
||||
protocol = BLKIF_PROTOCOL_NATIVE;
|
||||
} else {
|
||||
if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
|
||||
protocol = BLKIF_PROTOCOL_X86_32;
|
||||
} else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
|
||||
protocol = BLKIF_PROTOCOL_X86_64;
|
||||
} else {
|
||||
protocol = BLKIF_PROTOCOL_NATIVE;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
|
||||
event_channel, protocol, errp);
|
||||
|
||||
g_free(ring_ref);
|
||||
}
|
||||
|
||||
static void xen_block_unrealize(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
XenBlockDeviceClass *blockdev_class =
|
||||
XEN_BLOCK_DEVICE_GET_CLASS(xendev);
|
||||
const char *type = object_get_typename(OBJECT(blockdev));
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
|
||||
if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
|
||||
|
||||
/* Disconnect from the frontend in case this has not already happened */
|
||||
xen_block_disconnect(xendev, NULL);
|
||||
|
||||
xen_block_dataplane_destroy(blockdev->dataplane);
|
||||
blockdev->dataplane = NULL;
|
||||
|
||||
if (blockdev_class->unrealize) {
|
||||
blockdev_class->unrealize(blockdev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void xen_block_realize(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
XenBlockDeviceClass *blockdev_class =
|
||||
XEN_BLOCK_DEVICE_GET_CLASS(xendev);
|
||||
const char *type = object_get_typename(OBJECT(blockdev));
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
BlockConf *conf = &blockdev->props.conf;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
|
||||
error_setg(errp, "vdev property not set");
|
||||
return;
|
||||
}
|
||||
|
||||
trace_xen_block_realize(type, vdev->disk, vdev->partition);
|
||||
|
||||
if (blockdev_class->realize) {
|
||||
blockdev_class->realize(blockdev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The blkif protocol does not deal with removable media, so it must
|
||||
* always be present, even for CDRom devices.
|
||||
*/
|
||||
assert(conf->blk);
|
||||
if (!blk_is_inserted(conf->blk)) {
|
||||
error_setg(errp, "device needs media, but drive is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
|
||||
false, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(blockdev->info & VDISK_CDROM) &&
|
||||
!blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
blkconf_blocksizes(conf);
|
||||
|
||||
if (conf->logical_block_size > conf->physical_block_size) {
|
||||
error_setg(
|
||||
errp, "logical_block_size > physical_block_size not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
blk_set_guest_block_size(conf->blk, conf->logical_block_size);
|
||||
|
||||
if (conf->discard_granularity > 0) {
|
||||
xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
|
||||
}
|
||||
|
||||
xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
|
||||
xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
|
||||
blockdev->props.max_ring_page_order);
|
||||
xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
|
||||
|
||||
xen_device_frontend_printf(xendev, "virtual-device", "%lu",
|
||||
vdev->number);
|
||||
xen_device_frontend_printf(xendev, "device-type", "%s",
|
||||
blockdev->device_type);
|
||||
|
||||
xen_device_backend_printf(xendev, "sector-size", "%u",
|
||||
conf->logical_block_size);
|
||||
xen_device_backend_printf(xendev, "sectors", "%lu",
|
||||
blk_getlength(conf->blk) /
|
||||
conf->logical_block_size);
|
||||
|
||||
blockdev->dataplane =
|
||||
xen_block_dataplane_create(xendev, conf, blockdev->props.iothread);
|
||||
}
|
||||
|
||||
static void xen_block_frontend_changed(XenDevice *xendev,
|
||||
enum xenbus_state frontend_state,
|
||||
Error **errp)
|
||||
{
|
||||
enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
switch (frontend_state) {
|
||||
case XenbusStateInitialised:
|
||||
case XenbusStateConnected:
|
||||
if (backend_state == XenbusStateConnected) {
|
||||
break;
|
||||
}
|
||||
|
||||
xen_block_disconnect(xendev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
break;
|
||||
}
|
||||
|
||||
xen_block_connect(xendev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
break;
|
||||
}
|
||||
|
||||
xen_device_backend_set_state(xendev, XenbusStateConnected);
|
||||
break;
|
||||
|
||||
case XenbusStateClosing:
|
||||
xen_device_backend_set_state(xendev, XenbusStateClosing);
|
||||
break;
|
||||
|
||||
case XenbusStateClosed:
|
||||
xen_block_disconnect(xendev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
break;
|
||||
}
|
||||
|
||||
xen_device_backend_set_state(xendev, XenbusStateClosed);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *disk_to_vbd_name(unsigned int disk)
|
||||
{
|
||||
char *name, *prefix = (disk >= 26) ?
|
||||
disk_to_vbd_name((disk / 26) - 1) : g_strdup("");
|
||||
|
||||
name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26);
|
||||
g_free(prefix);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
|
||||
char *str;
|
||||
|
||||
switch (vdev->type) {
|
||||
case XEN_BLOCK_VDEV_TYPE_DP:
|
||||
str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition);
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_VDEV_TYPE_XVD:
|
||||
case XEN_BLOCK_VDEV_TYPE_HD:
|
||||
case XEN_BLOCK_VDEV_TYPE_SD: {
|
||||
char *name = disk_to_vbd_name(vdev->disk);
|
||||
|
||||
str = g_strdup_printf("%s%s%lu",
|
||||
(vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ?
|
||||
"xvd" :
|
||||
(vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ?
|
||||
"hd" :
|
||||
"sd",
|
||||
name, vdev->partition);
|
||||
g_free(name);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error_setg(errp, "invalid vdev type");
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, name, &str, errp);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static unsigned int vbd_name_to_disk(const char *name, const char **endp)
|
||||
{
|
||||
unsigned int disk = 0;
|
||||
|
||||
while (*name != '\0') {
|
||||
if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
disk *= 26;
|
||||
disk += *name++ - 'a' + 1;
|
||||
}
|
||||
*endp = name;
|
||||
|
||||
return disk - 1;
|
||||
}
|
||||
|
||||
static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
|
||||
Error *local_err = NULL;
|
||||
char *str, *p;
|
||||
const char *end;
|
||||
|
||||
if (dev->realized) {
|
||||
qdev_prop_set_after_realize(dev, name, errp);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, name, &str, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
p = strchr(str, 'd');
|
||||
if (!p) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
if (*str == '\0') {
|
||||
vdev->type = XEN_BLOCK_VDEV_TYPE_DP;
|
||||
} else if (strcmp(str, "xv") == 0) {
|
||||
vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
|
||||
} else if (strcmp(str, "h") == 0) {
|
||||
vdev->type = XEN_BLOCK_VDEV_TYPE_HD;
|
||||
} else if (strcmp(str, "s") == 0) {
|
||||
vdev->type = XEN_BLOCK_VDEV_TYPE_SD;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) {
|
||||
if (qemu_strtoul(p, &end, 10, &vdev->disk)) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*end == 'p') {
|
||||
p = (char *) ++end;
|
||||
if (*end == '\0') {
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vdev->disk = vbd_name_to_disk(p, &end);
|
||||
}
|
||||
|
||||
if (*end != '\0') {
|
||||
p = (char *)end;
|
||||
|
||||
if (qemu_strtoul(p, &end, 10, &vdev->partition)) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (*end != '\0') {
|
||||
goto invalid;
|
||||
}
|
||||
} else {
|
||||
vdev->partition = 0;
|
||||
}
|
||||
|
||||
switch (vdev->type) {
|
||||
case XEN_BLOCK_VDEV_TYPE_DP:
|
||||
case XEN_BLOCK_VDEV_TYPE_XVD:
|
||||
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
|
||||
vdev->number = (202 << 8) | (vdev->disk << 4) |
|
||||
vdev->partition;
|
||||
} else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
|
||||
vdev->number = (1 << 28) | (vdev->disk << 8) |
|
||||
vdev->partition;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_VDEV_TYPE_HD:
|
||||
if ((vdev->disk == 0 || vdev->disk == 1) &&
|
||||
vdev->partition < (1 << 6)) {
|
||||
vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
|
||||
} else if ((vdev->disk == 2 || vdev->disk == 3) &&
|
||||
vdev->partition < (1 << 6)) {
|
||||
vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
|
||||
vdev->partition;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_BLOCK_VDEV_TYPE_SD:
|
||||
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
|
||||
vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
error_setg(errp, "invalid virtual disk specifier");
|
||||
|
||||
vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID;
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* This property deals with 'vdev' names adhering to the Xen VBD naming
|
||||
* scheme described in:
|
||||
*
|
||||
* https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
|
||||
*/
|
||||
const PropertyInfo xen_block_prop_vdev = {
|
||||
.name = "str",
|
||||
.description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
|
||||
.get = xen_block_get_vdev,
|
||||
.set = xen_block_set_vdev,
|
||||
};
|
||||
|
||||
static Property xen_block_props[] = {
|
||||
DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
|
||||
xen_block_prop_vdev, XenBlockVdev),
|
||||
DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
|
||||
DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
|
||||
props.max_ring_page_order, 4),
|
||||
DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
|
||||
TYPE_IOTHREAD, IOThread *),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void xen_block_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dev_class = DEVICE_CLASS(class);
|
||||
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
|
||||
|
||||
xendev_class->backend = "qdisk";
|
||||
xendev_class->device = "vbd";
|
||||
xendev_class->get_name = xen_block_get_name;
|
||||
xendev_class->realize = xen_block_realize;
|
||||
xendev_class->frontend_changed = xen_block_frontend_changed;
|
||||
xendev_class->unrealize = xen_block_unrealize;
|
||||
|
||||
dev_class->props = xen_block_props;
|
||||
}
|
||||
|
||||
static const TypeInfo xen_block_type_info = {
|
||||
.name = TYPE_XEN_BLOCK_DEVICE,
|
||||
.parent = TYPE_XEN_DEVICE,
|
||||
.instance_size = sizeof(XenBlockDevice),
|
||||
.abstract = true,
|
||||
.class_size = sizeof(XenBlockDeviceClass),
|
||||
.class_init = xen_block_class_init,
|
||||
};
|
||||
|
||||
static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
|
||||
{
|
||||
trace_xen_disk_unrealize();
|
||||
}
|
||||
|
||||
static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
|
||||
{
|
||||
BlockConf *conf = &blockdev->props.conf;
|
||||
|
||||
trace_xen_disk_realize();
|
||||
|
||||
blockdev->device_type = "disk";
|
||||
|
||||
if (!conf->blk) {
|
||||
error_setg(errp, "drive property not set");
|
||||
return;
|
||||
}
|
||||
|
||||
blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
|
||||
}
|
||||
|
||||
static void xen_disk_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dev_class = DEVICE_CLASS(class);
|
||||
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
|
||||
|
||||
blockdev_class->realize = xen_disk_realize;
|
||||
blockdev_class->unrealize = xen_disk_unrealize;
|
||||
|
||||
dev_class->desc = "Xen Disk Device";
|
||||
}
|
||||
|
||||
static const TypeInfo xen_disk_type_info = {
|
||||
.name = TYPE_XEN_DISK_DEVICE,
|
||||
.parent = TYPE_XEN_BLOCK_DEVICE,
|
||||
.instance_size = sizeof(XenDiskDevice),
|
||||
.class_init = xen_disk_class_init,
|
||||
};
|
||||
|
||||
static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
|
||||
{
|
||||
trace_xen_cdrom_unrealize();
|
||||
}
|
||||
|
||||
static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
|
||||
{
|
||||
BlockConf *conf = &blockdev->props.conf;
|
||||
|
||||
trace_xen_cdrom_realize();
|
||||
|
||||
blockdev->device_type = "cdrom";
|
||||
|
||||
if (!conf->blk) {
|
||||
int rc;
|
||||
|
||||
/* Set up an empty drive */
|
||||
conf->blk = blk_new(0, BLK_PERM_ALL);
|
||||
|
||||
rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
|
||||
if (!rc) {
|
||||
error_setg_errno(errp, -rc, "failed to create drive");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blockdev->info = VDISK_READONLY | VDISK_CDROM;
|
||||
}
|
||||
|
||||
static void xen_cdrom_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dev_class = DEVICE_CLASS(class);
|
||||
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
|
||||
|
||||
blockdev_class->realize = xen_cdrom_realize;
|
||||
blockdev_class->unrealize = xen_cdrom_unrealize;
|
||||
|
||||
dev_class->desc = "Xen CD-ROM Device";
|
||||
}
|
||||
|
||||
static const TypeInfo xen_cdrom_type_info = {
|
||||
.name = TYPE_XEN_CDROM_DEVICE,
|
||||
.parent = TYPE_XEN_BLOCK_DEVICE,
|
||||
.instance_size = sizeof(XenCDRomDevice),
|
||||
.class_init = xen_cdrom_class_init,
|
||||
};
|
||||
|
||||
static void xen_block_register_types(void)
|
||||
{
|
||||
type_register_static(&xen_block_type_info);
|
||||
type_register_static(&xen_disk_type_info);
|
||||
type_register_static(&xen_cdrom_type_info);
|
||||
}
|
||||
|
||||
type_init(xen_block_register_types)
|
||||
|
||||
static void xen_block_blockdev_del(const char *node_name, Error **errp)
|
||||
{
|
||||
trace_xen_block_blockdev_del(node_name);
|
||||
|
||||
qmp_blockdev_del(node_name, errp);
|
||||
}
|
||||
|
||||
static char *xen_block_blockdev_add(const char *id, QDict *qdict,
|
||||
Error **errp)
|
||||
{
|
||||
const char *driver = qdict_get_try_str(qdict, "driver");
|
||||
BlockdevOptions *options = NULL;
|
||||
Error *local_err = NULL;
|
||||
char *node_name;
|
||||
Visitor *v;
|
||||
|
||||
if (!driver) {
|
||||
error_setg(errp, "no 'driver' parameter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_name = g_strdup_printf("%s-%s", id, driver);
|
||||
qdict_put_str(qdict, "node-name", node_name);
|
||||
|
||||
trace_xen_block_blockdev_add(node_name);
|
||||
|
||||
v = qobject_input_visitor_new(QOBJECT(qdict));
|
||||
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||
visit_free(v);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qmp_blockdev_add(options, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qapi_free_BlockdevOptions(options);
|
||||
|
||||
return node_name;
|
||||
|
||||
fail:
|
||||
if (options) {
|
||||
qapi_free_BlockdevOptions(options);
|
||||
}
|
||||
g_free(node_name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
|
||||
{
|
||||
char *node_name = drive->node_name;
|
||||
|
||||
if (node_name) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_block_blockdev_del(node_name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
g_free(node_name);
|
||||
drive->node_name = NULL;
|
||||
}
|
||||
g_free(drive->id);
|
||||
g_free(drive);
|
||||
}
|
||||
|
||||
static XenBlockDrive *xen_block_drive_create(const char *id,
|
||||
const char *device_type,
|
||||
QDict *opts, Error **errp)
|
||||
{
|
||||
const char *params = qdict_get_try_str(opts, "params");
|
||||
const char *mode = qdict_get_try_str(opts, "mode");
|
||||
const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
|
||||
const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
|
||||
char *driver = NULL;
|
||||
char *filename = NULL;
|
||||
XenBlockDrive *drive = NULL;
|
||||
Error *local_err = NULL;
|
||||
QDict *file_layer;
|
||||
QDict *driver_layer;
|
||||
|
||||
if (params) {
|
||||
char **v = g_strsplit(params, ":", 2);
|
||||
|
||||
if (v[1] == NULL) {
|
||||
filename = g_strdup(v[0]);
|
||||
driver = g_strdup("raw");
|
||||
} else {
|
||||
if (strcmp(v[0], "aio") == 0) {
|
||||
driver = g_strdup("raw");
|
||||
} else if (strcmp(v[0], "vhd") == 0) {
|
||||
driver = g_strdup("vpc");
|
||||
} else {
|
||||
driver = g_strdup(v[0]);
|
||||
}
|
||||
filename = g_strdup(v[1]);
|
||||
}
|
||||
|
||||
g_strfreev(v);
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
error_setg(errp, "no filename");
|
||||
goto done;
|
||||
}
|
||||
assert(driver);
|
||||
|
||||
drive = g_new0(XenBlockDrive, 1);
|
||||
drive->id = g_strdup(id);
|
||||
|
||||
file_layer = qdict_new();
|
||||
|
||||
qdict_put_str(file_layer, "driver", "file");
|
||||
qdict_put_str(file_layer, "filename", filename);
|
||||
|
||||
if (mode && *mode != 'w') {
|
||||
qdict_put_bool(file_layer, "read-only", true);
|
||||
}
|
||||
|
||||
if (direct_io_safe) {
|
||||
unsigned long value;
|
||||
|
||||
if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) {
|
||||
QDict *cache_qdict = qdict_new();
|
||||
|
||||
qdict_put_bool(cache_qdict, "direct", true);
|
||||
qdict_put_obj(file_layer, "cache", QOBJECT(cache_qdict));
|
||||
|
||||
qdict_put_str(file_layer, "aio", "native");
|
||||
}
|
||||
}
|
||||
|
||||
if (discard_enable) {
|
||||
unsigned long value;
|
||||
|
||||
if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) {
|
||||
qdict_put_str(file_layer, "discard", "unmap");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It is necessary to turn file locking off as an emulated device
|
||||
* may have already opened the same image file.
|
||||
*/
|
||||
qdict_put_str(file_layer, "locking", "off");
|
||||
|
||||
driver_layer = qdict_new();
|
||||
|
||||
qdict_put_str(driver_layer, "driver", driver);
|
||||
qdict_put_obj(driver_layer, "file", QOBJECT(file_layer));
|
||||
|
||||
g_assert(!drive->node_name);
|
||||
drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
|
||||
&local_err);
|
||||
|
||||
done:
|
||||
g_free(driver);
|
||||
g_free(filename);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
xen_block_drive_destroy(drive, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drive;
|
||||
}
|
||||
|
||||
static const char *xen_block_drive_get_node_name(XenBlockDrive *drive)
|
||||
{
|
||||
return drive->node_name ? drive->node_name : "";
|
||||
}
|
||||
|
||||
static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
|
||||
Error **errp)
|
||||
{
|
||||
qmp_object_del(iothread->id, errp);
|
||||
|
||||
g_free(iothread->id);
|
||||
g_free(iothread);
|
||||
}
|
||||
|
||||
static XenBlockIOThread *xen_block_iothread_create(const char *id,
|
||||
Error **errp)
|
||||
{
|
||||
XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
|
||||
Error *local_err = NULL;
|
||||
|
||||
iothread->id = g_strdup(id);
|
||||
|
||||
qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
|
||||
g_free(iothread->id);
|
||||
g_free(iothread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iothread;
|
||||
}
|
||||
|
||||
static void xen_block_device_create(XenBackendInstance *backend,
|
||||
QDict *opts, Error **errp)
|
||||
{
|
||||
XenBus *xenbus = xen_backend_get_bus(backend);
|
||||
const char *name = xen_backend_get_name(backend);
|
||||
unsigned long number;
|
||||
const char *vdev, *device_type;
|
||||
XenBlockDrive *drive = NULL;
|
||||
XenBlockIOThread *iothread = NULL;
|
||||
XenDevice *xendev = NULL;
|
||||
Error *local_err = NULL;
|
||||
const char *type;
|
||||
XenBlockDevice *blockdev;
|
||||
|
||||
if (qemu_strtoul(name, NULL, 10, &number)) {
|
||||
error_setg(errp, "failed to parse name '%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
trace_xen_block_device_create(number);
|
||||
|
||||
vdev = qdict_get_try_str(opts, "dev");
|
||||
if (!vdev) {
|
||||
error_setg(errp, "no dev parameter");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
device_type = qdict_get_try_str(opts, "device-type");
|
||||
if (!device_type) {
|
||||
error_setg(errp, "no device-type parameter");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!strcmp(device_type, "disk")) {
|
||||
type = TYPE_XEN_DISK_DEVICE;
|
||||
} else if (!strcmp(device_type, "cdrom")) {
|
||||
type = TYPE_XEN_CDROM_DEVICE;
|
||||
} else {
|
||||
error_setg(errp, "invalid device-type parameter '%s'", device_type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
|
||||
if (!drive) {
|
||||
error_propagate_prepend(errp, local_err, "failed to create drive: ");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iothread = xen_block_iothread_create(vdev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"failed to create iothread: ");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
|
||||
blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
|
||||
object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
object_property_set_str(OBJECT(xendev),
|
||||
xen_block_drive_get_node_name(drive), "drive",
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"failed to set 'iothread': ");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
blockdev->iothread = iothread;
|
||||
blockdev->drive = drive;
|
||||
|
||||
object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"realization of device %s failed: ",
|
||||
type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xen_backend_set_device(backend, xendev);
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (xendev) {
|
||||
object_unparent(OBJECT(xendev));
|
||||
}
|
||||
|
||||
if (iothread) {
|
||||
xen_block_iothread_destroy(iothread, NULL);
|
||||
}
|
||||
|
||||
if (drive) {
|
||||
xen_block_drive_destroy(drive, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void xen_block_device_destroy(XenBackendInstance *backend,
|
||||
Error **errp)
|
||||
{
|
||||
XenDevice *xendev = xen_backend_get_device(backend);
|
||||
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
|
||||
XenBlockVdev *vdev = &blockdev->props.vdev;
|
||||
XenBlockDrive *drive = blockdev->drive;
|
||||
XenBlockIOThread *iothread = blockdev->iothread;
|
||||
|
||||
trace_xen_block_device_destroy(vdev->number);
|
||||
|
||||
object_unparent(OBJECT(xendev));
|
||||
|
||||
if (iothread) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_block_iothread_destroy(iothread, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"failed to destroy iothread: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (drive) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_block_drive_destroy(drive, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate_prepend(errp, local_err,
|
||||
"failed to destroy drive: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const XenBackendInfo xen_block_backend_info = {
|
||||
.type = "qdisk",
|
||||
.create = xen_block_device_create,
|
||||
.destroy = xen_block_device_destroy,
|
||||
};
|
||||
|
||||
static void xen_block_register_backend(void)
|
||||
{
|
||||
xen_backend_register(&xen_block_backend_info);
|
||||
}
|
||||
|
||||
xen_backend_init(xen_block_register_backend);
|
1011
hw/block/xen_disk.c
1011
hw/block/xen_disk.c
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
|
||||
#include <xen/io/console.h>
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct buffer {
|
|||
};
|
||||
|
||||
struct XenConsole {
|
||||
struct XenDevice xendev; /* must be first */
|
||||
struct XenLegacyDevice xendev; /* must be first */
|
||||
struct buffer buffer;
|
||||
char console[XEN_BUFSIZE];
|
||||
int ring_ref;
|
||||
|
@ -173,7 +173,7 @@ static void xencons_send(struct XenConsole *con)
|
|||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static int con_init(struct XenDevice *xendev)
|
||||
static int con_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
char *type, *dom, label[32];
|
||||
|
@ -222,7 +222,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int con_initialise(struct XenDevice *xendev)
|
||||
static int con_initialise(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
int limit;
|
||||
|
@ -259,7 +259,7 @@ static int con_initialise(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void con_disconnect(struct XenDevice *xendev)
|
||||
static void con_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
|
||||
|
@ -276,7 +276,7 @@ static void con_disconnect(struct XenDevice *xendev)
|
|||
}
|
||||
}
|
||||
|
||||
static void con_event(struct XenDevice *xendev)
|
||||
static void con_event(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hw/hw.h"
|
||||
#include "ui/input.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
|
||||
#include <xen/event_channel.h>
|
||||
#include <xen/io/fbif.h>
|
||||
|
@ -46,7 +46,7 @@
|
|||
/* -------------------------------------------------------------------- */
|
||||
|
||||
struct common {
|
||||
struct XenDevice xendev; /* must be first */
|
||||
struct XenLegacyDevice xendev; /* must be first */
|
||||
void *page;
|
||||
};
|
||||
|
||||
|
@ -342,14 +342,14 @@ static QemuInputHandler xenfb_rel_mouse = {
|
|||
.sync = xenfb_mouse_sync,
|
||||
};
|
||||
|
||||
static int input_init(struct XenDevice *xendev)
|
||||
static int input_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
|
||||
xenstore_write_be_int(xendev, "feature-raw-pointer", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_initialise(struct XenDevice *xendev)
|
||||
static int input_initialise(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
|
||||
int rc;
|
||||
|
@ -361,7 +361,7 @@ static int input_initialise(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void input_connected(struct XenDevice *xendev)
|
||||
static void input_connected(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
|
||||
|
||||
|
@ -395,7 +395,7 @@ static void input_connected(struct XenDevice *xendev)
|
|||
}
|
||||
}
|
||||
|
||||
static void input_disconnect(struct XenDevice *xendev)
|
||||
static void input_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
|
||||
|
||||
|
@ -410,7 +410,7 @@ static void input_disconnect(struct XenDevice *xendev)
|
|||
common_unbind(&in->c);
|
||||
}
|
||||
|
||||
static void input_event(struct XenDevice *xendev)
|
||||
static void input_event(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
|
||||
struct xenkbd_page *page = xenfb->c.page;
|
||||
|
@ -867,7 +867,7 @@ static void xenfb_handle_events(struct XenFB *xenfb)
|
|||
page->out_cons = cons;
|
||||
}
|
||||
|
||||
static int fb_init(struct XenDevice *xendev)
|
||||
static int fb_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
#ifdef XENFB_TYPE_RESIZE
|
||||
xenstore_write_be_int(xendev, "feature-resize", 1);
|
||||
|
@ -875,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fb_initialise(struct XenDevice *xendev)
|
||||
static int fb_initialise(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
|
||||
struct xenfb_page *fb_page;
|
||||
|
@ -912,7 +912,7 @@ static int fb_initialise(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fb_disconnect(struct XenDevice *xendev)
|
||||
static void fb_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
|
||||
|
||||
|
@ -935,7 +935,8 @@ static void fb_disconnect(struct XenDevice *xendev)
|
|||
fb->bug_trigger = 0;
|
||||
}
|
||||
|
||||
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
|
||||
static void fb_frontend_changed(struct XenLegacyDevice *xendev,
|
||||
const char *node)
|
||||
{
|
||||
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
|
||||
|
||||
|
@ -953,7 +954,7 @@ static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
|
|||
}
|
||||
}
|
||||
|
||||
static void fb_event(struct XenDevice *xendev)
|
||||
static void fb_event(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -1484,6 +1485,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
|
|||
QLIST_INIT(&state->dev_list);
|
||||
device_listener_register(&state->device_listener);
|
||||
|
||||
xen_bus_init();
|
||||
|
||||
/* Initialize backend core & drivers */
|
||||
if (xen_be_init() != 0) {
|
||||
error_report("xen backend core setup failed");
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "qemu/bitmap.h"
|
||||
|
||||
#include <xen/hvm/params.h>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hw/pci/pci.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "trace.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
|
|
@ -28,14 +28,14 @@
|
|||
#include "net/net.h"
|
||||
#include "net/checksum.h"
|
||||
#include "net/util.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
|
||||
#include <xen/io/netif.h>
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
struct XenNetDev {
|
||||
struct XenDevice xendev; /* must be first */
|
||||
struct XenLegacyDevice xendev; /* must be first */
|
||||
char *mac;
|
||||
int tx_work;
|
||||
int tx_ring_ref;
|
||||
|
@ -276,7 +276,7 @@ static NetClientInfo net_xen_info = {
|
|||
.receive = net_rx_packet,
|
||||
};
|
||||
|
||||
static int net_init(struct XenDevice *xendev)
|
||||
static int net_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
|
||||
|
@ -308,7 +308,7 @@ static int net_init(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int net_connect(struct XenDevice *xendev)
|
||||
static int net_connect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
int rx_copy;
|
||||
|
@ -363,7 +363,7 @@ static int net_connect(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void net_disconnect(struct XenDevice *xendev)
|
||||
static void net_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
|
||||
|
@ -379,14 +379,14 @@ static void net_disconnect(struct XenDevice *xendev)
|
|||
}
|
||||
}
|
||||
|
||||
static void net_event(struct XenDevice *xendev)
|
||||
static void net_event(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
net_tx_packets(netdev);
|
||||
qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
|
||||
}
|
||||
|
||||
static int net_free(struct XenDevice *xendev)
|
||||
static int net_free(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "qemu/option.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/usb.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "monitor/qdev.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
@ -99,7 +99,7 @@ struct usbback_hotplug {
|
|||
};
|
||||
|
||||
struct usbback_info {
|
||||
struct XenDevice xendev; /* must be first */
|
||||
struct XenLegacyDevice xendev; /* must be first */
|
||||
USBBus bus;
|
||||
void *urb_sring;
|
||||
void *conn_sring;
|
||||
|
@ -142,7 +142,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
|
|||
unsigned int nr_segs, i, prot;
|
||||
uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
struct usbback_info *usbif = usbback_req->usbif;
|
||||
struct XenDevice *xendev = &usbif->xendev;
|
||||
struct XenLegacyDevice *xendev = &usbif->xendev;
|
||||
struct usbif_request_segment *seg;
|
||||
void *addr;
|
||||
|
||||
|
@ -220,7 +220,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
|
|||
|
||||
static int usbback_init_packet(struct usbback_req *usbback_req)
|
||||
{
|
||||
struct XenDevice *xendev = &usbback_req->usbif->xendev;
|
||||
struct XenLegacyDevice *xendev = &usbback_req->usbif->xendev;
|
||||
USBPacket *packet = &usbback_req->packet;
|
||||
USBDevice *dev = usbback_req->stub->dev;
|
||||
USBEndpoint *ep;
|
||||
|
@ -279,7 +279,7 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
|
|||
{
|
||||
struct usbback_info *usbif;
|
||||
struct usbif_urb_response *res;
|
||||
struct XenDevice *xendev;
|
||||
struct XenLegacyDevice *xendev;
|
||||
unsigned int notify;
|
||||
|
||||
usbif = usbback_req->usbif;
|
||||
|
@ -824,7 +824,7 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port)
|
|||
g_free(busid);
|
||||
}
|
||||
|
||||
static void usbback_disconnect(struct XenDevice *xendev)
|
||||
static void usbback_disconnect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
unsigned int i;
|
||||
|
@ -853,7 +853,7 @@ static void usbback_disconnect(struct XenDevice *xendev)
|
|||
TR_BUS(xendev, "finished\n");
|
||||
}
|
||||
|
||||
static int usbback_connect(struct XenDevice *xendev)
|
||||
static int usbback_connect(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
struct usbif_urb_sring *urb_sring;
|
||||
|
@ -913,7 +913,8 @@ static int usbback_connect(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
|
||||
static void usbback_backend_changed(struct XenLegacyDevice *xendev,
|
||||
const char *node)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
unsigned int i;
|
||||
|
@ -926,7 +927,7 @@ static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
|
|||
}
|
||||
}
|
||||
|
||||
static int usbback_init(struct XenDevice *xendev)
|
||||
static int usbback_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
|
||||
|
@ -1005,7 +1006,7 @@ static USBPortOps xen_usb_port_ops = {
|
|||
static USBBusOps xen_usb_bus_ops = {
|
||||
};
|
||||
|
||||
static void usbback_alloc(struct XenDevice *xendev)
|
||||
static void usbback_alloc(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
USBPort *p;
|
||||
|
@ -1027,7 +1028,7 @@ static void usbback_alloc(struct XenDevice *xendev)
|
|||
usbif->bh = qemu_bh_new(usbback_bh, usbif);
|
||||
}
|
||||
|
||||
static int usbback_free(struct XenDevice *xendev)
|
||||
static int usbback_free(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
struct usbback_req *usbback_req;
|
||||
|
@ -1066,7 +1067,7 @@ static int usbback_free(struct XenDevice *xendev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void usbback_event(struct XenDevice *xendev)
|
||||
static void usbback_event(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
struct usbback_info *usbif;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# xen backend driver support
|
||||
common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o xen_pvdev.o xen-common.o
|
||||
common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o xen-backend.o
|
||||
|
||||
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
|
||||
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o
|
||||
|
|
|
@ -12,3 +12,29 @@ xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id:
|
|||
xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
|
||||
xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
|
||||
xen_domid_restrict(int err) "err: %u"
|
||||
|
||||
# include/hw/xen/xen-bus.c
|
||||
xen_bus_realize(void) ""
|
||||
xen_bus_unrealize(void) ""
|
||||
xen_bus_enumerate(void) ""
|
||||
xen_bus_type_enumerate(const char *type) "type: %s"
|
||||
xen_bus_backend_create(const char *type, const char *path) "type: %s path: %s"
|
||||
xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
|
||||
xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
|
||||
xen_bus_watch(const char *token) "token: %s"
|
||||
xen_device_realize(const char *type, char *name) "type: %s name: %s"
|
||||
xen_device_unrealize(const char *type, char *name) "type: %s name: %s"
|
||||
xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
|
||||
xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u"
|
||||
xen_device_backend_changed(const char *type, char *name) "type: %s name: %s"
|
||||
xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
|
||||
xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s"
|
||||
xen_device_unplug(const char *type, char *name) "type: %s name: %s"
|
||||
|
||||
# include/hw/xen/xen-bus-helper.c
|
||||
xs_node_create(const char *node) "%s"
|
||||
xs_node_destroy(const char *node) "%s"
|
||||
xs_node_vprintf(char *path, char *value) "%s %s"
|
||||
xs_node_vscanf(char *path, char *value) "%s %s"
|
||||
xs_node_watch(char *path) "%s"
|
||||
xs_node_unwatch(char *path) "%s"
|
||||
|
|
165
hw/xen/xen-backend.c
Normal file
165
hw/xen/xen-backend.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/xen/xen-backend.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
|
||||
typedef struct XenBackendImpl {
|
||||
const char *type;
|
||||
XenBackendDeviceCreate create;
|
||||
XenBackendDeviceDestroy destroy;
|
||||
} XenBackendImpl;
|
||||
|
||||
struct XenBackendInstance {
|
||||
QLIST_ENTRY(XenBackendInstance) entry;
|
||||
const XenBackendImpl *impl;
|
||||
XenBus *xenbus;
|
||||
char *name;
|
||||
XenDevice *xendev;
|
||||
};
|
||||
|
||||
static GHashTable *xen_backend_table_get(void)
|
||||
{
|
||||
static GHashTable *table;
|
||||
|
||||
if (table == NULL) {
|
||||
table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void xen_backend_table_add(XenBackendImpl *impl)
|
||||
{
|
||||
g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl);
|
||||
}
|
||||
|
||||
static const XenBackendImpl *xen_backend_table_lookup(const char *type)
|
||||
{
|
||||
return g_hash_table_lookup(xen_backend_table_get(), type);
|
||||
}
|
||||
|
||||
void xen_backend_register(const XenBackendInfo *info)
|
||||
{
|
||||
XenBackendImpl *impl = g_new0(XenBackendImpl, 1);
|
||||
|
||||
g_assert(info->type);
|
||||
|
||||
if (xen_backend_table_lookup(info->type)) {
|
||||
error_report("attempt to register duplicate Xen backend type '%s'",
|
||||
info->type);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!info->create) {
|
||||
error_report("backend type '%s' has no creator", info->type);
|
||||
abort();
|
||||
}
|
||||
|
||||
impl->type = info->type;
|
||||
impl->create = info->create;
|
||||
impl->destroy = info->destroy;
|
||||
|
||||
xen_backend_table_add(impl);
|
||||
}
|
||||
|
||||
static QLIST_HEAD(, XenBackendInstance) backend_list;
|
||||
|
||||
static void xen_backend_list_add(XenBackendInstance *backend)
|
||||
{
|
||||
QLIST_INSERT_HEAD(&backend_list, backend, entry);
|
||||
}
|
||||
|
||||
static XenBackendInstance *xen_backend_list_find(XenDevice *xendev)
|
||||
{
|
||||
XenBackendInstance *backend;
|
||||
|
||||
QLIST_FOREACH(backend, &backend_list, entry) {
|
||||
if (backend->xendev == xendev) {
|
||||
return backend;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void xen_backend_list_remove(XenBackendInstance *backend)
|
||||
{
|
||||
QLIST_REMOVE(backend, entry);
|
||||
}
|
||||
|
||||
void xen_backend_device_create(XenBus *xenbus, const char *type,
|
||||
const char *name, QDict *opts, Error **errp)
|
||||
{
|
||||
const XenBackendImpl *impl = xen_backend_table_lookup(type);
|
||||
XenBackendInstance *backend;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (!impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
backend = g_new0(XenBackendInstance, 1);
|
||||
backend->xenbus = xenbus;
|
||||
backend->name = g_strdup(name);
|
||||
|
||||
impl->create(backend, opts, &local_error);
|
||||
if (local_error) {
|
||||
error_propagate(errp, local_error);
|
||||
g_free(backend->name);
|
||||
g_free(backend);
|
||||
return;
|
||||
}
|
||||
|
||||
backend->impl = impl;
|
||||
xen_backend_list_add(backend);
|
||||
}
|
||||
|
||||
XenBus *xen_backend_get_bus(XenBackendInstance *backend)
|
||||
{
|
||||
return backend->xenbus;
|
||||
}
|
||||
|
||||
const char *xen_backend_get_name(XenBackendInstance *backend)
|
||||
{
|
||||
return backend->name;
|
||||
}
|
||||
|
||||
void xen_backend_set_device(XenBackendInstance *backend,
|
||||
XenDevice *xendev)
|
||||
{
|
||||
g_assert(!backend->xendev);
|
||||
backend->xendev = xendev;
|
||||
}
|
||||
|
||||
XenDevice *xen_backend_get_device(XenBackendInstance *backend)
|
||||
{
|
||||
return backend->xendev;
|
||||
}
|
||||
|
||||
|
||||
bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp)
|
||||
{
|
||||
XenBackendInstance *backend = xen_backend_list_find(xendev);
|
||||
const XenBackendImpl *impl;
|
||||
|
||||
if (!backend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
impl = backend->impl;
|
||||
impl->destroy(backend, errp);
|
||||
|
||||
xen_backend_list_remove(backend);
|
||||
g_free(backend->name);
|
||||
g_free(backend);
|
||||
|
||||
return true;
|
||||
}
|
184
hw/xen/xen-bus-helper.c
Normal file
184
hw/xen/xen-bus-helper.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "hw/xen/xen-bus-helper.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
struct xs_state {
|
||||
enum xenbus_state statenum;
|
||||
const char *statestr;
|
||||
};
|
||||
#define XS_STATE(state) { state, #state }
|
||||
|
||||
static struct xs_state xs_state[] = {
|
||||
XS_STATE(XenbusStateUnknown),
|
||||
XS_STATE(XenbusStateInitialising),
|
||||
XS_STATE(XenbusStateInitWait),
|
||||
XS_STATE(XenbusStateInitialised),
|
||||
XS_STATE(XenbusStateConnected),
|
||||
XS_STATE(XenbusStateClosing),
|
||||
XS_STATE(XenbusStateClosed),
|
||||
XS_STATE(XenbusStateReconfiguring),
|
||||
XS_STATE(XenbusStateReconfigured),
|
||||
};
|
||||
|
||||
#undef XS_STATE
|
||||
|
||||
const char *xs_strstate(enum xenbus_state state)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(xs_state); i++) {
|
||||
if (xs_state[i].statenum == state) {
|
||||
return xs_state[i].statestr;
|
||||
}
|
||||
}
|
||||
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, struct xs_permissions perms[],
|
||||
unsigned int nr_perms, Error **errp)
|
||||
{
|
||||
trace_xs_node_create(node);
|
||||
|
||||
if (!xs_write(xsh, tid, node, "", 0)) {
|
||||
error_setg_errno(errp, errno, "failed to create node '%s'", node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!xs_set_permissions(xsh, tid, node, perms, nr_perms)) {
|
||||
error_setg_errno(errp, errno, "failed to set node '%s' permissions",
|
||||
node);
|
||||
}
|
||||
}
|
||||
|
||||
void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, Error **errp)
|
||||
{
|
||||
trace_xs_node_destroy(node);
|
||||
|
||||
if (!xs_rm(xsh, tid, node)) {
|
||||
error_setg_errno(errp, errno, "failed to destroy node '%s'", node);
|
||||
}
|
||||
}
|
||||
|
||||
void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
char *path, *value;
|
||||
int len;
|
||||
|
||||
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
|
||||
g_strdup(key);
|
||||
len = g_vasprintf(&value, fmt, ap);
|
||||
|
||||
trace_xs_node_vprintf(path, value);
|
||||
|
||||
if (!xs_write(xsh, tid, path, value, len)) {
|
||||
error_setg_errno(errp, errno, "failed to write '%s' to '%s'",
|
||||
value, path);
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xs_node_vprintf(xsh, tid, node, key, errp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
char *path, *value;
|
||||
int rc;
|
||||
|
||||
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
|
||||
g_strdup(key);
|
||||
value = xs_read(xsh, tid, path, NULL);
|
||||
|
||||
trace_xs_node_vscanf(path, value);
|
||||
|
||||
if (value) {
|
||||
rc = vsscanf(value, fmt, ap);
|
||||
} else {
|
||||
error_setg_errno(errp, errno, "failed to read from '%s'",
|
||||
path);
|
||||
rc = EOF;
|
||||
}
|
||||
|
||||
free(value);
|
||||
g_free(path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = xs_node_vscanf(xsh, tid, node, key, errp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
|
||||
char *token, Error **errp)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
|
||||
g_strdup(key);
|
||||
|
||||
trace_xs_node_watch(path);
|
||||
|
||||
if (!xs_watch(xsh, path, token)) {
|
||||
error_setg_errno(errp, errno, "failed to watch node '%s'", path);
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
void xs_node_unwatch(struct xs_handle *xsh, const char *node,
|
||||
const char *key, const char *token, Error **errp)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
|
||||
g_strdup(key);
|
||||
|
||||
trace_xs_node_unwatch(path);
|
||||
|
||||
if (!xs_unwatch(xsh, path, token)) {
|
||||
error_setg_errno(errp, errno, "failed to unwatch node '%s'", path);
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
}
|
1199
hw/xen/xen-bus.c
Normal file
1199
hw/xen/xen-bus.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "migration/misc.h"
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hw/boards.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen_pvdev.h"
|
||||
#include "monitor/qdev.h"
|
||||
|
||||
|
@ -42,49 +42,54 @@ BusState *xen_sysbus;
|
|||
/* ------------------------------------------------------------- */
|
||||
|
||||
/* public */
|
||||
struct xs_handle *xenstore = NULL;
|
||||
struct xs_handle *xenstore;
|
||||
const char *xen_protocol;
|
||||
|
||||
/* private */
|
||||
static bool xen_feature_grant_copy;
|
||||
static int debug;
|
||||
|
||||
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
|
||||
int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
|
||||
const char *val)
|
||||
{
|
||||
return xenstore_write_str(xendev->be, node, val);
|
||||
}
|
||||
|
||||
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
|
||||
int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int ival)
|
||||
{
|
||||
return xenstore_write_int(xendev->be, node, ival);
|
||||
}
|
||||
|
||||
int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
|
||||
int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
|
||||
int64_t ival)
|
||||
{
|
||||
return xenstore_write_int64(xendev->be, node, ival);
|
||||
}
|
||||
|
||||
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
|
||||
char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node)
|
||||
{
|
||||
return xenstore_read_str(xendev->be, node);
|
||||
}
|
||||
|
||||
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
|
||||
int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int *ival)
|
||||
{
|
||||
return xenstore_read_int(xendev->be, node, ival);
|
||||
}
|
||||
|
||||
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
|
||||
char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node)
|
||||
{
|
||||
return xenstore_read_str(xendev->fe, node);
|
||||
}
|
||||
|
||||
int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
|
||||
int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int *ival)
|
||||
{
|
||||
return xenstore_read_int(xendev->fe, node, ival);
|
||||
}
|
||||
|
||||
int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
|
||||
int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
|
||||
uint64_t *uval)
|
||||
{
|
||||
return xenstore_read_uint64(xendev->fe, node, uval);
|
||||
|
@ -92,7 +97,7 @@ int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
|
|||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
|
||||
int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -106,7 +111,7 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
|
||||
void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
|
||||
unsigned int nr_refs)
|
||||
{
|
||||
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
|
||||
|
@ -117,7 +122,7 @@ void xen_be_set_max_grant_refs(struct XenDevice *xendev,
|
|||
}
|
||||
}
|
||||
|
||||
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
|
||||
void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
|
||||
unsigned int nr_refs, int prot)
|
||||
{
|
||||
void *ptr;
|
||||
|
@ -135,7 +140,7 @@ void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
|
||||
void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
|
||||
unsigned int nr_refs)
|
||||
{
|
||||
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
|
||||
|
@ -146,7 +151,7 @@ void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
|
|||
}
|
||||
}
|
||||
|
||||
static int compat_copy_grant_refs(struct XenDevice *xendev,
|
||||
static int compat_copy_grant_refs(struct XenLegacyDevice *xendev,
|
||||
bool to_domain,
|
||||
XenGrantCopySegment segs[],
|
||||
unsigned int nr_segs)
|
||||
|
@ -195,7 +200,7 @@ static int compat_copy_grant_refs(struct XenDevice *xendev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int xen_be_copy_grant_refs(struct XenDevice *xendev,
|
||||
int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
|
||||
bool to_domain,
|
||||
XenGrantCopySegment segs[],
|
||||
unsigned int nr_segs)
|
||||
|
@ -259,10 +264,11 @@ int xen_be_copy_grant_refs(struct XenDevice *xendev,
|
|||
/*
|
||||
* get xen backend device, allocate a new one if it doesn't exist.
|
||||
*/
|
||||
static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
|
||||
struct XenDevOps *ops)
|
||||
static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
|
||||
int dev,
|
||||
struct XenDevOps *ops)
|
||||
{
|
||||
struct XenDevice *xendev;
|
||||
struct XenLegacyDevice *xendev;
|
||||
|
||||
xendev = xen_pv_find_xendev(type, dom, dev);
|
||||
if (xendev) {
|
||||
|
@ -314,7 +320,8 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
|
|||
* Node specifies the changed field. node = NULL means
|
||||
* update all fields (used for initialization).
|
||||
*/
|
||||
static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
|
||||
static void xen_be_backend_changed(struct XenLegacyDevice *xendev,
|
||||
const char *node)
|
||||
{
|
||||
if (node == NULL || strcmp(node, "online") == 0) {
|
||||
if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
|
||||
|
@ -330,7 +337,8 @@ static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
|
|||
}
|
||||
}
|
||||
|
||||
static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
|
||||
static void xen_be_frontend_changed(struct XenLegacyDevice *xendev,
|
||||
const char *node)
|
||||
{
|
||||
int fe_state;
|
||||
|
||||
|
@ -373,7 +381,7 @@ static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
|
|||
* only affects the xendev->be_state variable as xenbus should
|
||||
* already be put into that state by xend.
|
||||
*/
|
||||
static int xen_be_try_setup(struct XenDevice *xendev)
|
||||
static int xen_be_try_setup(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
char token[XEN_BUFSIZE];
|
||||
int be_state;
|
||||
|
@ -417,7 +425,7 @@ static int xen_be_try_setup(struct XenDevice *xendev)
|
|||
*
|
||||
* Goes to InitWait on success.
|
||||
*/
|
||||
static int xen_be_try_init(struct XenDevice *xendev)
|
||||
static int xen_be_try_init(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
@ -446,7 +454,7 @@ static int xen_be_try_init(struct XenDevice *xendev)
|
|||
*
|
||||
* Goes to Connected on success.
|
||||
*/
|
||||
static int xen_be_try_initialise(struct XenDevice *xendev)
|
||||
static int xen_be_try_initialise(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
@ -487,7 +495,7 @@ static int xen_be_try_initialise(struct XenDevice *xendev)
|
|||
* frontend being Connected. Note that this may be called more
|
||||
* than once since the backend state is not modified.
|
||||
*/
|
||||
static void xen_be_try_connected(struct XenDevice *xendev)
|
||||
static void xen_be_try_connected(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
if (!xendev->ops->connected) {
|
||||
return;
|
||||
|
@ -510,7 +518,8 @@ static void xen_be_try_connected(struct XenDevice *xendev)
|
|||
*
|
||||
* Goes to Closed when done.
|
||||
*/
|
||||
static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
|
||||
static void xen_be_disconnect(struct XenLegacyDevice *xendev,
|
||||
enum xenbus_state state)
|
||||
{
|
||||
if (xendev->be_state != XenbusStateClosing &&
|
||||
xendev->be_state != XenbusStateClosed &&
|
||||
|
@ -529,7 +538,7 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
|
|||
/*
|
||||
* Try to reset xendev, for reconnection by another frontend instance.
|
||||
*/
|
||||
static int xen_be_try_reset(struct XenDevice *xendev)
|
||||
static int xen_be_try_reset(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
if (xendev->fe_state != XenbusStateInitialising) {
|
||||
return -1;
|
||||
|
@ -543,7 +552,7 @@ static int xen_be_try_reset(struct XenDevice *xendev)
|
|||
/*
|
||||
* state change dispatcher function
|
||||
*/
|
||||
void xen_be_check_state(struct XenDevice *xendev)
|
||||
void xen_be_check_state(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
@ -587,7 +596,7 @@ void xen_be_check_state(struct XenDevice *xendev)
|
|||
|
||||
static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
|
||||
{
|
||||
struct XenDevice *xendev;
|
||||
struct XenLegacyDevice *xendev;
|
||||
char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
|
||||
char **dev = NULL;
|
||||
unsigned int cdev, j;
|
||||
|
@ -620,7 +629,7 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
|
|||
void xenstore_update_be(char *watch, char *type, int dom,
|
||||
struct XenDevOps *ops)
|
||||
{
|
||||
struct XenDevice *xendev;
|
||||
struct XenLegacyDevice *xendev;
|
||||
char path[XEN_BUFSIZE], *bepath;
|
||||
unsigned int len, dev;
|
||||
|
||||
|
@ -628,9 +637,9 @@ void xenstore_update_be(char *watch, char *type, int dom,
|
|||
if (strncmp(path, watch, len) != 0) {
|
||||
return;
|
||||
}
|
||||
if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
|
||||
if (sscanf(watch + len, "/%u/%255s", &dev, path) != 2) {
|
||||
strcpy(path, "");
|
||||
if (sscanf(watch+len, "/%u", &dev) != 1) {
|
||||
if (sscanf(watch + len, "/%u", &dev) != 1) {
|
||||
dev = -1;
|
||||
}
|
||||
}
|
||||
|
@ -651,7 +660,7 @@ void xenstore_update_be(char *watch, char *type, int dom,
|
|||
}
|
||||
}
|
||||
|
||||
void xenstore_update_fe(char *watch, struct XenDevice *xendev)
|
||||
void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev)
|
||||
{
|
||||
char *node;
|
||||
unsigned int len;
|
||||
|
@ -744,7 +753,6 @@ void xen_be_register_common(void)
|
|||
|
||||
xen_be_register("console", &xen_console_ops);
|
||||
xen_be_register("vkbd", &xen_kbdmouse_ops);
|
||||
xen_be_register("qdisk", &xen_blkdev_ops);
|
||||
#ifdef CONFIG_VIRTFS
|
||||
xen_be_register("9pfs", &xen_9pfs_ops);
|
||||
#endif
|
||||
|
@ -753,7 +761,7 @@ void xen_be_register_common(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int xen_be_bind_evtchn(struct XenDevice *xendev)
|
||||
int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
if (xendev->local_port != -1) {
|
||||
return 0;
|
||||
|
@ -789,7 +797,7 @@ static const TypeInfo xendev_type_info = {
|
|||
.name = TYPE_XENBACKEND,
|
||||
.parent = TYPE_XENSYSDEV,
|
||||
.class_init = xendev_class_init,
|
||||
.instance_size = sizeof(struct XenDevice),
|
||||
.instance_size = sizeof(struct XenLegacyDevice),
|
||||
};
|
||||
|
||||
static void xen_sysbus_class_init(ObjectClass *klass, void *data)
|
|
@ -1,5 +1,5 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "qemu/option.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
#include "hw/pci/pci.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "xen_pt.h"
|
||||
#include "qemu/range.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
@ -847,6 +847,12 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
|
|||
}
|
||||
|
||||
machine_irq = s->real_device.irq;
|
||||
if (machine_irq == 0) {
|
||||
XEN_PT_LOG(d, "machine irq is 0\n");
|
||||
cmd |= PCI_COMMAND_INTX_DISABLE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
|
||||
if (rc < 0) {
|
||||
error_setg_errno(errp, errno, "Mapping machine irq %u to"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "xen_pt.h"
|
||||
|
||||
#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
|
||||
|
@ -300,7 +300,9 @@ static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
|
|||
XenPTRegInfo *reg, uint32_t real_offset,
|
||||
uint32_t *data)
|
||||
{
|
||||
*data = xen_pt_pci_read_intx(s);
|
||||
if (s->real_device.irq) {
|
||||
*data = xen_pt_pci_read_intx(s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "xen_pt.h"
|
||||
#include "xen-host-pci-device.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
|
||||
static unsigned long igd_guest_opregion;
|
||||
static unsigned long igd_host_opregion;
|
||||
|
@ -185,8 +185,19 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
|
|||
return;
|
||||
}
|
||||
|
||||
if (bios_size < sizeof(struct rom_header)) {
|
||||
error_setg(errp, "VGA: VBIOS image corrupt (too small)");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Currently we fixed this address as a primary. */
|
||||
rom = (struct rom_header *)bios;
|
||||
|
||||
if (rom->pcioffset + sizeof(struct pci_data) > bios_size) {
|
||||
error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)");
|
||||
return;
|
||||
}
|
||||
|
||||
pd = (void *)(bios + (unsigned char)rom->pcioffset);
|
||||
|
||||
/* We may need to fixup Device Identification. */
|
||||
|
@ -194,6 +205,11 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
|
|||
pd->device = s->real_device.device_id;
|
||||
|
||||
len = rom->size * 512;
|
||||
if (len > bios_size) {
|
||||
error_setg(errp, "VGA: VBIOS image corrupt (bad size field)");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Then adjust the bios checksum */
|
||||
for (c = (char *)bios; c < ((char *)bios + len); c++) {
|
||||
checksum += *c;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "xen_pt.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen_pvdev.h"
|
||||
|
||||
/* private */
|
||||
|
@ -34,7 +34,7 @@ struct xs_dirs {
|
|||
static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
|
||||
QTAILQ_HEAD_INITIALIZER(xs_cleanup);
|
||||
|
||||
static QTAILQ_HEAD(, XenDevice) xendevs =
|
||||
static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
|
||||
QTAILQ_HEAD_INITIALIZER(xendevs);
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -195,7 +195,7 @@ const char *xenbus_strstate(enum xenbus_state state)
|
|||
* 2 == noisy debug messages (logfile only).
|
||||
* 3 == will flood your log (logfile only).
|
||||
*/
|
||||
void xen_pv_printf(struct XenDevice *xendev, int msg_level,
|
||||
void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
@ -230,7 +230,7 @@ void xen_pv_printf(struct XenDevice *xendev, int msg_level,
|
|||
|
||||
void xen_pv_evtchn_event(void *opaque)
|
||||
{
|
||||
struct XenDevice *xendev = opaque;
|
||||
struct XenLegacyDevice *xendev = opaque;
|
||||
evtchn_port_t port;
|
||||
|
||||
port = xenevtchn_pending(xendev->evtchndev);
|
||||
|
@ -247,7 +247,7 @@ void xen_pv_evtchn_event(void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
void xen_pv_unbind_evtchn(struct XenDevice *xendev)
|
||||
void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
if (xendev->local_port == -1) {
|
||||
return;
|
||||
|
@ -258,16 +258,16 @@ void xen_pv_unbind_evtchn(struct XenDevice *xendev)
|
|||
xendev->local_port = -1;
|
||||
}
|
||||
|
||||
int xen_pv_send_notify(struct XenDevice *xendev)
|
||||
int xen_pv_send_notify(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
|
||||
struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
|
||||
{
|
||||
struct XenDevice *xendev;
|
||||
struct XenLegacyDevice *xendev;
|
||||
|
||||
QTAILQ_FOREACH(xendev, &xendevs, next) {
|
||||
if (xendev->dom != dom) {
|
||||
|
@ -287,7 +287,7 @@ struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
|
|||
/*
|
||||
* release xen backend device.
|
||||
*/
|
||||
void xen_pv_del_xendev(struct XenDevice *xendev)
|
||||
void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
if (xendev->ops->free) {
|
||||
xendev->ops->free(xendev);
|
||||
|
@ -312,7 +312,7 @@ void xen_pv_del_xendev(struct XenDevice *xendev)
|
|||
qdev_unplug(&xendev->qdev, NULL);
|
||||
}
|
||||
|
||||
void xen_pv_insert_xendev(struct XenDevice *xendev)
|
||||
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
# Xen PV machine support
|
||||
obj-$(CONFIG_XEN) += xen_machine_pv.o
|
||||
# Xen PV machine builder support
|
||||
obj-$(CONFIG_XEN_PV_DOMAIN_BUILD) += xen_domainbuild.o
|
||||
|
|
|
@ -1,299 +0,0 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "xen_domainbuild.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#include <xenguest.h>
|
||||
|
||||
static int xenstore_domain_mkdir(char *path)
|
||||
{
|
||||
struct xs_permissions perms_ro[] = {{
|
||||
.id = 0, /* set owner: dom0 */
|
||||
},{
|
||||
.id = xen_domid,
|
||||
.perms = XS_PERM_READ,
|
||||
}};
|
||||
struct xs_permissions perms_rw[] = {{
|
||||
.id = 0, /* set owner: dom0 */
|
||||
},{
|
||||
.id = xen_domid,
|
||||
.perms = XS_PERM_READ | XS_PERM_WRITE,
|
||||
}};
|
||||
const char *writable[] = { "device", "control", "error", NULL };
|
||||
char subpath[256];
|
||||
int i;
|
||||
|
||||
if (!xs_mkdir(xenstore, 0, path)) {
|
||||
fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, path);
|
||||
return -1;
|
||||
}
|
||||
if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
|
||||
fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; writable[i]; i++) {
|
||||
snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
|
||||
if (!xs_mkdir(xenstore, 0, subpath)) {
|
||||
fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, subpath);
|
||||
return -1;
|
||||
}
|
||||
if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
|
||||
fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xenstore_domain_init1(const char *kernel, const char *ramdisk,
|
||||
const char *cmdline)
|
||||
{
|
||||
char *dom, uuid_string[42], vm[256], path[256];
|
||||
int i;
|
||||
|
||||
qemu_uuid_unparse(&qemu_uuid, uuid_string);
|
||||
dom = xs_get_domain_path(xenstore, xen_domid);
|
||||
snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
|
||||
|
||||
xenstore_domain_mkdir(dom);
|
||||
|
||||
xenstore_write_str(vm, "image/ostype", "linux");
|
||||
if (kernel)
|
||||
xenstore_write_str(vm, "image/kernel", kernel);
|
||||
if (ramdisk)
|
||||
xenstore_write_str(vm, "image/ramdisk", ramdisk);
|
||||
if (cmdline)
|
||||
xenstore_write_str(vm, "image/cmdline", cmdline);
|
||||
|
||||
/* name + id */
|
||||
xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
|
||||
xenstore_write_str(vm, "uuid", uuid_string);
|
||||
xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
|
||||
xenstore_write_int(dom, "domid", xen_domid);
|
||||
xenstore_write_str(dom, "vm", vm);
|
||||
|
||||
/* memory */
|
||||
xenstore_write_int(dom, "memory/target", ram_size / KiB);
|
||||
xenstore_write_int(vm, "memory", ram_size / MiB);
|
||||
xenstore_write_int(vm, "maxmem", ram_size / MiB);
|
||||
|
||||
/* cpus */
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
snprintf(path, sizeof(path), "cpu/%d/availability",i);
|
||||
xenstore_write_str(dom, path, "online");
|
||||
}
|
||||
xenstore_write_int(vm, "vcpu_avail", smp_cpus);
|
||||
xenstore_write_int(vm, "vcpus", smp_cpus);
|
||||
|
||||
/* vnc password */
|
||||
xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
|
||||
|
||||
free(dom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
|
||||
int console_port, int console_mfn)
|
||||
{
|
||||
char *dom;
|
||||
|
||||
dom = xs_get_domain_path(xenstore, xen_domid);
|
||||
|
||||
/* signal new domain */
|
||||
xs_introduce_domain(xenstore,
|
||||
xen_domid,
|
||||
xenstore_mfn,
|
||||
xenstore_port);
|
||||
|
||||
/* xenstore */
|
||||
xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
|
||||
xenstore_write_int(dom, "store/port", xenstore_port);
|
||||
|
||||
/* console */
|
||||
xenstore_write_str(dom, "console/type", "ioemu");
|
||||
xenstore_write_int(dom, "console/limit", 128 * KiB);
|
||||
xenstore_write_int(dom, "console/ring-ref", console_mfn);
|
||||
xenstore_write_int(dom, "console/port", console_port);
|
||||
xen_config_dev_console(0);
|
||||
|
||||
free(dom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static QEMUTimer *xen_poll;
|
||||
|
||||
/* check domain state once per second */
|
||||
static void xen_domain_poll(void *opaque)
|
||||
{
|
||||
struct xc_dominfo info;
|
||||
int rc;
|
||||
|
||||
rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
|
||||
if ((rc != 1) || (info.domid != xen_domid)) {
|
||||
qemu_log("xen: domain %d is gone\n", xen_domid);
|
||||
goto quit;
|
||||
}
|
||||
if (info.dying) {
|
||||
qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
|
||||
info.crashed ? "crashed" : "",
|
||||
info.shutdown ? "shutdown" : "");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
||||
return;
|
||||
|
||||
quit:
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
}
|
||||
|
||||
static int xen_domain_watcher(void)
|
||||
{
|
||||
int qemu_running = 1;
|
||||
int fd[2], i, n, rc;
|
||||
char byte;
|
||||
|
||||
if (pipe(fd) != 0) {
|
||||
qemu_log("%s: Huh? pipe error: %s\n", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fork() != 0)
|
||||
return 0; /* not child */
|
||||
|
||||
/* close all file handles, except stdio/out/err,
|
||||
* our watch pipe and the xen interface handle */
|
||||
n = getdtablesize();
|
||||
for (i = 3; i < n; i++) {
|
||||
if (i == fd[0])
|
||||
continue;
|
||||
close(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reopen xc interface, since the original is unsafe after fork
|
||||
* and was closed above.
|
||||
*/
|
||||
xen_xc = xc_interface_open(0, 0, 0);
|
||||
|
||||
/* ignore term signals */
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
/* wait for qemu exiting */
|
||||
while (qemu_running) {
|
||||
rc = read(fd[0], &byte, 1);
|
||||
switch (rc) {
|
||||
case -1:
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
qemu_log("%s: Huh? read error: %s\n", __func__, strerror(errno));
|
||||
qemu_running = 0;
|
||||
break;
|
||||
case 0:
|
||||
/* EOF -> qemu exited */
|
||||
qemu_running = 0;
|
||||
break;
|
||||
default:
|
||||
qemu_log("%s: Huh? data on the watch pipe?\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
qemu_log("%s: destroy domain %d\n", __func__, xen_domid);
|
||||
xc_domain_destroy(xen_xc, xen_domid);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* normal cleanup */
|
||||
static void xen_domain_cleanup(void)
|
||||
{
|
||||
char *dom;
|
||||
|
||||
dom = xs_get_domain_path(xenstore, xen_domid);
|
||||
if (dom) {
|
||||
xs_rm(xenstore, 0, dom);
|
||||
free(dom);
|
||||
}
|
||||
xs_release_domain(xenstore, xen_domid);
|
||||
}
|
||||
|
||||
int xen_domain_build_pv(const char *kernel, const char *ramdisk,
|
||||
const char *cmdline)
|
||||
{
|
||||
uint32_t ssidref = 0;
|
||||
uint32_t flags = 0;
|
||||
xen_domain_handle_t uuid;
|
||||
unsigned int xenstore_port = 0, console_port = 0;
|
||||
unsigned long xenstore_mfn = 0, console_mfn = 0;
|
||||
int rc;
|
||||
|
||||
memcpy(uuid, &qemu_uuid, sizeof(uuid));
|
||||
rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_domain_create() failed\n");
|
||||
goto err;
|
||||
}
|
||||
qemu_log("xen: created domain %d\n", xen_domid);
|
||||
atexit(xen_domain_cleanup);
|
||||
if (xen_domain_watcher() == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
xenstore_domain_init1(kernel, ramdisk, cmdline);
|
||||
|
||||
rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if 0
|
||||
rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size / KiB);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
|
||||
console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
|
||||
|
||||
rc = xc_linux_build(xen_xc, xen_domid, ram_size / MiB,
|
||||
kernel, ramdisk, cmdline,
|
||||
0, flags,
|
||||
xenstore_port, &xenstore_mfn,
|
||||
console_port, &console_mfn);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_linux_build() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
xenstore_domain_init2(xenstore_port, xenstore_mfn,
|
||||
console_port, console_mfn);
|
||||
|
||||
qemu_log("xen: unpausing domain %d\n", xen_domid);
|
||||
rc = xc_domain_unpause(xen_xc, xen_domid);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "xen: xc_domain_unpause() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL);
|
||||
timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef QEMU_HW_XEN_DOMAINBUILD_H
|
||||
#define QEMU_HW_XEN_DOMAINBUILD_H
|
||||
|
||||
#include "hw/xen/xen_common.h"
|
||||
|
||||
int xenstore_domain_init1(const char *kernel, const char *ramdisk,
|
||||
const char *cmdline);
|
||||
int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
|
||||
int console_port, int console_mfn);
|
||||
int xen_domain_build_pv(const char *kernel, const char *ramdisk,
|
||||
const char *cmdline);
|
||||
|
||||
#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
|
|
@ -26,8 +26,8 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "xen_domainbuild.h"
|
||||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
static void xen_init_pv(MachineState *machine)
|
||||
|
@ -43,21 +43,8 @@ static void xen_init_pv(MachineState *machine)
|
|||
|
||||
switch (xen_mode) {
|
||||
case XEN_ATTACH:
|
||||
/* nothing to do, xend handles everything */
|
||||
/* nothing to do, libxl handles everything */
|
||||
break;
|
||||
#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
|
||||
case XEN_CREATE: {
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
if (xen_domain_build_pv(kernel_filename, initrd_filename,
|
||||
kernel_cmdline) < 0) {
|
||||
error_report("xen pv domain creation failed");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case XEN_EMULATE:
|
||||
error_report("xen emulation not implemented (yet)");
|
||||
exit(1);
|
||||
|
@ -93,6 +80,8 @@ static void xen_init_pv(MachineState *machine)
|
|||
xen_config_dev_nic(nd_table + i);
|
||||
}
|
||||
|
||||
xen_bus_init();
|
||||
|
||||
/* config cleanup hook */
|
||||
atexit(xen_config_cleanup);
|
||||
}
|
||||
|
|
39
include/hw/xen/xen-backend.h
Normal file
39
include/hw/xen/xen-backend.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_XEN_BACKEND_H
|
||||
#define HW_XEN_BACKEND_H
|
||||
|
||||
#include "hw/xen/xen-bus.h"
|
||||
|
||||
typedef struct XenBackendInstance XenBackendInstance;
|
||||
|
||||
typedef void (*XenBackendDeviceCreate)(XenBackendInstance *backend,
|
||||
QDict *opts, Error **errp);
|
||||
typedef void (*XenBackendDeviceDestroy)(XenBackendInstance *backend,
|
||||
Error **errp);
|
||||
|
||||
typedef struct XenBackendInfo {
|
||||
const char *type;
|
||||
XenBackendDeviceCreate create;
|
||||
XenBackendDeviceDestroy destroy;
|
||||
} XenBackendInfo;
|
||||
|
||||
XenBus *xen_backend_get_bus(XenBackendInstance *backend);
|
||||
const char *xen_backend_get_name(XenBackendInstance *backend);
|
||||
|
||||
void xen_backend_set_device(XenBackendInstance *backend,
|
||||
XenDevice *xendevice);
|
||||
XenDevice *xen_backend_get_device(XenBackendInstance *backend);
|
||||
|
||||
void xen_backend_register(const XenBackendInfo *info);
|
||||
|
||||
void xen_backend_device_create(XenBus *xenbus, const char *type,
|
||||
const char *name, QDict *opts, Error **errp);
|
||||
bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp);
|
||||
|
||||
#endif /* HW_XEN_BACKEND_H */
|
94
include/hw/xen/xen-block.h
Normal file
94
include/hw/xen/xen-block.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_XEN_BLOCK_H
|
||||
#define HW_XEN_BLOCK_H
|
||||
|
||||
#include "hw/xen/xen-bus.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/block/dataplane/xen-block.h"
|
||||
#include "sysemu/iothread.h"
|
||||
|
||||
typedef enum XenBlockVdevType {
|
||||
XEN_BLOCK_VDEV_TYPE_INVALID,
|
||||
XEN_BLOCK_VDEV_TYPE_DP,
|
||||
XEN_BLOCK_VDEV_TYPE_XVD,
|
||||
XEN_BLOCK_VDEV_TYPE_HD,
|
||||
XEN_BLOCK_VDEV_TYPE_SD,
|
||||
XEN_BLOCK_VDEV_TYPE__MAX
|
||||
} XenBlockVdevType;
|
||||
|
||||
typedef struct XenBlockVdev {
|
||||
XenBlockVdevType type;
|
||||
unsigned long disk;
|
||||
unsigned long partition;
|
||||
unsigned long number;
|
||||
} XenBlockVdev;
|
||||
|
||||
|
||||
typedef struct XenBlockProperties {
|
||||
XenBlockVdev vdev;
|
||||
BlockConf conf;
|
||||
unsigned int max_ring_page_order;
|
||||
IOThread *iothread;
|
||||
} XenBlockProperties;
|
||||
|
||||
typedef struct XenBlockDrive {
|
||||
char *id;
|
||||
char *node_name;
|
||||
} XenBlockDrive;
|
||||
|
||||
typedef struct XenBlockIOThread {
|
||||
char *id;
|
||||
} XenBlockIOThread;
|
||||
|
||||
typedef struct XenBlockDevice {
|
||||
XenDevice xendev;
|
||||
XenBlockProperties props;
|
||||
const char *device_type;
|
||||
unsigned int info;
|
||||
XenBlockDataPlane *dataplane;
|
||||
XenBlockDrive *drive;
|
||||
XenBlockIOThread *iothread;
|
||||
} XenBlockDevice;
|
||||
|
||||
typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp);
|
||||
typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev, Error **errp);
|
||||
|
||||
typedef struct XenBlockDeviceClass {
|
||||
/*< private >*/
|
||||
XenDeviceClass parent_class;
|
||||
/*< public >*/
|
||||
XenBlockDeviceRealize realize;
|
||||
XenBlockDeviceUnrealize unrealize;
|
||||
} XenBlockDeviceClass;
|
||||
|
||||
#define TYPE_XEN_BLOCK_DEVICE "xen-block"
|
||||
#define XEN_BLOCK_DEVICE(obj) \
|
||||
OBJECT_CHECK(XenBlockDevice, (obj), TYPE_XEN_BLOCK_DEVICE)
|
||||
#define XEN_BLOCK_DEVICE_CLASS(class) \
|
||||
OBJECT_CLASS_CHECK(XenBlockDeviceClass, (class), TYPE_XEN_BLOCK_DEVICE)
|
||||
#define XEN_BLOCK_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XenBlockDeviceClass, (obj), TYPE_XEN_BLOCK_DEVICE)
|
||||
|
||||
typedef struct XenDiskDevice {
|
||||
XenBlockDevice blockdev;
|
||||
} XenDiskDevice;
|
||||
|
||||
#define TYPE_XEN_DISK_DEVICE "xen-disk"
|
||||
#define XEN_DISK_DEVICE(obj) \
|
||||
OBJECT_CHECK(XenDiskDevice, (obj), TYPE_XEN_DISK_DEVICE)
|
||||
|
||||
typedef struct XenCDRomDevice {
|
||||
XenBlockDevice blockdev;
|
||||
} XenCDRomDevice;
|
||||
|
||||
#define TYPE_XEN_CDROM_DEVICE "xen-cdrom"
|
||||
#define XEN_CDROM_DEVICE(obj) \
|
||||
OBJECT_CHECK(XenCDRomDevice, (obj), TYPE_XEN_CDROM_DEVICE)
|
||||
|
||||
#endif /* HW_XEN_BLOCK_H */
|
45
include/hw/xen/xen-bus-helper.h
Normal file
45
include/hw/xen/xen-bus-helper.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_XEN_BUS_HELPER_H
|
||||
#define HW_XEN_BUS_HELPER_H
|
||||
|
||||
#include "hw/xen/xen_common.h"
|
||||
|
||||
const char *xs_strstate(enum xenbus_state state);
|
||||
|
||||
void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, struct xs_permissions perms[],
|
||||
unsigned int nr_perms, Error **errp);
|
||||
void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, Error **errp);
|
||||
|
||||
/* Write to node/key unless node is empty, in which case write to key */
|
||||
void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, va_list ap)
|
||||
GCC_FMT_ATTR(6, 0);
|
||||
void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, ...)
|
||||
GCC_FMT_ATTR(6, 7);
|
||||
|
||||
/* Read from node/key unless node is empty, in which case read from key */
|
||||
int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, va_list ap);
|
||||
int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
|
||||
const char *node, const char *key, Error **errp,
|
||||
const char *fmt, ...);
|
||||
|
||||
/* Watch node/key unless node is empty, in which case watch key */
|
||||
void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
|
||||
char *token, Error **errp);
|
||||
void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *key,
|
||||
const char *token, Error **errp);
|
||||
|
||||
#endif /* HW_XEN_BUS_HELPER_H */
|
137
include/hw/xen/xen-bus.h
Normal file
137
include/hw/xen/xen-bus.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Citrix Systems Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_XEN_BUS_H
|
||||
#define HW_XEN_BUS_H
|
||||
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/notify.h"
|
||||
|
||||
typedef void (*XenWatchHandler)(void *opaque);
|
||||
|
||||
typedef struct XenWatch XenWatch;
|
||||
|
||||
typedef struct XenDevice {
|
||||
DeviceState qdev;
|
||||
domid_t frontend_id;
|
||||
char *name;
|
||||
char *backend_path, *frontend_path;
|
||||
enum xenbus_state backend_state, frontend_state;
|
||||
Notifier exit;
|
||||
XenWatch *backend_state_watch, *frontend_state_watch;
|
||||
bool backend_online;
|
||||
XenWatch *backend_online_watch;
|
||||
xengnttab_handle *xgth;
|
||||
bool feature_grant_copy;
|
||||
xenevtchn_handle *xeh;
|
||||
NotifierList event_notifiers;
|
||||
} XenDevice;
|
||||
|
||||
typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp);
|
||||
typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp);
|
||||
typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev,
|
||||
enum xenbus_state frontend_state,
|
||||
Error **errp);
|
||||
typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp);
|
||||
|
||||
typedef struct XenDeviceClass {
|
||||
/*< private >*/
|
||||
DeviceClass parent_class;
|
||||
/*< public >*/
|
||||
const char *backend;
|
||||
const char *device;
|
||||
XenDeviceGetName get_name;
|
||||
XenDeviceRealize realize;
|
||||
XenDeviceFrontendChanged frontend_changed;
|
||||
XenDeviceUnrealize unrealize;
|
||||
} XenDeviceClass;
|
||||
|
||||
#define TYPE_XEN_DEVICE "xen-device"
|
||||
#define XEN_DEVICE(obj) \
|
||||
OBJECT_CHECK(XenDevice, (obj), TYPE_XEN_DEVICE)
|
||||
#define XEN_DEVICE_CLASS(class) \
|
||||
OBJECT_CLASS_CHECK(XenDeviceClass, (class), TYPE_XEN_DEVICE)
|
||||
#define XEN_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XenDeviceClass, (obj), TYPE_XEN_DEVICE)
|
||||
|
||||
typedef struct XenBus {
|
||||
BusState qbus;
|
||||
domid_t backend_id;
|
||||
struct xs_handle *xsh;
|
||||
NotifierList watch_notifiers;
|
||||
XenWatch *backend_watch;
|
||||
} XenBus;
|
||||
|
||||
typedef struct XenBusClass {
|
||||
/*< private >*/
|
||||
BusClass parent_class;
|
||||
} XenBusClass;
|
||||
|
||||
#define TYPE_XEN_BUS "xen-bus"
|
||||
#define XEN_BUS(obj) \
|
||||
OBJECT_CHECK(XenBus, (obj), TYPE_XEN_BUS)
|
||||
#define XEN_BUS_CLASS(class) \
|
||||
OBJECT_CLASS_CHECK(XenBusClass, (class), TYPE_XEN_BUS)
|
||||
#define XEN_BUS_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(XenBusClass, (obj), TYPE_XEN_BUS)
|
||||
|
||||
void xen_bus_init(void);
|
||||
|
||||
void xen_device_backend_set_state(XenDevice *xendev,
|
||||
enum xenbus_state state);
|
||||
enum xenbus_state xen_device_backend_get_state(XenDevice *xendev);
|
||||
|
||||
void xen_device_backend_printf(XenDevice *xendev, const char *key,
|
||||
const char *fmt, ...)
|
||||
GCC_FMT_ATTR(3, 4);
|
||||
void xen_device_frontend_printf(XenDevice *xendev, const char *key,
|
||||
const char *fmt, ...)
|
||||
GCC_FMT_ATTR(3, 4);
|
||||
|
||||
int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
|
||||
const char *fmt, ...);
|
||||
|
||||
void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
|
||||
Error **errp);
|
||||
void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
|
||||
unsigned int nr_refs, int prot,
|
||||
Error **errp);
|
||||
void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
|
||||
unsigned int nr_refs, Error **errp);
|
||||
|
||||
typedef struct XenDeviceGrantCopySegment {
|
||||
union {
|
||||
void *virt;
|
||||
struct {
|
||||
uint32_t ref;
|
||||
off_t offset;
|
||||
} foreign;
|
||||
} source, dest;
|
||||
size_t len;
|
||||
} XenDeviceGrantCopySegment;
|
||||
|
||||
void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
|
||||
XenDeviceGrantCopySegment segs[],
|
||||
unsigned int nr_segs, Error **errp);
|
||||
|
||||
typedef struct XenEventChannel XenEventChannel;
|
||||
|
||||
typedef void (*XenEventHandler)(void *opaque);
|
||||
|
||||
XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
|
||||
unsigned int port,
|
||||
XenEventHandler handler,
|
||||
void *opaque, Error **errp);
|
||||
void xen_device_notify_event_channel(XenDevice *xendev,
|
||||
XenEventChannel *channel,
|
||||
Error **errp);
|
||||
void xen_device_unbind_event_channel(XenDevice *xendev,
|
||||
XenEventChannel *channel,
|
||||
Error **errp);
|
||||
|
||||
#endif /* HW_XEN_BUS_H */
|
|
@ -11,7 +11,7 @@
|
|||
#define TYPE_XENBACKEND "xen-backend"
|
||||
|
||||
#define XENBACKEND_DEVICE(obj) \
|
||||
OBJECT_CHECK(XenDevice, (obj), TYPE_XENBACKEND)
|
||||
OBJECT_CHECK(XenLegacyDevice, (obj), TYPE_XENBACKEND)
|
||||
|
||||
/* variables */
|
||||
extern struct xs_handle *xenstore;
|
||||
|
@ -20,32 +20,37 @@ extern DeviceState *xen_sysdev;
|
|||
extern BusState *xen_sysbus;
|
||||
|
||||
int xenstore_mkdir(char *path, int p);
|
||||
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
|
||||
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
|
||||
int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival);
|
||||
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
|
||||
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
|
||||
void xenstore_update_fe(char *watch, struct XenDevice *xendev);
|
||||
int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
|
||||
const char *val);
|
||||
int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int ival);
|
||||
int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
|
||||
int64_t ival);
|
||||
char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node);
|
||||
int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int *ival);
|
||||
void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev);
|
||||
void xenstore_update_be(char *watch, char *type, int dom,
|
||||
struct XenDevOps *ops);
|
||||
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
|
||||
int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
|
||||
int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
|
||||
char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node);
|
||||
int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
|
||||
int *ival);
|
||||
int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
|
||||
uint64_t *uval);
|
||||
|
||||
void xen_be_check_state(struct XenDevice *xendev);
|
||||
void xen_be_check_state(struct XenLegacyDevice *xendev);
|
||||
|
||||
/* xen backend driver bits */
|
||||
int xen_be_init(void);
|
||||
void xen_be_register_common(void);
|
||||
int xen_be_register(const char *type, struct XenDevOps *ops);
|
||||
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
|
||||
int xen_be_bind_evtchn(struct XenDevice *xendev);
|
||||
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
|
||||
int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state);
|
||||
int xen_be_bind_evtchn(struct XenLegacyDevice *xendev);
|
||||
void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
|
||||
unsigned int nr_refs);
|
||||
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
|
||||
void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
|
||||
unsigned int nr_refs, int prot);
|
||||
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
|
||||
void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
|
||||
unsigned int nr_refs);
|
||||
|
||||
typedef struct XenGrantCopySegment {
|
||||
|
@ -59,17 +64,17 @@ typedef struct XenGrantCopySegment {
|
|||
size_t len;
|
||||
} XenGrantCopySegment;
|
||||
|
||||
int xen_be_copy_grant_refs(struct XenDevice *xendev,
|
||||
int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
|
||||
bool to_domain, XenGrantCopySegment segs[],
|
||||
unsigned int nr_segs);
|
||||
|
||||
static inline void *xen_be_map_grant_ref(struct XenDevice *xendev,
|
||||
static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev,
|
||||
uint32_t ref, int prot)
|
||||
{
|
||||
return xen_be_map_grant_refs(xendev, &ref, 1, prot);
|
||||
}
|
||||
|
||||
static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev,
|
||||
static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev,
|
||||
void *ptr)
|
||||
{
|
||||
return xen_be_unmap_grant_refs(xendev, ptr, 1);
|
|
@ -15,8 +15,7 @@
|
|||
/* xen-machine.c */
|
||||
enum xen_mode {
|
||||
XEN_EMULATE = 0, // xen emulation, using xenner (default)
|
||||
XEN_CREATE, // create xen domain
|
||||
XEN_ATTACH // attach to xen domain created by xend
|
||||
XEN_ATTACH // attach to xen domain created by libxl
|
||||
};
|
||||
|
||||
extern uint32_t xen_domid;
|
||||
|
|
|
@ -32,6 +32,7 @@ extern xc_interface *xen_xc;
|
|||
typedef xc_interface xenforeignmemory_handle;
|
||||
typedef xc_evtchn xenevtchn_handle;
|
||||
typedef xc_gnttab xengnttab_handle;
|
||||
typedef evtchn_port_or_error_t xenevtchn_port_or_error_t;
|
||||
|
||||
#define xenevtchn_open(l, f) xc_evtchn_open(l, f);
|
||||
#define xenevtchn_close(h) xc_evtchn_close(h)
|
||||
|
@ -661,24 +662,6 @@ static inline int xen_set_ioreq_server_state(domid_t dom,
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
|
||||
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40700
|
||||
static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
|
||||
xen_domain_handle_t handle, uint32_t flags,
|
||||
uint32_t *pdomid)
|
||||
{
|
||||
return xc_domain_create(xc, ssidref, handle, flags, pdomid);
|
||||
}
|
||||
#else
|
||||
static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
|
||||
xen_domain_handle_t handle, uint32_t flags,
|
||||
uint32_t *pdomid)
|
||||
{
|
||||
return xc_domain_create(xc, ssidref, handle, flags, pdomid, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Xen before 4.8 */
|
||||
|
||||
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#define XEN_BUFSIZE 1024
|
||||
|
||||
struct XenDevice;
|
||||
struct XenLegacyDevice;
|
||||
|
||||
/* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */
|
||||
#define DEVOPS_FLAG_NEED_GNTDEV 1
|
||||
|
@ -16,19 +16,21 @@ struct XenDevice;
|
|||
struct XenDevOps {
|
||||
size_t size;
|
||||
uint32_t flags;
|
||||
void (*alloc)(struct XenDevice *xendev);
|
||||
int (*init)(struct XenDevice *xendev);
|
||||
int (*initialise)(struct XenDevice *xendev);
|
||||
void (*connected)(struct XenDevice *xendev);
|
||||
void (*event)(struct XenDevice *xendev);
|
||||
void (*disconnect)(struct XenDevice *xendev);
|
||||
int (*free)(struct XenDevice *xendev);
|
||||
void (*backend_changed)(struct XenDevice *xendev, const char *node);
|
||||
void (*frontend_changed)(struct XenDevice *xendev, const char *node);
|
||||
void (*alloc)(struct XenLegacyDevice *xendev);
|
||||
int (*init)(struct XenLegacyDevice *xendev);
|
||||
int (*initialise)(struct XenLegacyDevice *xendev);
|
||||
void (*connected)(struct XenLegacyDevice *xendev);
|
||||
void (*event)(struct XenLegacyDevice *xendev);
|
||||
void (*disconnect)(struct XenLegacyDevice *xendev);
|
||||
int (*free)(struct XenLegacyDevice *xendev);
|
||||
void (*backend_changed)(struct XenLegacyDevice *xendev,
|
||||
const char *node);
|
||||
void (*frontend_changed)(struct XenLegacyDevice *xendev,
|
||||
const char *node);
|
||||
int (*backend_register)(void);
|
||||
};
|
||||
|
||||
struct XenDevice {
|
||||
struct XenLegacyDevice {
|
||||
DeviceState qdev;
|
||||
const char *type;
|
||||
int dom;
|
||||
|
@ -49,7 +51,7 @@ struct XenDevice {
|
|||
xengnttab_handle *gnttabdev;
|
||||
|
||||
struct XenDevOps *ops;
|
||||
QTAILQ_ENTRY(XenDevice) next;
|
||||
QTAILQ_ENTRY(XenLegacyDevice) next;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -66,14 +68,14 @@ void xenstore_update(void *unused);
|
|||
const char *xenbus_strstate(enum xenbus_state state);
|
||||
|
||||
void xen_pv_evtchn_event(void *opaque);
|
||||
void xen_pv_insert_xendev(struct XenDevice *xendev);
|
||||
void xen_pv_del_xendev(struct XenDevice *xendev);
|
||||
struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
|
||||
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev);
|
||||
void xen_pv_del_xendev(struct XenLegacyDevice *xendev);
|
||||
struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
|
||||
|
||||
void xen_pv_unbind_evtchn(struct XenDevice *xendev);
|
||||
int xen_pv_send_notify(struct XenDevice *xendev);
|
||||
void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev);
|
||||
int xen_pv_send_notify(struct XenLegacyDevice *xendev);
|
||||
|
||||
void xen_pv_printf(struct XenDevice *xendev, int msg_level,
|
||||
void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
|
||||
const char *fmt, ...) GCC_FMT_ATTR(3, 4);
|
||||
|
||||
#endif /* QEMU_HW_XEN_PVDEV_H */
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef enum {
|
|||
MODULE_INIT_OPTS,
|
||||
MODULE_INIT_QOM,
|
||||
MODULE_INIT_TRACE,
|
||||
MODULE_INIT_XEN_BACKEND,
|
||||
MODULE_INIT_MAX
|
||||
} module_init_type;
|
||||
|
||||
|
@ -51,6 +52,8 @@ typedef enum {
|
|||
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
|
||||
#define type_init(function) module_init(function, MODULE_INIT_QOM)
|
||||
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
|
||||
#define xen_backend_init(function) module_init(function, \
|
||||
MODULE_INIT_XEN_BACKEND)
|
||||
|
||||
#define block_module_load_one(lib) module_load_one("block-", lib)
|
||||
#define ui_module_load_one(lib) module_load_one("ui-", lib)
|
||||
|
|
|
@ -3394,13 +3394,9 @@ ETEXI
|
|||
|
||||
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
|
||||
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
|
||||
DEF("xen-create", 0, QEMU_OPTION_xen_create,
|
||||
"-xen-create create domain using xen hypercalls, bypassing xend\n"
|
||||
" warning: should not be used when xend is in use\n",
|
||||
QEMU_ARCH_ALL)
|
||||
DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
|
||||
"-xen-attach attach to existing xen domain\n"
|
||||
" xend will use this when starting QEMU\n",
|
||||
" libxl will use this when starting QEMU\n",
|
||||
QEMU_ARCH_ALL)
|
||||
DEF("xen-domid-restrict", 0, QEMU_OPTION_xen_domid_restrict,
|
||||
"-xen-domid-restrict restrict set of available xen operations\n"
|
||||
|
@ -3411,14 +3407,10 @@ STEXI
|
|||
@item -xen-domid @var{id}
|
||||
@findex -xen-domid
|
||||
Specify xen guest domain @var{id} (XEN only).
|
||||
@item -xen-create
|
||||
@findex -xen-create
|
||||
Create domain using xen hypercalls, bypassing xend.
|
||||
Warning: should not be used when xend is in use (XEN only).
|
||||
@item -xen-attach
|
||||
@findex -xen-attach
|
||||
Attach to existing xen domain.
|
||||
xend will use this when starting QEMU (XEN only).
|
||||
libxl will use this when starting QEMU (XEN only).
|
||||
@findex -xen-domid-restrict
|
||||
Restrict set of available xen operations to specified domain id (XEN only).
|
||||
ETEXI
|
||||
|
|
7
vl.c
7
vl.c
|
@ -3856,13 +3856,6 @@ int main(int argc, char **argv, char **envp)
|
|||
}
|
||||
xen_domid = atoi(optarg);
|
||||
break;
|
||||
case QEMU_OPTION_xen_create:
|
||||
if (!(xen_available())) {
|
||||
error_report("Option not supported for this target");
|
||||
exit(1);
|
||||
}
|
||||
xen_mode = XEN_CREATE;
|
||||
break;
|
||||
case QEMU_OPTION_xen_attach:
|
||||
if (!(xen_available())) {
|
||||
error_report("Option not supported for this target");
|
||||
|
|
Loading…
Reference in a new issue