mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* Speed up AddressSpaceDispatch creation (Alexey) * Fix kvm.c assert (David) * Memory fixes and further speedup (me) * Persistent reservation manager infrastructure (me) * virtio-serial: add enable_backend callback (Pavel) * chardev GMainContext fixes (Peter) # gpg: Signature made Fri 22 Sep 2017 20:07:33 BST # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (32 commits) chardev: remove context in chr_update_read_handler chardev: use per-dev context for io_add_watch_poll chardev: add Chardev.gcontext field chardev: new qemu_chr_be_update_read_handlers() scsi: add persistent reservation manager using qemu-pr-helper scsi: add multipath support to qemu-pr-helper scsi: build qemu-pr-helper scsi, file-posix: add support for persistent reservation management memory: Share special empty FlatView memory: seek FlatView sharing candidates among children subregions memory: trace FlatView creation and destruction memory: Create FlatView directly memory: Get rid of address_space_init_shareable memory: Rework "info mtree" to print flat views and dispatch trees memory: Do not allocate FlatView in address_space_init memory: Share FlatView's and dispatch trees between address spaces memory: Move address_space_update_ioeventfds memory: Alloc dispatch tree where topology is generared memory: Store physical root MR in FlatView memory: Rename mem_begin/mem_commit/mem_add helpers ... # Conflicts: # configure
This commit is contained in:
@@ -372,6 +372,11 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
|
||||
endif
|
||||
|
||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||
|
||||
@@ -488,7 +493,7 @@ clean:
|
||||
rm -f *.msi
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
rm -f fsdev/*.pod scsi/*.pod
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
|
||||
@# May not be present in GENERATED_FILES
|
||||
|
||||
@@ -171,6 +171,7 @@ trace-events-subdirs += qapi
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += nbd
|
||||
trace-events-subdirs += scsi
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
|
||||
@@ -722,7 +722,6 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, size);
|
||||
if (!add) {
|
||||
if (!mem) {
|
||||
g_assert(!memory_region_is_ram(mr) && !writeable && !mr->romd_mode);
|
||||
return;
|
||||
}
|
||||
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "block/raw-aio.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
||||
#include "scsi/pr-manager.h"
|
||||
#include "scsi/constants.h"
|
||||
|
||||
#if defined(__APPLE__) && (__MACH__)
|
||||
#include <paths.h>
|
||||
#include <sys/param.h>
|
||||
@@ -155,6 +158,8 @@ typedef struct BDRVRawState {
|
||||
bool page_cache_inconsistent:1;
|
||||
bool has_fallocate;
|
||||
bool needs_alignment;
|
||||
|
||||
PRManager *pr_mgr;
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
@@ -402,6 +407,11 @@ static QemuOptsList raw_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "file locking mode (on/off/auto, default: auto)",
|
||||
},
|
||||
{
|
||||
.name = "pr-manager",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "id of persistent reservation manager object (default: none)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -413,6 +423,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename = NULL;
|
||||
const char *str;
|
||||
BlockdevAioOptions aio, aio_default;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
@@ -476,6 +487,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
abort();
|
||||
}
|
||||
|
||||
str = qemu_opt_get(opts, "pr-manager");
|
||||
if (str) {
|
||||
s->pr_mgr = pr_manager_lookup(str, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
s->open_flags = open_flags;
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||
|
||||
@@ -2597,6 +2618,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
|
||||
if (fd_open(bs) < 0)
|
||||
return NULL;
|
||||
|
||||
if (req == SG_IO && s->pr_mgr) {
|
||||
struct sg_io_hdr *io_hdr = buf;
|
||||
if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
|
||||
io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
|
||||
return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
|
||||
s->fd, io_hdr, cb, opaque);
|
||||
}
|
||||
}
|
||||
|
||||
acb = g_new(RawPosixAIOData, 1);
|
||||
acb->bs = bs;
|
||||
acb->aio_type = QEMU_AIO_IOCTL;
|
||||
|
||||
+2
-3
@@ -84,8 +84,7 @@ static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||
return qio_channel_create_watch(s->ioc_out, cond);
|
||||
}
|
||||
|
||||
static void fd_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void fd_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
FDChardev *s = FD_CHARDEV(chr);
|
||||
|
||||
@@ -94,7 +93,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc_in,
|
||||
fd_chr_read_poll,
|
||||
fd_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -253,7 +253,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
bool set_open)
|
||||
{
|
||||
Chardev *s;
|
||||
ChardevClass *cc;
|
||||
int fe_open;
|
||||
|
||||
s = b->chr;
|
||||
@@ -261,7 +260,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
return;
|
||||
}
|
||||
|
||||
cc = CHARDEV_GET_CLASS(s);
|
||||
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
|
||||
fe_open = 0;
|
||||
remove_fd_in_watch(s);
|
||||
@@ -273,9 +271,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
b->chr_event = fd_event;
|
||||
b->chr_be_change = be_change;
|
||||
b->opaque = opaque;
|
||||
if (cc->chr_update_read_handler) {
|
||||
cc->chr_update_read_handler(s, context);
|
||||
}
|
||||
|
||||
qemu_chr_be_update_read_handlers(s, context);
|
||||
|
||||
if (set_open) {
|
||||
qemu_chr_fe_set_open(b, fe_open);
|
||||
|
||||
+2
-3
@@ -112,8 +112,7 @@ static void pty_chr_update_read_handler_locked(Chardev *chr)
|
||||
}
|
||||
}
|
||||
|
||||
static void pty_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void pty_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
qemu_mutex_lock(&chr->chr_write_lock);
|
||||
pty_chr_update_read_handler_locked(chr);
|
||||
@@ -219,7 +218,7 @@ static void pty_chr_state(Chardev *chr, int connected)
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
pty_chr_read_poll,
|
||||
pty_chr_read,
|
||||
chr, NULL);
|
||||
chr, chr->gcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,13 +516,12 @@ static void tcp_chr_connect(void *opaque)
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read,
|
||||
chr, NULL);
|
||||
chr, chr->gcontext);
|
||||
}
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void tcp_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
|
||||
@@ -535,7 +534,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -100,8 +100,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void udp_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void udp_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
UdpChardev *s = UDP_CHARDEV(chr);
|
||||
|
||||
@@ -110,7 +109,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
udp_chr_read_poll,
|
||||
udp_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,17 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_chr_be_update_read_handlers(Chardev *s,
|
||||
GMainContext *context)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_GET_CLASS(s);
|
||||
|
||||
s->gcontext = context;
|
||||
if (cc->chr_update_read_handler) {
|
||||
cc->chr_update_read_handler(s);
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_chr_add_client(Chardev *s, int fd)
|
||||
{
|
||||
return CHARDEV_GET_CLASS(s)->chr_add_client ?
|
||||
|
||||
@@ -290,6 +290,7 @@ netmap="no"
|
||||
sdl=""
|
||||
sdlabi=""
|
||||
virtfs=""
|
||||
mpath=""
|
||||
vnc="yes"
|
||||
sparse="no"
|
||||
vde=""
|
||||
@@ -936,6 +937,10 @@ for opt do
|
||||
;;
|
||||
--enable-virtfs) virtfs="yes"
|
||||
;;
|
||||
--disable-mpath) mpath="no"
|
||||
;;
|
||||
--enable-mpath) mpath="yes"
|
||||
;;
|
||||
--disable-vnc) vnc="no"
|
||||
;;
|
||||
--enable-vnc) vnc="yes"
|
||||
@@ -1479,6 +1484,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
vnc-png PNG compression for VNC server
|
||||
cocoa Cocoa UI (Mac OS X only)
|
||||
virtfs VirtFS
|
||||
mpath Multipath persistent reservation passthrough
|
||||
xen xen backend driver support
|
||||
xen-pci-passthrough
|
||||
brlapi BrlAPI (Braile)
|
||||
@@ -3294,6 +3300,30 @@ else
|
||||
"Please install the pixman devel package."
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libmpathpersist probe
|
||||
|
||||
if test "$mpath" != "no" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <libudev.h>
|
||||
#include <mpath_persist.h>
|
||||
unsigned mpath_mx_alloc_len = 1024;
|
||||
int logsink;
|
||||
int main(void) {
|
||||
struct udev *udev = udev_new();
|
||||
mpath_lib_init(udev);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
|
||||
mpathpersist=yes
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libcap probe
|
||||
|
||||
@@ -5023,16 +5053,34 @@ if test "$want_tools" = "yes" ; then
|
||||
fi
|
||||
fi
|
||||
if test "$softmmu" = yes ; then
|
||||
if test "$virtfs" != no ; then
|
||||
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
|
||||
if test "$linux" = yes; then
|
||||
if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
|
||||
virtfs=yes
|
||||
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
|
||||
error_exit "VirtFS requires libcap devel and libattr devel"
|
||||
fi
|
||||
virtfs=no
|
||||
fi
|
||||
if test "$mpath" != no && test "$mpathpersist" = yes ; then
|
||||
mpath=yes
|
||||
else
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath requires libmpathpersist devel"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
error_exit "VirtFS is supported only on Linux"
|
||||
fi
|
||||
virtfs=no
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath is supported only on Linux"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -5278,6 +5326,7 @@ echo "Audio drivers $audio_drv_list"
|
||||
echo "Block whitelist (rw) $block_drv_rw_whitelist"
|
||||
echo "Block whitelist (ro) $block_drv_ro_whitelist"
|
||||
echo "VirtFS support $virtfs"
|
||||
echo "Multipath support $mpath"
|
||||
echo "VNC support $vnc"
|
||||
if test "$vnc" = "yes" ; then
|
||||
echo "VNC SASL support $vnc_sasl"
|
||||
@@ -5729,6 +5778,9 @@ fi
|
||||
if test "$virtfs" = "yes" ; then
|
||||
echo "CONFIG_VIRTFS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$mpath" = "yes" ; then
|
||||
echo "CONFIG_MPATH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$vhost_scsi" = "yes" ; then
|
||||
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -6510,7 +6562,7 @@ fi
|
||||
|
||||
# build tree in object directory in case the source is not in the current directory
|
||||
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
|
||||
DIRS="$DIRS docs docs/interop fsdev"
|
||||
DIRS="$DIRS docs docs/interop fsdev scsi"
|
||||
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
|
||||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS qapi-generated"
|
||||
|
||||
@@ -1764,8 +1764,9 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
/* If the target cpu hasn't set up any address spaces itself,
|
||||
* give it the default one.
|
||||
*/
|
||||
AddressSpace *as = address_space_init_shareable(cpu->memory,
|
||||
"cpu-memory");
|
||||
AddressSpace *as = g_new0(AddressSpace, 1);
|
||||
|
||||
address_space_init(as, cpu->memory, "cpu-memory");
|
||||
cpu->num_ases = 1;
|
||||
cpu_address_space_init(cpu, as, 0);
|
||||
}
|
||||
|
||||
+13
-1
@@ -63,11 +63,23 @@ operations:
|
||||
typeof(*ptr) atomic_fetch_sub(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_and(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_or(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_xor(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_inc_nonzero(ptr)
|
||||
typeof(*ptr) atomic_xchg(ptr, val)
|
||||
typeof(*ptr) atomic_cmpxchg(ptr, old, new)
|
||||
|
||||
all of which return the old value of *ptr. These operations are
|
||||
polymorphic; they operate on any type that is as wide as an int.
|
||||
polymorphic; they operate on any type that is as wide as a pointer.
|
||||
|
||||
Similar operations return the new value of *ptr:
|
||||
|
||||
typeof(*ptr) atomic_inc_fetch(ptr)
|
||||
typeof(*ptr) atomic_dec_fetch(ptr)
|
||||
typeof(*ptr) atomic_add_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_sub_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_and_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_or_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_xor_fetch(ptr, val)
|
||||
|
||||
Sequentially consistent loads and stores can be done using:
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
..
|
||||
|
||||
======================================
|
||||
Persistent reservation helper protocol
|
||||
======================================
|
||||
|
||||
QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
|
||||
can delegate implementation of persistent reservations to an external
|
||||
(and typically privileged) program. Persistent Reservations allow
|
||||
restricting access to block devices to specific initiators in a shared
|
||||
storage setup.
|
||||
|
||||
For a more detailed reference please refer the the SCSI Primary
|
||||
Commands standard, specifically the section on Reservations and the
|
||||
"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
|
||||
|
||||
This document describes the socket protocol used between QEMU's
|
||||
``pr-manager-helper`` object and the external program.
|
||||
|
||||
.. contents::
|
||||
|
||||
Connection and initialization
|
||||
-----------------------------
|
||||
|
||||
All data transmitted on the socket is big-endian.
|
||||
|
||||
After connecting to the helper program's socket, the helper starts a simple
|
||||
feature negotiation process by writing four bytes corresponding to
|
||||
the features it exposes (``supported_features``). QEMU reads it,
|
||||
then writes four bytes corresponding to the desired features of the
|
||||
helper program (``requested_features``).
|
||||
|
||||
If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
|
||||
the corresponding feature is not supported by the helper and the connection
|
||||
is closed. On the other hand, it is acceptable for a bit to be 0 in
|
||||
``requested_features`` and 1 in ``supported_features``; in this case,
|
||||
the helper will not enable the feature.
|
||||
|
||||
Right now no feature is defined, so the two parties always write four
|
||||
zero bytes.
|
||||
|
||||
Command format
|
||||
--------------
|
||||
|
||||
It is invalid to send multiple commands concurrently on the same
|
||||
socket. It is however possible to connect multiple sockets to the
|
||||
helper and send multiple commands to the helper for one or more
|
||||
file descriptors.
|
||||
|
||||
A command consists of a request and a response. A request consists
|
||||
of a 16-byte SCSI CDB. A file descriptor must be passed to the helper
|
||||
together with the SCSI CDB using ancillary data.
|
||||
|
||||
The CDB has the following limitations:
|
||||
|
||||
- the command (stored in the first byte) must be one of 0x5E
|
||||
(PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
|
||||
|
||||
- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
|
||||
RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
|
||||
for PERSISTENT RESERVE OUT) is limited to 8 KiB.
|
||||
|
||||
For PERSISTENT RESERVE OUT, the parameter list is sent right after the
|
||||
CDB. The length of the parameter list is taken from the CDB itself.
|
||||
|
||||
The helper's reply has the following structure:
|
||||
|
||||
- 4 bytes for the SCSI status
|
||||
|
||||
- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN
|
||||
and only if the SCSI status is 0x00, i.e. GOOD)
|
||||
|
||||
- 96 bytes for the SCSI sense data
|
||||
|
||||
- if the size is nonzero, the payload follows
|
||||
|
||||
The sense data is always sent to keep the protocol simple, even though
|
||||
it is only valid if the SCSI status is CHECK CONDITION (0x02).
|
||||
|
||||
The payload size is always less than or equal to the allocation length
|
||||
specified in the CDB for the PERSISTENT RESERVE IN command.
|
||||
|
||||
If the protocol is violated, the helper closes the socket.
|
||||
@@ -0,0 +1,111 @@
|
||||
======================================
|
||||
Persistent reservation managers
|
||||
======================================
|
||||
|
||||
SCSI persistent Reservations allow restricting access to block devices
|
||||
to specific initiators in a shared storage setup. When implementing
|
||||
clustering of virtual machines, it is a common requirement for virtual
|
||||
machines to send persistent reservation SCSI commands. However,
|
||||
the operating system restricts sending these commands to unprivileged
|
||||
programs because incorrect usage can disrupt regular operation of the
|
||||
storage fabric.
|
||||
|
||||
For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
|
||||
and ``scsi-generic`` (both are only available on Linux) can delegate
|
||||
implementation of persistent reservations to a separate object,
|
||||
the "persistent reservation manager". Only PERSISTENT RESERVE OUT and
|
||||
PERSISTENT RESERVE IN commands are passed to the persistent reservation
|
||||
manager object; other commands are processed by QEMU as usual.
|
||||
|
||||
-----------------------------------------
|
||||
Defining a persistent reservation manager
|
||||
-----------------------------------------
|
||||
|
||||
A persistent reservation manager is an instance of a subclass of the
|
||||
"pr-manager" QOM class.
|
||||
|
||||
Right now only one subclass is defined, ``pr-manager-helper``, which
|
||||
forwards the commands to an external privileged helper program
|
||||
over Unix sockets. The helper program only allows sending persistent
|
||||
reservation commands to devices for which QEMU has a file descriptor,
|
||||
so that QEMU will not be able to effect persistent reservations
|
||||
unless it has access to both the socket and the device.
|
||||
|
||||
``pr-manager-helper`` has a single string property, ``path``, which
|
||||
accepts the path to the helper program's Unix socket. For example,
|
||||
the following command line defines a ``pr-manager-helper`` object and
|
||||
attaches it to a SCSI passthrough device::
|
||||
|
||||
$ qemu-system-x86_64
|
||||
-device virtio-scsi \
|
||||
-object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
|
||||
-drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
|
||||
-device scsi-block,drive=hd
|
||||
|
||||
Alternatively, using ``-blockdev``::
|
||||
|
||||
$ qemu-system-x86_64
|
||||
-device virtio-scsi \
|
||||
-object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
|
||||
-blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
|
||||
-device scsi-block,drive=hd
|
||||
|
||||
----------------------------------
|
||||
Invoking :program:`qemu-pr-helper`
|
||||
----------------------------------
|
||||
|
||||
QEMU provides an implementation of the persistent reservation helper,
|
||||
called :program:`qemu-pr-helper`. The helper should be started as a
|
||||
system service and supports the following option:
|
||||
|
||||
-d, --daemon run in the background
|
||||
-q, --quiet decrease verbosity
|
||||
-v, --verbose increase verbosity
|
||||
-f, --pidfile=path PID file when running as a daemon
|
||||
-k, --socket=path path to the socket
|
||||
-T, --trace=trace-opts tracing options
|
||||
|
||||
By default, the socket and PID file are placed in the runtime state
|
||||
directory, for example :file:`/var/run/qemu-pr-helper.sock` and
|
||||
:file:`/var/run/qemu-pr-helper.pid`. The PID file is not created
|
||||
unless :option:`-d` is passed too.
|
||||
|
||||
:program:`qemu-pr-helper` can also use the systemd socket activation
|
||||
protocol. In this case, the systemd socket unit should specify a
|
||||
Unix stream socket, like this::
|
||||
|
||||
[Socket]
|
||||
ListenStream=/var/run/qemu-pr-helper.sock
|
||||
|
||||
After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
|
||||
root privileges, except for those capabilities that are needed for
|
||||
its operation. To do this, add the following options:
|
||||
|
||||
-u, --user=user user to drop privileges to
|
||||
-g, --group=group group to drop privileges to
|
||||
|
||||
---------------------------------------------
|
||||
Multipath devices and persistent reservations
|
||||
---------------------------------------------
|
||||
|
||||
Proper support of persistent reservation for multipath devices requires
|
||||
communication with the multipath daemon, so that the reservation is
|
||||
registered and applied when a path is newly discovered or becomes online
|
||||
again. :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
|
||||
library was available on the system at build time.
|
||||
|
||||
As of August 2017, a reservation key must be specified in ``multipath.conf``
|
||||
for ``multipathd`` to check for persistent reservation for newly
|
||||
discovered paths or reinstated paths. The attribute can be added
|
||||
to the ``defaults`` section or the ``multipaths`` section; for example::
|
||||
|
||||
multipaths {
|
||||
multipath {
|
||||
wwid XXXXXXXXXXXXXXXX
|
||||
alias yellow
|
||||
reservation_key 0x123abc
|
||||
}
|
||||
}
|
||||
|
||||
Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
|
||||
its usage on regular SCSI devices.
|
||||
@@ -250,9 +250,10 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "mtree",
|
||||
.args_type = "flatview:-f",
|
||||
.params = "[-f]",
|
||||
.help = "show memory tree (-f: dump flat view for address spaces)",
|
||||
.args_type = "flatview:-f,dispatch_tree:-d",
|
||||
.params = "[-f][-d]",
|
||||
.help = "show memory tree (-f: dump flat view for address spaces;"
|
||||
"-d: dump dispatch tree, valid with -f only)",
|
||||
.cmd = hmp_info_mtree,
|
||||
},
|
||||
|
||||
|
||||
+4
-5
@@ -41,7 +41,7 @@ static MemTxResult bitband_read(void *opaque, hwaddr offset,
|
||||
|
||||
/* Find address in underlying memory and round down to multiple of size */
|
||||
addr = bitband_addr(s, offset) & (-size);
|
||||
res = address_space_read(s->source_as, addr, attrs, buf, size);
|
||||
res = address_space_read(&s->source_as, addr, attrs, buf, size);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
|
||||
/* Find address in underlying memory and round down to multiple of size */
|
||||
addr = bitband_addr(s, offset) & (-size);
|
||||
res = address_space_read(s->source_as, addr, attrs, buf, size);
|
||||
res = address_space_read(&s->source_as, addr, attrs, buf, size);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
} else {
|
||||
buf[bitpos >> 3] &= ~bit;
|
||||
}
|
||||
return address_space_write(s->source_as, addr, attrs, buf, size);
|
||||
return address_space_write(&s->source_as, addr, attrs, buf, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bitband_ops = {
|
||||
@@ -111,8 +111,7 @@ static void bitband_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
s->source_as = address_space_init_shareable(s->source_memory,
|
||||
"bitband-source");
|
||||
address_space_init(&s->source_as, s->source_memory, "bitband-source");
|
||||
}
|
||||
|
||||
/* Board init. */
|
||||
|
||||
@@ -187,6 +187,26 @@ static int chr_be_change(void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtconsole_enable_backend(VirtIOSerialPort *port, bool enable)
|
||||
{
|
||||
VirtConsole *vcon = VIRTIO_CONSOLE(port);
|
||||
|
||||
if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||
|
||||
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
|
||||
k->is_console ? NULL : chr_event,
|
||||
chr_be_change, vcon, NULL, false);
|
||||
} else {
|
||||
qemu_chr_fe_set_handlers(&vcon->chr, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtconsole_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
||||
@@ -258,6 +278,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data)
|
||||
k->unrealize = virtconsole_unrealize;
|
||||
k->have_data = flush_buf;
|
||||
k->set_guest_connected = set_guest_connected;
|
||||
k->enable_backend = virtconsole_enable_backend;
|
||||
k->guest_writable = guest_writable;
|
||||
dc->props = virtserialport_properties;
|
||||
}
|
||||
|
||||
@@ -637,6 +637,13 @@ static void set_status(VirtIODevice *vdev, uint8_t status)
|
||||
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
guest_reset(vser);
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(port, &vser->ports, next) {
|
||||
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||
if (vsc->enable_backend) {
|
||||
vsc->enable_backend(port, vdev->vm_running);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vser_reset(VirtIODevice *vdev)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user