diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2023-11-07 18:57:40 +0800 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2023-11-07 18:57:40 +0800 |
commit | 3e34860a3a03f969ad0720ec9c12ea10e88738a6 (patch) | |
tree | 9dedf147b3ebe237114fb0406f7183eff5e31e25 /hw/block | |
parent | bb541a7068d2eee51a9abbe2dedcdf27298b1872 (diff) | |
parent | cc9d10b9e89f0325c1a14955534d6b28ea586fba (diff) |
Merge tag 'pull-xenfv.for-upstream-20231107' of git://git.infradead.org/users/dwmw2/qemu into staging
Xen PV guest support for 8.2
Add Xen PV console and network support, the former of which enables the
Xen "PV shim" to be used to support PV guests.
Also clean up the block support and make it work when the user passes
just 'drive file=IMAGE,if=xen' on the command line.
Update the documentation to reflect all of these, taking the opportunity
to simplify what it says about q35 by making unplug work for AHCI.
Ignore the VCPU_SSHOTTMR_future timer flag, and advertise the 'fixed'
per-vCPU upcall vector support, as newer upstream Xen do.
# -----BEGIN PGP SIGNATURE-----
#
# iQJIBAABCAAyFiEEvgfZ/VSAmrLEsP9fY3Ys2mfi81kFAmVJ/7EUHGR3bXcyQGlu
# ZnJhZGVhZC5vcmcACgkQY3Ys2mfi81k+/xAAswivVR4+nwz3wTSN7EboGogS3hy+
# ZsTpvbJnfprGQJAK8vv8OP4eunaCJkO/dy3M/33Dh270msmV6I/1ki0E1RIPG45D
# n5wKM1Zxk0ABvjIgdp3xiLwITTdruJ+k9aqV8U9quhjgNFdOa7yjBOG8MD32GEPZ
# KHbavJ++huOu7+DZHJRNRq4gI/fREIULoPGHVg7WuEiRDYokOOmMROXqmTHTaUkV
# yFhkofzWxlpYhh7qRQx6/A80CSf7xwCof8krjdMCOYj3XGzYVZND0z5ZfHQYEwqt
# fowhargA8gH4V3d21S/MWCaZ+QrswFXZhcnl5wuGgWakV4ChvFETKs+fz2mODWUx
# 2T13trqeFJ5ElTrSpH1iWCoSEy6KCeLecvx7c/6HPSkDYQ3w5q8dXPpqgEtXY24S
# Wcmw4PkQ+HrLX7wbSU7QLyTZjvCQLFZ3Sb0uTf2zwsJZyeCCiT2lqAaogoMm6Kg0
# m/jG1JzE+9AC3j0Upp1lS3EK1qdxIuLdBuIcaEBEjy7Am+Y14PlZYoU2c751KbRF
# kqnIOYMoijX0PJDomPqCQtYNE0mrtogo0AbcFFIu+4k25vGbkl7xS5p2du9qw2Rd
# ++IdqQYzdzrUcIwmxocFQqFBJQ2dcbOGB1d7+VJ+A1Uj3yY2/DnFG5WqSaqS0KJi
# ZhBdFs3OTlPnRoM=
# =Dg79
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 07 Nov 2023 17:13:21 HKT
# gpg: using RSA key BE07D9FD54809AB2C4B0FF5F63762CDA67E2F359
# gpg: issuer "dwmw2@infradead.org"
# gpg: Good signature from "David Woodhouse <dwmw2@infradead.org>" [unknown]
# gpg: aka "David Woodhouse <dwmw2@exim.org>" [unknown]
# gpg: aka "David Woodhouse <david@woodhou.se>" [unknown]
# gpg: aka "David Woodhouse <dwmw2@kernel.org>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: BE07 D9FD 5480 9AB2 C4B0 FF5F 6376 2CDA 67E2 F359
* tag 'pull-xenfv.for-upstream-20231107' of git://git.infradead.org/users/dwmw2/qemu:
docs: update Xen-on-KVM documentation
xen-platform: unplug AHCI disks
hw/i386/pc: support '-nic' for xen-net-device
hw/xen: update Xen PV NIC to XenDevice model
hw/xen: only remove peers of PCI NICs on unplug
hw/xen: add support for Xen primary console in emulated mode
hw/xen: update Xen console to XenDevice model
hw/xen: do not repeatedly try to create a failing backend device
hw/xen: add get_frontend_path() method to XenDeviceClass
hw/xen: automatically assign device index to block devices
hw/xen: populate store frontend nodes with XenStore PFN/port
i386/xen: advertise XEN_HVM_CPUID_UPCALL_VECTOR in CPUID
include: update Xen public headers to Xen 4.17.2 release
hw/xen: Clean up event channel 'type_val' handling to use union
i386/xen: Ignore VCPU_SSHOTTMR_future flag in set_singleshot_timer()
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw/block')
-rw-r--r-- | hw/block/xen-block.c | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index bfa53960c3..6d64ede94f 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -27,13 +27,119 @@ #include "sysemu/block-backend.h" #include "sysemu/iothread.h" #include "dataplane/xen-block.h" +#include "hw/xen/interface/io/xs_wire.h" #include "trace.h" +#define XVDA_MAJOR 202 +#define XVDQ_MAJOR (1 << 20) +#define XVDBGQCV_MAJOR ((1 << 21) - 1) +#define HDA_MAJOR 3 +#define HDC_MAJOR 22 +#define SDA_MAJOR 8 + + +static int vdev_to_diskno(unsigned int vdev_nr) +{ + switch (vdev_nr >> 8) { + case XVDA_MAJOR: + case SDA_MAJOR: + return (vdev_nr >> 4) & 0x15; + + case HDA_MAJOR: + return (vdev_nr >> 6) & 1; + + case HDC_MAJOR: + return ((vdev_nr >> 6) & 1) + 2; + + case XVDQ_MAJOR ... XVDBGQCV_MAJOR: + return (vdev_nr >> 8) & 0xfffff; + + default: + return -1; + } +} + +#define MAX_AUTO_VDEV 4096 + +/* + * Find a free device name in the xvda → xvdfan range and set it in + * blockdev->props.vdev. Our definition of "free" is that there must + * be no other disk or partition with the same disk number. + * + * You are technically permitted to have all of hda, hda1, sda, sda1, + * xvda and xvda1 as *separate* PV block devices with separate backing + * stores. That doesn't make it a good idea. This code will skip xvda + * if *any* of those "conflicting" devices already exists. + * + * The limit of xvdfan (disk 4095) is fairly arbitrary just to avoid a + * stupidly sized bitmap, but Linux as of v6.6 doesn't support anything + * higher than that anyway. + */ +static bool xen_block_find_free_vdev(XenBlockDevice *blockdev, Error **errp) +{ + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(blockdev))); + unsigned long used_devs[BITS_TO_LONGS(MAX_AUTO_VDEV)]; + XenBlockVdev *vdev = &blockdev->props.vdev; + char fe_path[XENSTORE_ABS_PATH_MAX + 1]; + char **existing_frontends; + unsigned int nr_existing = 0; + unsigned int vdev_nr; + int i, disk = 0; + + snprintf(fe_path, sizeof(fe_path), "/local/domain/%u/device/vbd", + blockdev->xendev.frontend_id); + + existing_frontends = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, fe_path, + &nr_existing); + if (!existing_frontends && errno != ENOENT) { + error_setg_errno(errp, errno, "cannot read %s", fe_path); + return false; + } + + memset(used_devs, 0, sizeof(used_devs)); + for (i = 0; i < nr_existing; i++) { + if (qemu_strtoui(existing_frontends[i], NULL, 10, &vdev_nr)) { + free(existing_frontends[i]); + continue; + } + + free(existing_frontends[i]); + + disk = vdev_to_diskno(vdev_nr); + if (disk < 0 || disk >= MAX_AUTO_VDEV) { + continue; + } + + set_bit(disk, used_devs); + } + free(existing_frontends); + + disk = find_first_zero_bit(used_devs, MAX_AUTO_VDEV); + if (disk == MAX_AUTO_VDEV) { + error_setg(errp, "cannot find device vdev for block device"); + return false; + } + + vdev->type = XEN_BLOCK_VDEV_TYPE_XVD; + vdev->partition = 0; + vdev->disk = disk; + if (disk < (1 << 4)) { + vdev->number = (XVDA_MAJOR << 8) | (disk << 4); + } else { + vdev->number = (XVDQ_MAJOR << 8) | (disk << 8); + } + return true; +} + static char *xen_block_get_name(XenDevice *xendev, Error **errp) { XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev); XenBlockVdev *vdev = &blockdev->props.vdev; + if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID && + !xen_block_find_free_vdev(blockdev, errp)) { + return NULL; + } return g_strdup_printf("%lu", vdev->number); } @@ -482,10 +588,10 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, 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->number = (XVDA_MAJOR << 8) | (vdev->disk << 4) | vdev->partition; } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) { - vdev->number = (1 << 28) | (vdev->disk << 8) | + vdev->number = (XVDQ_MAJOR << 8) | (vdev->disk << 8) | vdev->partition; } else { goto invalid; @@ -495,10 +601,11 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, 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; + vdev->number = (HDA_MAJOR << 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->number = (HDC_MAJOR << 8) | ((vdev->disk - 2) << 6) | vdev->partition; } else { goto invalid; @@ -507,7 +614,8 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name, case XEN_BLOCK_VDEV_TYPE_SD: if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) { - vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition; + vdev->number = (SDA_MAJOR << 8) | (vdev->disk << 4) | + vdev->partition; } else { goto invalid; } |