提交 460b6c8e 编写于 作者: P Peter Maydell

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
......@@ -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;
......
......@@ -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);
}
}
......
......@@ -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);
......
......@@ -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);
}
}
......
......@@ -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);
}
......
......@@ -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:
......
..
======================================
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.
======================================
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,
},
......
......@@ -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)
......
......@@ -124,7 +124,7 @@ static void kvm_openpic_region_add(MemoryListener *listener,
uint64_t reg_base;
int ret;
if (section->address_space != &address_space_memory) {
if (section->fv != address_space_to_flatview(&address_space_memory)) {
abort();
}
......
......@@ -55,6 +55,7 @@ struct Chardev {
int logfd;
int be_open;
GSource *gsource;
GMainContext *gcontext;
DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
};
......@@ -168,6 +169,16 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
*/
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
/**
* @qemu_chr_be_update_read_handlers:
*
* Invoked when frontend read handlers are setup
*
* @context the gcontext that will be used to attach the watch sources
*/
void qemu_chr_be_update_read_handlers(Chardev *s,
GMainContext *context);
/**
* @qemu_chr_be_event:
*
......@@ -227,7 +238,7 @@ typedef struct ChardevClass {
int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
void (*chr_update_read_handler)(Chardev *s, GMainContext *context);
void (*chr_update_read_handler)(Chardev *s);
int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
int (*get_msgfds)(Chardev *s, int* fds, int num);
int (*set_msgfds)(Chardev *s, int *fds, int num);
......
......@@ -22,14 +22,22 @@
#ifndef CONFIG_USER_ONLY
typedef struct AddressSpaceDispatch AddressSpaceDispatch;
void address_space_init_dispatch(AddressSpace *as);
void address_space_unregister(AddressSpace *as);
void address_space_destroy_dispatch(AddressSpace *as);
extern const MemoryRegionOps unassigned_mem_ops;
bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
unsigned size, bool is_write);
void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
void address_space_dispatch_compact(AddressSpaceDispatch *d);
AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as);
AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv);
void address_space_dispatch_free(AddressSpaceDispatch *d);
void mtree_print_dispatch(fprintf_function mon, void *f,
struct AddressSpaceDispatch *d,
MemoryRegion *root);
#endif
#endif
......@@ -308,21 +308,18 @@ struct AddressSpace {
struct rcu_head rcu;
char *name;
MemoryRegion *root;
int ref_count;
bool malloced;
/* Accessed via RCU. */
struct FlatView *current_map;
int ioeventfd_nb;
struct MemoryRegionIoeventfd *ioeventfds;
struct AddressSpaceDispatch *dispatch;
struct AddressSpaceDispatch *next_dispatch;
MemoryListener dispatch_listener;
QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
};
FlatView *address_space_to_flatview(AddressSpace *as);
/**
* MemoryRegionSection: describes a fragment of a #MemoryRegion
*
......@@ -336,7 +333,7 @@ struct AddressSpace {
*/
struct MemoryRegionSection {
MemoryRegion *mr;
AddressSpace *address_space;
FlatView *fv;
hwaddr offset_within_region;
Int128 size;
hwaddr offset_within_address_space;
......@@ -1515,7 +1512,8 @@ void memory_global_dirty_log_start(void);
*/
void memory_global_dirty_log_stop(void);
void mtree_info(fprintf_function mon_printf, void *f, bool flatview);
void mtree_info(fprintf_function mon_printf, void *f, bool flatview,
bool dispatch_tree);
/**
* memory_region_request_mmio_ptr: request a pointer to an mmio
......@@ -1584,23 +1582,6 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
*/
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name);
/**
* address_space_init_shareable: return an address space for a memory region,
* creating it if it does not already exist
*
* @root: a #MemoryRegion that routes addresses for the address space
* @name: an address space name. The name is only used for debugging
* output.
*
* This function will return a pointer to an existing AddressSpace
* which was initialized with the specified MemoryRegion, or it will
* create and initialize one if it does not already exist. The ASes
* are reference-counted, so the memory will be freed automatically
* when the AddressSpace is destroyed via address_space_destroy.
*/
AddressSpace *address_space_init_shareable(MemoryRegion *root,
const char *name);
/**
* address_space_destroy: destroy an address space
*
......@@ -1845,9 +1826,17 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
* @len: pointer to length
* @is_write: indicates the transfer direction
*/
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
hwaddr *xlat, hwaddr *len,
bool is_write);
MemoryRegion *flatview_translate(FlatView *fv,
hwaddr addr, hwaddr *xlat,
hwaddr *len, bool is_write);
static inline MemoryRegion *address_space_translate(AddressSpace *as,
hwaddr addr, hwaddr *xlat,
hwaddr *len, bool is_write)
{
return flatview_translate(address_space_to_flatview(as),
addr, xlat, len, is_write);
}
/* address_space_access_valid: check for validity of accessing an address
* space range
......@@ -1898,12 +1887,13 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
/* Internal functions, part of the implementation of address_space_read. */
MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf,
int len, hwaddr addr1, hwaddr l,
MemoryRegion *mr);
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf, int len);
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf,
int len, hwaddr addr1, hwaddr l,
MemoryRegion *mr);
MemTxResult flatview_read_full(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf, int len);
void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
......@@ -1930,8 +1920,8 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
* @buf: buffer with the data transferred
*/
static inline __attribute__((__always_inline__))
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
uint8_t *buf, int len)
MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
uint8_t *buf, int len)
{
MemTxResult result = MEMTX_OK;
hwaddr l, addr1;
......@@ -1942,22 +1932,29 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
if (len) {
rcu_read_lock();
l = len;
mr = address_space_translate(as, addr, &addr1, &l, false);
mr = flatview_translate(fv, addr, &addr1, &l, false);
if (len == l && memory_access_is_direct(mr, false)) {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
memcpy(buf, ptr, len);
} else {
result = address_space_read_continue(as, addr, attrs, buf, len,
addr1, l, mr);
result = flatview_read_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
}
rcu_read_unlock();
}
} else {
result = address_space_read_full(as, addr, attrs, buf, len);
result = flatview_read_full(fv, addr, attrs, buf, len);
}
return result;
}
static inline MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf,
int len)
{
return flatview_read(address_space_to_flatview(as), addr, attrs, buf, len);
}
/**
* address_space_read_cached: read from a cached RAM region
*
......
......@@ -21,7 +21,7 @@ typedef struct {
SysBusDevice parent_obj;
/*< public >*/
AddressSpace *source_as;
AddressSpace source_as;
MemoryRegion iomem;
uint32_t base;
MemoryRegion *source_memory;
......
......@@ -58,6 +58,9 @@ typedef struct VirtIOSerialPortClass {
/* Guest opened/closed device. */
void (*set_guest_connected)(VirtIOSerialPort *port, int guest_connected);
/* Enable/disable backend for virtio serial port */
void (*enable_backend)(VirtIOSerialPort *port, bool enable);
/* Guest is now ready to accept data (virtqueues set up). */
void (*guest_ready)(VirtIOSerialPort *port);
......
......@@ -442,4 +442,12 @@
} while(0)
#endif
#define atomic_fetch_inc_nonzero(ptr) ({ \
typeof_strip_qual(*ptr) _oldn = atomic_read(ptr); \
while (_oldn && atomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \
_oldn = atomic_read(ptr); \
} \
_oldn; \
})
#endif /* QEMU_ATOMIC_H */
......@@ -30,6 +30,7 @@ typedef struct DisplaySurface DisplaySurface;
typedef struct DriveInfo DriveInfo;
typedef struct Error Error;
typedef struct EventNotifier EventNotifier;
typedef struct FlatView FlatView;
typedef struct FWCfgEntry FWCfgEntry;
typedef struct FWCfgIoState FWCfgIoState;
typedef struct FWCfgMemState FWCfgMemState;
......
#ifndef PR_MANAGER_H
#define PR_MANAGER_H
#include "qom/object.h"
#include "qapi/qmp/qdict.h"
#include "qapi/visitor.h"
#include "qom/object_interfaces.h"
#include "block/aio.h"
#define TYPE_PR_MANAGER "pr-manager"
#define PR_MANAGER_CLASS(klass) \
OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER)
#define PR_MANAGER_GET_CLASS(obj) \
OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER)
#define PR_MANAGER(obj) \
OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER)
struct sg_io_hdr;
typedef struct PRManager {
/* <private> */
Object parent;
} PRManager;
/**
* PRManagerClass:
* @parent_class: the base class
* @run: callback invoked in thread pool context
*/
typedef struct PRManagerClass {
/* <private> */
ObjectClass parent_class;
/* <public> */
int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr);
} PRManagerClass;
BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
AioContext *ctx, int fd,
struct sg_io_hdr *hdr,
BlockCompletionFunc *complete,
void *opaque);
#ifdef CONFIG_LINUX
PRManager *pr_manager_lookup(const char *id, Error **errp);
#else
static inline PRManager *pr_manager_lookup(const char *id, Error **errp)
{
/* The classes do not exist at all! */
error_setg(errp, "No persistent reservation manager with id '%s'", id);
return NULL;
}
#endif
#endif
......@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR;
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
/* Command aborted, Logical Unit failure */
extern const struct SCSISense sense_code_LUN_FAILURE;
/* Command aborted, LUN Communication failure */
extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
/* Command aborted, Overlapped Commands Attempted */
extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
/* LUN not ready, Capacity data has changed */
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
/* Unit attention, SCSI bus reset */
extern const struct SCSISense sense_code_SCSI_BUS_RESET;
/* LUN not ready, Medium not present */
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
/* Unit attention, Power on, reset or bus device reset occurred */
......
此差异已折叠。
......@@ -1703,8 +1703,9 @@ static void hmp_boot_set(Monitor *mon, const QDict *qdict)
static void hmp_info_mtree(Monitor *mon, const QDict *qdict)
{
bool flatview = qdict_get_try_bool(qdict, "flatview", false);
bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false);
mtree_info((fprintf_function)monitor_printf, mon, flatview);
mtree_info((fprintf_function)monitor_printf, mon, flatview, dispatch_tree);
}
static void hmp_info_numa(Monitor *mon, const QDict *qdict)
......
......@@ -2241,6 +2241,9 @@
# Driver specific block device options for the file backend.
#
# @filename: path to the image file
# @pr-manager: the id for the object that will handle persistent reservations
# for this device (default: none, forward the commands via SG_IO;
# since 2.11)
# @aio: AIO backend (default: threads) (since: 2.8)
# @locking: whether to enable file locking. If set to 'auto', only enable
# when Open File Descriptor (OFD) locking API is available
......@@ -2250,6 +2253,7 @@
##
{ 'struct': 'BlockdevOptionsFile',
'data': { 'filename': 'str',
'*pr-manager': 'str',
'*locking': 'OnOffAuto',
'*aio': 'BlockdevAioOptions' } }
......
block-obj-y += utils.o
block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o
/* Definitions for QEMU's persistent reservation helper daemon
*
* Copyright (C) 2017 Red Hat, Inc.
*
* Author:
* Paolo Bonzini <pbonzini@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef QEMU_PR_HELPER_H
#define QEMU_PR_HELPER_H 1
#include <stdint.h>
#define PR_HELPER_CDB_SIZE 16
#define PR_HELPER_SENSE_SIZE 96
#define PR_HELPER_DATA_SIZE 8192
typedef struct PRHelperResponse {
int32_t result;
int32_t sz;
uint8_t sense[PR_HELPER_SENSE_SIZE];
} PRHelperResponse;
#endif
/*
* Persistent reservation manager that talks to qemu-pr-helper
*
* Copyright (c) 2017 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* This code is licensed under the LGPL v2.1 or later.
*
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "scsi/constants.h"
#include "scsi/pr-manager.h"
#include "scsi/utils.h"
#include "io/channel.h"
#include "io/channel-socket.h"
#include "pr-helper.h"
#include <scsi/sg.h>
#define PR_MAX_RECONNECT_ATTEMPTS 5
#define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
#define PR_MANAGER_HELPER(obj) \
OBJECT_CHECK(PRManagerHelper, (obj), \
TYPE_PR_MANAGER_HELPER)
typedef struct PRManagerHelper {
/* <private> */
PRManager parent;
char *path;
QemuMutex lock;
QIOChannel *ioc;
} PRManagerHelper;
/* Called with lock held. */
static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
void *buf, int sz, Error **errp)
{
ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
if (r < 0) {
object_unref(OBJECT(pr_mgr->ioc));
pr_mgr->ioc = NULL;
return -EINVAL;
}
return 0;
}
/* Called with lock held. */
static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
int fd,
const void *buf, int sz, Error **errp)
{
size_t nfds = (fd != -1);
while (sz > 0) {
struct iovec iov;
ssize_t n_written;
iov.iov_base = (void *)buf;
iov.iov_len = sz;
n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
nfds ? &fd : NULL, nfds, errp);
if (n_written <= 0) {
assert(n_written != QIO_CHANNEL_ERR_BLOCK);
object_unref(OBJECT(pr_mgr->ioc));
return n_written < 0 ? -EINVAL : 0;
}
nfds = 0;
buf += n_written;
sz -= n_written;
}
return 0;
}
/* Called with lock held. */
static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
Error **errp)
{
char *path = g_strdup(pr_mgr->path);
SocketAddress saddr = {
.type = SOCKET_ADDRESS_TYPE_UNIX,
.u.q_unix.path = path
};
QIOChannelSocket *sioc = qio_channel_socket_new();
Error *local_err = NULL;
uint32_t flags;
int r;
assert(!pr_mgr->ioc);
qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
qio_channel_socket_connect_sync(sioc,
&saddr,
&local_err);
g_free(path);
if (local_err) {
object_unref(OBJECT(sioc));
error_propagate(errp, local_err);
return -ENOTCONN;
}
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
pr_mgr->ioc = QIO_CHANNEL(sioc);
/* A simple feature negotation protocol, even though there is
* no optional feature right now.
*/
r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp);
if (r < 0) {
goto out_close;
}
flags = 0;
r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp);
if (r < 0) {
goto out_close;
}
return 0;
out_close:
object_unref(OBJECT(pr_mgr->ioc));
pr_mgr->ioc = NULL;
return r;
}
static int pr_manager_helper_run(PRManager *p,
int fd, struct sg_io_hdr *io_hdr)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
uint32_t len;
PRHelperResponse resp;
int ret;
int expected_dir;
int attempts;
uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
return -EINVAL;
}
memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
expected_dir =
(cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
if (io_hdr->dxfer_direction != expected_dir) {
return -EINVAL;
}
len = scsi_cdb_xfer(cdb);
if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
return -EINVAL;
}
qemu_mutex_lock(&pr_mgr->lock);
/* Try to reconnect while sending the CDB. */
for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
if (!pr_mgr->ioc) {
ret = pr_manager_helper_initialize(pr_mgr, NULL);
if (ret < 0) {
qemu_mutex_unlock(&pr_mgr->lock);
g_usleep(G_USEC_PER_SEC);
qemu_mutex_lock(&pr_mgr->lock);
continue;
}
}
ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL);
if (ret >= 0) {
break;
}
}
if (ret < 0) {
goto out;
}
/* After sending the CDB, any communications failure causes the
* command to fail. The failure is transient, retrying the command
* will invoke pr_manager_helper_initialize again.
*/
if (expected_dir == SG_DXFER_TO_DEV) {
io_hdr->resid = io_hdr->dxfer_len - len;
ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL);
if (ret < 0) {
goto out;
}
}
ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL);
if (ret < 0) {
goto out;
}
resp.result = be32_to_cpu(resp.result);
resp.sz = be32_to_cpu(resp.sz);
if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) {
assert(resp.sz <= io_hdr->dxfer_len);
ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL);
if (ret < 0) {
goto out;
}
io_hdr->resid = io_hdr->dxfer_len - resp.sz;
} else {
assert(resp.sz == 0);
}
io_hdr->status = resp.result;
if (resp.result == CHECK_CONDITION) {
io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
}
out:
if (ret < 0) {
int sense_len = scsi_build_sense(io_hdr->sbp,
SENSE_CODE(LUN_COMM_FAILURE));
io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
io_hdr->status = CHECK_CONDITION;
}
qemu_mutex_unlock(&pr_mgr->lock);
return ret;
}
static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
qemu_mutex_lock(&pr_mgr->lock);
pr_manager_helper_initialize(pr_mgr, errp);
qemu_mutex_unlock(&pr_mgr->lock);
}
static char *get_path(Object *obj, Error **errp)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
return g_strdup(pr_mgr->path);
}
static void set_path(Object *obj, const char *str, Error **errp)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
g_free(pr_mgr->path);
pr_mgr->path = g_strdup(str);
}
static void pr_manager_helper_instance_finalize(Object *obj)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
object_unref(OBJECT(pr_mgr->ioc));
qemu_mutex_destroy(&pr_mgr->lock);
}
static void pr_manager_helper_instance_init(Object *obj)
{
PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
qemu_mutex_init(&pr_mgr->lock);
}
static void pr_manager_helper_class_init(ObjectClass *klass,
void *class_data G_GNUC_UNUSED)
{
PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
object_class_property_add_str(klass, "path", get_path, set_path,
&error_abort);
uc_klass->complete = pr_manager_helper_complete;
prmgr_klass->run = pr_manager_helper_run;
}
static const TypeInfo pr_manager_helper_info = {
.parent = TYPE_PR_MANAGER,
.name = TYPE_PR_MANAGER_HELPER,
.instance_size = sizeof(PRManagerHelper),
.instance_init = pr_manager_helper_instance_init,
.instance_finalize = pr_manager_helper_instance_finalize,
.class_init = pr_manager_helper_class_init,
};
static void pr_manager_helper_register_types(void)
{
type_register_static(&pr_manager_helper_info);
}
type_init(pr_manager_helper_register_types);
/*
* Persistent reservation manager abstract class
*
* Copyright (c) 2017 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* This code is licensed under the LGPL.
*
*/
#include "qemu/osdep.h"
#include <scsi/sg.h>
#include "qapi/error.h"
#include "block/aio.h"
#include "block/thread-pool.h"
#include "scsi/pr-manager.h"
#include "trace.h"
typedef struct PRManagerData {
PRManager *pr_mgr;
struct sg_io_hdr *hdr;
int fd;
} PRManagerData;
static int pr_manager_worker(void *opaque)
{
PRManagerData *data = opaque;
PRManager *pr_mgr = data->pr_mgr;
PRManagerClass *pr_mgr_class =
PR_MANAGER_GET_CLASS(pr_mgr);
struct sg_io_hdr *hdr = data->hdr;
int fd = data->fd;
int r;
g_free(data);
trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]);
/* The reference was taken in pr_manager_execute. */
r = pr_mgr_class->run(pr_mgr, fd, hdr);
object_unref(OBJECT(pr_mgr));
return r;
}
BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
AioContext *ctx, int fd,
struct sg_io_hdr *hdr,
BlockCompletionFunc *complete,
void *opaque)
{
PRManagerData *data = g_new(PRManagerData, 1);
ThreadPool *pool = aio_get_thread_pool(ctx);
trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque);
data->pr_mgr = pr_mgr;
data->fd = fd;
data->hdr = hdr;
/* The matching object_unref is in pr_manager_worker. */
object_ref(OBJECT(pr_mgr));
return thread_pool_submit_aio(pool, pr_manager_worker,
data, complete, opaque);
}
static const TypeInfo pr_manager_info = {
.parent = TYPE_OBJECT,
.name = TYPE_PR_MANAGER,
.class_size = sizeof(PRManagerClass),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
};
PRManager *pr_manager_lookup(const char *id, Error **errp)
{
Object *obj;
PRManager *pr_mgr;
obj = object_resolve_path_component(object_get_objects_root(), id);
if (!obj) {
error_setg(errp, "No persistent reservation manager with id '%s'", id);
return NULL;
}
pr_mgr = (PRManager *)
object_dynamic_cast(obj,
TYPE_PR_MANAGER);
if (!pr_mgr) {
error_setg(errp,
"Object with id '%s' is not a persistent reservation manager",
id);
return NULL;
}
return pr_mgr;
}
static void
pr_manager_register_types(void)
{
type_register_static(&pr_manager_info);
}
type_init(pr_manager_register_types);
此差异已折叠。
# scsi/pr-manager.c
pr_manager_execute(int fd, int cmd, int sa, void *opaque) "fd=%d cmd=0x%02x service action=0x%02x opaque=%p"
pr_manager_run(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x"
......@@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
.key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
};
/* Command aborted, LUN Communication Failure */
const struct SCSISense sense_code_LUN_COMM_FAILURE = {
.key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
};
/* Unit attention, Capacity data has changed */
const struct SCSISense sense_code_CAPACITY_CHANGED = {
.key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
......@@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET = {
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
};
/* Unit attention, SCSI bus reset */
const struct SCSISense sense_code_SCSI_BUS_RESET = {
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02
};
/* Unit attention, No medium */
const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
.key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
......
......@@ -691,6 +691,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
CPUARMState *env = &cpu->env;
int pagebits;
Error *local_err = NULL;
#ifndef CONFIG_USER_ONLY
AddressSpace *as;
#endif
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
......@@ -881,24 +884,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
#ifndef CONFIG_USER_ONLY
if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) {
AddressSpace *as;
as = g_new0(AddressSpace, 1);
cs->num_ases = 2;
if (!cpu->secure_memory) {
cpu->secure_memory = cs->memory;
}
as = address_space_init_shareable(cpu->secure_memory,
"cpu-secure-memory");
address_space_init(as, cpu->secure_memory, "cpu-secure-memory");
cpu_address_space_init(cs, as, ARMASIdx_S);
} else {
cs->num_ases = 1;
}
cpu_address_space_init(cs,
address_space_init_shareable(cs->memory,
"cpu-memory"),
ARMASIdx_NS);
as = g_new0(AddressSpace, 1);
address_space_init(as, cs->memory, "cpu-memory");
cpu_address_space_init(cs, as, ARMASIdx_NS);
#endif
qemu_init_vcpu(cs);
......
......@@ -3738,10 +3738,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
#ifndef CONFIG_USER_ONLY
if (tcg_enabled()) {
AddressSpace *as_normal = address_space_init_shareable(cs->memory,
"cpu-memory");
AddressSpace *as_normal = g_new0(AddressSpace, 1);
AddressSpace *as_smm = g_new(AddressSpace, 1);
address_space_init(as_normal, cs->memory, "cpu-memory");
cpu->cpu_as_mem = g_new(MemoryRegion, 1);
cpu->cpu_as_root = g_new(MemoryRegion, 1);
......
......@@ -64,6 +64,9 @@ memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned siz
memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
flatview_new(FlatView *view, MemoryRegion *root) "%p (root %p)"
flatview_destroy(FlatView *view, MemoryRegion *root) "%p (root %p)"
flatview_destroy_rcu(FlatView *view, MemoryRegion *root) "%p (root %p)"
### Guest events, keep at bottom
......
......@@ -2889,7 +2889,8 @@ static int machine_set_property(void *opaque,
*/
static bool object_create_initial(const char *type)
{
if (g_str_equal(type, "rng-egd")) {
if (g_str_equal(type, "rng-egd") ||
g_str_has_prefix(type, "pr-manager-")) {
return false;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册