1
The following changes since commit 77f3804ab7ed94b471a14acb260e5aeacf26193f:
1
The following changes since commit 91f5f7a5df1fda8c34677a7c49ee8a4bb5b56a36:
2
2
3
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2021-02-02 16:47:51 +0000)
3
Merge remote-tracking branch 'remotes/lvivier-gitlab/tags/linux-user-for-7.0-pull-request' into staging (2022-01-12 11:51:47 +0000)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 026362226f1ff6a1168524a326bbd6347ad40e85:
9
for you to fetch changes up to db608fb78444c58896db69495729e4458eeaace1:
10
10
11
docs: fix Parallels Image "dirty bitmap" section (2021-02-03 16:48:21 +0000)
11
virtio: unify dataplane and non-dataplane ->handle_output() (2022-01-12 17:09:39 +0000)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Pull request
15
15
16
The pull request includes Multi-Process QEMU, GitLab repo URL updates, and even
17
a block layer patch to fix the Parallels Image format specification!
18
19
----------------------------------------------------------------
16
----------------------------------------------------------------
20
17
21
Denis V. Lunev (1):
18
Stefan Hajnoczi (6):
22
docs: fix Parallels Image "dirty bitmap" section
19
aio-posix: split poll check from ready handler
20
virtio: get rid of VirtIOHandleAIOOutput
21
virtio-blk: drop unused virtio_blk_handle_vq() return value
22
virtio-scsi: prepare virtio_scsi_handle_cmd for dataplane
23
virtio: use ->handle_output() instead of ->handle_aio_output()
24
virtio: unify dataplane and non-dataplane ->handle_output()
23
25
24
Elena Ufimtseva (8):
26
include/block/aio.h | 4 +-
25
multi-process: add configure and usage information
27
include/hw/virtio/virtio-blk.h | 2 +-
26
io: add qio_channel_writev_full_all helper
28
include/hw/virtio/virtio.h | 5 +-
27
io: add qio_channel_readv_full_all_eof & qio_channel_readv_full_all
29
util/aio-posix.h | 1 +
28
helpers
30
block/curl.c | 11 ++--
29
multi-process: define MPQemuMsg format and transmission functions
31
block/export/fuse.c | 4 +-
30
multi-process: introduce proxy object
32
block/io_uring.c | 19 ++++---
31
multi-process: add proxy communication functions
33
block/iscsi.c | 4 +-
32
multi-process: Forward PCI config space acceses to the remote process
34
block/linux-aio.c | 16 +++---
33
multi-process: perform device reset in the remote process
35
block/nfs.c | 6 +--
34
36
block/nvme.c | 51 ++++++++++++-------
35
Jagannathan Raman (11):
37
block/ssh.c | 4 +-
36
memory: alloc RAM from file at offset
38
block/win32-aio.c | 4 +-
37
multi-process: Add config option for multi-process QEMU
39
hw/block/dataplane/virtio-blk.c | 16 +-----
38
multi-process: setup PCI host bridge for remote device
40
hw/block/virtio-blk.c | 14 ++----
39
multi-process: setup a machine object for remote device process
41
hw/scsi/virtio-scsi-dataplane.c | 60 +++-------------------
40
multi-process: Initialize message handler in remote device
42
hw/scsi/virtio-scsi.c | 2 +-
41
multi-process: Associate fd of a PCIDevice with its object
43
hw/virtio/virtio.c | 73 +++++++++------------------
42
multi-process: setup memory manager for remote device
44
hw/xen/xen-bus.c | 6 +--
43
multi-process: PCI BAR read/write handling for proxy & remote
45
io/channel-command.c | 6 ++-
44
endpoints
46
io/channel-file.c | 3 +-
45
multi-process: Synchronize remote memory
47
io/channel-socket.c | 3 +-
46
multi-process: create IOHUB object to handle irq
48
migration/rdma.c | 8 +--
47
multi-process: Retrieve PCI info from remote process
49
tests/unit/test-aio.c | 4 +-
48
50
tests/unit/test-fdmon-epoll.c | 4 +-
49
John G Johnson (1):
51
util/aio-posix.c | 89 +++++++++++++++++++++++++--------
50
multi-process: add the concept description to
52
util/aio-win32.c | 4 +-
51
docs/devel/qemu-multiprocess
53
util/async.c | 10 +++-
52
54
util/main-loop.c | 4 +-
53
Stefan Hajnoczi (6):
55
util/qemu-coroutine-io.c | 5 +-
54
.github: point Repo Lockdown bot to GitLab repo
56
util/vhost-user-server.c | 11 ++--
55
gitmodules: use GitLab repos instead of qemu.org
57
31 files changed, 221 insertions(+), 232 deletions(-)
56
gitlab-ci: remove redundant GitLab repo URL command
57
docs: update README to use GitLab repo URLs
58
pc-bios: update mirror URLs to GitLab
59
get_maintainer: update repo URL to GitLab
60
61
MAINTAINERS | 24 +
62
README.rst | 4 +-
63
docs/devel/index.rst | 1 +
64
docs/devel/multi-process.rst | 966 ++++++++++++++++++++++
65
docs/system/index.rst | 1 +
66
docs/system/multi-process.rst | 64 ++
67
docs/interop/parallels.txt | 2 +-
68
configure | 10 +
69
meson.build | 5 +-
70
hw/remote/trace.h | 1 +
71
include/exec/memory.h | 2 +
72
include/exec/ram_addr.h | 2 +-
73
include/hw/pci-host/remote.h | 30 +
74
include/hw/pci/pci_ids.h | 3 +
75
include/hw/remote/iohub.h | 42 +
76
include/hw/remote/machine.h | 38 +
77
include/hw/remote/memory.h | 19 +
78
include/hw/remote/mpqemu-link.h | 99 +++
79
include/hw/remote/proxy-memory-listener.h | 28 +
80
include/hw/remote/proxy.h | 48 ++
81
include/io/channel.h | 78 ++
82
include/qemu/mmap-alloc.h | 4 +-
83
include/sysemu/iothread.h | 6 +
84
backends/hostmem-memfd.c | 2 +-
85
hw/misc/ivshmem.c | 3 +-
86
hw/pci-host/remote.c | 75 ++
87
hw/remote/iohub.c | 119 +++
88
hw/remote/machine.c | 80 ++
89
hw/remote/memory.c | 65 ++
90
hw/remote/message.c | 230 ++++++
91
hw/remote/mpqemu-link.c | 267 ++++++
92
hw/remote/proxy-memory-listener.c | 227 +++++
93
hw/remote/proxy.c | 379 +++++++++
94
hw/remote/remote-obj.c | 203 +++++
95
io/channel.c | 116 ++-
96
iothread.c | 6 +
97
softmmu/memory.c | 3 +-
98
softmmu/physmem.c | 11 +-
99
util/mmap-alloc.c | 7 +-
100
util/oslib-posix.c | 2 +-
101
.github/lockdown.yml | 8 +-
102
.gitlab-ci.yml | 1 -
103
.gitmodules | 44 +-
104
Kconfig.host | 4 +
105
hw/Kconfig | 1 +
106
hw/meson.build | 1 +
107
hw/pci-host/Kconfig | 3 +
108
hw/pci-host/meson.build | 1 +
109
hw/remote/Kconfig | 4 +
110
hw/remote/meson.build | 13 +
111
hw/remote/trace-events | 4 +
112
pc-bios/README | 4 +-
113
scripts/get_maintainer.pl | 2 +-
114
53 files changed, 3294 insertions(+), 68 deletions(-)
115
create mode 100644 docs/devel/multi-process.rst
116
create mode 100644 docs/system/multi-process.rst
117
create mode 100644 hw/remote/trace.h
118
create mode 100644 include/hw/pci-host/remote.h
119
create mode 100644 include/hw/remote/iohub.h
120
create mode 100644 include/hw/remote/machine.h
121
create mode 100644 include/hw/remote/memory.h
122
create mode 100644 include/hw/remote/mpqemu-link.h
123
create mode 100644 include/hw/remote/proxy-memory-listener.h
124
create mode 100644 include/hw/remote/proxy.h
125
create mode 100644 hw/pci-host/remote.c
126
create mode 100644 hw/remote/iohub.c
127
create mode 100644 hw/remote/machine.c
128
create mode 100644 hw/remote/memory.c
129
create mode 100644 hw/remote/message.c
130
create mode 100644 hw/remote/mpqemu-link.c
131
create mode 100644 hw/remote/proxy-memory-listener.c
132
create mode 100644 hw/remote/proxy.c
133
create mode 100644 hw/remote/remote-obj.c
134
create mode 100644 hw/remote/Kconfig
135
create mode 100644 hw/remote/meson.build
136
create mode 100644 hw/remote/trace-events
137
58
138
--
59
--
139
2.29.2
60
2.34.1
140
61
62
63
diff view generated by jsdifflib
Deleted patch
1
Use the GitLab repo URL as the main repo location in order to reduce
2
load on qemu.org.
3
1
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
6
Reviewed-by: Thomas Huth <thuth@redhat.com>
7
Message-id: 20210111115017.156802-2-stefanha@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
.github/lockdown.yml | 8 ++++----
11
1 file changed, 4 insertions(+), 4 deletions(-)
12
13
diff --git a/.github/lockdown.yml b/.github/lockdown.yml
14
index XXXXXXX..XXXXXXX 100644
15
--- a/.github/lockdown.yml
16
+++ b/.github/lockdown.yml
17
@@ -XXX,XX +XXX,XX @@ issues:
18
comment: |
19
Thank you for your interest in the QEMU project.
20
21
- This repository is a read-only mirror of the project's master
22
- repostories hosted on https://git.qemu.org/git/qemu.git.
23
+ This repository is a read-only mirror of the project's repostories hosted
24
+ at https://gitlab.com/qemu-project/qemu.git.
25
The project does not process issues filed on GitHub.
26
27
The project issues are tracked on Launchpad:
28
@@ -XXX,XX +XXX,XX @@ pulls:
29
comment: |
30
Thank you for your interest in the QEMU project.
31
32
- This repository is a read-only mirror of the project's master
33
- repostories hosted on https://git.qemu.org/git/qemu.git.
34
+ This repository is a read-only mirror of the project's repostories hosted
35
+ on https://gitlab.com/qemu-project/qemu.git.
36
The project does not process merge requests filed on GitHub.
37
38
QEMU welcomes contributions of code (either fixing bugs or adding new
39
--
40
2.29.2
41
diff view generated by jsdifflib
1
From: Jagannathan Raman <jag.raman@oracle.com>
1
Adaptive polling measures the execution time of the polling check plus
2
2
handlers called when a polled event becomes ready. Handlers can take a
3
Add ProxyMemoryListener object which is used to keep the view of the RAM
3
significant amount of time, making it look like polling was running for
4
in sync between QEMU and remote process.
4
a long time when in fact the event handler was running for a long time.
5
A MemoryListener is registered for system-memory AddressSpace. The
5
6
listener sends SYNC_SYSMEM message to the remote process when memory
6
For example, on Linux the io_submit(2) syscall invoked when a virtio-blk
7
listener commits the changes to memory, the remote process receives
7
device's virtqueue becomes ready can take 10s of microseconds. This
8
the message and processes it in the handler for SYNC_SYSMEM message.
8
can exceed the default polling interval (32 microseconds) and cause
9
9
adaptive polling to stop polling.
10
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
10
11
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
11
By excluding the handler's execution time from the polling check we make
12
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
12
the adaptive polling calculation more accurate. As a result, the event
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
loop now stays in polling mode where previously it would have fallen
14
Message-id: 04fe4e6a9ca90d4f11ab6f59be7652f5b086a071.1611938319.git.jag.raman@oracle.com
14
back to file descriptor monitoring.
15
16
The following data was collected with virtio-blk num-queues=2
17
event_idx=off using an IOThread. Before:
18
19
168k IOPS, IOThread syscalls:
20
21
9837.115 ( 0.020 ms): IO iothread1/620155 io_submit(ctx_id: 140512552468480, nr: 16, iocbpp: 0x7fcb9f937db0) = 16
22
9837.158 ( 0.002 ms): IO iothread1/620155 write(fd: 103, buf: 0x556a2ef71b88, count: 8) = 8
23
9837.161 ( 0.001 ms): IO iothread1/620155 write(fd: 104, buf: 0x556a2ef71b88, count: 8) = 8
24
9837.163 ( 0.001 ms): IO iothread1/620155 ppoll(ufds: 0x7fcb90002800, nfds: 4, tsp: 0x7fcb9f1342d0, sigsetsize: 8) = 3
25
9837.164 ( 0.001 ms): IO iothread1/620155 read(fd: 107, buf: 0x7fcb9f939cc0, count: 512) = 8
26
9837.174 ( 0.001 ms): IO iothread1/620155 read(fd: 105, buf: 0x7fcb9f939cc0, count: 512) = 8
27
9837.176 ( 0.001 ms): IO iothread1/620155 read(fd: 106, buf: 0x7fcb9f939cc0, count: 512) = 8
28
9837.209 ( 0.035 ms): IO iothread1/620155 io_submit(ctx_id: 140512552468480, nr: 32, iocbpp: 0x7fca7d0cebe0) = 32
29
30
174k IOPS (+3.6%), IOThread syscalls:
31
32
9809.566 ( 0.036 ms): IO iothread1/623061 io_submit(ctx_id: 140539805028352, nr: 32, iocbpp: 0x7fd0cdd62be0) = 32
33
9809.625 ( 0.001 ms): IO iothread1/623061 write(fd: 103, buf: 0x5647cfba5f58, count: 8) = 8
34
9809.627 ( 0.002 ms): IO iothread1/623061 write(fd: 104, buf: 0x5647cfba5f58, count: 8) = 8
35
9809.663 ( 0.036 ms): IO iothread1/623061 io_submit(ctx_id: 140539805028352, nr: 32, iocbpp: 0x7fd0d0388b50) = 32
36
37
Notice that ppoll(2) and eventfd read(2) syscalls are eliminated because
38
the IOThread stays in polling mode instead of falling back to file
39
descriptor monitoring.
40
41
As usual, polling is not implemented on Windows so this patch ignores
42
the new io_poll_read() callback in aio-win32.c.
43
44
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
45
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
46
Message-id: 20211207132336.36627-2-stefanha@redhat.com
47
48
[Fixed up aio_set_event_notifier() calls in
49
tests/unit/test-fdmon-epoll.c added after this series was queued.
50
--Stefan]
51
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
52
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
53
---
17
MAINTAINERS | 2 +
54
include/block/aio.h | 4 +-
18
include/hw/remote/proxy-memory-listener.h | 28 +++
55
util/aio-posix.h | 1 +
19
include/hw/remote/proxy.h | 2 +
56
block/curl.c | 11 +++--
20
hw/remote/message.c | 4 +
57
block/export/fuse.c | 4 +-
21
hw/remote/proxy-memory-listener.c | 227 ++++++++++++++++++++++
58
block/io_uring.c | 19 ++++----
22
hw/remote/proxy.c | 6 +
59
block/iscsi.c | 4 +-
23
hw/remote/meson.build | 1 +
60
block/linux-aio.c | 16 ++++---
24
7 files changed, 270 insertions(+)
61
block/nfs.c | 6 +--
25
create mode 100644 include/hw/remote/proxy-memory-listener.h
62
block/nvme.c | 51 +++++++++++++-------
26
create mode 100644 hw/remote/proxy-memory-listener.c
63
block/ssh.c | 4 +-
27
64
block/win32-aio.c | 4 +-
28
diff --git a/MAINTAINERS b/MAINTAINERS
65
hw/virtio/virtio.c | 16 ++++---
29
index XXXXXXX..XXXXXXX 100644
66
hw/xen/xen-bus.c | 6 +--
30
--- a/MAINTAINERS
67
io/channel-command.c | 6 ++-
31
+++ b/MAINTAINERS
68
io/channel-file.c | 3 +-
32
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/memory.h
69
io/channel-socket.c | 3 +-
33
F: hw/remote/memory.c
70
migration/rdma.c | 8 ++--
34
F: hw/remote/proxy.c
71
tests/unit/test-aio.c | 4 +-
35
F: include/hw/remote/proxy.h
72
tests/unit/test-fdmon-epoll.c | 4 +-
36
+F: hw/remote/proxy-memory-listener.c
73
util/aio-posix.c | 89 ++++++++++++++++++++++++++---------
37
+F: include/hw/remote/proxy-memory-listener.h
74
util/aio-win32.c | 4 +-
38
75
util/async.c | 10 +++-
39
Build and test automation
76
util/main-loop.c | 4 +-
40
-------------------------
77
util/qemu-coroutine-io.c | 5 +-
41
diff --git a/include/hw/remote/proxy-memory-listener.h b/include/hw/remote/proxy-memory-listener.h
78
util/vhost-user-server.c | 11 +++--
42
new file mode 100644
79
25 files changed, 193 insertions(+), 104 deletions(-)
43
index XXXXXXX..XXXXXXX
80
44
--- /dev/null
81
diff --git a/include/block/aio.h b/include/block/aio.h
45
+++ b/include/hw/remote/proxy-memory-listener.h
82
index XXXXXXX..XXXXXXX 100644
46
@@ -XXX,XX +XXX,XX @@
83
--- a/include/block/aio.h
47
+/*
84
+++ b/include/block/aio.h
48
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
85
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
49
+ *
86
IOHandler *io_read,
50
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
87
IOHandler *io_write,
51
+ * See the COPYING file in the top-level directory.
88
AioPollFn *io_poll,
52
+ *
89
+ IOHandler *io_poll_ready,
53
+ */
90
void *opaque);
54
+
91
55
+#ifndef PROXY_MEMORY_LISTENER_H
92
/* Set polling begin/end callbacks for a file descriptor that has already been
56
+#define PROXY_MEMORY_LISTENER_H
93
@@ -XXX,XX +XXX,XX @@ void aio_set_event_notifier(AioContext *ctx,
57
+
94
EventNotifier *notifier,
58
+#include "exec/memory.h"
95
bool is_external,
59
+#include "io/channel.h"
96
EventNotifierHandler *io_read,
60
+
97
- AioPollFn *io_poll);
61
+typedef struct ProxyMemoryListener {
98
+ AioPollFn *io_poll,
62
+ MemoryListener listener;
99
+ EventNotifierHandler *io_poll_ready);
63
+
100
64
+ int n_mr_sections;
101
/* Set polling begin/end callbacks for an event notifier that has already been
65
+ MemoryRegionSection *mr_sections;
102
* registered with aio_set_event_notifier. Do nothing if the event notifier is
66
+
103
diff --git a/util/aio-posix.h b/util/aio-posix.h
67
+ QIOChannel *ioc;
104
index XXXXXXX..XXXXXXX 100644
68
+} ProxyMemoryListener;
105
--- a/util/aio-posix.h
69
+
106
+++ b/util/aio-posix.h
70
+void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener,
107
@@ -XXX,XX +XXX,XX @@ struct AioHandler {
71
+ QIOChannel *ioc);
108
IOHandler *io_read;
72
+void proxy_memory_listener_deconfigure(ProxyMemoryListener *proxy_listener);
109
IOHandler *io_write;
73
+
110
AioPollFn *io_poll;
74
+#endif
111
+ IOHandler *io_poll_ready;
75
diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h
112
IOHandler *io_poll_begin;
76
index XXXXXXX..XXXXXXX 100644
113
IOHandler *io_poll_end;
77
--- a/include/hw/remote/proxy.h
114
void *opaque;
78
+++ b/include/hw/remote/proxy.h
115
diff --git a/block/curl.c b/block/curl.c
79
@@ -XXX,XX +XXX,XX @@
116
index XXXXXXX..XXXXXXX 100644
80
117
--- a/block/curl.c
81
#include "hw/pci/pci.h"
118
+++ b/block/curl.c
82
#include "io/channel.h"
119
@@ -XXX,XX +XXX,XX @@ static gboolean curl_drop_socket(void *key, void *value, void *opaque)
83
+#include "hw/remote/proxy-memory-listener.h"
120
BDRVCURLState *s = socket->s;
84
121
85
#define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev"
122
aio_set_fd_handler(s->aio_context, socket->fd, false,
86
OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV)
123
- NULL, NULL, NULL, NULL);
87
@@ -XXX,XX +XXX,XX @@ struct PCIProxyDev {
124
+ NULL, NULL, NULL, NULL, NULL);
88
QemuMutex io_mutex;
125
return true;
89
QIOChannel *ioc;
126
}
90
Error *migration_blocker;
127
91
+ ProxyMemoryListener proxy_listener;
128
@@ -XXX,XX +XXX,XX @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
92
ProxyMemoryRegion region[PCI_NUM_REGIONS];
129
switch (action) {
93
};
130
case CURL_POLL_IN:
94
131
aio_set_fd_handler(s->aio_context, fd, false,
95
diff --git a/hw/remote/message.c b/hw/remote/message.c
132
- curl_multi_do, NULL, NULL, socket);
96
index XXXXXXX..XXXXXXX 100644
133
+ curl_multi_do, NULL, NULL, NULL, socket);
97
--- a/hw/remote/message.c
98
+++ b/hw/remote/message.c
99
@@ -XXX,XX +XXX,XX @@
100
#include "sysemu/runstate.h"
101
#include "hw/pci/pci.h"
102
#include "exec/memattrs.h"
103
+#include "hw/remote/memory.h"
104
105
static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
106
MPQemuMsg *msg, Error **errp);
107
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
108
case MPQEMU_CMD_BAR_READ:
109
process_bar_read(com->ioc, &msg, &local_err);
110
break;
134
break;
111
+ case MPQEMU_CMD_SYNC_SYSMEM:
135
case CURL_POLL_OUT:
112
+ remote_sysmem_reconfig(&msg, &local_err);
136
aio_set_fd_handler(s->aio_context, fd, false,
113
+ break;
137
- NULL, curl_multi_do, NULL, socket);
114
default:
138
+ NULL, curl_multi_do, NULL, NULL, socket);
115
error_setg(&local_err,
139
break;
116
"Unknown command (%d) received for device %s"
140
case CURL_POLL_INOUT:
117
diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c
141
aio_set_fd_handler(s->aio_context, fd, false,
118
new file mode 100644
142
- curl_multi_do, curl_multi_do, NULL, socket);
119
index XXXXXXX..XXXXXXX
143
+ curl_multi_do, curl_multi_do,
120
--- /dev/null
144
+ NULL, NULL, socket);
121
+++ b/hw/remote/proxy-memory-listener.c
145
break;
122
@@ -XXX,XX +XXX,XX @@
146
case CURL_POLL_REMOVE:
123
+/*
147
aio_set_fd_handler(s->aio_context, fd, false,
124
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
148
- NULL, NULL, NULL, NULL);
125
+ *
149
+ NULL, NULL, NULL, NULL, NULL);
126
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
150
break;
127
+ * See the COPYING file in the top-level directory.
151
}
128
+ *
152
129
+ */
153
diff --git a/block/export/fuse.c b/block/export/fuse.c
130
+
154
index XXXXXXX..XXXXXXX 100644
131
+#include "qemu/osdep.h"
155
--- a/block/export/fuse.c
132
+#include "qemu-common.h"
156
+++ b/block/export/fuse.c
133
+
157
@@ -XXX,XX +XXX,XX @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
134
+#include "qemu/compiler.h"
158
135
+#include "qemu/int128.h"
159
aio_set_fd_handler(exp->common.ctx,
136
+#include "qemu/range.h"
160
fuse_session_fd(exp->fuse_session), true,
137
+#include "exec/memory.h"
161
- read_from_fuse_export, NULL, NULL, exp);
138
+#include "exec/cpu-common.h"
162
+ read_from_fuse_export, NULL, NULL, NULL, exp);
139
+#include "cpu.h"
163
exp->fd_handler_set_up = true;
140
+#include "exec/ram_addr.h"
164
141
+#include "exec/address-spaces.h"
165
return 0;
142
+#include "qapi/error.h"
166
@@ -XXX,XX +XXX,XX @@ static void fuse_export_shutdown(BlockExport *blk_exp)
143
+#include "hw/remote/mpqemu-link.h"
167
if (exp->fd_handler_set_up) {
144
+#include "hw/remote/proxy-memory-listener.h"
168
aio_set_fd_handler(exp->common.ctx,
145
+
169
fuse_session_fd(exp->fuse_session), true,
146
+/*
170
- NULL, NULL, NULL, NULL);
147
+ * TODO: get_fd_from_hostaddr(), proxy_mrs_can_merge() and
171
+ NULL, NULL, NULL, NULL, NULL);
148
+ * proxy_memory_listener_commit() defined below perform tasks similar to the
172
exp->fd_handler_set_up = false;
149
+ * functions defined in vhost-user.c. These functions are good candidates
173
}
150
+ * for refactoring.
174
}
151
+ *
175
diff --git a/block/io_uring.c b/block/io_uring.c
152
+ */
176
index XXXXXXX..XXXXXXX 100644
153
+
177
--- a/block/io_uring.c
154
+static void proxy_memory_listener_reset(MemoryListener *listener)
178
+++ b/block/io_uring.c
179
@@ -XXX,XX +XXX,XX @@ static bool qemu_luring_poll_cb(void *opaque)
180
{
181
LuringState *s = opaque;
182
183
- if (io_uring_cq_ready(&s->ring)) {
184
- luring_process_completions_and_submit(s);
185
- return true;
186
- }
187
+ return io_uring_cq_ready(&s->ring);
188
+}
189
190
- return false;
191
+static void qemu_luring_poll_ready(void *opaque)
155
+{
192
+{
156
+ ProxyMemoryListener *proxy_listener = container_of(listener,
193
+ LuringState *s = opaque;
157
+ ProxyMemoryListener,
194
+
158
+ listener);
195
+ luring_process_completions_and_submit(s);
159
+ int mrs;
196
}
160
+
197
161
+ for (mrs = 0; mrs < proxy_listener->n_mr_sections; mrs++) {
198
static void ioq_init(LuringQueue *io_q)
162
+ memory_region_unref(proxy_listener->mr_sections[mrs].mr);
199
@@ -XXX,XX +XXX,XX @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
163
+ }
200
164
+
201
void luring_detach_aio_context(LuringState *s, AioContext *old_context)
165
+ g_free(proxy_listener->mr_sections);
202
{
166
+ proxy_listener->mr_sections = NULL;
203
- aio_set_fd_handler(old_context, s->ring.ring_fd, false, NULL, NULL, NULL,
167
+ proxy_listener->n_mr_sections = 0;
204
- s);
205
+ aio_set_fd_handler(old_context, s->ring.ring_fd, false,
206
+ NULL, NULL, NULL, NULL, s);
207
qemu_bh_delete(s->completion_bh);
208
s->aio_context = NULL;
209
}
210
@@ -XXX,XX +XXX,XX @@ void luring_attach_aio_context(LuringState *s, AioContext *new_context)
211
s->aio_context = new_context;
212
s->completion_bh = aio_bh_new(new_context, qemu_luring_completion_bh, s);
213
aio_set_fd_handler(s->aio_context, s->ring.ring_fd, false,
214
- qemu_luring_completion_cb, NULL, qemu_luring_poll_cb, s);
215
+ qemu_luring_completion_cb, NULL,
216
+ qemu_luring_poll_cb, qemu_luring_poll_ready, s);
217
}
218
219
LuringState *luring_init(Error **errp)
220
diff --git a/block/iscsi.c b/block/iscsi.c
221
index XXXXXXX..XXXXXXX 100644
222
--- a/block/iscsi.c
223
+++ b/block/iscsi.c
224
@@ -XXX,XX +XXX,XX @@ iscsi_set_events(IscsiLun *iscsilun)
225
false,
226
(ev & POLLIN) ? iscsi_process_read : NULL,
227
(ev & POLLOUT) ? iscsi_process_write : NULL,
228
- NULL,
229
+ NULL, NULL,
230
iscsilun);
231
iscsilun->events = ev;
232
}
233
@@ -XXX,XX +XXX,XX @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
234
IscsiLun *iscsilun = bs->opaque;
235
236
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi),
237
- false, NULL, NULL, NULL, NULL);
238
+ false, NULL, NULL, NULL, NULL, NULL);
239
iscsilun->events = 0;
240
241
if (iscsilun->nop_timer) {
242
diff --git a/block/linux-aio.c b/block/linux-aio.c
243
index XXXXXXX..XXXXXXX 100644
244
--- a/block/linux-aio.c
245
+++ b/block/linux-aio.c
246
@@ -XXX,XX +XXX,XX @@ static bool qemu_laio_poll_cb(void *opaque)
247
LinuxAioState *s = container_of(e, LinuxAioState, e);
248
struct io_event *events;
249
250
- if (!io_getevents_peek(s->ctx, &events)) {
251
- return false;
252
- }
253
+ return io_getevents_peek(s->ctx, &events);
168
+}
254
+}
169
+
255
+
170
+static int get_fd_from_hostaddr(uint64_t host, ram_addr_t *offset)
256
+static void qemu_laio_poll_ready(EventNotifier *opaque)
171
+{
257
+{
172
+ MemoryRegion *mr;
258
+ EventNotifier *e = opaque;
173
+ ram_addr_t off;
259
+ LinuxAioState *s = container_of(e, LinuxAioState, e);
174
+
260
175
+ /**
261
qemu_laio_process_completions_and_submit(s);
176
+ * Assumes that the host address is a valid address as it's
262
- return true;
177
+ * coming from the MemoryListener system. In the case host
263
}
178
+ * address is not valid, the following call would return
264
179
+ * the default subregion of "system_memory" region, and
265
static void ioq_init(LaioQueue *io_q)
180
+ * not NULL. So it's not possible to check for NULL here.
266
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
181
+ */
267
182
+ mr = memory_region_from_host((void *)(uintptr_t)host, &off);
268
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
183
+
269
{
184
+ if (offset) {
270
- aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
185
+ *offset = off;
271
+ aio_set_event_notifier(old_context, &s->e, false, NULL, NULL, NULL);
186
+ }
272
qemu_bh_delete(s->completion_bh);
187
+
273
s->aio_context = NULL;
188
+ return memory_region_get_fd(mr);
274
}
189
+}
275
@@ -XXX,XX +XXX,XX @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
190
+
276
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
191
+static bool proxy_mrs_can_merge(uint64_t host, uint64_t prev_host, size_t size)
277
aio_set_event_notifier(new_context, &s->e, false,
192
+{
278
qemu_laio_completion_cb,
193
+ if (((prev_host + size) != host)) {
279
- qemu_laio_poll_cb);
194
+ return false;
280
+ qemu_laio_poll_cb,
195
+ }
281
+ qemu_laio_poll_ready);
196
+
282
}
197
+ if (get_fd_from_hostaddr(host, NULL) !=
283
198
+ get_fd_from_hostaddr(prev_host, NULL)) {
284
LinuxAioState *laio_init(Error **errp)
199
+ return false;
285
diff --git a/block/nfs.c b/block/nfs.c
200
+ }
286
index XXXXXXX..XXXXXXX 100644
201
+
287
--- a/block/nfs.c
202
+ return true;
288
+++ b/block/nfs.c
203
+}
289
@@ -XXX,XX +XXX,XX @@ static void nfs_set_events(NFSClient *client)
204
+
290
false,
205
+static bool try_merge(ProxyMemoryListener *proxy_listener,
291
(ev & POLLIN) ? nfs_process_read : NULL,
206
+ MemoryRegionSection *section)
292
(ev & POLLOUT) ? nfs_process_write : NULL,
207
+{
293
- NULL, client);
208
+ uint64_t mrs_size, mrs_gpa, mrs_page;
294
+ NULL, NULL, client);
209
+ MemoryRegionSection *prev_sec;
295
210
+ bool merged = false;
296
}
211
+ uintptr_t mrs_host;
297
client->events = ev;
212
+ RAMBlock *mrs_rb;
298
@@ -XXX,XX +XXX,XX @@ static void nfs_detach_aio_context(BlockDriverState *bs)
213
+
299
NFSClient *client = bs->opaque;
214
+ if (!proxy_listener->n_mr_sections) {
300
215
+ return false;
301
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
216
+ }
302
- false, NULL, NULL, NULL, NULL);
217
+
303
+ false, NULL, NULL, NULL, NULL, NULL);
218
+ mrs_rb = section->mr->ram_block;
304
client->events = 0;
219
+ mrs_page = (uint64_t)qemu_ram_pagesize(mrs_rb);
305
}
220
+ mrs_size = int128_get64(section->size);
306
221
+ mrs_gpa = section->offset_within_address_space;
307
@@ -XXX,XX +XXX,XX @@ static void nfs_client_close(NFSClient *client)
222
+ mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
308
if (client->context) {
223
+ section->offset_within_region;
309
qemu_mutex_lock(&client->mutex);
224
+
310
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
225
+ if (get_fd_from_hostaddr(mrs_host, NULL) < 0) {
311
- false, NULL, NULL, NULL, NULL);
226
+ return true;
312
+ false, NULL, NULL, NULL, NULL, NULL);
227
+ }
313
qemu_mutex_unlock(&client->mutex);
228
+
314
if (client->fh) {
229
+ mrs_host = mrs_host & ~(mrs_page - 1);
315
nfs_close(client->context, client->fh);
230
+ mrs_gpa = mrs_gpa & ~(mrs_page - 1);
316
diff --git a/block/nvme.c b/block/nvme.c
231
+ mrs_size = ROUND_UP(mrs_size, mrs_page);
317
index XXXXXXX..XXXXXXX 100644
232
+
318
--- a/block/nvme.c
233
+ prev_sec = proxy_listener->mr_sections +
319
+++ b/block/nvme.c
234
+ (proxy_listener->n_mr_sections - 1);
320
@@ -XXX,XX +XXX,XX @@ out:
235
+ uint64_t prev_gpa_start = prev_sec->offset_within_address_space;
321
return ret;
236
+ uint64_t prev_size = int128_get64(prev_sec->size);
322
}
237
+ uint64_t prev_gpa_end = range_get_last(prev_gpa_start, prev_size);
323
238
+ uint64_t prev_host_start =
324
-static bool nvme_poll_queue(NVMeQueuePair *q)
239
+ (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr) +
325
+static void nvme_poll_queue(NVMeQueuePair *q)
240
+ prev_sec->offset_within_region;
326
{
241
+ uint64_t prev_host_end = range_get_last(prev_host_start, prev_size);
327
- bool progress = false;
242
+
328
-
243
+ if (mrs_gpa <= (prev_gpa_end + 1)) {
329
const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES;
244
+ g_assert(mrs_gpa > prev_gpa_start);
330
NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset];
245
+
331
246
+ if ((section->mr == prev_sec->mr) &&
332
@@ -XXX,XX +XXX,XX @@ static bool nvme_poll_queue(NVMeQueuePair *q)
247
+ proxy_mrs_can_merge(mrs_host, prev_host_start,
333
* cannot race with itself.
248
+ (mrs_gpa - prev_gpa_start))) {
334
*/
249
+ uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size);
335
if ((le16_to_cpu(cqe->status) & 0x1) == q->cq_phase) {
250
+ merged = true;
336
- return false;
251
+ prev_sec->offset_within_address_space =
337
+ return;
252
+ MIN(prev_gpa_start, mrs_gpa);
338
}
253
+ prev_sec->offset_within_region =
339
254
+ MIN(prev_host_start, mrs_host) -
340
qemu_mutex_lock(&q->lock);
255
+ (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr);
341
while (nvme_process_completion(q)) {
256
+ prev_sec->size = int128_make64(max_end - MIN(prev_host_start,
342
/* Keep polling */
257
+ mrs_host));
343
- progress = true;
344
}
345
qemu_mutex_unlock(&q->lock);
346
-
347
- return progress;
348
}
349
350
-static bool nvme_poll_queues(BDRVNVMeState *s)
351
+static void nvme_poll_queues(BDRVNVMeState *s)
352
{
353
- bool progress = false;
354
int i;
355
356
for (i = 0; i < s->queue_count; i++) {
357
- if (nvme_poll_queue(s->queues[i])) {
358
- progress = true;
359
- }
360
+ nvme_poll_queue(s->queues[i]);
361
}
362
- return progress;
363
}
364
365
static void nvme_handle_event(EventNotifier *n)
366
@@ -XXX,XX +XXX,XX @@ static bool nvme_poll_cb(void *opaque)
367
EventNotifier *e = opaque;
368
BDRVNVMeState *s = container_of(e, BDRVNVMeState,
369
irq_notifier[MSIX_SHARED_IRQ_IDX]);
370
+ int i;
371
372
- return nvme_poll_queues(s);
373
+ for (i = 0; i < s->queue_count; i++) {
374
+ NVMeQueuePair *q = s->queues[i];
375
+ const size_t cqe_offset = q->cq.head * NVME_CQ_ENTRY_BYTES;
376
+ NvmeCqe *cqe = (NvmeCqe *)&q->cq.queue[cqe_offset];
377
+
378
+ /*
379
+ * q->lock isn't needed because nvme_process_completion() only runs in
380
+ * the event loop thread and cannot race with itself.
381
+ */
382
+ if ((le16_to_cpu(cqe->status) & 0x1) != q->cq_phase) {
383
+ return true;
258
+ }
384
+ }
259
+ }
385
+ }
260
+
386
+ return false;
261
+ return merged;
262
+}
387
+}
263
+
388
+
264
+static void proxy_memory_listener_region_addnop(MemoryListener *listener,
389
+static void nvme_poll_ready(EventNotifier *e)
265
+ MemoryRegionSection *section)
266
+{
390
+{
267
+ ProxyMemoryListener *proxy_listener = container_of(listener,
391
+ BDRVNVMeState *s = container_of(e, BDRVNVMeState,
268
+ ProxyMemoryListener,
392
+ irq_notifier[MSIX_SHARED_IRQ_IDX]);
269
+ listener);
393
+
270
+
394
+ nvme_poll_queues(s);
271
+ if (!memory_region_is_ram(section->mr) ||
395
}
272
+ memory_region_is_rom(section->mr)) {
396
273
+ return;
397
static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
398
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
399
}
400
aio_set_event_notifier(bdrv_get_aio_context(bs),
401
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
402
- false, nvme_handle_event, nvme_poll_cb);
403
+ false, nvme_handle_event, nvme_poll_cb,
404
+ nvme_poll_ready);
405
406
if (!nvme_identify(bs, namespace, errp)) {
407
ret = -EIO;
408
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
409
g_free(s->queues);
410
aio_set_event_notifier(bdrv_get_aio_context(bs),
411
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
412
- false, NULL, NULL);
413
+ false, NULL, NULL, NULL);
414
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
415
qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map,
416
0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE);
417
@@ -XXX,XX +XXX,XX @@ static void nvme_detach_aio_context(BlockDriverState *bs)
418
419
aio_set_event_notifier(bdrv_get_aio_context(bs),
420
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
421
- false, NULL, NULL);
422
+ false, NULL, NULL, NULL);
423
}
424
425
static void nvme_attach_aio_context(BlockDriverState *bs,
426
@@ -XXX,XX +XXX,XX @@ static void nvme_attach_aio_context(BlockDriverState *bs,
427
428
s->aio_context = new_context;
429
aio_set_event_notifier(new_context, &s->irq_notifier[MSIX_SHARED_IRQ_IDX],
430
- false, nvme_handle_event, nvme_poll_cb);
431
+ false, nvme_handle_event, nvme_poll_cb,
432
+ nvme_poll_ready);
433
434
for (unsigned i = 0; i < s->queue_count; i++) {
435
NVMeQueuePair *q = s->queues[i];
436
diff --git a/block/ssh.c b/block/ssh.c
437
index XXXXXXX..XXXXXXX 100644
438
--- a/block/ssh.c
439
+++ b/block/ssh.c
440
@@ -XXX,XX +XXX,XX @@ static void restart_coroutine(void *opaque)
441
AioContext *ctx = bdrv_get_aio_context(bs);
442
443
trace_ssh_restart_coroutine(restart->co);
444
- aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL);
445
+ aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL, NULL);
446
447
aio_co_wake(restart->co);
448
}
449
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
450
trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
451
452
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
453
- false, rd_handler, wr_handler, NULL, &restart);
454
+ false, rd_handler, wr_handler, NULL, NULL, &restart);
455
qemu_coroutine_yield();
456
trace_ssh_co_yield_back(s->sock);
457
}
458
diff --git a/block/win32-aio.c b/block/win32-aio.c
459
index XXXXXXX..XXXXXXX 100644
460
--- a/block/win32-aio.c
461
+++ b/block/win32-aio.c
462
@@ -XXX,XX +XXX,XX @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
463
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
464
AioContext *old_context)
465
{
466
- aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL);
467
+ aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL, NULL);
468
aio->aio_ctx = NULL;
469
}
470
471
@@ -XXX,XX +XXX,XX @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
472
{
473
aio->aio_ctx = new_context;
474
aio_set_event_notifier(new_context, &aio->e, false,
475
- win32_aio_completion_cb, NULL);
476
+ win32_aio_completion_cb, NULL, NULL);
477
}
478
479
QEMUWin32AIOState *win32_aio_init(void)
480
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
481
index XXXXXXX..XXXXXXX 100644
482
--- a/hw/virtio/virtio.c
483
+++ b/hw/virtio/virtio.c
484
@@ -XXX,XX +XXX,XX @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque)
485
EventNotifier *n = opaque;
486
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
487
488
- if (!vq->vring.desc || virtio_queue_empty(vq)) {
489
- return false;
490
- }
491
+ return vq->vring.desc && !virtio_queue_empty(vq);
492
+}
493
494
- return virtio_queue_notify_aio_vq(vq);
495
+static void virtio_queue_host_notifier_aio_poll_ready(EventNotifier *n)
496
+{
497
+ VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
498
+
499
+ virtio_queue_notify_aio_vq(vq);
500
}
501
502
static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
503
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
504
vq->handle_aio_output = handle_output;
505
aio_set_event_notifier(ctx, &vq->host_notifier, true,
506
virtio_queue_host_notifier_aio_read,
507
- virtio_queue_host_notifier_aio_poll);
508
+ virtio_queue_host_notifier_aio_poll,
509
+ virtio_queue_host_notifier_aio_poll_ready);
510
aio_set_event_notifier_poll(ctx, &vq->host_notifier,
511
virtio_queue_host_notifier_aio_poll_begin,
512
virtio_queue_host_notifier_aio_poll_end);
513
} else {
514
- aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL);
515
+ aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
516
/* Test and clear notifier before after disabling event,
517
* in case poll callback didn't have time to run. */
518
virtio_queue_host_notifier_aio_read(&vq->host_notifier);
519
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
520
index XXXXXXX..XXXXXXX 100644
521
--- a/hw/xen/xen-bus.c
522
+++ b/hw/xen/xen-bus.c
523
@@ -XXX,XX +XXX,XX @@ void xen_device_set_event_channel_context(XenDevice *xendev,
524
525
if (channel->ctx)
526
aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
527
- NULL, NULL, NULL, NULL);
528
+ NULL, NULL, NULL, NULL, NULL);
529
530
channel->ctx = ctx;
531
aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
532
- xen_device_event, NULL, xen_device_poll, channel);
533
+ xen_device_event, NULL, xen_device_poll, NULL, channel);
534
}
535
536
XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
537
@@ -XXX,XX +XXX,XX @@ void xen_device_unbind_event_channel(XenDevice *xendev,
538
QLIST_REMOVE(channel, list);
539
540
aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
541
- NULL, NULL, NULL, NULL);
542
+ NULL, NULL, NULL, NULL, NULL);
543
544
if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
545
error_setg_errno(errp, errno, "xenevtchn_unbind failed");
546
diff --git a/io/channel-command.c b/io/channel-command.c
547
index XXXXXXX..XXXXXXX 100644
548
--- a/io/channel-command.c
549
+++ b/io/channel-command.c
550
@@ -XXX,XX +XXX,XX @@ static void qio_channel_command_set_aio_fd_handler(QIOChannel *ioc,
551
void *opaque)
552
{
553
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
554
- aio_set_fd_handler(ctx, cioc->readfd, false, io_read, NULL, NULL, opaque);
555
- aio_set_fd_handler(ctx, cioc->writefd, false, NULL, io_write, NULL, opaque);
556
+ aio_set_fd_handler(ctx, cioc->readfd, false,
557
+ io_read, NULL, NULL, NULL, opaque);
558
+ aio_set_fd_handler(ctx, cioc->writefd, false,
559
+ NULL, io_write, NULL, NULL, opaque);
560
}
561
562
563
diff --git a/io/channel-file.c b/io/channel-file.c
564
index XXXXXXX..XXXXXXX 100644
565
--- a/io/channel-file.c
566
+++ b/io/channel-file.c
567
@@ -XXX,XX +XXX,XX @@ static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
568
void *opaque)
569
{
570
QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
571
- aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write, NULL, opaque);
572
+ aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write,
573
+ NULL, NULL, opaque);
574
}
575
576
static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
577
diff --git a/io/channel-socket.c b/io/channel-socket.c
578
index XXXXXXX..XXXXXXX 100644
579
--- a/io/channel-socket.c
580
+++ b/io/channel-socket.c
581
@@ -XXX,XX +XXX,XX @@ static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc,
582
void *opaque)
583
{
584
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
585
- aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque);
586
+ aio_set_fd_handler(ctx, sioc->fd, false,
587
+ io_read, io_write, NULL, NULL, opaque);
588
}
589
590
static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
591
diff --git a/migration/rdma.c b/migration/rdma.c
592
index XXXXXXX..XXXXXXX 100644
593
--- a/migration/rdma.c
594
+++ b/migration/rdma.c
595
@@ -XXX,XX +XXX,XX @@ static void qio_channel_rdma_set_aio_fd_handler(QIOChannel *ioc,
596
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
597
if (io_read) {
598
aio_set_fd_handler(ctx, rioc->rdmain->recv_comp_channel->fd,
599
- false, io_read, io_write, NULL, opaque);
600
+ false, io_read, io_write, NULL, NULL, opaque);
601
aio_set_fd_handler(ctx, rioc->rdmain->send_comp_channel->fd,
602
- false, io_read, io_write, NULL, opaque);
603
+ false, io_read, io_write, NULL, NULL, opaque);
604
} else {
605
aio_set_fd_handler(ctx, rioc->rdmaout->recv_comp_channel->fd,
606
- false, io_read, io_write, NULL, opaque);
607
+ false, io_read, io_write, NULL, NULL, opaque);
608
aio_set_fd_handler(ctx, rioc->rdmaout->send_comp_channel->fd,
609
- false, io_read, io_write, NULL, opaque);
610
+ false, io_read, io_write, NULL, NULL, opaque);
611
}
612
}
613
614
diff --git a/tests/unit/test-aio.c b/tests/unit/test-aio.c
615
index XXXXXXX..XXXXXXX 100644
616
--- a/tests/unit/test-aio.c
617
+++ b/tests/unit/test-aio.c
618
@@ -XXX,XX +XXX,XX @@ static void *test_acquire_thread(void *opaque)
619
static void set_event_notifier(AioContext *ctx, EventNotifier *notifier,
620
EventNotifierHandler *handler)
621
{
622
- aio_set_event_notifier(ctx, notifier, false, handler, NULL);
623
+ aio_set_event_notifier(ctx, notifier, false, handler, NULL, NULL);
624
}
625
626
static void dummy_notifier_read(EventNotifier *n)
627
@@ -XXX,XX +XXX,XX @@ static void test_aio_external_client(void)
628
for (i = 1; i < 3; i++) {
629
EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true };
630
event_notifier_init(&data.e, false);
631
- aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL);
632
+ aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL, NULL);
633
event_notifier_set(&data.e);
634
for (j = 0; j < i; j++) {
635
aio_disable_external(ctx);
636
diff --git a/tests/unit/test-fdmon-epoll.c b/tests/unit/test-fdmon-epoll.c
637
index XXXXXXX..XXXXXXX 100644
638
--- a/tests/unit/test-fdmon-epoll.c
639
+++ b/tests/unit/test-fdmon-epoll.c
640
@@ -XXX,XX +XXX,XX @@ static void add_event_notifiers(EventNotifier *notifiers, size_t n)
641
for (size_t i = 0; i < n; i++) {
642
event_notifier_init(&notifiers[i], false);
643
aio_set_event_notifier(ctx, &notifiers[i], false,
644
- dummy_fd_handler, NULL);
645
+ dummy_fd_handler, NULL, NULL);
646
}
647
}
648
649
static void remove_event_notifiers(EventNotifier *notifiers, size_t n)
650
{
651
for (size_t i = 0; i < n; i++) {
652
- aio_set_event_notifier(ctx, &notifiers[i], false, NULL, NULL);
653
+ aio_set_event_notifier(ctx, &notifiers[i], false, NULL, NULL, NULL);
654
event_notifier_cleanup(&notifiers[i]);
655
}
656
}
657
diff --git a/util/aio-posix.c b/util/aio-posix.c
658
index XXXXXXX..XXXXXXX 100644
659
--- a/util/aio-posix.c
660
+++ b/util/aio-posix.c
661
@@ -XXX,XX +XXX,XX @@
662
#include "trace.h"
663
#include "aio-posix.h"
664
665
+/*
666
+ * G_IO_IN and G_IO_OUT are not appropriate revents values for polling, since
667
+ * the handler may not need to access the file descriptor. For example, the
668
+ * handler doesn't need to read from an EventNotifier if it polled a memory
669
+ * location and a read syscall would be slow. Define our own unique revents
670
+ * value to indicate that polling determined this AioHandler is ready.
671
+ */
672
+#define REVENTS_POLL_READY 0
673
+
674
/* Stop userspace polling on a handler if it isn't active for some time */
675
#define POLL_IDLE_INTERVAL_NS (7 * NANOSECONDS_PER_SECOND)
676
677
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
678
IOHandler *io_read,
679
IOHandler *io_write,
680
AioPollFn *io_poll,
681
+ IOHandler *io_poll_ready,
682
void *opaque)
683
{
684
AioHandler *node;
685
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
686
bool deleted = false;
687
int poll_disable_change;
688
689
+ if (io_poll && !io_poll_ready) {
690
+ io_poll = NULL; /* polling only makes sense if there is a handler */
274
+ }
691
+ }
275
+
692
+
276
+ if (try_merge(proxy_listener, section)) {
693
qemu_lockcnt_lock(&ctx->list_lock);
277
+ return;
694
695
node = find_aio_handler(ctx, fd);
696
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
697
new_node->io_read = io_read;
698
new_node->io_write = io_write;
699
new_node->io_poll = io_poll;
700
+ new_node->io_poll_ready = io_poll_ready;
701
new_node->opaque = opaque;
702
new_node->is_external = is_external;
703
704
@@ -XXX,XX +XXX,XX @@ void aio_set_event_notifier(AioContext *ctx,
705
EventNotifier *notifier,
706
bool is_external,
707
EventNotifierHandler *io_read,
708
- AioPollFn *io_poll)
709
+ AioPollFn *io_poll,
710
+ EventNotifierHandler *io_poll_ready)
711
{
712
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external,
713
- (IOHandler *)io_read, NULL, io_poll, notifier);
714
+ (IOHandler *)io_read, NULL, io_poll,
715
+ (IOHandler *)io_poll_ready, notifier);
716
}
717
718
void aio_set_event_notifier_poll(AioContext *ctx,
719
@@ -XXX,XX +XXX,XX @@ void aio_set_event_notifier_poll(AioContext *ctx,
720
(IOHandler *)io_poll_end);
721
}
722
723
-static bool poll_set_started(AioContext *ctx, bool started)
724
+static bool poll_set_started(AioContext *ctx, AioHandlerList *ready_list,
725
+ bool started)
726
{
727
AioHandler *node;
728
bool progress = false;
729
@@ -XXX,XX +XXX,XX @@ static bool poll_set_started(AioContext *ctx, bool started)
730
}
731
732
/* Poll one last time in case ->io_poll_end() raced with the event */
733
- if (!started) {
734
- progress = node->io_poll(node->opaque) || progress;
735
+ if (!started && node->io_poll(node->opaque)) {
736
+ aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY);
737
+ progress = true;
738
}
739
}
740
qemu_lockcnt_dec(&ctx->list_lock);
741
@@ -XXX,XX +XXX,XX @@ static bool poll_set_started(AioContext *ctx, bool started)
742
743
bool aio_prepare(AioContext *ctx)
744
{
745
+ AioHandlerList ready_list = QLIST_HEAD_INITIALIZER(ready_list);
746
+
747
/* Poll mode cannot be used with glib's event loop, disable it. */
748
- poll_set_started(ctx, false);
749
+ poll_set_started(ctx, &ready_list, false);
750
+ /* TODO what to do with this list? */
751
752
return false;
753
}
754
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node)
755
}
756
QLIST_INSERT_HEAD(&ctx->poll_aio_handlers, node, node_poll);
757
}
758
+ if (!QLIST_IS_INSERTED(node, node_deleted) &&
759
+ revents == 0 &&
760
+ aio_node_check(ctx, node->is_external) &&
761
+ node->io_poll_ready) {
762
+ node->io_poll_ready(node->opaque);
763
+
764
+ /*
765
+ * Return early since revents was zero. aio_notify() does not count as
766
+ * progress.
767
+ */
768
+ return node->opaque != &ctx->notifier;
278
+ }
769
+ }
279
+
770
280
+ ++proxy_listener->n_mr_sections;
771
if (!QLIST_IS_INSERTED(node, node_deleted) &&
281
+ proxy_listener->mr_sections = g_renew(MemoryRegionSection,
772
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
282
+ proxy_listener->mr_sections,
773
@@ -XXX,XX +XXX,XX @@ void aio_dispatch(AioContext *ctx)
283
+ proxy_listener->n_mr_sections);
774
}
284
+ proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1] = *section;
775
285
+ proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1].fv = NULL;
776
static bool run_poll_handlers_once(AioContext *ctx,
286
+ memory_region_ref(section->mr);
777
+ AioHandlerList *ready_list,
778
int64_t now,
779
int64_t *timeout)
780
{
781
@@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers_once(AioContext *ctx,
782
QLIST_FOREACH_SAFE(node, &ctx->poll_aio_handlers, node_poll, tmp) {
783
if (aio_node_check(ctx, node->is_external) &&
784
node->io_poll(node->opaque)) {
785
+ aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY);
786
+
787
node->poll_idle_timeout = now + POLL_IDLE_INTERVAL_NS;
788
789
/*
790
@@ -XXX,XX +XXX,XX @@ static bool fdmon_supports_polling(AioContext *ctx)
791
return ctx->fdmon_ops->need_wait != aio_poll_disabled;
792
}
793
794
-static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now)
795
+static bool remove_idle_poll_handlers(AioContext *ctx,
796
+ AioHandlerList *ready_list,
797
+ int64_t now)
798
{
799
AioHandler *node;
800
AioHandler *tmp;
801
@@ -XXX,XX +XXX,XX @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now)
802
* Nevermind about re-adding the handler in the rare case where
803
* this causes progress.
804
*/
805
- progress = node->io_poll(node->opaque) || progress;
806
+ if (node->io_poll(node->opaque)) {
807
+ aio_add_ready_handler(ready_list, node,
808
+ REVENTS_POLL_READY);
809
+ progress = true;
810
+ }
811
}
812
}
813
}
814
@@ -XXX,XX +XXX,XX @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now)
815
816
/* run_poll_handlers:
817
* @ctx: the AioContext
818
+ * @ready_list: the list to place ready handlers on
819
* @max_ns: maximum time to poll for, in nanoseconds
820
*
821
* Polls for a given time.
822
@@ -XXX,XX +XXX,XX @@ static bool remove_idle_poll_handlers(AioContext *ctx, int64_t now)
823
*
824
* Returns: true if progress was made, false otherwise
825
*/
826
-static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
827
+static bool run_poll_handlers(AioContext *ctx, AioHandlerList *ready_list,
828
+ int64_t max_ns, int64_t *timeout)
829
{
830
bool progress;
831
int64_t start_time, elapsed_time;
832
@@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
833
834
start_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
835
do {
836
- progress = run_poll_handlers_once(ctx, start_time, timeout);
837
+ progress = run_poll_handlers_once(ctx, ready_list,
838
+ start_time, timeout);
839
elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time;
840
max_ns = qemu_soonest_timeout(*timeout, max_ns);
841
assert(!(max_ns && progress));
842
} while (elapsed_time < max_ns && !ctx->fdmon_ops->need_wait(ctx));
843
844
- if (remove_idle_poll_handlers(ctx, start_time + elapsed_time)) {
845
+ if (remove_idle_poll_handlers(ctx, ready_list,
846
+ start_time + elapsed_time)) {
847
*timeout = 0;
848
progress = true;
849
}
850
@@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
851
852
/* try_poll_mode:
853
* @ctx: the AioContext
854
+ * @ready_list: list to add handlers that need to be run
855
* @timeout: timeout for blocking wait, computed by the caller and updated if
856
* polling succeeds.
857
*
858
@@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
859
*
860
* Returns: true if progress was made, false otherwise
861
*/
862
-static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
863
+static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list,
864
+ int64_t *timeout)
865
{
866
int64_t max_ns;
867
868
@@ -XXX,XX +XXX,XX @@ static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
869
870
max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns);
871
if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) {
872
- poll_set_started(ctx, true);
873
+ poll_set_started(ctx, ready_list, true);
874
875
- if (run_poll_handlers(ctx, max_ns, timeout)) {
876
+ if (run_poll_handlers(ctx, ready_list, max_ns, timeout)) {
877
return true;
878
}
879
}
880
881
- if (poll_set_started(ctx, false)) {
882
+ if (poll_set_started(ctx, ready_list, false)) {
883
*timeout = 0;
884
return true;
885
}
886
@@ -XXX,XX +XXX,XX @@ static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
887
bool aio_poll(AioContext *ctx, bool blocking)
888
{
889
AioHandlerList ready_list = QLIST_HEAD_INITIALIZER(ready_list);
890
- int ret = 0;
891
bool progress;
892
bool use_notify_me;
893
int64_t timeout;
894
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
895
}
896
897
timeout = blocking ? aio_compute_timeout(ctx) : 0;
898
- progress = try_poll_mode(ctx, &timeout);
899
+ progress = try_poll_mode(ctx, &ready_list, &timeout);
900
assert(!(timeout && progress));
901
902
/*
903
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
904
* system call---a single round of run_poll_handlers_once suffices.
905
*/
906
if (timeout || ctx->fdmon_ops->need_wait(ctx)) {
907
- ret = ctx->fdmon_ops->wait(ctx, &ready_list, timeout);
908
+ ctx->fdmon_ops->wait(ctx, &ready_list, timeout);
909
}
910
911
if (use_notify_me) {
912
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
913
}
914
915
progress |= aio_bh_poll(ctx);
916
-
917
- if (ret > 0) {
918
- progress |= aio_dispatch_ready_handlers(ctx, &ready_list);
919
- }
920
+ progress |= aio_dispatch_ready_handlers(ctx, &ready_list);
921
922
aio_free_deleted_handlers(ctx);
923
924
diff --git a/util/aio-win32.c b/util/aio-win32.c
925
index XXXXXXX..XXXXXXX 100644
926
--- a/util/aio-win32.c
927
+++ b/util/aio-win32.c
928
@@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx,
929
IOHandler *io_read,
930
IOHandler *io_write,
931
AioPollFn *io_poll,
932
+ IOHandler *io_poll_ready,
933
void *opaque)
934
{
935
/* fd is a SOCKET in our case */
936
@@ -XXX,XX +XXX,XX @@ void aio_set_event_notifier(AioContext *ctx,
937
EventNotifier *e,
938
bool is_external,
939
EventNotifierHandler *io_notify,
940
- AioPollFn *io_poll)
941
+ AioPollFn *io_poll,
942
+ EventNotifierHandler *io_poll_ready)
943
{
944
AioHandler *node;
945
946
diff --git a/util/async.c b/util/async.c
947
index XXXXXXX..XXXXXXX 100644
948
--- a/util/async.c
949
+++ b/util/async.c
950
@@ -XXX,XX +XXX,XX @@ aio_ctx_finalize(GSource *source)
951
g_free(bh);
952
}
953
954
- aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL);
955
+ aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL, NULL);
956
event_notifier_cleanup(&ctx->notifier);
957
qemu_rec_mutex_destroy(&ctx->lock);
958
qemu_lockcnt_destroy(&ctx->list_lock);
959
@@ -XXX,XX +XXX,XX @@ static bool aio_context_notifier_poll(void *opaque)
960
return qatomic_read(&ctx->notified);
961
}
962
963
+static void aio_context_notifier_poll_ready(EventNotifier *e)
964
+{
965
+ /* Do nothing, we just wanted to kick the event loop */
287
+}
966
+}
288
+
967
+
289
+static void proxy_memory_listener_commit(MemoryListener *listener)
968
static void co_schedule_bh_cb(void *opaque)
290
+{
969
{
291
+ ProxyMemoryListener *proxy_listener = container_of(listener,
970
AioContext *ctx = opaque;
292
+ ProxyMemoryListener,
971
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
293
+ listener);
972
aio_set_event_notifier(ctx, &ctx->notifier,
294
+ MPQemuMsg msg;
973
false,
295
+ MemoryRegionSection *section;
974
aio_context_notifier_cb,
296
+ ram_addr_t offset;
975
- aio_context_notifier_poll);
297
+ uintptr_t host_addr;
976
+ aio_context_notifier_poll,
298
+ int region;
977
+ aio_context_notifier_poll_ready);
299
+ Error *local_err = NULL;
978
#ifdef CONFIG_LINUX_AIO
300
+
979
ctx->linux_aio = NULL;
301
+ memset(&msg, 0, sizeof(MPQemuMsg));
980
#endif
302
+
981
diff --git a/util/main-loop.c b/util/main-loop.c
303
+ msg.cmd = MPQEMU_CMD_SYNC_SYSMEM;
982
index XXXXXXX..XXXXXXX 100644
304
+ msg.num_fds = proxy_listener->n_mr_sections;
983
--- a/util/main-loop.c
305
+ msg.size = sizeof(SyncSysmemMsg);
984
+++ b/util/main-loop.c
306
+ if (msg.num_fds > REMOTE_MAX_FDS) {
985
@@ -XXX,XX +XXX,XX @@ void qemu_set_fd_handler(int fd,
307
+ error_report("Number of fds is more than %d", REMOTE_MAX_FDS);
986
{
308
+ return;
987
iohandler_init();
309
+ }
988
aio_set_fd_handler(iohandler_ctx, fd, false,
310
+
989
- fd_read, fd_write, NULL, opaque);
311
+ for (region = 0; region < proxy_listener->n_mr_sections; region++) {
990
+ fd_read, fd_write, NULL, NULL, opaque);
312
+ section = &proxy_listener->mr_sections[region];
991
}
313
+ msg.data.sync_sysmem.gpas[region] =
992
314
+ section->offset_within_address_space;
993
void event_notifier_set_handler(EventNotifier *e,
315
+ msg.data.sync_sysmem.sizes[region] = int128_get64(section->size);
994
@@ -XXX,XX +XXX,XX @@ void event_notifier_set_handler(EventNotifier *e,
316
+ host_addr = (uintptr_t)memory_region_get_ram_ptr(section->mr) +
995
{
317
+ section->offset_within_region;
996
iohandler_init();
318
+ msg.fds[region] = get_fd_from_hostaddr(host_addr, &offset);
997
aio_set_event_notifier(iohandler_ctx, e, false,
319
+ msg.data.sync_sysmem.offsets[region] = offset;
998
- handler, NULL);
320
+ }
999
+ handler, NULL, NULL);
321
+ if (!mpqemu_msg_send(&msg, proxy_listener->ioc, &local_err)) {
1000
}
322
+ error_report_err(local_err);
1001
diff --git a/util/qemu-coroutine-io.c b/util/qemu-coroutine-io.c
323
+ }
1002
index XXXXXXX..XXXXXXX 100644
324
+}
1003
--- a/util/qemu-coroutine-io.c
325
+
1004
+++ b/util/qemu-coroutine-io.c
326
+void proxy_memory_listener_deconfigure(ProxyMemoryListener *proxy_listener)
1005
@@ -XXX,XX +XXX,XX @@ typedef struct {
327
+{
1006
static void fd_coroutine_enter(void *opaque)
328
+ memory_listener_unregister(&proxy_listener->listener);
1007
{
329
+
1008
FDYieldUntilData *data = opaque;
330
+ proxy_memory_listener_reset(&proxy_listener->listener);
1009
- aio_set_fd_handler(data->ctx, data->fd, false, NULL, NULL, NULL, NULL);
331
+}
1010
+ aio_set_fd_handler(data->ctx, data->fd, false,
332
+
1011
+ NULL, NULL, NULL, NULL, NULL);
333
+void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener,
1012
qemu_coroutine_enter(data->co);
334
+ QIOChannel *ioc)
1013
}
335
+{
1014
336
+ proxy_listener->n_mr_sections = 0;
1015
@@ -XXX,XX +XXX,XX @@ void coroutine_fn yield_until_fd_readable(int fd)
337
+ proxy_listener->mr_sections = NULL;
1016
data.co = qemu_coroutine_self();
338
+
1017
data.fd = fd;
339
+ proxy_listener->ioc = ioc;
1018
aio_set_fd_handler(
340
+
1019
- data.ctx, fd, false, fd_coroutine_enter, NULL, NULL, &data);
341
+ proxy_listener->listener.begin = proxy_memory_listener_reset;
1020
+ data.ctx, fd, false, fd_coroutine_enter, NULL, NULL, NULL, &data);
342
+ proxy_listener->listener.commit = proxy_memory_listener_commit;
1021
qemu_coroutine_yield();
343
+ proxy_listener->listener.region_add = proxy_memory_listener_region_addnop;
1022
}
344
+ proxy_listener->listener.region_nop = proxy_memory_listener_region_addnop;
1023
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
345
+ proxy_listener->listener.priority = 10;
1024
index XXXXXXX..XXXXXXX 100644
346
+
1025
--- a/util/vhost-user-server.c
347
+ memory_listener_register(&proxy_listener->listener,
1026
+++ b/util/vhost-user-server.c
348
+ &address_space_memory);
1027
@@ -XXX,XX +XXX,XX @@ set_watch(VuDev *vu_dev, int fd, int vu_evt,
349
+}
1028
vu_fd_watch->cb = cb;
350
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
1029
qemu_set_nonblock(fd);
351
index XXXXXXX..XXXXXXX 100644
1030
aio_set_fd_handler(server->ioc->ctx, fd, true, kick_handler,
352
--- a/hw/remote/proxy.c
1031
- NULL, NULL, vu_fd_watch);
353
+++ b/hw/remote/proxy.c
1032
+ NULL, NULL, NULL, vu_fd_watch);
354
@@ -XXX,XX +XXX,XX @@
1033
vu_fd_watch->vu_dev = vu_dev;
355
#include "qemu/sockets.h"
1034
vu_fd_watch->pvt = pvt;
356
#include "hw/remote/mpqemu-link.h"
1035
}
357
#include "qemu/error-report.h"
1036
@@ -XXX,XX +XXX,XX @@ static void remove_watch(VuDev *vu_dev, int fd)
358
+#include "hw/remote/proxy-memory-listener.h"
1037
if (!vu_fd_watch) {
359
+#include "qom/object.h"
1038
return;
360
1039
}
361
static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
1040
- aio_set_fd_handler(server->ioc->ctx, fd, true, NULL, NULL, NULL, NULL);
362
{
1041
+ aio_set_fd_handler(server->ioc->ctx, fd, true,
363
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
1042
+ NULL, NULL, NULL, NULL, NULL);
364
1043
365
qemu_mutex_init(&dev->io_mutex);
1044
QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
366
qio_channel_set_blocking(dev->ioc, true, NULL);
1045
g_free(vu_fd_watch);
367
+
1046
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_stop(VuServer *server)
368
+ proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc);
1047
369
}
1048
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
370
1049
aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
371
static void pci_proxy_dev_exit(PCIDevice *pdev)
1050
- NULL, NULL, NULL, vu_fd_watch);
372
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev)
1051
+ NULL, NULL, NULL, NULL, vu_fd_watch);
373
migrate_del_blocker(dev->migration_blocker);
1052
}
374
1053
375
error_free(dev->migration_blocker);
1054
qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
376
+
1055
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx)
377
+ proxy_memory_listener_deconfigure(&dev->proxy_listener);
1056
378
}
1057
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
379
1058
aio_set_fd_handler(ctx, vu_fd_watch->fd, true, kick_handler, NULL,
380
static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
1059
- NULL, vu_fd_watch);
381
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
1060
+ NULL, NULL, vu_fd_watch);
382
index XXXXXXX..XXXXXXX 100644
1061
}
383
--- a/hw/remote/meson.build
1062
384
+++ b/hw/remote/meson.build
1063
aio_co_schedule(ctx, server->co_trip);
385
@@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
1064
@@ -XXX,XX +XXX,XX @@ void vhost_user_server_detach_aio_context(VuServer *server)
386
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c'))
1065
387
1066
QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
388
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c'))
1067
aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
389
+specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c'))
1068
- NULL, NULL, NULL, vu_fd_watch);
390
1069
+ NULL, NULL, NULL, NULL, vu_fd_watch);
391
softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
1070
}
1071
1072
qio_channel_detach_aio_context(server->ioc);
392
--
1073
--
393
2.29.2
1074
2.34.1
394
1075
1076
diff view generated by jsdifflib
1
From: Jagannathan Raman <jag.raman@oracle.com>
1
The virtqueue host notifier API
2
virtio_queue_aio_set_host_notifier_handler() polls the virtqueue for new
3
buffers. AioContext previously required a bool progress return value
4
indicating whether an event was handled or not. This is no longer
5
necessary because the AioContext polling API has been split into a poll
6
check function and an event handler function. The event handler is only
7
run when we know there is work to do, so it doesn't return bool.
2
8
3
Proxy device object implements handler for PCI BAR writes and reads.
9
The VirtIOHandleAIOOutput function signature is now the same as
4
The handler uses BAR_WRITE/BAR_READ message to communicate to the
10
VirtIOHandleOutput. Get rid of the bool return value.
5
remote process with the BAR address and value to be written/read.
6
The remote process implements handler for BAR_WRITE/BAR_READ
7
message.
8
11
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
12
Further simplifications will be made for virtio-blk and virtio-scsi in
10
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
13
the next patch.
11
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
14
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: a8b76714a9688be5552c4c92d089bc9e8a4707ff.1611938319.git.jag.raman@oracle.com
16
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
17
Message-id: 20211207132336.36627-3-stefanha@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
19
---
16
include/hw/remote/mpqemu-link.h | 10 ++++
20
include/hw/virtio/virtio.h | 3 +--
17
include/hw/remote/proxy.h | 9 ++++
21
hw/block/dataplane/virtio-blk.c | 4 ++--
18
hw/remote/message.c | 83 +++++++++++++++++++++++++++++++++
22
hw/scsi/virtio-scsi-dataplane.c | 18 ++++++------------
19
hw/remote/mpqemu-link.c | 6 +++
23
hw/virtio/virtio.c | 12 ++++--------
20
hw/remote/proxy.c | 60 ++++++++++++++++++++++++
24
4 files changed, 13 insertions(+), 24 deletions(-)
21
5 files changed, 168 insertions(+)
22
25
23
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
26
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
24
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/remote/mpqemu-link.h
28
--- a/include/hw/virtio/virtio.h
26
+++ b/include/hw/remote/mpqemu-link.h
29
+++ b/include/hw/virtio/virtio.h
27
@@ -XXX,XX +XXX,XX @@ typedef enum {
30
@@ -XXX,XX +XXX,XX @@ void virtio_error(VirtIODevice *vdev, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
28
MPQEMU_CMD_RET,
31
void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name);
29
MPQEMU_CMD_PCI_CFGWRITE,
32
30
MPQEMU_CMD_PCI_CFGREAD,
33
typedef void (*VirtIOHandleOutput)(VirtIODevice *, VirtQueue *);
31
+ MPQEMU_CMD_BAR_WRITE,
34
-typedef bool (*VirtIOHandleAIOOutput)(VirtIODevice *, VirtQueue *);
32
+ MPQEMU_CMD_BAR_READ,
35
33
MPQEMU_CMD_MAX,
36
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
34
} MPQemuCmd;
37
VirtIOHandleOutput handle_output);
35
38
@@ -XXX,XX +XXX,XX @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
36
@@ -XXX,XX +XXX,XX @@ typedef struct {
39
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
37
int len;
40
void virtio_queue_host_notifier_read(EventNotifier *n);
38
} PciConfDataMsg;
41
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
39
42
- VirtIOHandleAIOOutput handle_output);
40
+typedef struct {
43
+ VirtIOHandleOutput handle_output);
41
+ hwaddr addr;
44
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
42
+ uint64_t val;
45
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
43
+ unsigned size;
46
44
+ bool memory;
47
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
45
+} BarAccessMsg;
46
+
47
/**
48
* MPQemuMsg:
49
* @cmd: The remote command
50
@@ -XXX,XX +XXX,XX @@ typedef struct {
51
uint64_t u64;
52
PciConfDataMsg pci_conf_data;
53
SyncSysmemMsg sync_sysmem;
54
+ BarAccessMsg bar_access;
55
} data;
56
57
int fds[REMOTE_MAX_FDS];
58
diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h
59
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
60
--- a/include/hw/remote/proxy.h
49
--- a/hw/block/dataplane/virtio-blk.c
61
+++ b/include/hw/remote/proxy.h
50
+++ b/hw/block/dataplane/virtio-blk.c
62
@@ -XXX,XX +XXX,XX @@
51
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
63
#define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev"
52
g_free(s);
64
OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV)
53
}
65
54
66
+typedef struct ProxyMemoryRegion {
55
-static bool virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
67
+ PCIProxyDev *dev;
56
+static void virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
68
+ MemoryRegion mr;
57
VirtQueue *vq)
69
+ bool memory;
58
{
70
+ bool present;
59
VirtIOBlock *s = (VirtIOBlock *)vdev;
71
+ uint8_t type;
60
@@ -XXX,XX +XXX,XX @@ static bool virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
72
+} ProxyMemoryRegion;
61
assert(s->dataplane);
73
+
62
assert(s->dataplane_started);
74
struct PCIProxyDev {
63
75
PCIDevice parent_dev;
64
- return virtio_blk_handle_vq(s, vq);
76
char *fd;
65
+ virtio_blk_handle_vq(s, vq);
77
@@ -XXX,XX +XXX,XX @@ struct PCIProxyDev {
66
}
78
QemuMutex io_mutex;
67
79
QIOChannel *ioc;
68
/* Context: QEMU global mutex held */
80
Error *migration_blocker;
69
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
81
+ ProxyMemoryRegion region[PCI_NUM_REGIONS];
82
};
83
84
#endif /* PROXY_H */
85
diff --git a/hw/remote/message.c b/hw/remote/message.c
86
index XXXXXXX..XXXXXXX 100644
70
index XXXXXXX..XXXXXXX 100644
87
--- a/hw/remote/message.c
71
--- a/hw/scsi/virtio-scsi-dataplane.c
88
+++ b/hw/remote/message.c
72
+++ b/hw/scsi/virtio-scsi-dataplane.c
89
@@ -XXX,XX +XXX,XX @@
73
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
90
#include "qapi/error.h"
91
#include "sysemu/runstate.h"
92
#include "hw/pci/pci.h"
93
+#include "exec/memattrs.h"
94
95
static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
96
MPQemuMsg *msg, Error **errp);
97
static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
98
MPQemuMsg *msg, Error **errp);
99
+static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
100
+static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
101
102
void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
103
{
104
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
105
case MPQEMU_CMD_PCI_CFGREAD:
106
process_config_read(com->ioc, pci_dev, &msg, &local_err);
107
break;
108
+ case MPQEMU_CMD_BAR_WRITE:
109
+ process_bar_write(com->ioc, &msg, &local_err);
110
+ break;
111
+ case MPQEMU_CMD_BAR_READ:
112
+ process_bar_read(com->ioc, &msg, &local_err);
113
+ break;
114
default:
115
error_setg(&local_err,
116
"Unknown command (%d) received for device %s"
117
@@ -XXX,XX +XXX,XX @@ static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
118
getpid());
119
}
74
}
120
}
75
}
121
+
76
122
+static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
77
-static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
123
+{
78
+static void virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
124
+ ERRP_GUARD();
79
VirtQueue *vq)
125
+ BarAccessMsg *bar_access = &msg->data.bar_access;
80
{
126
+ AddressSpace *as =
81
- bool progress = false;
127
+ bar_access->memory ? &address_space_memory : &address_space_io;
82
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
128
+ MPQemuMsg ret = { 0 };
83
129
+ MemTxResult res;
84
virtio_scsi_acquire(s);
130
+ uint64_t val;
85
if (!s->dataplane_fenced) {
131
+
86
assert(s->ctx && s->dataplane_started);
132
+ if (!is_power_of_2(bar_access->size) ||
87
- progress = virtio_scsi_handle_cmd_vq(s, vq);
133
+ (bar_access->size > sizeof(uint64_t))) {
88
+ virtio_scsi_handle_cmd_vq(s, vq);
134
+ ret.data.u64 = UINT64_MAX;
89
}
135
+ goto fail;
90
virtio_scsi_release(s);
136
+ }
91
- return progress;
137
+
92
}
138
+ val = cpu_to_le64(bar_access->val);
93
139
+
94
-static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
140
+ res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
95
+static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
141
+ (void *)&val, bar_access->size, true);
96
VirtQueue *vq)
142
+
97
{
143
+ if (res != MEMTX_OK) {
98
- bool progress = false;
144
+ error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".",
99
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
145
+ bar_access->addr, getpid());
100
146
+ ret.data.u64 = -1;
101
virtio_scsi_acquire(s);
147
+ }
102
if (!s->dataplane_fenced) {
148
+
103
assert(s->ctx && s->dataplane_started);
149
+fail:
104
- progress = virtio_scsi_handle_ctrl_vq(s, vq);
150
+ ret.cmd = MPQEMU_CMD_RET;
105
+ virtio_scsi_handle_ctrl_vq(s, vq);
151
+ ret.size = sizeof(ret.data.u64);
106
}
152
+
107
virtio_scsi_release(s);
153
+ if (!mpqemu_msg_send(&ret, ioc, NULL)) {
108
- return progress;
154
+ error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
109
}
155
+ getpid());
110
156
+ }
111
-static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
157
+}
112
+static void virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
158
+
113
VirtQueue *vq)
159
+static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
114
{
160
+{
115
- bool progress = false;
161
+ ERRP_GUARD();
116
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
162
+ BarAccessMsg *bar_access = &msg->data.bar_access;
117
163
+ MPQemuMsg ret = { 0 };
118
virtio_scsi_acquire(s);
164
+ AddressSpace *as;
119
if (!s->dataplane_fenced) {
165
+ MemTxResult res;
120
assert(s->ctx && s->dataplane_started);
166
+ uint64_t val = 0;
121
- progress = virtio_scsi_handle_event_vq(s, vq);
167
+
122
+ virtio_scsi_handle_event_vq(s, vq);
168
+ as = bar_access->memory ? &address_space_memory : &address_space_io;
123
}
169
+
124
virtio_scsi_release(s);
170
+ if (!is_power_of_2(bar_access->size) ||
125
- return progress;
171
+ (bar_access->size > sizeof(uint64_t))) {
126
}
172
+ val = UINT64_MAX;
127
173
+ goto fail;
128
static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
174
+ }
129
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
175
+
176
+ res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
177
+ (void *)&val, bar_access->size, false);
178
+
179
+ if (res != MEMTX_OK) {
180
+ error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".",
181
+ bar_access->addr, getpid());
182
+ val = UINT64_MAX;
183
+ }
184
+
185
+fail:
186
+ ret.cmd = MPQEMU_CMD_RET;
187
+ ret.data.u64 = le64_to_cpu(val);
188
+ ret.size = sizeof(ret.data.u64);
189
+
190
+ if (!mpqemu_msg_send(&ret, ioc, NULL)) {
191
+ error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
192
+ getpid());
193
+ }
194
+}
195
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
196
index XXXXXXX..XXXXXXX 100644
130
index XXXXXXX..XXXXXXX 100644
197
--- a/hw/remote/mpqemu-link.c
131
--- a/hw/virtio/virtio.c
198
+++ b/hw/remote/mpqemu-link.c
132
+++ b/hw/virtio/virtio.c
199
@@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg)
133
@@ -XXX,XX +XXX,XX @@ struct VirtQueue
200
return false;
134
135
uint16_t vector;
136
VirtIOHandleOutput handle_output;
137
- VirtIOHandleAIOOutput handle_aio_output;
138
+ VirtIOHandleOutput handle_aio_output;
139
VirtIODevice *vdev;
140
EventNotifier guest_notifier;
141
EventNotifier host_notifier;
142
@@ -XXX,XX +XXX,XX @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
143
}
144
}
145
146
-static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
147
+static void virtio_queue_notify_aio_vq(VirtQueue *vq)
148
{
149
- bool ret = false;
150
-
151
if (vq->vring.desc && vq->handle_aio_output) {
152
VirtIODevice *vdev = vq->vdev;
153
154
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
155
- ret = vq->handle_aio_output(vdev, vq);
156
+ vq->handle_aio_output(vdev, vq);
157
158
if (unlikely(vdev->start_on_kick)) {
159
virtio_set_started(vdev, true);
201
}
160
}
202
break;
203
+ case MPQEMU_CMD_BAR_WRITE:
204
+ case MPQEMU_CMD_BAR_READ:
205
+ if ((msg->size != sizeof(BarAccessMsg)) || (msg->num_fds != 0)) {
206
+ return false;
207
+ }
208
+ break;
209
default:
210
break;
211
}
161
}
212
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
162
-
213
index XXXXXXX..XXXXXXX 100644
163
- return ret;
214
--- a/hw/remote/proxy.c
215
+++ b/hw/remote/proxy.c
216
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_register_types(void)
217
}
164
}
218
165
219
type_init(pci_proxy_dev_register_types)
166
static void virtio_queue_notify_vq(VirtQueue *vq)
220
+
167
@@ -XXX,XX +XXX,XX @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
221
+static void send_bar_access_msg(PCIProxyDev *pdev, MemoryRegion *mr,
168
}
222
+ bool write, hwaddr addr, uint64_t *val,
169
223
+ unsigned size, bool memory)
170
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
224
+{
171
- VirtIOHandleAIOOutput handle_output)
225
+ MPQemuMsg msg = { 0 };
172
+ VirtIOHandleOutput handle_output)
226
+ long ret = -EINVAL;
173
{
227
+ Error *local_err = NULL;
174
if (handle_output) {
228
+
175
vq->handle_aio_output = handle_output;
229
+ msg.size = sizeof(BarAccessMsg);
230
+ msg.data.bar_access.addr = mr->addr + addr;
231
+ msg.data.bar_access.size = size;
232
+ msg.data.bar_access.memory = memory;
233
+
234
+ if (write) {
235
+ msg.cmd = MPQEMU_CMD_BAR_WRITE;
236
+ msg.data.bar_access.val = *val;
237
+ } else {
238
+ msg.cmd = MPQEMU_CMD_BAR_READ;
239
+ }
240
+
241
+ ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
242
+ if (local_err) {
243
+ error_report_err(local_err);
244
+ }
245
+
246
+ if (!write) {
247
+ *val = ret;
248
+ }
249
+}
250
+
251
+static void proxy_bar_write(void *opaque, hwaddr addr, uint64_t val,
252
+ unsigned size)
253
+{
254
+ ProxyMemoryRegion *pmr = opaque;
255
+
256
+ send_bar_access_msg(pmr->dev, &pmr->mr, true, addr, &val, size,
257
+ pmr->memory);
258
+}
259
+
260
+static uint64_t proxy_bar_read(void *opaque, hwaddr addr, unsigned size)
261
+{
262
+ ProxyMemoryRegion *pmr = opaque;
263
+ uint64_t val;
264
+
265
+ send_bar_access_msg(pmr->dev, &pmr->mr, false, addr, &val, size,
266
+ pmr->memory);
267
+
268
+ return val;
269
+}
270
+
271
+const MemoryRegionOps proxy_mr_ops = {
272
+ .read = proxy_bar_read,
273
+ .write = proxy_bar_write,
274
+ .endianness = DEVICE_NATIVE_ENDIAN,
275
+ .impl = {
276
+ .min_access_size = 1,
277
+ .max_access_size = 8,
278
+ },
279
+};
280
--
176
--
281
2.29.2
177
2.34.1
282
178
179
diff view generated by jsdifflib
1
From: Jagannathan Raman <jag.raman@oracle.com>
1
The return value of virtio_blk_handle_vq() is no longer used. Get rid of
2
it. This is a step towards unifying the dataplane and non-dataplane
3
virtqueue handler functions.
2
4
3
IOHUB object is added to manage PCI IRQs. It uses KVM_IRQFD
5
Prepare virtio_blk_handle_output() to be used by both dataplane and
4
ioctl to create irqfd to injecting PCI interrupts to the guest.
6
non-dataplane by making the condition for starting ioeventfd more
5
IOHUB object forwards the irqfd to the remote process. Remote process
7
specific. This way it won't trigger when dataplane has already been
6
uses this fd to directly send interrupts to the guest, bypassing QEMU.
8
started.
7
9
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
11
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
10
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
12
Message-id: 20211207132336.36627-4-stefanha@redhat.com
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: 51d5c3d54e28a68b002e3875c59599c9f5a424a1.1611938319.git.jag.raman@oracle.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
14
---
15
MAINTAINERS | 2 +
15
include/hw/virtio/virtio-blk.h | 2 +-
16
include/hw/pci/pci_ids.h | 3 +
16
hw/block/virtio-blk.c | 14 +++-----------
17
include/hw/remote/iohub.h | 42 +++++++++++
17
2 files changed, 4 insertions(+), 12 deletions(-)
18
include/hw/remote/machine.h | 2 +
19
include/hw/remote/mpqemu-link.h | 1 +
20
include/hw/remote/proxy.h | 4 ++
21
hw/remote/iohub.c | 119 ++++++++++++++++++++++++++++++++
22
hw/remote/machine.c | 10 +++
23
hw/remote/message.c | 4 ++
24
hw/remote/mpqemu-link.c | 5 ++
25
hw/remote/proxy.c | 56 +++++++++++++++
26
hw/remote/meson.build | 1 +
27
12 files changed, 249 insertions(+)
28
create mode 100644 include/hw/remote/iohub.h
29
create mode 100644 hw/remote/iohub.c
30
18
31
diff --git a/MAINTAINERS b/MAINTAINERS
19
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
32
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
33
--- a/MAINTAINERS
21
--- a/include/hw/virtio/virtio-blk.h
34
+++ b/MAINTAINERS
22
+++ b/include/hw/virtio/virtio-blk.h
35
@@ -XXX,XX +XXX,XX @@ F: hw/remote/proxy.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct MultiReqBuffer {
36
F: include/hw/remote/proxy.h
24
bool is_write;
37
F: hw/remote/proxy-memory-listener.c
25
} MultiReqBuffer;
38
F: include/hw/remote/proxy-memory-listener.h
26
39
+F: hw/remote/iohub.c
27
-bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
40
+F: include/hw/remote/iohub.h
28
+void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq);
41
29
void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh);
42
Build and test automation
30
43
-------------------------
31
#endif
44
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
32
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
45
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
46
--- a/include/hw/pci/pci_ids.h
34
--- a/hw/block/virtio-blk.c
47
+++ b/include/hw/pci/pci_ids.h
35
+++ b/hw/block/virtio-blk.c
48
@@ -XXX,XX +XXX,XX @@
36
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
49
#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
37
return 0;
50
#define PCI_DEVICE_ID_SUN_SABRE 0xa000
38
}
51
39
52
+#define PCI_VENDOR_ID_ORACLE 0x108e
40
-bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
53
+#define PCI_DEVICE_ID_REMOTE_IOHUB 0xb000
41
+void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
54
+
55
#define PCI_VENDOR_ID_CMD 0x1095
56
#define PCI_DEVICE_ID_CMD_646 0x0646
57
58
diff --git a/include/hw/remote/iohub.h b/include/hw/remote/iohub.h
59
new file mode 100644
60
index XXXXXXX..XXXXXXX
61
--- /dev/null
62
+++ b/include/hw/remote/iohub.h
63
@@ -XXX,XX +XXX,XX @@
64
+/*
65
+ * IO Hub for remote device
66
+ *
67
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
68
+ *
69
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
70
+ * See the COPYING file in the top-level directory.
71
+ *
72
+ */
73
+
74
+#ifndef REMOTE_IOHUB_H
75
+#define REMOTE_IOHUB_H
76
+
77
+#include "hw/pci/pci.h"
78
+#include "qemu/event_notifier.h"
79
+#include "qemu/thread-posix.h"
80
+#include "hw/remote/mpqemu-link.h"
81
+
82
+#define REMOTE_IOHUB_NB_PIRQS PCI_DEVFN_MAX
83
+
84
+typedef struct ResampleToken {
85
+ void *iohub;
86
+ int pirq;
87
+} ResampleToken;
88
+
89
+typedef struct RemoteIOHubState {
90
+ PCIDevice d;
91
+ EventNotifier irqfds[REMOTE_IOHUB_NB_PIRQS];
92
+ EventNotifier resamplefds[REMOTE_IOHUB_NB_PIRQS];
93
+ unsigned int irq_level[REMOTE_IOHUB_NB_PIRQS];
94
+ ResampleToken token[REMOTE_IOHUB_NB_PIRQS];
95
+ QemuMutex irq_level_lock[REMOTE_IOHUB_NB_PIRQS];
96
+} RemoteIOHubState;
97
+
98
+int remote_iohub_map_irq(PCIDevice *pci_dev, int intx);
99
+void remote_iohub_set_irq(void *opaque, int pirq, int level);
100
+void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg);
101
+
102
+void remote_iohub_init(RemoteIOHubState *iohub);
103
+void remote_iohub_finalize(RemoteIOHubState *iohub);
104
+
105
+#endif
106
diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h
107
index XXXXXXX..XXXXXXX 100644
108
--- a/include/hw/remote/machine.h
109
+++ b/include/hw/remote/machine.h
110
@@ -XXX,XX +XXX,XX @@
111
#include "hw/boards.h"
112
#include "hw/pci-host/remote.h"
113
#include "io/channel.h"
114
+#include "hw/remote/iohub.h"
115
116
struct RemoteMachineState {
117
MachineState parent_obj;
118
119
RemotePCIHost *host;
120
+ RemoteIOHubState iohub;
121
};
122
123
/* Used to pass to co-routine device and ioc. */
124
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
125
index XXXXXXX..XXXXXXX 100644
126
--- a/include/hw/remote/mpqemu-link.h
127
+++ b/include/hw/remote/mpqemu-link.h
128
@@ -XXX,XX +XXX,XX @@ typedef enum {
129
MPQEMU_CMD_PCI_CFGREAD,
130
MPQEMU_CMD_BAR_WRITE,
131
MPQEMU_CMD_BAR_READ,
132
+ MPQEMU_CMD_SET_IRQFD,
133
MPQEMU_CMD_MAX,
134
} MPQemuCmd;
135
136
diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h
137
index XXXXXXX..XXXXXXX 100644
138
--- a/include/hw/remote/proxy.h
139
+++ b/include/hw/remote/proxy.h
140
@@ -XXX,XX +XXX,XX @@
141
#include "hw/pci/pci.h"
142
#include "io/channel.h"
143
#include "hw/remote/proxy-memory-listener.h"
144
+#include "qemu/event_notifier.h"
145
146
#define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev"
147
OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV)
148
@@ -XXX,XX +XXX,XX @@ struct PCIProxyDev {
149
QIOChannel *ioc;
150
Error *migration_blocker;
151
ProxyMemoryListener proxy_listener;
152
+ int virq;
153
+ EventNotifier intr;
154
+ EventNotifier resample;
155
ProxyMemoryRegion region[PCI_NUM_REGIONS];
156
};
157
158
diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c
159
new file mode 100644
160
index XXXXXXX..XXXXXXX
161
--- /dev/null
162
+++ b/hw/remote/iohub.c
163
@@ -XXX,XX +XXX,XX @@
164
+/*
165
+ * Remote IO Hub
166
+ *
167
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
168
+ *
169
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
170
+ * See the COPYING file in the top-level directory.
171
+ *
172
+ */
173
+
174
+#include "qemu/osdep.h"
175
+#include "qemu-common.h"
176
+
177
+#include "hw/pci/pci.h"
178
+#include "hw/pci/pci_ids.h"
179
+#include "hw/pci/pci_bus.h"
180
+#include "qemu/thread.h"
181
+#include "hw/boards.h"
182
+#include "hw/remote/machine.h"
183
+#include "hw/remote/iohub.h"
184
+#include "qemu/main-loop.h"
185
+
186
+void remote_iohub_init(RemoteIOHubState *iohub)
187
+{
188
+ int pirq;
189
+
190
+ memset(&iohub->irqfds, 0, sizeof(iohub->irqfds));
191
+ memset(&iohub->resamplefds, 0, sizeof(iohub->resamplefds));
192
+
193
+ for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
194
+ qemu_mutex_init(&iohub->irq_level_lock[pirq]);
195
+ iohub->irq_level[pirq] = 0;
196
+ event_notifier_init_fd(&iohub->irqfds[pirq], -1);
197
+ event_notifier_init_fd(&iohub->resamplefds[pirq], -1);
198
+ }
199
+}
200
+
201
+void remote_iohub_finalize(RemoteIOHubState *iohub)
202
+{
203
+ int pirq;
204
+
205
+ for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
206
+ qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
207
+ NULL, NULL, NULL);
208
+ event_notifier_cleanup(&iohub->irqfds[pirq]);
209
+ event_notifier_cleanup(&iohub->resamplefds[pirq]);
210
+ qemu_mutex_destroy(&iohub->irq_level_lock[pirq]);
211
+ }
212
+}
213
+
214
+int remote_iohub_map_irq(PCIDevice *pci_dev, int intx)
215
+{
216
+ return pci_dev->devfn;
217
+}
218
+
219
+void remote_iohub_set_irq(void *opaque, int pirq, int level)
220
+{
221
+ RemoteIOHubState *iohub = opaque;
222
+
223
+ assert(pirq >= 0);
224
+ assert(pirq < PCI_DEVFN_MAX);
225
+
226
+ QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
227
+
228
+ if (level) {
229
+ if (++iohub->irq_level[pirq] == 1) {
230
+ event_notifier_set(&iohub->irqfds[pirq]);
231
+ }
232
+ } else if (iohub->irq_level[pirq] > 0) {
233
+ iohub->irq_level[pirq]--;
234
+ }
235
+}
236
+
237
+static void intr_resample_handler(void *opaque)
238
+{
239
+ ResampleToken *token = opaque;
240
+ RemoteIOHubState *iohub = token->iohub;
241
+ int pirq, s;
242
+
243
+ pirq = token->pirq;
244
+
245
+ s = event_notifier_test_and_clear(&iohub->resamplefds[pirq]);
246
+
247
+ assert(s >= 0);
248
+
249
+ QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
250
+
251
+ if (iohub->irq_level[pirq]) {
252
+ event_notifier_set(&iohub->irqfds[pirq]);
253
+ }
254
+}
255
+
256
+void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg)
257
+{
258
+ RemoteMachineState *machine = REMOTE_MACHINE(current_machine);
259
+ RemoteIOHubState *iohub = &machine->iohub;
260
+ int pirq, intx;
261
+
262
+ intx = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
263
+
264
+ pirq = remote_iohub_map_irq(pci_dev, intx);
265
+
266
+ if (event_notifier_get_fd(&iohub->irqfds[pirq]) != -1) {
267
+ qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
268
+ NULL, NULL, NULL);
269
+ event_notifier_cleanup(&iohub->irqfds[pirq]);
270
+ event_notifier_cleanup(&iohub->resamplefds[pirq]);
271
+ memset(&iohub->token[pirq], 0, sizeof(ResampleToken));
272
+ }
273
+
274
+ event_notifier_init_fd(&iohub->irqfds[pirq], msg->fds[0]);
275
+ event_notifier_init_fd(&iohub->resamplefds[pirq], msg->fds[1]);
276
+
277
+ iohub->token[pirq].iohub = iohub;
278
+ iohub->token[pirq].pirq = pirq;
279
+
280
+ qemu_set_fd_handler(msg->fds[1], intr_resample_handler, NULL,
281
+ &iohub->token[pirq]);
282
+}
283
diff --git a/hw/remote/machine.c b/hw/remote/machine.c
284
index XXXXXXX..XXXXXXX 100644
285
--- a/hw/remote/machine.c
286
+++ b/hw/remote/machine.c
287
@@ -XXX,XX +XXX,XX @@
288
#include "exec/address-spaces.h"
289
#include "exec/memory.h"
290
#include "qapi/error.h"
291
+#include "hw/pci/pci_host.h"
292
+#include "hw/remote/iohub.h"
293
294
static void remote_machine_init(MachineState *machine)
295
{
42
{
296
MemoryRegion *system_memory, *system_io, *pci_memory;
43
VirtIOBlockReq *req;
297
RemoteMachineState *s = REMOTE_MACHINE(machine);
44
MultiReqBuffer mrb = {};
298
RemotePCIHost *rem_host;
45
bool suppress_notifications = virtio_queue_get_notification(vq);
299
+ PCIHostState *pci_host;
46
- bool progress = false;
300
47
301
system_memory = get_system_memory();
48
aio_context_acquire(blk_get_aio_context(s->blk));
302
system_io = get_system_io();
49
blk_io_plug(s->blk);
303
@@ -XXX,XX +XXX,XX @@ static void remote_machine_init(MachineState *machine)
50
@@ -XXX,XX +XXX,XX @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
304
memory_region_add_subregion_overlap(system_memory, 0x0, pci_memory, -1);
51
}
305
52
306
qdev_realize(DEVICE(rem_host), sysbus_get_default(), &error_fatal);
53
while ((req = virtio_blk_get_request(s, vq))) {
307
+
54
- progress = true;
308
+ pci_host = PCI_HOST_BRIDGE(rem_host);
55
if (virtio_blk_handle_request(req, &mrb)) {
309
+
56
virtqueue_detach_element(req->vq, &req->elem, 0);
310
+ remote_iohub_init(&s->iohub);
57
virtio_blk_free_request(req);
311
+
58
@@ -XXX,XX +XXX,XX @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
312
+ pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq,
59
313
+ &s->iohub, REMOTE_IOHUB_NB_PIRQS);
60
blk_io_unplug(s->blk);
61
aio_context_release(blk_get_aio_context(s->blk));
62
- return progress;
63
-}
64
-
65
-static void virtio_blk_handle_output_do(VirtIOBlock *s, VirtQueue *vq)
66
-{
67
- virtio_blk_handle_vq(s, vq);
314
}
68
}
315
69
316
static void remote_machine_class_init(ObjectClass *oc, void *data)
70
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
317
diff --git a/hw/remote/message.c b/hw/remote/message.c
71
{
318
index XXXXXXX..XXXXXXX 100644
72
VirtIOBlock *s = (VirtIOBlock *)vdev;
319
--- a/hw/remote/message.c
73
320
+++ b/hw/remote/message.c
74
- if (s->dataplane) {
321
@@ -XXX,XX +XXX,XX @@
75
+ if (s->dataplane && !s->dataplane_started) {
322
#include "hw/pci/pci.h"
76
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
323
#include "exec/memattrs.h"
77
* dataplane here instead of waiting for .set_status().
324
#include "hw/remote/memory.h"
78
*/
325
+#include "hw/remote/iohub.h"
79
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
326
80
return;
327
static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
328
MPQemuMsg *msg, Error **errp);
329
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
330
case MPQEMU_CMD_SYNC_SYSMEM:
331
remote_sysmem_reconfig(&msg, &local_err);
332
break;
333
+ case MPQEMU_CMD_SET_IRQFD:
334
+ process_set_irqfd_msg(pci_dev, &msg);
335
+ break;
336
default:
337
error_setg(&local_err,
338
"Unknown command (%d) received for device %s"
339
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/hw/remote/mpqemu-link.c
342
+++ b/hw/remote/mpqemu-link.c
343
@@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg)
344
return false;
345
}
81
}
346
break;
347
+ case MPQEMU_CMD_SET_IRQFD:
348
+ if (msg->size || (msg->num_fds != 2)) {
349
+ return false;
350
+ }
351
+ break;
352
default:
353
break;
354
}
82
}
355
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
83
- virtio_blk_handle_output_do(s, vq);
356
index XXXXXXX..XXXXXXX 100644
84
+ virtio_blk_handle_vq(s, vq);
357
--- a/hw/remote/proxy.c
358
+++ b/hw/remote/proxy.c
359
@@ -XXX,XX +XXX,XX @@
360
#include "qemu/error-report.h"
361
#include "hw/remote/proxy-memory-listener.h"
362
#include "qom/object.h"
363
+#include "qemu/event_notifier.h"
364
+#include "sysemu/kvm.h"
365
+#include "util/event_notifier-posix.c"
366
+
367
+static void proxy_intx_update(PCIDevice *pci_dev)
368
+{
369
+ PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev);
370
+ PCIINTxRoute route;
371
+ int pin = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
372
+
373
+ if (dev->virq != -1) {
374
+ kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &dev->intr, dev->virq);
375
+ dev->virq = -1;
376
+ }
377
+
378
+ route = pci_device_route_intx_to_irq(pci_dev, pin);
379
+
380
+ dev->virq = route.irq;
381
+
382
+ if (dev->virq != -1) {
383
+ kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &dev->intr,
384
+ &dev->resample, dev->virq);
385
+ }
386
+}
387
+
388
+static void setup_irqfd(PCIProxyDev *dev)
389
+{
390
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
391
+ MPQemuMsg msg;
392
+ Error *local_err = NULL;
393
+
394
+ event_notifier_init(&dev->intr, 0);
395
+ event_notifier_init(&dev->resample, 0);
396
+
397
+ memset(&msg, 0, sizeof(MPQemuMsg));
398
+ msg.cmd = MPQEMU_CMD_SET_IRQFD;
399
+ msg.num_fds = 2;
400
+ msg.fds[0] = event_notifier_get_fd(&dev->intr);
401
+ msg.fds[1] = event_notifier_get_fd(&dev->resample);
402
+ msg.size = 0;
403
+
404
+ if (!mpqemu_msg_send(&msg, dev->ioc, &local_err)) {
405
+ error_report_err(local_err);
406
+ }
407
+
408
+ dev->virq = -1;
409
+
410
+ proxy_intx_update(pci_dev);
411
+
412
+ pci_device_set_intx_routing_notifier(pci_dev, proxy_intx_update);
413
+}
414
415
static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
416
{
417
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
418
qio_channel_set_blocking(dev->ioc, true, NULL);
419
420
proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc);
421
+
422
+ setup_irqfd(dev);
423
}
85
}
424
86
425
static void pci_proxy_dev_exit(PCIDevice *pdev)
87
void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh)
426
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev)
427
error_free(dev->migration_blocker);
428
429
proxy_memory_listener_deconfigure(&dev->proxy_listener);
430
+
431
+ event_notifier_cleanup(&dev->intr);
432
+ event_notifier_cleanup(&dev->resample);
433
}
434
435
static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
436
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
437
index XXXXXXX..XXXXXXX 100644
438
--- a/hw/remote/meson.build
439
+++ b/hw/remote/meson.build
440
@@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
441
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
442
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
443
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c'))
444
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c'))
445
446
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c'))
447
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c'))
448
--
88
--
449
2.29.2
89
2.34.1
450
90
91
diff view generated by jsdifflib
1
qemu.org is running out of bandwidth and the QEMU project is moving
1
Prepare virtio_scsi_handle_cmd() to be used by both dataplane and
2
towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org
2
non-dataplane by making the condition for starting ioeventfd more
3
(they will become mirrors).
3
specific. This way it won't trigger when dataplane has already been
4
started.
4
5
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
8
Message-id: 20211207132336.36627-5-stefanha@redhat.com
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: 20210111115017.156802-7-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
10
---
12
scripts/get_maintainer.pl | 2 +-
11
hw/scsi/virtio-scsi.c | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
14
13
15
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
14
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
16
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
17
--- a/scripts/get_maintainer.pl
16
--- a/hw/scsi/virtio-scsi.c
18
+++ b/scripts/get_maintainer.pl
17
+++ b/hw/scsi/virtio-scsi.c
19
@@ -XXX,XX +XXX,XX @@ sub vcs_exists {
18
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
20
    warn("$P: No supported VCS found. Add --nogit to options?\n");
19
/* use non-QOM casts in the data path */
21
    warn("Using a git repository produces better results.\n");
20
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
22
    warn("Try latest git repository using:\n");
21
23
-    warn("git clone https://git.qemu.org/git/qemu.git\n");
22
- if (s->ctx) {
24
+    warn("git clone https://gitlab.com/qemu-project/qemu.git\n");
23
+ if (s->ctx && !s->dataplane_started) {
25
    $printed_novcs = 1;
24
virtio_device_start_ioeventfd(vdev);
26
}
25
if (!s->dataplane_fenced) {
27
return 0;
26
return;
28
--
27
--
29
2.29.2
28
2.34.1
30
29
30
diff view generated by jsdifflib
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
1
The difference between ->handle_output() and ->handle_aio_output() was
2
that ->handle_aio_output() returned a bool return value indicating
3
progress. This was needed by the old polling API but now that the bool
4
return value is gone, the two functions can be unified.
2
5
3
Perform device reset in the remote process when QEMU performs
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
device reset. This is required to reset the internal state
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
5
(like registers, etc...) of emulated devices
8
Message-id: 20211207132336.36627-6-stefanha@redhat.com
6
7
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: 7cb220a51f565dc0817bd76e2f540e89c2d2b850.1611938319.git.jag.raman@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
10
---
14
include/hw/remote/mpqemu-link.h | 1 +
11
hw/virtio/virtio.c | 33 +++------------------------------
15
hw/remote/message.c | 22 ++++++++++++++++++++++
12
1 file changed, 3 insertions(+), 30 deletions(-)
16
hw/remote/proxy.c | 19 +++++++++++++++++++
17
3 files changed, 42 insertions(+)
18
13
19
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
14
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/remote/mpqemu-link.h
16
--- a/hw/virtio/virtio.c
22
+++ b/include/hw/remote/mpqemu-link.h
17
+++ b/hw/virtio/virtio.c
23
@@ -XXX,XX +XXX,XX @@ typedef enum {
18
@@ -XXX,XX +XXX,XX @@ struct VirtQueue
24
MPQEMU_CMD_BAR_WRITE,
19
25
MPQEMU_CMD_BAR_READ,
20
uint16_t vector;
26
MPQEMU_CMD_SET_IRQFD,
21
VirtIOHandleOutput handle_output;
27
+ MPQEMU_CMD_DEVICE_RESET,
22
- VirtIOHandleOutput handle_aio_output;
28
MPQEMU_CMD_MAX,
23
VirtIODevice *vdev;
29
} MPQemuCmd;
24
EventNotifier guest_notifier;
30
25
EventNotifier host_notifier;
31
diff --git a/hw/remote/message.c b/hw/remote/message.c
26
@@ -XXX,XX +XXX,XX @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/remote/message.c
34
+++ b/hw/remote/message.c
35
@@ -XXX,XX +XXX,XX @@
36
#include "exec/memattrs.h"
37
#include "hw/remote/memory.h"
38
#include "hw/remote/iohub.h"
39
+#include "sysemu/reset.h"
40
41
static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
42
MPQemuMsg *msg, Error **errp);
43
@@ -XXX,XX +XXX,XX @@ static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
44
MPQemuMsg *msg, Error **errp);
45
static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
46
static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
47
+static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
48
+ Error **errp);
49
50
void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
51
{
52
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
53
case MPQEMU_CMD_SET_IRQFD:
54
process_set_irqfd_msg(pci_dev, &msg);
55
break;
56
+ case MPQEMU_CMD_DEVICE_RESET:
57
+ process_device_reset_msg(com->ioc, pci_dev, &local_err);
58
+ break;
59
default:
60
error_setg(&local_err,
61
"Unknown command (%d) received for device %s"
62
@@ -XXX,XX +XXX,XX @@ fail:
63
getpid());
64
}
27
}
65
}
28
}
66
+
29
67
+static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
30
-static void virtio_queue_notify_aio_vq(VirtQueue *vq)
68
+ Error **errp)
31
-{
69
+{
32
- if (vq->vring.desc && vq->handle_aio_output) {
70
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
33
- VirtIODevice *vdev = vq->vdev;
71
+ DeviceState *s = DEVICE(dev);
34
-
72
+ MPQemuMsg ret = { 0 };
35
- trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
73
+
36
- vq->handle_aio_output(vdev, vq);
74
+ if (dc->reset) {
37
-
75
+ dc->reset(s);
38
- if (unlikely(vdev->start_on_kick)) {
76
+ }
39
- virtio_set_started(vdev, true);
77
+
40
- }
78
+ ret.cmd = MPQEMU_CMD_RET;
41
- }
79
+
42
-}
80
+ mpqemu_msg_send(&ret, ioc, errp);
43
-
81
+}
44
static void virtio_queue_notify_vq(VirtQueue *vq)
82
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/hw/remote/proxy.c
85
+++ b/hw/remote/proxy.c
86
@@ -XXX,XX +XXX,XX @@
87
#include "util/event_notifier-posix.c"
88
89
static void probe_pci_info(PCIDevice *dev, Error **errp);
90
+static void proxy_device_reset(DeviceState *dev);
91
92
static void proxy_intx_update(PCIDevice *pci_dev)
93
{
45
{
94
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
46
if (vq->vring.desc && vq->handle_output) {
95
k->config_read = pci_proxy_read_config;
47
@@ -XXX,XX +XXX,XX @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
96
k->config_write = pci_proxy_write_config;
48
vdev->vq[i].vring.num_default = queue_size;
97
49
vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
98
+ dc->reset = proxy_device_reset;
50
vdev->vq[i].handle_output = handle_output;
99
+
51
- vdev->vq[i].handle_aio_output = NULL;
100
device_class_set_props(dc, proxy_properties);
52
vdev->vq[i].used_elems = g_malloc0(sizeof(VirtQueueElement) *
53
queue_size);
54
55
@@ -XXX,XX +XXX,XX @@ void virtio_delete_queue(VirtQueue *vq)
56
vq->vring.num = 0;
57
vq->vring.num_default = 0;
58
vq->handle_output = NULL;
59
- vq->handle_aio_output = NULL;
60
g_free(vq->used_elems);
61
vq->used_elems = NULL;
62
virtio_virtqueue_reset_region_cache(vq);
63
@@ -XXX,XX +XXX,XX @@ EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
64
return &vq->guest_notifier;
101
}
65
}
102
66
103
@@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp)
67
-static void virtio_queue_host_notifier_aio_read(EventNotifier *n)
104
}
68
-{
69
- VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
70
- if (event_notifier_test_and_clear(n)) {
71
- virtio_queue_notify_aio_vq(vq);
72
- }
73
-}
74
-
75
static void virtio_queue_host_notifier_aio_poll_begin(EventNotifier *n)
76
{
77
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
78
@@ -XXX,XX +XXX,XX @@ static void virtio_queue_host_notifier_aio_poll_ready(EventNotifier *n)
79
{
80
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
81
82
- virtio_queue_notify_aio_vq(vq);
83
+ virtio_queue_notify_vq(vq);
84
}
85
86
static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
87
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
88
VirtIOHandleOutput handle_output)
89
{
90
if (handle_output) {
91
- vq->handle_aio_output = handle_output;
92
aio_set_event_notifier(ctx, &vq->host_notifier, true,
93
- virtio_queue_host_notifier_aio_read,
94
+ virtio_queue_host_notifier_read,
95
virtio_queue_host_notifier_aio_poll,
96
virtio_queue_host_notifier_aio_poll_ready);
97
aio_set_event_notifier_poll(ctx, &vq->host_notifier,
98
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
99
aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
100
/* Test and clear notifier before after disabling event,
101
* in case poll callback didn't have time to run. */
102
- virtio_queue_host_notifier_aio_read(&vq->host_notifier);
103
- vq->handle_aio_output = NULL;
104
+ virtio_queue_host_notifier_read(&vq->host_notifier);
105
}
105
}
106
}
106
}
107
+
107
108
+static void proxy_device_reset(DeviceState *dev)
109
+{
110
+ PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
111
+ MPQemuMsg msg = { 0 };
112
+ Error *local_err = NULL;
113
+
114
+ msg.cmd = MPQEMU_CMD_DEVICE_RESET;
115
+ msg.size = 0;
116
+
117
+ mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
118
+ if (local_err) {
119
+ error_report_err(local_err);
120
+ }
121
+
122
+}
123
--
108
--
124
2.29.2
109
2.34.1
125
110
111
diff view generated by jsdifflib
1
qemu.org is running out of bandwidth and the QEMU project is moving
1
Now that virtio-blk and virtio-scsi are ready, get rid of
2
towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org
2
the handle_aio_output() callback. It's no longer needed.
3
(they will become mirrors).
4
3
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
5
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
6
Message-id: 20211207132336.36627-7-stefanha@redhat.com
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: 20210111115017.156802-3-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
8
---
12
.gitmodules | 44 ++++++++++++++++++++++----------------------
9
include/hw/virtio/virtio.h | 4 +--
13
1 file changed, 22 insertions(+), 22 deletions(-)
10
hw/block/dataplane/virtio-blk.c | 16 ++--------
14
11
hw/scsi/virtio-scsi-dataplane.c | 54 ++++-----------------------------
15
diff --git a/.gitmodules b/.gitmodules
12
hw/virtio/virtio.c | 32 +++++++++----------
16
index XXXXXXX..XXXXXXX 100644
13
4 files changed, 26 insertions(+), 80 deletions(-)
17
--- a/.gitmodules
14
18
+++ b/.gitmodules
15
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
19
@@ -XXX,XX +XXX,XX @@
16
index XXXXXXX..XXXXXXX 100644
20
[submodule "roms/seabios"]
17
--- a/include/hw/virtio/virtio.h
21
    path = roms/seabios
18
+++ b/include/hw/virtio/virtio.h
22
-    url = https://git.qemu.org/git/seabios.git/
19
@@ -XXX,XX +XXX,XX @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev);
23
+    url = https://gitlab.com/qemu-project/seabios.git/
20
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
24
[submodule "roms/SLOF"]
21
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
25
    path = roms/SLOF
22
void virtio_queue_host_notifier_read(EventNotifier *n);
26
-    url = https://git.qemu.org/git/SLOF.git
23
-void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
27
+    url = https://gitlab.com/qemu-project/SLOF.git
24
- VirtIOHandleOutput handle_output);
28
[submodule "roms/ipxe"]
25
+void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx);
29
    path = roms/ipxe
26
+void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx);
30
-    url = https://git.qemu.org/git/ipxe.git
27
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
31
+    url = https://gitlab.com/qemu-project/ipxe.git
28
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
32
[submodule "roms/openbios"]
29
33
    path = roms/openbios
30
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
34
-    url = https://git.qemu.org/git/openbios.git
31
index XXXXXXX..XXXXXXX 100644
35
+    url = https://gitlab.com/qemu-project/openbios.git
32
--- a/hw/block/dataplane/virtio-blk.c
36
[submodule "roms/qemu-palcode"]
33
+++ b/hw/block/dataplane/virtio-blk.c
37
    path = roms/qemu-palcode
34
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
38
-    url = https://git.qemu.org/git/qemu-palcode.git
35
g_free(s);
39
+    url = https://gitlab.com/qemu-project/qemu-palcode.git
36
}
40
[submodule "roms/sgabios"]
37
41
    path = roms/sgabios
38
-static void virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
42
-    url = https://git.qemu.org/git/sgabios.git
39
- VirtQueue *vq)
43
+    url = https://gitlab.com/qemu-project/sgabios.git
40
-{
44
[submodule "dtc"]
41
- VirtIOBlock *s = (VirtIOBlock *)vdev;
45
    path = dtc
42
-
46
-    url = https://git.qemu.org/git/dtc.git
43
- assert(s->dataplane);
47
+    url = https://gitlab.com/qemu-project/dtc.git
44
- assert(s->dataplane_started);
48
[submodule "roms/u-boot"]
45
-
49
    path = roms/u-boot
46
- virtio_blk_handle_vq(s, vq);
50
-    url = https://git.qemu.org/git/u-boot.git
47
-}
51
+    url = https://gitlab.com/qemu-project/u-boot.git
48
-
52
[submodule "roms/skiboot"]
49
/* Context: QEMU global mutex held */
53
    path = roms/skiboot
50
int virtio_blk_data_plane_start(VirtIODevice *vdev)
54
-    url = https://git.qemu.org/git/skiboot.git
51
{
55
+    url = https://gitlab.com/qemu-project/skiboot.git
52
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
56
[submodule "roms/QemuMacDrivers"]
53
for (i = 0; i < nvqs; i++) {
57
    path = roms/QemuMacDrivers
54
VirtQueue *vq = virtio_get_queue(s->vdev, i);
58
-    url = https://git.qemu.org/git/QemuMacDrivers.git
55
59
+    url = https://gitlab.com/qemu-project/QemuMacDrivers.git
56
- virtio_queue_aio_set_host_notifier_handler(vq, s->ctx,
60
[submodule "ui/keycodemapdb"]
57
- virtio_blk_data_plane_handle_output);
61
    path = ui/keycodemapdb
58
+ virtio_queue_aio_attach_host_notifier(vq, s->ctx);
62
-    url = https://git.qemu.org/git/keycodemapdb.git
59
}
63
+    url = https://gitlab.com/qemu-project/keycodemapdb.git
60
aio_context_release(s->ctx);
64
[submodule "capstone"]
61
return 0;
65
    path = capstone
62
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_data_plane_stop_bh(void *opaque)
66
-    url = https://git.qemu.org/git/capstone.git
63
for (i = 0; i < s->conf->num_queues; i++) {
67
+    url = https://gitlab.com/qemu-project/capstone.git
64
VirtQueue *vq = virtio_get_queue(s->vdev, i);
68
[submodule "roms/seabios-hppa"]
65
69
    path = roms/seabios-hppa
66
- virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL);
70
-    url = https://git.qemu.org/git/seabios-hppa.git
67
+ virtio_queue_aio_detach_host_notifier(vq, s->ctx);
71
+    url = https://gitlab.com/qemu-project/seabios-hppa.git
68
}
72
[submodule "roms/u-boot-sam460ex"]
69
}
73
    path = roms/u-boot-sam460ex
70
74
-    url = https://git.qemu.org/git/u-boot-sam460ex.git
71
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
75
+    url = https://gitlab.com/qemu-project/u-boot-sam460ex.git
72
index XXXXXXX..XXXXXXX 100644
76
[submodule "tests/fp/berkeley-testfloat-3"]
73
--- a/hw/scsi/virtio-scsi-dataplane.c
77
    path = tests/fp/berkeley-testfloat-3
74
+++ b/hw/scsi/virtio-scsi-dataplane.c
78
-    url = https://git.qemu.org/git/berkeley-testfloat-3.git
75
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
79
+    url = https://gitlab.com/qemu-project/berkeley-testfloat-3.git
76
}
80
[submodule "tests/fp/berkeley-softfloat-3"]
77
}
81
    path = tests/fp/berkeley-softfloat-3
78
82
-    url = https://git.qemu.org/git/berkeley-softfloat-3.git
79
-static void virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
83
+    url = https://gitlab.com/qemu-project/berkeley-softfloat-3.git
80
- VirtQueue *vq)
84
[submodule "roms/edk2"]
81
-{
85
    path = roms/edk2
82
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
86
-    url = https://git.qemu.org/git/edk2.git
83
-
87
+    url = https://gitlab.com/qemu-project/edk2.git
84
- virtio_scsi_acquire(s);
88
[submodule "slirp"]
85
- if (!s->dataplane_fenced) {
89
    path = slirp
86
- assert(s->ctx && s->dataplane_started);
90
-    url = https://git.qemu.org/git/libslirp.git
87
- virtio_scsi_handle_cmd_vq(s, vq);
91
+    url = https://gitlab.com/qemu-project/libslirp.git
88
- }
92
[submodule "roms/opensbi"]
89
- virtio_scsi_release(s);
93
    path = roms/opensbi
90
-}
94
-    url =     https://git.qemu.org/git/opensbi.git
91
-
95
+    url =     https://gitlab.com/qemu-project/opensbi.git
92
-static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
96
[submodule "roms/qboot"]
93
- VirtQueue *vq)
97
    path = roms/qboot
94
-{
98
-    url = https://git.qemu.org/git/qboot.git
95
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
99
+    url = https://gitlab.com/qemu-project/qboot.git
96
-
100
[submodule "meson"]
97
- virtio_scsi_acquire(s);
101
    path = meson
98
- if (!s->dataplane_fenced) {
102
-    url = https://git.qemu.org/git/meson.git
99
- assert(s->ctx && s->dataplane_started);
103
+    url = https://gitlab.com/qemu-project/meson.git
100
- virtio_scsi_handle_ctrl_vq(s, vq);
104
[submodule "roms/vbootrom"]
101
- }
105
    path = roms/vbootrom
102
- virtio_scsi_release(s);
106
-    url = https://git.qemu.org/git/vbootrom.git
103
-}
107
+    url = https://gitlab.com/qemu-project/vbootrom.git
104
-
105
-static void virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
106
- VirtQueue *vq)
107
-{
108
- VirtIOSCSI *s = VIRTIO_SCSI(vdev);
109
-
110
- virtio_scsi_acquire(s);
111
- if (!s->dataplane_fenced) {
112
- assert(s->ctx && s->dataplane_started);
113
- virtio_scsi_handle_event_vq(s, vq);
114
- }
115
- virtio_scsi_release(s);
116
-}
117
-
118
static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
119
{
120
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
121
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_dataplane_stop_bh(void *opaque)
122
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
123
int i;
124
125
- virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL);
126
- virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL);
127
+ virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx);
128
+ virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx);
129
for (i = 0; i < vs->conf.num_queues; i++) {
130
- virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL);
131
+ virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx);
132
}
133
}
134
135
@@ -XXX,XX +XXX,XX @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
136
memory_region_transaction_commit();
137
138
aio_context_acquire(s->ctx);
139
- virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx,
140
- virtio_scsi_data_plane_handle_ctrl);
141
- virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx,
142
- virtio_scsi_data_plane_handle_event);
143
+ virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
144
+ virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx);
145
146
for (i = 0; i < vs->conf.num_queues; i++) {
147
- virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx,
148
- virtio_scsi_data_plane_handle_cmd);
149
+ virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
150
}
151
152
s->dataplane_starting = false;
153
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/hw/virtio/virtio.c
156
+++ b/hw/virtio/virtio.c
157
@@ -XXX,XX +XXX,XX @@ static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n)
158
virtio_queue_set_notification(vq, 1);
159
}
160
161
-void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
162
- VirtIOHandleOutput handle_output)
163
+void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
164
{
165
- if (handle_output) {
166
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
167
- virtio_queue_host_notifier_read,
168
- virtio_queue_host_notifier_aio_poll,
169
- virtio_queue_host_notifier_aio_poll_ready);
170
- aio_set_event_notifier_poll(ctx, &vq->host_notifier,
171
- virtio_queue_host_notifier_aio_poll_begin,
172
- virtio_queue_host_notifier_aio_poll_end);
173
- } else {
174
- aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
175
- /* Test and clear notifier before after disabling event,
176
- * in case poll callback didn't have time to run. */
177
- virtio_queue_host_notifier_read(&vq->host_notifier);
178
- }
179
+ aio_set_event_notifier(ctx, &vq->host_notifier, true,
180
+ virtio_queue_host_notifier_read,
181
+ virtio_queue_host_notifier_aio_poll,
182
+ virtio_queue_host_notifier_aio_poll_ready);
183
+ aio_set_event_notifier_poll(ctx, &vq->host_notifier,
184
+ virtio_queue_host_notifier_aio_poll_begin,
185
+ virtio_queue_host_notifier_aio_poll_end);
186
+}
187
+
188
+void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
189
+{
190
+ aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
191
+ /* Test and clear notifier before after disabling event,
192
+ * in case poll callback didn't have time to run. */
193
+ virtio_queue_host_notifier_read(&vq->host_notifier);
194
}
195
196
void virtio_queue_host_notifier_read(EventNotifier *n)
108
--
197
--
109
2.29.2
198
2.34.1
110
199
200
diff view generated by jsdifflib
Deleted patch
1
It is no longer necessary to point .gitmodules at GitLab repos when
2
running in GitLab CI since they are now used all the time.
3
1
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
6
Reviewed-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20210111115017.156802-4-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
.gitlab-ci.yml | 1 -
12
1 file changed, 1 deletion(-)
13
14
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
15
index XXXXXXX..XXXXXXX 100644
16
--- a/.gitlab-ci.yml
17
+++ b/.gitlab-ci.yml
18
@@ -XXX,XX +XXX,XX @@ include:
19
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
20
before_script:
21
- JOBS=$(expr $(nproc) + 1)
22
- - sed -i s,git.qemu.org/git,gitlab.com/qemu-project, .gitmodules
23
script:
24
- mkdir build
25
- cd build
26
--
27
2.29.2
28
diff view generated by jsdifflib
Deleted patch
1
qemu.org is running out of bandwidth and the QEMU project is moving
2
towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org
3
(they will become mirrors).
4
1
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: 20210111115017.156802-5-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
README.rst | 4 ++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
14
15
diff --git a/README.rst b/README.rst
16
index XXXXXXX..XXXXXXX 100644
17
--- a/README.rst
18
+++ b/README.rst
19
@@ -XXX,XX +XXX,XX @@ The QEMU source code is maintained under the GIT version control system.
20
21
.. code-block:: shell
22
23
- git clone https://git.qemu.org/git/qemu.git
24
+ git clone https://gitlab.com/qemu-project/qemu.git
25
26
When submitting patches, one common approach is to use 'git
27
format-patch' and/or 'git send-email' to format & send the mail to the
28
@@ -XXX,XX +XXX,XX @@ The QEMU website is also maintained under source control.
29
30
.. code-block:: shell
31
32
- git clone https://git.qemu.org/git/qemu-web.git
33
+ git clone https://gitlab.com/qemu-project/qemu-web.git
34
35
* `<https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/>`_
36
37
--
38
2.29.2
39
diff view generated by jsdifflib
Deleted patch
1
qemu.org is running out of bandwidth and the QEMU project is moving
2
towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org
3
(they will become mirrors).
4
1
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: 20210111115017.156802-6-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
pc-bios/README | 4 ++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
14
15
diff --git a/pc-bios/README b/pc-bios/README
16
index XXXXXXX..XXXXXXX 100644
17
--- a/pc-bios/README
18
+++ b/pc-bios/README
19
@@ -XXX,XX +XXX,XX @@
20
legacy x86 software to communicate with an attached serial console as
21
if a video card were attached. The master sources reside in a subversion
22
repository at http://sgabios.googlecode.com/svn/trunk. A git mirror is
23
- available at https://git.qemu.org/git/sgabios.git.
24
+ available at https://gitlab.com/qemu-project/sgabios.git.
25
26
- The PXE roms come from the iPXE project. Built with BANNER_TIME 0.
27
Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping:
28
@@ -XXX,XX +XXX,XX @@
29
30
- The u-boot binary for e500 comes from the upstream denx u-boot project where
31
it was compiled using the qemu-ppce500 target.
32
- A git mirror is available at: https://git.qemu.org/git/u-boot.git
33
+ A git mirror is available at: https://gitlab.com/qemu-project/u-boot.git
34
The hash used to compile the current version is: 2072e72
35
36
- Skiboot (https://github.com/open-power/skiboot/) is an OPAL
37
--
38
2.29.2
39
diff view generated by jsdifflib
Deleted patch
1
From: John G Johnson <john.g.johnson@oracle.com>
2
1
3
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
4
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
5
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-id: 02a68adef99f5df6a380bf8fd7b90948777e411c.1611938319.git.jag.raman@oracle.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
MAINTAINERS | 7 +
11
docs/devel/index.rst | 1 +
12
docs/devel/multi-process.rst | 966 +++++++++++++++++++++++++++++++++++
13
3 files changed, 974 insertions(+)
14
create mode 100644 docs/devel/multi-process.rst
15
16
diff --git a/MAINTAINERS b/MAINTAINERS
17
index XXXXXXX..XXXXXXX 100644
18
--- a/MAINTAINERS
19
+++ b/MAINTAINERS
20
@@ -XXX,XX +XXX,XX @@ S: Maintained
21
F: hw/semihosting/
22
F: include/hw/semihosting/
23
24
+Multi-process QEMU
25
+M: Elena Ufimtseva <elena.ufimtseva@oracle.com>
26
+M: Jagannathan Raman <jag.raman@oracle.com>
27
+M: John G Johnson <john.g.johnson@oracle.com>
28
+S: Maintained
29
+F: docs/devel/multi-process.rst
30
+
31
Build and test automation
32
-------------------------
33
Build and test automation
34
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
35
index XXXXXXX..XXXXXXX 100644
36
--- a/docs/devel/index.rst
37
+++ b/docs/devel/index.rst
38
@@ -XXX,XX +XXX,XX @@ Contents:
39
clocks
40
qom
41
block-coroutine-wrapper
42
+ multi-process
43
diff --git a/docs/devel/multi-process.rst b/docs/devel/multi-process.rst
44
new file mode 100644
45
index XXXXXXX..XXXXXXX
46
--- /dev/null
47
+++ b/docs/devel/multi-process.rst
48
@@ -XXX,XX +XXX,XX @@
49
+This is the design document for multi-process QEMU. It does not
50
+necessarily reflect the status of the current implementation, which
51
+may lack features or be considerably different from what is described
52
+in this document. This document is still useful as a description of
53
+the goals and general direction of this feature.
54
+
55
+Please refer to the following wiki for latest details:
56
+https://wiki.qemu.org/Features/MultiProcessQEMU
57
+
58
+Multi-process QEMU
59
+===================
60
+
61
+QEMU is often used as the hypervisor for virtual machines running in the
62
+Oracle cloud. Since one of the advantages of cloud computing is the
63
+ability to run many VMs from different tenants in the same cloud
64
+infrastructure, a guest that compromised its hypervisor could
65
+potentially use the hypervisor's access privileges to access data it is
66
+not authorized for.
67
+
68
+QEMU can be susceptible to security attacks because it is a large,
69
+monolithic program that provides many features to the VMs it services.
70
+Many of these features can be configured out of QEMU, but even a reduced
71
+configuration QEMU has a large amount of code a guest can potentially
72
+attack. Separating QEMU reduces the attack surface by aiding to
73
+limit each component in the system to only access the resources that
74
+it needs to perform its job.
75
+
76
+QEMU services
77
+-------------
78
+
79
+QEMU can be broadly described as providing three main services. One is a
80
+VM control point, where VMs can be created, migrated, re-configured, and
81
+destroyed. A second is to emulate the CPU instructions within the VM,
82
+often accelerated by HW virtualization features such as Intel's VT
83
+extensions. Finally, it provides IO services to the VM by emulating HW
84
+IO devices, such as disk and network devices.
85
+
86
+A multi-process QEMU
87
+~~~~~~~~~~~~~~~~~~~~
88
+
89
+A multi-process QEMU involves separating QEMU services into separate
90
+host processes. Each of these processes can be given only the privileges
91
+it needs to provide its service, e.g., a disk service could be given
92
+access only to the disk images it provides, and not be allowed to
93
+access other files, or any network devices. An attacker who compromised
94
+this service would not be able to use this exploit to access files or
95
+devices beyond what the disk service was given access to.
96
+
97
+A QEMU control process would remain, but in multi-process mode, will
98
+have no direct interfaces to the VM. During VM execution, it would still
99
+provide the user interface to hot-plug devices or live migrate the VM.
100
+
101
+A first step in creating a multi-process QEMU is to separate IO services
102
+from the main QEMU program, which would continue to provide CPU
103
+emulation. i.e., the control process would also be the CPU emulation
104
+process. In a later phase, CPU emulation could be separated from the
105
+control process.
106
+
107
+Separating IO services
108
+----------------------
109
+
110
+Separating IO services into individual host processes is a good place to
111
+begin for a couple of reasons. One is the sheer number of IO devices QEMU
112
+can emulate provides a large surface of interfaces which could potentially
113
+be exploited, and, indeed, have been a source of exploits in the past.
114
+Another is the modular nature of QEMU device emulation code provides
115
+interface points where the QEMU functions that perform device emulation
116
+can be separated from the QEMU functions that manage the emulation of
117
+guest CPU instructions. The devices emulated in the separate process are
118
+referred to as remote devices.
119
+
120
+QEMU device emulation
121
+~~~~~~~~~~~~~~~~~~~~~
122
+
123
+QEMU uses an object oriented SW architecture for device emulation code.
124
+Configured objects are all compiled into the QEMU binary, then objects
125
+are instantiated by name when used by the guest VM. For example, the
126
+code to emulate a device named "foo" is always present in QEMU, but its
127
+instantiation code is only run when the device is included in the target
128
+VM. (e.g., via the QEMU command line as *-device foo*)
129
+
130
+The object model is hierarchical, so device emulation code names its
131
+parent object (such as "pci-device" for a PCI device) and QEMU will
132
+instantiate a parent object before calling the device's instantiation
133
+code.
134
+
135
+Current separation models
136
+~~~~~~~~~~~~~~~~~~~~~~~~~
137
+
138
+In order to separate the device emulation code from the CPU emulation
139
+code, the device object code must run in a different process. There are
140
+a couple of existing QEMU features that can run emulation code
141
+separately from the main QEMU process. These are examined below.
142
+
143
+vhost user model
144
+^^^^^^^^^^^^^^^^
145
+
146
+Virtio guest device drivers can be connected to vhost user applications
147
+in order to perform their IO operations. This model uses special virtio
148
+device drivers in the guest and vhost user device objects in QEMU, but
149
+once the QEMU vhost user code has configured the vhost user application,
150
+mission-mode IO is performed by the application. The vhost user
151
+application is a daemon process that can be contacted via a known UNIX
152
+domain socket.
153
+
154
+vhost socket
155
+''''''''''''
156
+
157
+As mentioned above, one of the tasks of the vhost device object within
158
+QEMU is to contact the vhost application and send it configuration
159
+information about this device instance. As part of the configuration
160
+process, the application can also be sent other file descriptors over
161
+the socket, which then can be used by the vhost user application in
162
+various ways, some of which are described below.
163
+
164
+vhost MMIO store acceleration
165
+'''''''''''''''''''''''''''''
166
+
167
+VMs are often run using HW virtualization features via the KVM kernel
168
+driver. This driver allows QEMU to accelerate the emulation of guest CPU
169
+instructions by running the guest in a virtual HW mode. When the guest
170
+executes instructions that cannot be executed by virtual HW mode,
171
+execution returns to the KVM driver so it can inform QEMU to emulate the
172
+instructions in SW.
173
+
174
+One of the events that can cause a return to QEMU is when a guest device
175
+driver accesses an IO location. QEMU then dispatches the memory
176
+operation to the corresponding QEMU device object. In the case of a
177
+vhost user device, the memory operation would need to be sent over a
178
+socket to the vhost application. This path is accelerated by the QEMU
179
+virtio code by setting up an eventfd file descriptor that the vhost
180
+application can directly receive MMIO store notifications from the KVM
181
+driver, instead of needing them to be sent to the QEMU process first.
182
+
183
+vhost interrupt acceleration
184
+''''''''''''''''''''''''''''
185
+
186
+Another optimization used by the vhost application is the ability to
187
+directly inject interrupts into the VM via the KVM driver, again,
188
+bypassing the need to send the interrupt back to the QEMU process first.
189
+The QEMU virtio setup code configures the KVM driver with an eventfd
190
+that triggers the device interrupt in the guest when the eventfd is
191
+written. This irqfd file descriptor is then passed to the vhost user
192
+application program.
193
+
194
+vhost access to guest memory
195
+''''''''''''''''''''''''''''
196
+
197
+The vhost application is also allowed to directly access guest memory,
198
+instead of needing to send the data as messages to QEMU. This is also
199
+done with file descriptors sent to the vhost user application by QEMU.
200
+These descriptors can be passed to ``mmap()`` by the vhost application
201
+to map the guest address space into the vhost application.
202
+
203
+IOMMUs introduce another level of complexity, since the address given to
204
+the guest virtio device to DMA to or from is not a guest physical
205
+address. This case is handled by having vhost code within QEMU register
206
+as a listener for IOMMU mapping changes. The vhost application maintains
207
+a cache of IOMMMU translations: sending translation requests back to
208
+QEMU on cache misses, and in turn receiving flush requests from QEMU
209
+when mappings are purged.
210
+
211
+applicability to device separation
212
+''''''''''''''''''''''''''''''''''
213
+
214
+Much of the vhost model can be re-used by separated device emulation. In
215
+particular, the ideas of using a socket between QEMU and the device
216
+emulation application, using a file descriptor to inject interrupts into
217
+the VM via KVM, and allowing the application to ``mmap()`` the guest
218
+should be re used.
219
+
220
+There are, however, some notable differences between how a vhost
221
+application works and the needs of separated device emulation. The most
222
+basic is that vhost uses custom virtio device drivers which always
223
+trigger IO with MMIO stores. A separated device emulation model must
224
+work with existing IO device models and guest device drivers. MMIO loads
225
+break vhost store acceleration since they are synchronous - guest
226
+progress cannot continue until the load has been emulated. By contrast,
227
+stores are asynchronous, the guest can continue after the store event
228
+has been sent to the vhost application.
229
+
230
+Another difference is that in the vhost user model, a single daemon can
231
+support multiple QEMU instances. This is contrary to the security regime
232
+desired, in which the emulation application should only be allowed to
233
+access the files or devices the VM it's running on behalf of can access.
234
+#### qemu-io model
235
+
236
+Qemu-io is a test harness used to test changes to the QEMU block backend
237
+object code. (e.g., the code that implements disk images for disk driver
238
+emulation) Qemu-io is not a device emulation application per se, but it
239
+does compile the QEMU block objects into a separate binary from the main
240
+QEMU one. This could be useful for disk device emulation, since its
241
+emulation applications will need to include the QEMU block objects.
242
+
243
+New separation model based on proxy objects
244
+-------------------------------------------
245
+
246
+A different model based on proxy objects in the QEMU program
247
+communicating with remote emulation programs could provide separation
248
+while minimizing the changes needed to the device emulation code. The
249
+rest of this section is a discussion of how a proxy object model would
250
+work.
251
+
252
+Remote emulation processes
253
+~~~~~~~~~~~~~~~~~~~~~~~~~~
254
+
255
+The remote emulation process will run the QEMU object hierarchy without
256
+modification. The device emulation objects will be also be based on the
257
+QEMU code, because for anything but the simplest device, it would not be
258
+a tractable to re-implement both the object model and the many device
259
+backends that QEMU has.
260
+
261
+The processes will communicate with the QEMU process over UNIX domain
262
+sockets. The processes can be executed either as standalone processes,
263
+or be executed by QEMU. In both cases, the host backends the emulation
264
+processes will provide are specified on its command line, as they would
265
+be for QEMU. For example:
266
+
267
+::
268
+
269
+ disk-proc -blockdev driver=file,node-name=file0,filename=disk-file0 \
270
+ -blockdev driver=qcow2,node-name=drive0,file=file0
271
+
272
+would indicate process *disk-proc* uses a qcow2 emulated disk named
273
+*file0* as its backend.
274
+
275
+Emulation processes may emulate more than one guest controller. A common
276
+configuration might be to put all controllers of the same device class
277
+(e.g., disk, network, etc.) in a single process, so that all backends of
278
+the same type can be managed by a single QMP monitor.
279
+
280
+communication with QEMU
281
+^^^^^^^^^^^^^^^^^^^^^^^
282
+
283
+The first argument to the remote emulation process will be a Unix domain
284
+socket that connects with the Proxy object. This is a required argument.
285
+
286
+::
287
+
288
+ disk-proc <socket number> <backend list>
289
+
290
+remote process QMP monitor
291
+^^^^^^^^^^^^^^^^^^^^^^^^^^
292
+
293
+Remote emulation processes can be monitored via QMP, similar to QEMU
294
+itself. The QMP monitor socket is specified the same as for a QEMU
295
+process:
296
+
297
+::
298
+
299
+ disk-proc -qmp unix:/tmp/disk-mon,server
300
+
301
+can be monitored over the UNIX socket path */tmp/disk-mon*.
302
+
303
+QEMU command line
304
+~~~~~~~~~~~~~~~~~
305
+
306
+Each remote device emulated in a remote process on the host is
307
+represented as a *-device* of type *pci-proxy-dev*. A socket
308
+sub-option to this option specifies the Unix socket that connects
309
+to the remote process. An *id* sub-option is required, and it should
310
+be the same id as used in the remote process.
311
+
312
+::
313
+
314
+ qemu-system-x86_64 ... -device pci-proxy-dev,id=lsi0,socket=3
315
+
316
+can be used to add a device emulated in a remote process
317
+
318
+
319
+QEMU management of remote processes
320
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
321
+
322
+QEMU is not aware of the type of type of the remote PCI device. It is
323
+a pass through device as far as QEMU is concerned.
324
+
325
+communication with emulation process
326
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
327
+
328
+primary channel
329
+'''''''''''''''
330
+
331
+The primary channel (referred to as com in the code) is used to bootstrap
332
+the remote process. It is also used to pass on device-agnostic commands
333
+like reset.
334
+
335
+per-device channels
336
+'''''''''''''''''''
337
+
338
+Each remote device communicates with QEMU using a dedicated communication
339
+channel. The proxy object sets up this channel using the primary
340
+channel during its initialization.
341
+
342
+QEMU device proxy objects
343
+~~~~~~~~~~~~~~~~~~~~~~~~~
344
+
345
+QEMU has an object model based on sub-classes inherited from the
346
+"object" super-class. The sub-classes that are of interest here are the
347
+"device" and "bus" sub-classes whose child sub-classes make up the
348
+device tree of a QEMU emulated system.
349
+
350
+The proxy object model will use device proxy objects to replace the
351
+device emulation code within the QEMU process. These objects will live
352
+in the same place in the object and bus hierarchies as the objects they
353
+replace. i.e., the proxy object for an LSI SCSI controller will be a
354
+sub-class of the "pci-device" class, and will have the same PCI bus
355
+parent and the same SCSI bus child objects as the LSI controller object
356
+it replaces.
357
+
358
+It is worth noting that the same proxy object is used to mediate with
359
+all types of remote PCI devices.
360
+
361
+object initialization
362
+^^^^^^^^^^^^^^^^^^^^^
363
+
364
+The Proxy device objects are initialized in the exact same manner in
365
+which any other QEMU device would be initialized.
366
+
367
+In addition, the Proxy objects perform the following two tasks:
368
+- Parses the "socket" sub option and connects to the remote process
369
+using this channel
370
+- Uses the "id" sub-option to connect to the emulated device on the
371
+separate process
372
+
373
+class\_init
374
+'''''''''''
375
+
376
+The ``class_init()`` method of a proxy object will, in general behave
377
+similarly to the object it replaces, including setting any static
378
+properties and methods needed by the proxy.
379
+
380
+instance\_init / realize
381
+''''''''''''''''''''''''
382
+
383
+The ``instance_init()`` and ``realize()`` functions would only need to
384
+perform tasks related to being a proxy, such are registering its own
385
+MMIO handlers, or creating a child bus that other proxy devices can be
386
+attached to later.
387
+
388
+Other tasks will be device-specific. For example, PCI device objects
389
+will initialize the PCI config space in order to make a valid PCI device
390
+tree within the QEMU process.
391
+
392
+address space registration
393
+^^^^^^^^^^^^^^^^^^^^^^^^^^
394
+
395
+Most devices are driven by guest device driver accesses to IO addresses
396
+or ports. The QEMU device emulation code uses QEMU's memory region
397
+function calls (such as ``memory_region_init_io()``) to add callback
398
+functions that QEMU will invoke when the guest accesses the device's
399
+areas of the IO address space. When a guest driver does access the
400
+device, the VM will exit HW virtualization mode and return to QEMU,
401
+which will then lookup and execute the corresponding callback function.
402
+
403
+A proxy object would need to mirror the memory region calls the actual
404
+device emulator would perform in its initialization code, but with its
405
+own callbacks. When invoked by QEMU as a result of a guest IO operation,
406
+they will forward the operation to the device emulation process.
407
+
408
+PCI config space
409
+^^^^^^^^^^^^^^^^
410
+
411
+PCI devices also have a configuration space that can be accessed by the
412
+guest driver. Guest accesses to this space is not handled by the device
413
+emulation object, but by its PCI parent object. Much of this space is
414
+read-only, but certain registers (especially BAR and MSI-related ones)
415
+need to be propagated to the emulation process.
416
+
417
+PCI parent proxy
418
+''''''''''''''''
419
+
420
+One way to propagate guest PCI config accesses is to create a
421
+"pci-device-proxy" class that can serve as the parent of a PCI device
422
+proxy object. This class's parent would be "pci-device" and it would
423
+override the PCI parent's ``config_read()`` and ``config_write()``
424
+methods with ones that forward these operations to the emulation
425
+program.
426
+
427
+interrupt receipt
428
+^^^^^^^^^^^^^^^^^
429
+
430
+A proxy for a device that generates interrupts will need to create a
431
+socket to receive interrupt indications from the emulation process. An
432
+incoming interrupt indication would then be sent up to its bus parent to
433
+be injected into the guest. For example, a PCI device object may use
434
+``pci_set_irq()``.
435
+
436
+live migration
437
+^^^^^^^^^^^^^^
438
+
439
+The proxy will register to save and restore any *vmstate* it needs over
440
+a live migration event. The device proxy does not need to manage the
441
+remote device's *vmstate*; that will be handled by the remote process
442
+proxy (see below).
443
+
444
+QEMU remote device operation
445
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
446
+
447
+Generic device operations, such as DMA, will be performed by the remote
448
+process proxy by sending messages to the remote process.
449
+
450
+DMA operations
451
+^^^^^^^^^^^^^^
452
+
453
+DMA operations would be handled much like vhost applications do. One of
454
+the initial messages sent to the emulation process is a guest memory
455
+table. Each entry in this table consists of a file descriptor and size
456
+that the emulation process can ``mmap()`` to directly access guest
457
+memory, similar to ``vhost_user_set_mem_table()``. Note guest memory
458
+must be backed by file descriptors, such as when QEMU is given the
459
+*-mem-path* command line option.
460
+
461
+IOMMU operations
462
+^^^^^^^^^^^^^^^^
463
+
464
+When the emulated system includes an IOMMU, the remote process proxy in
465
+QEMU will need to create a socket for IOMMU requests from the emulation
466
+process. It will handle those requests with an
467
+``address_space_get_iotlb_entry()`` call. In order to handle IOMMU
468
+unmaps, the remote process proxy will also register as a listener on the
469
+device's DMA address space. When an IOMMU memory region is created
470
+within the DMA address space, an IOMMU notifier for unmaps will be added
471
+to the memory region that will forward unmaps to the emulation process
472
+over the IOMMU socket.
473
+
474
+device hot-plug via QMP
475
+^^^^^^^^^^^^^^^^^^^^^^^
476
+
477
+An QMP "device\_add" command can add a device emulated by a remote
478
+process. It will also have "rid" option to the command, just as the
479
+*-device* command line option does. The remote process may either be one
480
+started at QEMU startup, or be one added by the "add-process" QMP
481
+command described above. In either case, the remote process proxy will
482
+forward the new device's JSON description to the corresponding emulation
483
+process.
484
+
485
+live migration
486
+^^^^^^^^^^^^^^
487
+
488
+The remote process proxy will also register for live migration
489
+notifications with ``vmstate_register()``. When called to save state,
490
+the proxy will send the remote process a secondary socket file
491
+descriptor to save the remote process's device *vmstate* over. The
492
+incoming byte stream length and data will be saved as the proxy's
493
+*vmstate*. When the proxy is resumed on its new host, this *vmstate*
494
+will be extracted, and a secondary socket file descriptor will be sent
495
+to the new remote process through which it receives the *vmstate* in
496
+order to restore the devices there.
497
+
498
+device emulation in remote process
499
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
500
+
501
+The parts of QEMU that the emulation program will need include the
502
+object model; the memory emulation objects; the device emulation objects
503
+of the targeted device, and any dependent devices; and, the device's
504
+backends. It will also need code to setup the machine environment,
505
+handle requests from the QEMU process, and route machine-level requests
506
+(such as interrupts or IOMMU mappings) back to the QEMU process.
507
+
508
+initialization
509
+^^^^^^^^^^^^^^
510
+
511
+The process initialization sequence will follow the same sequence
512
+followed by QEMU. It will first initialize the backend objects, then
513
+device emulation objects. The JSON descriptions sent by the QEMU process
514
+will drive which objects need to be created.
515
+
516
+- address spaces
517
+
518
+Before the device objects are created, the initial address spaces and
519
+memory regions must be configured with ``memory_map_init()``. This
520
+creates a RAM memory region object (*system\_memory*) and an IO memory
521
+region object (*system\_io*).
522
+
523
+- RAM
524
+
525
+RAM memory region creation will follow how ``pc_memory_init()`` creates
526
+them, but must use ``memory_region_init_ram_from_fd()`` instead of
527
+``memory_region_allocate_system_memory()``. The file descriptors needed
528
+will be supplied by the guest memory table from above. Those RAM regions
529
+would then be added to the *system\_memory* memory region with
530
+``memory_region_add_subregion()``.
531
+
532
+- PCI
533
+
534
+IO initialization will be driven by the JSON descriptions sent from the
535
+QEMU process. For a PCI device, a PCI bus will need to be created with
536
+``pci_root_bus_new()``, and a PCI memory region will need to be created
537
+and added to the *system\_memory* memory region with
538
+``memory_region_add_subregion_overlap()``. The overlap version is
539
+required for architectures where PCI memory overlaps with RAM memory.
540
+
541
+MMIO handling
542
+^^^^^^^^^^^^^
543
+
544
+The device emulation objects will use ``memory_region_init_io()`` to
545
+install their MMIO handlers, and ``pci_register_bar()`` to associate
546
+those handlers with a PCI BAR, as they do within QEMU currently.
547
+
548
+In order to use ``address_space_rw()`` in the emulation process to
549
+handle MMIO requests from QEMU, the PCI physical addresses must be the
550
+same in the QEMU process and the device emulation process. In order to
551
+accomplish that, guest BAR programming must also be forwarded from QEMU
552
+to the emulation process.
553
+
554
+interrupt injection
555
+^^^^^^^^^^^^^^^^^^^
556
+
557
+When device emulation wants to inject an interrupt into the VM, the
558
+request climbs the device's bus object hierarchy until the point where a
559
+bus object knows how to signal the interrupt to the guest. The details
560
+depend on the type of interrupt being raised.
561
+
562
+- PCI pin interrupts
563
+
564
+On x86 systems, there is an emulated IOAPIC object attached to the root
565
+PCI bus object, and the root PCI object forwards interrupt requests to
566
+it. The IOAPIC object, in turn, calls the KVM driver to inject the
567
+corresponding interrupt into the VM. The simplest way to handle this in
568
+an emulation process would be to setup the root PCI bus driver (via
569
+``pci_bus_irqs()``) to send a interrupt request back to the QEMU
570
+process, and have the device proxy object reflect it up the PCI tree
571
+there.
572
+
573
+- PCI MSI/X interrupts
574
+
575
+PCI MSI/X interrupts are implemented in HW as DMA writes to a
576
+CPU-specific PCI address. In QEMU on x86, a KVM APIC object receives
577
+these DMA writes, then calls into the KVM driver to inject the interrupt
578
+into the VM. A simple emulation process implementation would be to send
579
+the MSI DMA address from QEMU as a message at initialization, then
580
+install an address space handler at that address which forwards the MSI
581
+message back to QEMU.
582
+
583
+DMA operations
584
+^^^^^^^^^^^^^^
585
+
586
+When a emulation object wants to DMA into or out of guest memory, it
587
+first must use dma\_memory\_map() to convert the DMA address to a local
588
+virtual address. The emulation process memory region objects setup above
589
+will be used to translate the DMA address to a local virtual address the
590
+device emulation code can access.
591
+
592
+IOMMU
593
+^^^^^
594
+
595
+When an IOMMU is in use in QEMU, DMA translation uses IOMMU memory
596
+regions to translate the DMA address to a guest physical address before
597
+that physical address can be translated to a local virtual address. The
598
+emulation process will need similar functionality.
599
+
600
+- IOTLB cache
601
+
602
+The emulation process will maintain a cache of recent IOMMU translations
603
+(the IOTLB). When the translate() callback of an IOMMU memory region is
604
+invoked, the IOTLB cache will be searched for an entry that will map the
605
+DMA address to a guest PA. On a cache miss, a message will be sent back
606
+to QEMU requesting the corresponding translation entry, which be both be
607
+used to return a guest address and be added to the cache.
608
+
609
+- IOTLB purge
610
+
611
+The IOMMU emulation will also need to act on unmap requests from QEMU.
612
+These happen when the guest IOMMU driver purges an entry from the
613
+guest's translation table.
614
+
615
+live migration
616
+^^^^^^^^^^^^^^
617
+
618
+When a remote process receives a live migration indication from QEMU, it
619
+will set up a channel using the received file descriptor with
620
+``qio_channel_socket_new_fd()``. This channel will be used to create a
621
+*QEMUfile* that can be passed to ``qemu_save_device_state()`` to send
622
+the process's device state back to QEMU. This method will be reversed on
623
+restore - the channel will be passed to ``qemu_loadvm_state()`` to
624
+restore the device state.
625
+
626
+Accelerating device emulation
627
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
628
+
629
+The messages that are required to be sent between QEMU and the emulation
630
+process can add considerable latency to IO operations. The optimizations
631
+described below attempt to ameliorate this effect by allowing the
632
+emulation process to communicate directly with the kernel KVM driver.
633
+The KVM file descriptors created would be passed to the emulation process
634
+via initialization messages, much like the guest memory table is done.
635
+#### MMIO acceleration
636
+
637
+Vhost user applications can receive guest virtio driver stores directly
638
+from KVM. The issue with the eventfd mechanism used by vhost user is
639
+that it does not pass any data with the event indication, so it cannot
640
+handle guest loads or guest stores that carry store data. This concept
641
+could, however, be expanded to cover more cases.
642
+
643
+The expanded idea would require a new type of KVM device:
644
+*KVM\_DEV\_TYPE\_USER*. This device has two file descriptors: a master
645
+descriptor that QEMU can use for configuration, and a slave descriptor
646
+that the emulation process can use to receive MMIO notifications. QEMU
647
+would create both descriptors using the KVM driver, and pass the slave
648
+descriptor to the emulation process via an initialization message.
649
+
650
+data structures
651
+^^^^^^^^^^^^^^^
652
+
653
+- guest physical range
654
+
655
+The guest physical range structure describes the address range that a
656
+device will respond to. It includes the base and length of the range, as
657
+well as which bus the range resides on (e.g., on an x86machine, it can
658
+specify whether the range refers to memory or IO addresses).
659
+
660
+A device can have multiple physical address ranges it responds to (e.g.,
661
+a PCI device can have multiple BARs), so the structure will also include
662
+an enumerated identifier to specify which of the device's ranges is
663
+being referred to.
664
+
665
++--------+----------------------------+
666
+| Name | Description |
667
++========+============================+
668
+| addr | range base address |
669
++--------+----------------------------+
670
+| len | range length |
671
++--------+----------------------------+
672
+| bus | addr type (memory or IO) |
673
++--------+----------------------------+
674
+| id | range ID (e.g., PCI BAR) |
675
++--------+----------------------------+
676
+
677
+- MMIO request structure
678
+
679
+This structure describes an MMIO operation. It includes which guest
680
+physical range the MMIO was within, the offset within that range, the
681
+MMIO type (e.g., load or store), and its length and data. It also
682
+includes a sequence number that can be used to reply to the MMIO, and
683
+the CPU that issued the MMIO.
684
+
685
++----------+------------------------+
686
+| Name | Description |
687
++==========+========================+
688
+| rid | range MMIO is within |
689
++----------+------------------------+
690
+| offset | offset withing *rid* |
691
++----------+------------------------+
692
+| type | e.g., load or store |
693
++----------+------------------------+
694
+| len | MMIO length |
695
++----------+------------------------+
696
+| data | store data |
697
++----------+------------------------+
698
+| seq | sequence ID |
699
++----------+------------------------+
700
+
701
+- MMIO request queues
702
+
703
+MMIO request queues are FIFO arrays of MMIO request structures. There
704
+are two queues: pending queue is for MMIOs that haven't been read by the
705
+emulation program, and the sent queue is for MMIOs that haven't been
706
+acknowledged. The main use of the second queue is to validate MMIO
707
+replies from the emulation program.
708
+
709
+- scoreboard
710
+
711
+Each CPU in the VM is emulated in QEMU by a separate thread, so multiple
712
+MMIOs may be waiting to be consumed by an emulation program and multiple
713
+threads may be waiting for MMIO replies. The scoreboard would contain a
714
+wait queue and sequence number for the per-CPU threads, allowing them to
715
+be individually woken when the MMIO reply is received from the emulation
716
+program. It also tracks the number of posted MMIO stores to the device
717
+that haven't been replied to, in order to satisfy the PCI constraint
718
+that a load to a device will not complete until all previous stores to
719
+that device have been completed.
720
+
721
+- device shadow memory
722
+
723
+Some MMIO loads do not have device side-effects. These MMIOs can be
724
+completed without sending a MMIO request to the emulation program if the
725
+emulation program shares a shadow image of the device's memory image
726
+with the KVM driver.
727
+
728
+The emulation program will ask the KVM driver to allocate memory for the
729
+shadow image, and will then use ``mmap()`` to directly access it. The
730
+emulation program can control KVM access to the shadow image by sending
731
+KVM an access map telling it which areas of the image have no
732
+side-effects (and can be completed immediately), and which require a
733
+MMIO request to the emulation program. The access map can also inform
734
+the KVM drive which size accesses are allowed to the image.
735
+
736
+master descriptor
737
+^^^^^^^^^^^^^^^^^
738
+
739
+The master descriptor is used by QEMU to configure the new KVM device.
740
+The descriptor would be returned by the KVM driver when QEMU issues a
741
+*KVM\_CREATE\_DEVICE* ``ioctl()`` with a *KVM\_DEV\_TYPE\_USER* type.
742
+
743
+KVM\_DEV\_TYPE\_USER device ops
744
+
745
+
746
+The *KVM\_DEV\_TYPE\_USER* operations vector will be registered by a
747
+``kvm_register_device_ops()`` call when the KVM system in initialized by
748
+``kvm_init()``. These device ops are called by the KVM driver when QEMU
749
+executes certain ``ioctl()`` operations on its KVM file descriptor. They
750
+include:
751
+
752
+- create
753
+
754
+This routine is called when QEMU issues a *KVM\_CREATE\_DEVICE*
755
+``ioctl()`` on its per-VM file descriptor. It will allocate and
756
+initialize a KVM user device specific data structure, and assign the
757
+*kvm\_device* private field to it.
758
+
759
+- ioctl
760
+
761
+This routine is invoked when QEMU issues an ``ioctl()`` on the master
762
+descriptor. The ``ioctl()`` commands supported are defined by the KVM
763
+device type. *KVM\_DEV\_TYPE\_USER* ones will need several commands:
764
+
765
+*KVM\_DEV\_USER\_SLAVE\_FD* creates the slave file descriptor that will
766
+be passed to the device emulation program. Only one slave can be created
767
+by each master descriptor. The file operations performed by this
768
+descriptor are described below.
769
+
770
+The *KVM\_DEV\_USER\_PA\_RANGE* command configures a guest physical
771
+address range that the slave descriptor will receive MMIO notifications
772
+for. The range is specified by a guest physical range structure
773
+argument. For buses that assign addresses to devices dynamically, this
774
+command can be executed while the guest is running, such as the case
775
+when a guest changes a device's PCI BAR registers.
776
+
777
+*KVM\_DEV\_USER\_PA\_RANGE* will use ``kvm_io_bus_register_dev()`` to
778
+register *kvm\_io\_device\_ops* callbacks to be invoked when the guest
779
+performs a MMIO operation within the range. When a range is changed,
780
+``kvm_io_bus_unregister_dev()`` is used to remove the previous
781
+instantiation.
782
+
783
+*KVM\_DEV\_USER\_TIMEOUT* will configure a timeout value that specifies
784
+how long KVM will wait for the emulation process to respond to a MMIO
785
+indication.
786
+
787
+- destroy
788
+
789
+This routine is called when the VM instance is destroyed. It will need
790
+to destroy the slave descriptor; and free any memory allocated by the
791
+driver, as well as the *kvm\_device* structure itself.
792
+
793
+slave descriptor
794
+^^^^^^^^^^^^^^^^
795
+
796
+The slave descriptor will have its own file operations vector, which
797
+responds to system calls on the descriptor performed by the device
798
+emulation program.
799
+
800
+- read
801
+
802
+A read returns any pending MMIO requests from the KVM driver as MMIO
803
+request structures. Multiple structures can be returned if there are
804
+multiple MMIO operations pending. The MMIO requests are moved from the
805
+pending queue to the sent queue, and if there are threads waiting for
806
+space in the pending to add new MMIO operations, they will be woken
807
+here.
808
+
809
+- write
810
+
811
+A write also consists of a set of MMIO requests. They are compared to
812
+the MMIO requests in the sent queue. Matches are removed from the sent
813
+queue, and any threads waiting for the reply are woken. If a store is
814
+removed, then the number of posted stores in the per-CPU scoreboard is
815
+decremented. When the number is zero, and a non side-effect load was
816
+waiting for posted stores to complete, the load is continued.
817
+
818
+- ioctl
819
+
820
+There are several ioctl()s that can be performed on the slave
821
+descriptor.
822
+
823
+A *KVM\_DEV\_USER\_SHADOW\_SIZE* ``ioctl()`` causes the KVM driver to
824
+allocate memory for the shadow image. This memory can later be
825
+``mmap()``\ ed by the emulation process to share the emulation's view of
826
+device memory with the KVM driver.
827
+
828
+A *KVM\_DEV\_USER\_SHADOW\_CTRL* ``ioctl()`` controls access to the
829
+shadow image. It will send the KVM driver a shadow control map, which
830
+specifies which areas of the image can complete guest loads without
831
+sending the load request to the emulation program. It will also specify
832
+the size of load operations that are allowed.
833
+
834
+- poll
835
+
836
+An emulation program will use the ``poll()`` call with a *POLLIN* flag
837
+to determine if there are MMIO requests waiting to be read. It will
838
+return if the pending MMIO request queue is not empty.
839
+
840
+- mmap
841
+
842
+This call allows the emulation program to directly access the shadow
843
+image allocated by the KVM driver. As device emulation updates device
844
+memory, changes with no side-effects will be reflected in the shadow,
845
+and the KVM driver can satisfy guest loads from the shadow image without
846
+needing to wait for the emulation program.
847
+
848
+kvm\_io\_device ops
849
+^^^^^^^^^^^^^^^^^^^
850
+
851
+Each KVM per-CPU thread can handle MMIO operation on behalf of the guest
852
+VM. KVM will use the MMIO's guest physical address to search for a
853
+matching *kvm\_io\_device* to see if the MMIO can be handled by the KVM
854
+driver instead of exiting back to QEMU. If a match is found, the
855
+corresponding callback will be invoked.
856
+
857
+- read
858
+
859
+This callback is invoked when the guest performs a load to the device.
860
+Loads with side-effects must be handled synchronously, with the KVM
861
+driver putting the QEMU thread to sleep waiting for the emulation
862
+process reply before re-starting the guest. Loads that do not have
863
+side-effects may be optimized by satisfying them from the shadow image,
864
+if there are no outstanding stores to the device by this CPU. PCI memory
865
+ordering demands that a load cannot complete before all older stores to
866
+the same device have been completed.
867
+
868
+- write
869
+
870
+Stores can be handled asynchronously unless the pending MMIO request
871
+queue is full. In this case, the QEMU thread must sleep waiting for
872
+space in the queue. Stores will increment the number of posted stores in
873
+the per-CPU scoreboard, in order to implement the PCI ordering
874
+constraint above.
875
+
876
+interrupt acceleration
877
+^^^^^^^^^^^^^^^^^^^^^^
878
+
879
+This performance optimization would work much like a vhost user
880
+application does, where the QEMU process sets up *eventfds* that cause
881
+the device's corresponding interrupt to be triggered by the KVM driver.
882
+These irq file descriptors are sent to the emulation process at
883
+initialization, and are used when the emulation code raises a device
884
+interrupt.
885
+
886
+intx acceleration
887
+'''''''''''''''''
888
+
889
+Traditional PCI pin interrupts are level based, so, in addition to an
890
+irq file descriptor, a re-sampling file descriptor needs to be sent to
891
+the emulation program. This second file descriptor allows multiple
892
+devices sharing an irq to be notified when the interrupt has been
893
+acknowledged by the guest, so they can re-trigger the interrupt if their
894
+device has not de-asserted its interrupt.
895
+
896
+intx irq descriptor
897
+
898
+
899
+The irq descriptors are created by the proxy object
900
+``using event_notifier_init()`` to create the irq and re-sampling
901
+*eventds*, and ``kvm_vm_ioctl(KVM_IRQFD)`` to bind them to an interrupt.
902
+The interrupt route can be found with
903
+``pci_device_route_intx_to_irq()``.
904
+
905
+intx routing changes
906
+
907
+
908
+Intx routing can be changed when the guest programs the APIC the device
909
+pin is connected to. The proxy object in QEMU will use
910
+``pci_device_set_intx_routing_notifier()`` to be informed of any guest
911
+changes to the route. This handler will broadly follow the VFIO
912
+interrupt logic to change the route: de-assigning the existing irq
913
+descriptor from its route, then assigning it the new route. (see
914
+``vfio_intx_update()``)
915
+
916
+MSI/X acceleration
917
+''''''''''''''''''
918
+
919
+MSI/X interrupts are sent as DMA transactions to the host. The interrupt
920
+data contains a vector that is programmed by the guest, A device may have
921
+multiple MSI interrupts associated with it, so multiple irq descriptors
922
+may need to be sent to the emulation program.
923
+
924
+MSI/X irq descriptor
925
+
926
+
927
+This case will also follow the VFIO example. For each MSI/X interrupt,
928
+an *eventfd* is created, a virtual interrupt is allocated by
929
+``kvm_irqchip_add_msi_route()``, and the virtual interrupt is bound to
930
+the eventfd with ``kvm_irqchip_add_irqfd_notifier()``.
931
+
932
+MSI/X config space changes
933
+
934
+
935
+The guest may dynamically update several MSI-related tables in the
936
+device's PCI config space. These include per-MSI interrupt enables and
937
+vector data. Additionally, MSIX tables exist in device memory space, not
938
+config space. Much like the BAR case above, the proxy object must look
939
+at guest config space programming to keep the MSI interrupt state
940
+consistent between QEMU and the emulation program.
941
+
942
+--------------
943
+
944
+Disaggregated CPU emulation
945
+---------------------------
946
+
947
+After IO services have been disaggregated, a second phase would be to
948
+separate a process to handle CPU instruction emulation from the main
949
+QEMU control function. There are no object separation points for this
950
+code, so the first task would be to create one.
951
+
952
+Host access controls
953
+--------------------
954
+
955
+Separating QEMU relies on the host OS's access restriction mechanisms to
956
+enforce that the differing processes can only access the objects they
957
+are entitled to. There are a couple types of mechanisms usually provided
958
+by general purpose OSs.
959
+
960
+Discretionary access control
961
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
962
+
963
+Discretionary access control allows each user to control who can access
964
+their files. In Linux, this type of control is usually too coarse for
965
+QEMU separation, since it only provides three separate access controls:
966
+one for the same user ID, the second for users IDs with the same group
967
+ID, and the third for all other user IDs. Each device instance would
968
+need a separate user ID to provide access control, which is likely to be
969
+unwieldy for dynamically created VMs.
970
+
971
+Mandatory access control
972
+~~~~~~~~~~~~~~~~~~~~~~~~
973
+
974
+Mandatory access control allows the OS to add an additional set of
975
+controls on top of discretionary access for the OS to control. It also
976
+adds other attributes to processes and files such as types, roles, and
977
+categories, and can establish rules for how processes and files can
978
+interact.
979
+
980
+Type enforcement
981
+^^^^^^^^^^^^^^^^
982
+
983
+Type enforcement assigns a *type* attribute to processes and files, and
984
+allows rules to be written on what operations a process with a given
985
+type can perform on a file with a given type. QEMU separation could take
986
+advantage of type enforcement by running the emulation processes with
987
+different types, both from the main QEMU process, and from the emulation
988
+processes of different classes of devices.
989
+
990
+For example, guest disk images and disk emulation processes could have
991
+types separate from the main QEMU process and non-disk emulation
992
+processes, and the type rules could prevent processes other than disk
993
+emulation ones from accessing guest disk images. Similarly, network
994
+emulation processes can have a type separate from the main QEMU process
995
+and non-network emulation process, and only that type can access the
996
+host tun/tap device used to provide guest networking.
997
+
998
+Category enforcement
999
+^^^^^^^^^^^^^^^^^^^^
1000
+
1001
+Category enforcement assigns a set of numbers within a given range to
1002
+the process or file. The process is granted access to the file if the
1003
+process's set is a superset of the file's set. This enforcement can be
1004
+used to separate multiple instances of devices in the same class.
1005
+
1006
+For example, if there are multiple disk devices provides to a guest,
1007
+each device emulation process could be provisioned with a separate
1008
+category. The different device emulation processes would not be able to
1009
+access each other's backing disk images.
1010
+
1011
+Alternatively, categories could be used in lieu of the type enforcement
1012
+scheme described above. In this scenario, different categories would be
1013
+used to prevent device emulation processes in different classes from
1014
+accessing resources assigned to other classes.
1015
--
1016
2.29.2
1017
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Adds documentation explaining the command-line arguments needed
4
to use multi-process.
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: 49f757a84e5dd6fae14b22544897d1124c5fdbad.1611938319.git.jag.raman@oracle.com
11
12
[Move orphan docs/multi-process.rst document into docs/system/ and add
13
it to index.rst to prevent Sphinx "document isn't included in any
14
toctree" error.
15
--Stefan]
16
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
19
MAINTAINERS | 1 +
20
docs/system/index.rst | 1 +
21
docs/system/multi-process.rst | 64 +++++++++++++++++++++++++++++++++++
22
3 files changed, 66 insertions(+)
23
create mode 100644 docs/system/multi-process.rst
24
25
diff --git a/MAINTAINERS b/MAINTAINERS
26
index XXXXXXX..XXXXXXX 100644
27
--- a/MAINTAINERS
28
+++ b/MAINTAINERS
29
@@ -XXX,XX +XXX,XX @@ M: Jagannathan Raman <jag.raman@oracle.com>
30
M: John G Johnson <john.g.johnson@oracle.com>
31
S: Maintained
32
F: docs/devel/multi-process.rst
33
+F: docs/system/multi-process.rst
34
35
Build and test automation
36
-------------------------
37
diff --git a/docs/system/index.rst b/docs/system/index.rst
38
index XXXXXXX..XXXXXXX 100644
39
--- a/docs/system/index.rst
40
+++ b/docs/system/index.rst
41
@@ -XXX,XX +XXX,XX @@ Contents:
42
pr-manager
43
targets
44
security
45
+ multi-process
46
deprecated
47
removed-features
48
build-platforms
49
diff --git a/docs/system/multi-process.rst b/docs/system/multi-process.rst
50
new file mode 100644
51
index XXXXXXX..XXXXXXX
52
--- /dev/null
53
+++ b/docs/system/multi-process.rst
54
@@ -XXX,XX +XXX,XX @@
55
+Multi-process QEMU
56
+==================
57
+
58
+This document describes how to configure and use multi-process qemu.
59
+For the design document refer to docs/devel/qemu-multiprocess.
60
+
61
+1) Configuration
62
+----------------
63
+
64
+multi-process is enabled by default for targets that enable KVM
65
+
66
+
67
+2) Usage
68
+--------
69
+
70
+Multi-process QEMU requires an orchestrator to launch.
71
+
72
+Following is a description of command-line used to launch mpqemu.
73
+
74
+* Orchestrator:
75
+
76
+ - The Orchestrator creates a unix socketpair
77
+
78
+ - It launches the remote process and passes one of the
79
+ sockets to it via command-line.
80
+
81
+ - It then launches QEMU and specifies the other socket as an option
82
+ to the Proxy device object
83
+
84
+* Remote Process:
85
+
86
+ - QEMU can enter remote process mode by using the "remote" machine
87
+ option.
88
+
89
+ - The orchestrator creates a "remote-object" with details about
90
+ the device and the file descriptor for the device
91
+
92
+ - The remaining options are no different from how one launches QEMU with
93
+ devices.
94
+
95
+ - Example command-line for the remote process is as follows:
96
+
97
+ /usr/bin/qemu-system-x86_64 \
98
+ -machine x-remote \
99
+ -device lsi53c895a,id=lsi0 \
100
+ -drive id=drive_image2,file=/build/ol7-nvme-test-1.qcow2 \
101
+ -device scsi-hd,id=drive2,drive=drive_image2,bus=lsi0.0,scsi-id=0 \
102
+ -object x-remote-object,id=robj1,devid=lsi1,fd=4,
103
+
104
+* QEMU:
105
+
106
+ - Since parts of the RAM are shared between QEMU & remote process, a
107
+ memory-backend-memfd is required to facilitate this, as follows:
108
+
109
+ -object memory-backend-memfd,id=mem,size=2G
110
+
111
+ - A "x-pci-proxy-dev" device is created for each of the PCI devices emulated
112
+ in the remote process. A "socket" sub-option specifies the other end of
113
+ unix channel created by orchestrator. The "id" sub-option must be specified
114
+ and should be the same as the "id" specified for the remote PCI device
115
+
116
+ - Example commandline for QEMU is as follows:
117
+
118
+ -device x-pci-proxy-dev,id=lsi0,socket=3
119
--
120
2.29.2
121
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
Allow RAM MemoryRegion to be created from an offset in a file, instead
4
of allocating at offset of 0 by default. This is needed to synchronize
5
RAM between QEMU & remote process.
6
7
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
9
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: 609996697ad8617e3b01df38accc5c208c24d74e.1611938319.git.jag.raman@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
include/exec/memory.h | 2 ++
15
include/exec/ram_addr.h | 2 +-
16
include/qemu/mmap-alloc.h | 4 +++-
17
backends/hostmem-memfd.c | 2 +-
18
hw/misc/ivshmem.c | 3 ++-
19
softmmu/memory.c | 3 ++-
20
softmmu/physmem.c | 11 +++++++----
21
util/mmap-alloc.c | 7 ++++---
22
util/oslib-posix.c | 2 +-
23
9 files changed, 23 insertions(+), 13 deletions(-)
24
25
diff --git a/include/exec/memory.h b/include/exec/memory.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/include/exec/memory.h
28
+++ b/include/exec/memory.h
29
@@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
30
* @size: size of the region.
31
* @share: %true if memory must be mmaped with the MAP_SHARED flag
32
* @fd: the fd to mmap.
33
+ * @offset: offset within the file referenced by fd
34
* @errp: pointer to Error*, to store an error if it happens.
35
*
36
* Note that this function does not do anything to cause the data in the
37
@@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
38
uint64_t size,
39
bool share,
40
int fd,
41
+ ram_addr_t offset,
42
Error **errp);
43
#endif
44
45
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/include/exec/ram_addr.h
48
+++ b/include/exec/ram_addr.h
49
@@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
50
Error **errp);
51
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
52
uint32_t ram_flags, int fd,
53
- Error **errp);
54
+ off_t offset, Error **errp);
55
56
RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
57
MemoryRegion *mr, Error **errp);
58
diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h
59
index XXXXXXX..XXXXXXX 100644
60
--- a/include/qemu/mmap-alloc.h
61
+++ b/include/qemu/mmap-alloc.h
62
@@ -XXX,XX +XXX,XX @@ size_t qemu_mempath_getpagesize(const char *mem_path);
63
* otherwise, the alignment in use will be determined by QEMU.
64
* @shared: map has RAM_SHARED flag.
65
* @is_pmem: map has RAM_PMEM flag.
66
+ * @map_offset: map starts at offset of map_offset from the start of fd
67
*
68
* Return:
69
* On success, return a pointer to the mapped area.
70
@@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd,
71
size_t size,
72
size_t align,
73
bool shared,
74
- bool is_pmem);
75
+ bool is_pmem,
76
+ off_t map_offset);
77
78
void qemu_ram_munmap(int fd, void *ptr, size_t size);
79
80
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/backends/hostmem-memfd.c
83
+++ b/backends/hostmem-memfd.c
84
@@ -XXX,XX +XXX,XX @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
85
name = host_memory_backend_get_name(backend);
86
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
87
name, backend->size,
88
- backend->share, fd, errp);
89
+ backend->share, fd, 0, errp);
90
g_free(name);
91
}
92
93
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
94
index XXXXXXX..XXXXXXX 100644
95
--- a/hw/misc/ivshmem.c
96
+++ b/hw/misc/ivshmem.c
97
@@ -XXX,XX +XXX,XX @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
98
99
/* mmap the region and map into the BAR2 */
100
memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
101
- "ivshmem.bar2", size, true, fd, &local_err);
102
+ "ivshmem.bar2", size, true, fd, 0,
103
+ &local_err);
104
if (local_err) {
105
error_propagate(errp, local_err);
106
return;
107
diff --git a/softmmu/memory.c b/softmmu/memory.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/softmmu/memory.c
110
+++ b/softmmu/memory.c
111
@@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
112
uint64_t size,
113
bool share,
114
int fd,
115
+ ram_addr_t offset,
116
Error **errp)
117
{
118
Error *err = NULL;
119
@@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
120
mr->destructor = memory_region_destructor_ram;
121
mr->ram_block = qemu_ram_alloc_from_fd(size, mr,
122
share ? RAM_SHARED : 0,
123
- fd, &err);
124
+ fd, offset, &err);
125
if (err) {
126
mr->size = int128_zero();
127
object_unparent(OBJECT(mr));
128
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/softmmu/physmem.c
131
+++ b/softmmu/physmem.c
132
@@ -XXX,XX +XXX,XX @@ static void *file_ram_alloc(RAMBlock *block,
133
ram_addr_t memory,
134
int fd,
135
bool truncate,
136
+ off_t offset,
137
Error **errp)
138
{
139
void *area;
140
@@ -XXX,XX +XXX,XX @@ static void *file_ram_alloc(RAMBlock *block,
141
}
142
143
area = qemu_ram_mmap(fd, memory, block->mr->align,
144
- block->flags & RAM_SHARED, block->flags & RAM_PMEM);
145
+ block->flags & RAM_SHARED, block->flags & RAM_PMEM,
146
+ offset);
147
if (area == MAP_FAILED) {
148
error_setg_errno(errp, errno,
149
"unable to map backing store for guest RAM");
150
@@ -XXX,XX +XXX,XX @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared)
151
#ifdef CONFIG_POSIX
152
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
153
uint32_t ram_flags, int fd,
154
- Error **errp)
155
+ off_t offset, Error **errp)
156
{
157
RAMBlock *new_block;
158
Error *local_err = NULL;
159
@@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
160
new_block->used_length = size;
161
new_block->max_length = size;
162
new_block->flags = ram_flags;
163
- new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp);
164
+ new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset,
165
+ errp);
166
if (!new_block->host) {
167
g_free(new_block);
168
return NULL;
169
@@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
170
return NULL;
171
}
172
173
- block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, errp);
174
+ block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, 0, errp);
175
if (!block) {
176
if (created) {
177
unlink(mem_path);
178
diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/util/mmap-alloc.c
181
+++ b/util/mmap-alloc.c
182
@@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd,
183
size_t size,
184
size_t align,
185
bool shared,
186
- bool is_pmem)
187
+ bool is_pmem,
188
+ off_t map_offset)
189
{
190
int flags;
191
int map_sync_flags = 0;
192
@@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd,
193
offset = QEMU_ALIGN_UP((uintptr_t)guardptr, align) - (uintptr_t)guardptr;
194
195
ptr = mmap(guardptr + offset, size, PROT_READ | PROT_WRITE,
196
- flags | map_sync_flags, fd, 0);
197
+ flags | map_sync_flags, fd, map_offset);
198
199
if (ptr == MAP_FAILED && map_sync_flags) {
200
if (errno == ENOTSUP) {
201
@@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd,
202
* we will remove these flags to handle compatibility.
203
*/
204
ptr = mmap(guardptr + offset, size, PROT_READ | PROT_WRITE,
205
- flags, fd, 0);
206
+ flags, fd, map_offset);
207
}
208
209
if (ptr == MAP_FAILED) {
210
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
211
index XXXXXXX..XXXXXXX 100644
212
--- a/util/oslib-posix.c
213
+++ b/util/oslib-posix.c
214
@@ -XXX,XX +XXX,XX @@ void *qemu_memalign(size_t alignment, size_t size)
215
void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared)
216
{
217
size_t align = QEMU_VMALLOC_ALIGN;
218
- void *ptr = qemu_ram_mmap(-1, size, align, shared, false);
219
+ void *ptr = qemu_ram_mmap(-1, size, align, shared, false, 0);
220
221
if (ptr == MAP_FAILED) {
222
return NULL;
223
--
224
2.29.2
225
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
Add configuration options to enable or disable multiprocess QEMU code
4
5
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
6
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
7
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 6cc37253e35418ebd7b675a31a3df6e3c7a12dc1.1611938319.git.jag.raman@oracle.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
configure | 10 ++++++++++
13
meson.build | 4 +++-
14
Kconfig.host | 4 ++++
15
hw/Kconfig | 1 +
16
hw/remote/Kconfig | 3 +++
17
5 files changed, 21 insertions(+), 1 deletion(-)
18
create mode 100644 hw/remote/Kconfig
19
20
diff --git a/configure b/configure
21
index XXXXXXX..XXXXXXX 100755
22
--- a/configure
23
+++ b/configure
24
@@ -XXX,XX +XXX,XX @@ skip_meson=no
25
gettext="auto"
26
fuse="auto"
27
fuse_lseek="auto"
28
+multiprocess="no"
29
30
malloc_trim="auto"
31
32
@@ -XXX,XX +XXX,XX @@ Linux)
33
linux="yes"
34
linux_user="yes"
35
vhost_user=${default_feature:-yes}
36
+ multiprocess=${default_feature:-yes}
37
;;
38
esac
39
40
@@ -XXX,XX +XXX,XX @@ for opt do
41
;;
42
--disable-fuse-lseek) fuse_lseek="disabled"
43
;;
44
+ --enable-multiprocess) multiprocess="yes"
45
+ ;;
46
+ --disable-multiprocess) multiprocess="no"
47
+ ;;
48
*)
49
echo "ERROR: unknown option $opt"
50
echo "Try '$0 --help' for more information"
51
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available
52
libdaxctl libdaxctl support
53
fuse FUSE block device export
54
fuse-lseek SEEK_HOLE/SEEK_DATA support for FUSE exports
55
+ multiprocess Multiprocess QEMU support
56
57
NOTE: The object files are built at the place where configure is launched
58
EOF
59
@@ -XXX,XX +XXX,XX @@ fi
60
if test "$have_mlockall" = "yes" ; then
61
echo "HAVE_MLOCKALL=y" >> $config_host_mak
62
fi
63
+if test "$multiprocess" = "yes" ; then
64
+ echo "CONFIG_MULTIPROCESS_ALLOWED=y" >> $config_host_mak
65
+fi
66
if test "$fuzzing" = "yes" ; then
67
# If LIB_FUZZING_ENGINE is set, assume we are running on OSS-Fuzz, and the
68
# needed CFLAGS have already been provided
69
diff --git a/meson.build b/meson.build
70
index XXXXXXX..XXXXXXX 100644
71
--- a/meson.build
72
+++ b/meson.build
73
@@ -XXX,XX +XXX,XX @@ host_kconfig = \
74
('CONFIG_VHOST_KERNEL' in config_host ? ['CONFIG_VHOST_KERNEL=y'] : []) + \
75
(have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \
76
('CONFIG_LINUX' in config_host ? ['CONFIG_LINUX=y'] : []) + \
77
- ('CONFIG_PVRDMA' in config_host ? ['CONFIG_PVRDMA=y'] : [])
78
+ ('CONFIG_PVRDMA' in config_host ? ['CONFIG_PVRDMA=y'] : []) + \
79
+ ('CONFIG_MULTIPROCESS_ALLOWED' in config_host ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : [])
80
81
ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
82
83
@@ -XXX,XX +XXX,XX @@ summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')}
84
summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')}
85
summary_info += {'libudev': libudev.found()}
86
summary_info += {'FUSE lseek': fuse_lseek.found()}
87
+summary_info += {'Multiprocess QEMU': config_host.has_key('CONFIG_MULTIPROCESS_ALLOWED')}
88
summary(summary_info, bool_yn: true, section: 'Dependencies')
89
90
if not supported_cpus.contains(cpu)
91
diff --git a/Kconfig.host b/Kconfig.host
92
index XXXXXXX..XXXXXXX 100644
93
--- a/Kconfig.host
94
+++ b/Kconfig.host
95
@@ -XXX,XX +XXX,XX @@ config VIRTFS
96
97
config PVRDMA
98
bool
99
+
100
+config MULTIPROCESS_ALLOWED
101
+ bool
102
+ imply MULTIPROCESS
103
diff --git a/hw/Kconfig b/hw/Kconfig
104
index XXXXXXX..XXXXXXX 100644
105
--- a/hw/Kconfig
106
+++ b/hw/Kconfig
107
@@ -XXX,XX +XXX,XX @@ source pci-host/Kconfig
108
source pcmcia/Kconfig
109
source pci/Kconfig
110
source rdma/Kconfig
111
+source remote/Kconfig
112
source rtc/Kconfig
113
source scsi/Kconfig
114
source sd/Kconfig
115
diff --git a/hw/remote/Kconfig b/hw/remote/Kconfig
116
new file mode 100644
117
index XXXXXXX..XXXXXXX
118
--- /dev/null
119
+++ b/hw/remote/Kconfig
120
@@ -XXX,XX +XXX,XX @@
121
+config MULTIPROCESS
122
+ bool
123
+ depends on PCI && KVM
124
--
125
2.29.2
126
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
PCI host bridge is setup for the remote device process. It is
4
implemented using remote-pcihost object. It is an extension of the PCI
5
host bridge setup by QEMU.
6
Remote-pcihost configures a PCI bus which could be used by the remote
7
PCI device to latch on to.
8
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
10
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
11
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: 0871ba857abb2eafacde07e7fe66a3f12415bfb2.1611938319.git.jag.raman@oracle.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
MAINTAINERS | 2 +
17
include/hw/pci-host/remote.h | 29 ++++++++++++++
18
hw/pci-host/remote.c | 75 ++++++++++++++++++++++++++++++++++++
19
hw/pci-host/Kconfig | 3 ++
20
hw/pci-host/meson.build | 1 +
21
hw/remote/Kconfig | 1 +
22
6 files changed, 111 insertions(+)
23
create mode 100644 include/hw/pci-host/remote.h
24
create mode 100644 hw/pci-host/remote.c
25
26
diff --git a/MAINTAINERS b/MAINTAINERS
27
index XXXXXXX..XXXXXXX 100644
28
--- a/MAINTAINERS
29
+++ b/MAINTAINERS
30
@@ -XXX,XX +XXX,XX @@ M: John G Johnson <john.g.johnson@oracle.com>
31
S: Maintained
32
F: docs/devel/multi-process.rst
33
F: docs/system/multi-process.rst
34
+F: hw/pci-host/remote.c
35
+F: include/hw/pci-host/remote.h
36
37
Build and test automation
38
-------------------------
39
diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h
40
new file mode 100644
41
index XXXXXXX..XXXXXXX
42
--- /dev/null
43
+++ b/include/hw/pci-host/remote.h
44
@@ -XXX,XX +XXX,XX @@
45
+/*
46
+ * PCI Host for remote device
47
+ *
48
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
49
+ *
50
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
51
+ * See the COPYING file in the top-level directory.
52
+ *
53
+ */
54
+
55
+#ifndef REMOTE_PCIHOST_H
56
+#define REMOTE_PCIHOST_H
57
+
58
+#include "exec/memory.h"
59
+#include "hw/pci/pcie_host.h"
60
+
61
+#define TYPE_REMOTE_PCIHOST "remote-pcihost"
62
+OBJECT_DECLARE_SIMPLE_TYPE(RemotePCIHost, REMOTE_PCIHOST)
63
+
64
+struct RemotePCIHost {
65
+ /*< private >*/
66
+ PCIExpressHost parent_obj;
67
+ /*< public >*/
68
+
69
+ MemoryRegion *mr_pci_mem;
70
+ MemoryRegion *mr_sys_io;
71
+};
72
+
73
+#endif
74
diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/hw/pci-host/remote.c
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Remote PCI host device
82
+ *
83
+ * Unlike PCI host devices that model physical hardware, the purpose
84
+ * of this PCI host is to host multi-process QEMU devices.
85
+ *
86
+ * Multi-process QEMU extends the PCI host of a QEMU machine into a
87
+ * remote process. Any PCI device attached to the remote process is
88
+ * visible in the QEMU guest. This allows existing QEMU device models
89
+ * to be reused in the remote process.
90
+ *
91
+ * This PCI host is purely a container for PCI devices. It's fake in the
92
+ * sense that the guest never sees this PCI host and has no way of
93
+ * accessing it. Its job is just to provide the environment that QEMU
94
+ * PCI device models need when running in a remote process.
95
+ *
96
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
97
+ *
98
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
99
+ * See the COPYING file in the top-level directory.
100
+ *
101
+ */
102
+
103
+#include "qemu/osdep.h"
104
+#include "qemu-common.h"
105
+
106
+#include "hw/pci/pci.h"
107
+#include "hw/pci/pci_host.h"
108
+#include "hw/pci/pcie_host.h"
109
+#include "hw/qdev-properties.h"
110
+#include "hw/pci-host/remote.h"
111
+#include "exec/memory.h"
112
+
113
+static const char *remote_pcihost_root_bus_path(PCIHostState *host_bridge,
114
+ PCIBus *rootbus)
115
+{
116
+ return "0000:00";
117
+}
118
+
119
+static void remote_pcihost_realize(DeviceState *dev, Error **errp)
120
+{
121
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
122
+ RemotePCIHost *s = REMOTE_PCIHOST(dev);
123
+
124
+ pci->bus = pci_root_bus_new(DEVICE(s), "remote-pci",
125
+ s->mr_pci_mem, s->mr_sys_io,
126
+ 0, TYPE_PCIE_BUS);
127
+}
128
+
129
+static void remote_pcihost_class_init(ObjectClass *klass, void *data)
130
+{
131
+ DeviceClass *dc = DEVICE_CLASS(klass);
132
+ PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
133
+
134
+ hc->root_bus_path = remote_pcihost_root_bus_path;
135
+ dc->realize = remote_pcihost_realize;
136
+
137
+ dc->user_creatable = false;
138
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
139
+ dc->fw_name = "pci";
140
+}
141
+
142
+static const TypeInfo remote_pcihost_info = {
143
+ .name = TYPE_REMOTE_PCIHOST,
144
+ .parent = TYPE_PCIE_HOST_BRIDGE,
145
+ .instance_size = sizeof(RemotePCIHost),
146
+ .class_init = remote_pcihost_class_init,
147
+};
148
+
149
+static void remote_pcihost_register(void)
150
+{
151
+ type_register_static(&remote_pcihost_info);
152
+}
153
+
154
+type_init(remote_pcihost_register)
155
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
156
index XXXXXXX..XXXXXXX 100644
157
--- a/hw/pci-host/Kconfig
158
+++ b/hw/pci-host/Kconfig
159
@@ -XXX,XX +XXX,XX @@ config PCI_POWERNV
160
select PCI_EXPRESS
161
select MSI_NONBROKEN
162
select PCIE_PORT
163
+
164
+config REMOTE_PCIHOST
165
+ bool
166
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
167
index XXXXXXX..XXXXXXX 100644
168
--- a/hw/pci-host/meson.build
169
+++ b/hw/pci-host/meson.build
170
@@ -XXX,XX +XXX,XX @@ pci_ss.add(when: 'CONFIG_PCI_EXPRESS_XILINX', if_true: files('xilinx-pcie.c'))
171
pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c'))
172
pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c'))
173
pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
174
+pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
175
176
# PPC devices
177
pci_ss.add(when: 'CONFIG_PREP_PCI', if_true: files('prep.c'))
178
diff --git a/hw/remote/Kconfig b/hw/remote/Kconfig
179
index XXXXXXX..XXXXXXX 100644
180
--- a/hw/remote/Kconfig
181
+++ b/hw/remote/Kconfig
182
@@ -XXX,XX +XXX,XX @@
183
config MULTIPROCESS
184
bool
185
depends on PCI && KVM
186
+ select REMOTE_PCIHOST
187
--
188
2.29.2
189
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
x-remote-machine object sets up various subsystems of the remote
4
device process. Instantiate PCI host bridge object and initialize RAM, IO &
5
PCI memory regions.
6
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: c537f38d17f90453ca610c6b70cf3480274e0ba1.1611938319.git.jag.raman@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
MAINTAINERS | 2 ++
15
include/hw/pci-host/remote.h | 1 +
16
include/hw/remote/machine.h | 27 ++++++++++++++
17
hw/remote/machine.c | 70 ++++++++++++++++++++++++++++++++++++
18
hw/meson.build | 1 +
19
hw/remote/meson.build | 5 +++
20
6 files changed, 106 insertions(+)
21
create mode 100644 include/hw/remote/machine.h
22
create mode 100644 hw/remote/machine.c
23
create mode 100644 hw/remote/meson.build
24
25
diff --git a/MAINTAINERS b/MAINTAINERS
26
index XXXXXXX..XXXXXXX 100644
27
--- a/MAINTAINERS
28
+++ b/MAINTAINERS
29
@@ -XXX,XX +XXX,XX @@ F: docs/devel/multi-process.rst
30
F: docs/system/multi-process.rst
31
F: hw/pci-host/remote.c
32
F: include/hw/pci-host/remote.h
33
+F: hw/remote/machine.c
34
+F: include/hw/remote/machine.h
35
36
Build and test automation
37
-------------------------
38
diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/include/hw/pci-host/remote.h
41
+++ b/include/hw/pci-host/remote.h
42
@@ -XXX,XX +XXX,XX @@ struct RemotePCIHost {
43
44
MemoryRegion *mr_pci_mem;
45
MemoryRegion *mr_sys_io;
46
+ MemoryRegion *mr_sys_mem;
47
};
48
49
#endif
50
diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h
51
new file mode 100644
52
index XXXXXXX..XXXXXXX
53
--- /dev/null
54
+++ b/include/hw/remote/machine.h
55
@@ -XXX,XX +XXX,XX @@
56
+/*
57
+ * Remote machine configuration
58
+ *
59
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
60
+ *
61
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
62
+ * See the COPYING file in the top-level directory.
63
+ *
64
+ */
65
+
66
+#ifndef REMOTE_MACHINE_H
67
+#define REMOTE_MACHINE_H
68
+
69
+#include "qom/object.h"
70
+#include "hw/boards.h"
71
+#include "hw/pci-host/remote.h"
72
+
73
+struct RemoteMachineState {
74
+ MachineState parent_obj;
75
+
76
+ RemotePCIHost *host;
77
+};
78
+
79
+#define TYPE_REMOTE_MACHINE "x-remote-machine"
80
+OBJECT_DECLARE_SIMPLE_TYPE(RemoteMachineState, REMOTE_MACHINE)
81
+
82
+#endif
83
diff --git a/hw/remote/machine.c b/hw/remote/machine.c
84
new file mode 100644
85
index XXXXXXX..XXXXXXX
86
--- /dev/null
87
+++ b/hw/remote/machine.c
88
@@ -XXX,XX +XXX,XX @@
89
+/*
90
+ * Machine for remote device
91
+ *
92
+ * This machine type is used by the remote device process in multi-process
93
+ * QEMU. QEMU device models depend on parent busses, interrupt controllers,
94
+ * memory regions, etc. The remote machine type offers this environment so
95
+ * that QEMU device models can be used as remote devices.
96
+ *
97
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
98
+ *
99
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
100
+ * See the COPYING file in the top-level directory.
101
+ *
102
+ */
103
+
104
+#include "qemu/osdep.h"
105
+#include "qemu-common.h"
106
+
107
+#include "hw/remote/machine.h"
108
+#include "exec/address-spaces.h"
109
+#include "exec/memory.h"
110
+#include "qapi/error.h"
111
+
112
+static void remote_machine_init(MachineState *machine)
113
+{
114
+ MemoryRegion *system_memory, *system_io, *pci_memory;
115
+ RemoteMachineState *s = REMOTE_MACHINE(machine);
116
+ RemotePCIHost *rem_host;
117
+
118
+ system_memory = get_system_memory();
119
+ system_io = get_system_io();
120
+
121
+ pci_memory = g_new(MemoryRegion, 1);
122
+ memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
123
+
124
+ rem_host = REMOTE_PCIHOST(qdev_new(TYPE_REMOTE_PCIHOST));
125
+
126
+ rem_host->mr_pci_mem = pci_memory;
127
+ rem_host->mr_sys_mem = system_memory;
128
+ rem_host->mr_sys_io = system_io;
129
+
130
+ s->host = rem_host;
131
+
132
+ object_property_add_child(OBJECT(s), "remote-pcihost", OBJECT(rem_host));
133
+ memory_region_add_subregion_overlap(system_memory, 0x0, pci_memory, -1);
134
+
135
+ qdev_realize(DEVICE(rem_host), sysbus_get_default(), &error_fatal);
136
+}
137
+
138
+static void remote_machine_class_init(ObjectClass *oc, void *data)
139
+{
140
+ MachineClass *mc = MACHINE_CLASS(oc);
141
+
142
+ mc->init = remote_machine_init;
143
+ mc->desc = "Experimental remote machine";
144
+}
145
+
146
+static const TypeInfo remote_machine = {
147
+ .name = TYPE_REMOTE_MACHINE,
148
+ .parent = TYPE_MACHINE,
149
+ .instance_size = sizeof(RemoteMachineState),
150
+ .class_init = remote_machine_class_init,
151
+};
152
+
153
+static void remote_machine_register_types(void)
154
+{
155
+ type_register_static(&remote_machine);
156
+}
157
+
158
+type_init(remote_machine_register_types);
159
diff --git a/hw/meson.build b/hw/meson.build
160
index XXXXXXX..XXXXXXX 100644
161
--- a/hw/meson.build
162
+++ b/hw/meson.build
163
@@ -XXX,XX +XXX,XX @@ subdir('moxie')
164
subdir('nios2')
165
subdir('openrisc')
166
subdir('ppc')
167
+subdir('remote')
168
subdir('riscv')
169
subdir('rx')
170
subdir('s390x')
171
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
172
new file mode 100644
173
index XXXXXXX..XXXXXXX
174
--- /dev/null
175
+++ b/hw/remote/meson.build
176
@@ -XXX,XX +XXX,XX @@
177
+remote_ss = ss.source_set()
178
+
179
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c'))
180
+
181
+softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
182
--
183
2.29.2
184
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Adds qio_channel_writev_full_all() to transmit both data and FDs.
4
Refactors existing code to use this helper.
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
11
Message-id: 480fbf1fe4152495d60596c9b665124549b426a5.1611938319.git.jag.raman@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
include/io/channel.h | 25 +++++++++++++++++++++++++
15
io/channel.c | 15 ++++++++++++++-
16
2 files changed, 39 insertions(+), 1 deletion(-)
17
18
diff --git a/include/io/channel.h b/include/io/channel.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/io/channel.h
21
+++ b/include/io/channel.h
22
@@ -XXX,XX +XXX,XX @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
23
IOHandler *io_write,
24
void *opaque);
25
26
+/**
27
+ * qio_channel_writev_full_all:
28
+ * @ioc: the channel object
29
+ * @iov: the array of memory regions to write data from
30
+ * @niov: the length of the @iov array
31
+ * @fds: an array of file handles to send
32
+ * @nfds: number of file handles in @fds
33
+ * @errp: pointer to a NULL-initialized error object
34
+ *
35
+ *
36
+ * Behaves like qio_channel_writev_full but will attempt
37
+ * to send all data passed (file handles and memory regions).
38
+ * The function will wait for all requested data
39
+ * to be written, yielding from the current coroutine
40
+ * if required.
41
+ *
42
+ * Returns: 0 if all bytes were written, or -1 on error
43
+ */
44
+
45
+int qio_channel_writev_full_all(QIOChannel *ioc,
46
+ const struct iovec *iov,
47
+ size_t niov,
48
+ int *fds, size_t nfds,
49
+ Error **errp);
50
+
51
#endif /* QIO_CHANNEL_H */
52
diff --git a/io/channel.c b/io/channel.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/io/channel.c
55
+++ b/io/channel.c
56
@@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc,
57
const struct iovec *iov,
58
size_t niov,
59
Error **errp)
60
+{
61
+ return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, errp);
62
+}
63
+
64
+int qio_channel_writev_full_all(QIOChannel *ioc,
65
+ const struct iovec *iov,
66
+ size_t niov,
67
+ int *fds, size_t nfds,
68
+ Error **errp)
69
{
70
int ret = -1;
71
struct iovec *local_iov = g_new(struct iovec, niov);
72
@@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc,
73
74
while (nlocal_iov > 0) {
75
ssize_t len;
76
- len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
77
+ len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, nfds,
78
+ errp);
79
if (len == QIO_CHANNEL_ERR_BLOCK) {
80
if (qemu_in_coroutine()) {
81
qio_channel_yield(ioc, G_IO_OUT);
82
@@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc,
83
}
84
85
iov_discard_front(&local_iov, &nlocal_iov, len);
86
+
87
+ fds = NULL;
88
+ nfds = 0;
89
}
90
91
ret = 0;
92
--
93
2.29.2
94
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Adds qio_channel_readv_full_all_eof() and qio_channel_readv_full_all()
4
to read both data and FDs. Refactors existing code to use these helpers.
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
10
Message-id: b059c4cc0fb741e794d644c144cc21372cad877d.1611938319.git.jag.raman@oracle.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
include/io/channel.h | 53 +++++++++++++++++++++++
14
io/channel.c | 101 ++++++++++++++++++++++++++++++++++---------
15
2 files changed, 134 insertions(+), 20 deletions(-)
16
17
diff --git a/include/io/channel.h b/include/io/channel.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/io/channel.h
20
+++ b/include/io/channel.h
21
@@ -XXX,XX +XXX,XX @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
22
IOHandler *io_write,
23
void *opaque);
24
25
+/**
26
+ * qio_channel_readv_full_all_eof:
27
+ * @ioc: the channel object
28
+ * @iov: the array of memory regions to read data to
29
+ * @niov: the length of the @iov array
30
+ * @fds: an array of file handles to read
31
+ * @nfds: number of file handles in @fds
32
+ * @errp: pointer to a NULL-initialized error object
33
+ *
34
+ *
35
+ * Performs same function as qio_channel_readv_all_eof.
36
+ * Additionally, attempts to read file descriptors shared
37
+ * over the channel. The function will wait for all
38
+ * requested data to be read, yielding from the current
39
+ * coroutine if required. data refers to both file
40
+ * descriptors and the iovs.
41
+ *
42
+ * Returns: 1 if all bytes were read, 0 if end-of-file
43
+ * occurs without data, or -1 on error
44
+ */
45
+
46
+int qio_channel_readv_full_all_eof(QIOChannel *ioc,
47
+ const struct iovec *iov,
48
+ size_t niov,
49
+ int **fds, size_t *nfds,
50
+ Error **errp);
51
+
52
+/**
53
+ * qio_channel_readv_full_all:
54
+ * @ioc: the channel object
55
+ * @iov: the array of memory regions to read data to
56
+ * @niov: the length of the @iov array
57
+ * @fds: an array of file handles to read
58
+ * @nfds: number of file handles in @fds
59
+ * @errp: pointer to a NULL-initialized error object
60
+ *
61
+ *
62
+ * Performs same function as qio_channel_readv_all_eof.
63
+ * Additionally, attempts to read file descriptors shared
64
+ * over the channel. The function will wait for all
65
+ * requested data to be read, yielding from the current
66
+ * coroutine if required. data refers to both file
67
+ * descriptors and the iovs.
68
+ *
69
+ * Returns: 0 if all bytes were read, or -1 on error
70
+ */
71
+
72
+int qio_channel_readv_full_all(QIOChannel *ioc,
73
+ const struct iovec *iov,
74
+ size_t niov,
75
+ int **fds, size_t *nfds,
76
+ Error **errp);
77
+
78
/**
79
* qio_channel_writev_full_all:
80
* @ioc: the channel object
81
diff --git a/io/channel.c b/io/channel.c
82
index XXXXXXX..XXXXXXX 100644
83
--- a/io/channel.c
84
+++ b/io/channel.c
85
@@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
86
const struct iovec *iov,
87
size_t niov,
88
Error **errp)
89
+{
90
+ return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
91
+}
92
+
93
+int qio_channel_readv_all(QIOChannel *ioc,
94
+ const struct iovec *iov,
95
+ size_t niov,
96
+ Error **errp)
97
+{
98
+ return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp);
99
+}
100
+
101
+int qio_channel_readv_full_all_eof(QIOChannel *ioc,
102
+ const struct iovec *iov,
103
+ size_t niov,
104
+ int **fds, size_t *nfds,
105
+ Error **errp)
106
{
107
int ret = -1;
108
struct iovec *local_iov = g_new(struct iovec, niov);
109
struct iovec *local_iov_head = local_iov;
110
unsigned int nlocal_iov = niov;
111
+ int **local_fds = fds;
112
+ size_t *local_nfds = nfds;
113
bool partial = false;
114
115
+ if (nfds) {
116
+ *nfds = 0;
117
+ }
118
+
119
+ if (fds) {
120
+ *fds = NULL;
121
+ }
122
+
123
nlocal_iov = iov_copy(local_iov, nlocal_iov,
124
iov, niov,
125
0, iov_size(iov, niov));
126
127
- while (nlocal_iov > 0) {
128
+ while ((nlocal_iov > 0) || local_fds) {
129
ssize_t len;
130
- len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
131
+ len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
132
+ local_nfds, errp);
133
if (len == QIO_CHANNEL_ERR_BLOCK) {
134
if (qemu_in_coroutine()) {
135
qio_channel_yield(ioc, G_IO_IN);
136
@@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
137
qio_channel_wait(ioc, G_IO_IN);
138
}
139
continue;
140
- } else if (len < 0) {
141
- goto cleanup;
142
- } else if (len == 0) {
143
- if (partial) {
144
- error_setg(errp,
145
- "Unexpected end-of-file before all bytes were read");
146
- } else {
147
+ }
148
+
149
+ if (len == 0) {
150
+ if (local_nfds && *local_nfds) {
151
+ /*
152
+ * Got some FDs, but no data yet. This isn't an EOF
153
+ * scenario (yet), so carry on to try to read data
154
+ * on next loop iteration
155
+ */
156
+ goto next_iter;
157
+ } else if (!partial) {
158
+ /* No fds and no data - EOF before any data read */
159
ret = 0;
160
+ goto cleanup;
161
+ } else {
162
+ len = -1;
163
+ error_setg(errp,
164
+ "Unexpected end-of-file before all data were read");
165
+ /* Fallthrough into len < 0 handling */
166
+ }
167
+ }
168
+
169
+ if (len < 0) {
170
+ /* Close any FDs we previously received */
171
+ if (nfds && fds) {
172
+ size_t i;
173
+ for (i = 0; i < (*nfds); i++) {
174
+ close((*fds)[i]);
175
+ }
176
+ g_free(*fds);
177
+ *fds = NULL;
178
+ *nfds = 0;
179
}
180
goto cleanup;
181
}
182
183
+ if (nlocal_iov) {
184
+ iov_discard_front(&local_iov, &nlocal_iov, len);
185
+ }
186
+
187
+next_iter:
188
partial = true;
189
- iov_discard_front(&local_iov, &nlocal_iov, len);
190
+ local_fds = NULL;
191
+ local_nfds = NULL;
192
}
193
194
ret = 1;
195
@@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
196
return ret;
197
}
198
199
-int qio_channel_readv_all(QIOChannel *ioc,
200
- const struct iovec *iov,
201
- size_t niov,
202
- Error **errp)
203
+int qio_channel_readv_full_all(QIOChannel *ioc,
204
+ const struct iovec *iov,
205
+ size_t niov,
206
+ int **fds, size_t *nfds,
207
+ Error **errp)
208
{
209
- int ret = qio_channel_readv_all_eof(ioc, iov, niov, errp);
210
+ int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
211
212
if (ret == 0) {
213
- ret = -1;
214
- error_setg(errp,
215
- "Unexpected end-of-file before all bytes were read");
216
- } else if (ret == 1) {
217
- ret = 0;
218
+ error_prepend(errp,
219
+ "Unexpected end-of-file before all data were read.");
220
+ return -1;
221
}
222
+ if (ret == 1) {
223
+ return 0;
224
+ }
225
+
226
return ret;
227
}
228
229
--
230
2.29.2
231
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Defines MPQemuMsg, which is the message that is sent to the remote
4
process. This message is sent over QIOChannel and is used to
5
command the remote process to perform various tasks.
6
Define transmission functions used by proxy and by remote.
7
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
10
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: 56ca8bcf95195b2b195b08f6b9565b6d7410bce5.1611938319.git.jag.raman@oracle.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
MAINTAINERS | 2 +
16
meson.build | 1 +
17
hw/remote/trace.h | 1 +
18
include/hw/remote/mpqemu-link.h | 63 ++++++++++
19
include/sysemu/iothread.h | 6 +
20
hw/remote/mpqemu-link.c | 205 ++++++++++++++++++++++++++++++++
21
iothread.c | 6 +
22
hw/remote/meson.build | 1 +
23
hw/remote/trace-events | 4 +
24
9 files changed, 289 insertions(+)
25
create mode 100644 hw/remote/trace.h
26
create mode 100644 include/hw/remote/mpqemu-link.h
27
create mode 100644 hw/remote/mpqemu-link.c
28
create mode 100644 hw/remote/trace-events
29
30
diff --git a/MAINTAINERS b/MAINTAINERS
31
index XXXXXXX..XXXXXXX 100644
32
--- a/MAINTAINERS
33
+++ b/MAINTAINERS
34
@@ -XXX,XX +XXX,XX @@ F: hw/pci-host/remote.c
35
F: include/hw/pci-host/remote.h
36
F: hw/remote/machine.c
37
F: include/hw/remote/machine.h
38
+F: hw/remote/mpqemu-link.c
39
+F: include/hw/remote/mpqemu-link.h
40
41
Build and test automation
42
-------------------------
43
diff --git a/meson.build b/meson.build
44
index XXXXXXX..XXXXXXX 100644
45
--- a/meson.build
46
+++ b/meson.build
47
@@ -XXX,XX +XXX,XX @@ if have_system
48
'net',
49
'softmmu',
50
'ui',
51
+ 'hw/remote',
52
]
53
endif
54
trace_events_subdirs += [
55
diff --git a/hw/remote/trace.h b/hw/remote/trace.h
56
new file mode 100644
57
index XXXXXXX..XXXXXXX
58
--- /dev/null
59
+++ b/hw/remote/trace.h
60
@@ -0,0 +1 @@
61
+#include "trace/trace-hw_remote.h"
62
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
63
new file mode 100644
64
index XXXXXXX..XXXXXXX
65
--- /dev/null
66
+++ b/include/hw/remote/mpqemu-link.h
67
@@ -XXX,XX +XXX,XX @@
68
+/*
69
+ * Communication channel between QEMU and remote device process
70
+ *
71
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
72
+ *
73
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
74
+ * See the COPYING file in the top-level directory.
75
+ *
76
+ */
77
+
78
+#ifndef MPQEMU_LINK_H
79
+#define MPQEMU_LINK_H
80
+
81
+#include "qom/object.h"
82
+#include "qemu/thread.h"
83
+#include "io/channel.h"
84
+
85
+#define REMOTE_MAX_FDS 8
86
+
87
+#define MPQEMU_MSG_HDR_SIZE offsetof(MPQemuMsg, data.u64)
88
+
89
+/**
90
+ * MPQemuCmd:
91
+ *
92
+ * MPQemuCmd enum type to specify the command to be executed on the remote
93
+ * device.
94
+ *
95
+ * This uses a private protocol between QEMU and the remote process. vfio-user
96
+ * protocol would supersede this in the future.
97
+ *
98
+ */
99
+typedef enum {
100
+ MPQEMU_CMD_MAX,
101
+} MPQemuCmd;
102
+
103
+/**
104
+ * MPQemuMsg:
105
+ * @cmd: The remote command
106
+ * @size: Size of the data to be shared
107
+ * @data: Structured data
108
+ * @fds: File descriptors to be shared with remote device
109
+ *
110
+ * MPQemuMsg Format of the message sent to the remote device from QEMU.
111
+ *
112
+ */
113
+typedef struct {
114
+ int cmd;
115
+ size_t size;
116
+
117
+ union {
118
+ uint64_t u64;
119
+ } data;
120
+
121
+ int fds[REMOTE_MAX_FDS];
122
+ int num_fds;
123
+} MPQemuMsg;
124
+
125
+bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp);
126
+bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp);
127
+
128
+bool mpqemu_msg_valid(MPQemuMsg *msg);
129
+
130
+#endif
131
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
132
index XXXXXXX..XXXXXXX 100644
133
--- a/include/sysemu/iothread.h
134
+++ b/include/sysemu/iothread.h
135
@@ -XXX,XX +XXX,XX @@ IOThread *iothread_create(const char *id, Error **errp);
136
void iothread_stop(IOThread *iothread);
137
void iothread_destroy(IOThread *iothread);
138
139
+/*
140
+ * Returns true if executing withing IOThread context,
141
+ * false otherwise.
142
+ */
143
+bool qemu_in_iothread(void);
144
+
145
#endif /* IOTHREAD_H */
146
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
147
new file mode 100644
148
index XXXXXXX..XXXXXXX
149
--- /dev/null
150
+++ b/hw/remote/mpqemu-link.c
151
@@ -XXX,XX +XXX,XX @@
152
+/*
153
+ * Communication channel between QEMU and remote device process
154
+ *
155
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
156
+ *
157
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
158
+ * See the COPYING file in the top-level directory.
159
+ *
160
+ */
161
+
162
+#include "qemu/osdep.h"
163
+#include "qemu-common.h"
164
+
165
+#include "qemu/module.h"
166
+#include "hw/remote/mpqemu-link.h"
167
+#include "qapi/error.h"
168
+#include "qemu/iov.h"
169
+#include "qemu/error-report.h"
170
+#include "qemu/main-loop.h"
171
+#include "io/channel.h"
172
+#include "sysemu/iothread.h"
173
+#include "trace.h"
174
+
175
+/*
176
+ * Send message over the ioc QIOChannel.
177
+ * This function is safe to call from:
178
+ * - main loop in co-routine context. Will block the main loop if not in
179
+ * co-routine context;
180
+ * - vCPU thread with no co-routine context and if the channel is not part
181
+ * of the main loop handling;
182
+ * - IOThread within co-routine context, outside of co-routine context
183
+ * will block IOThread;
184
+ * Returns true if no errors were encountered, false otherwise.
185
+ */
186
+bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
187
+{
188
+ ERRP_GUARD();
189
+ bool iolock = qemu_mutex_iothread_locked();
190
+ bool iothread = qemu_in_iothread();
191
+ struct iovec send[2] = {0};
192
+ int *fds = NULL;
193
+ size_t nfds = 0;
194
+ bool ret = false;
195
+
196
+ send[0].iov_base = msg;
197
+ send[0].iov_len = MPQEMU_MSG_HDR_SIZE;
198
+
199
+ send[1].iov_base = (void *)&msg->data;
200
+ send[1].iov_len = msg->size;
201
+
202
+ if (msg->num_fds) {
203
+ nfds = msg->num_fds;
204
+ fds = msg->fds;
205
+ }
206
+
207
+ /*
208
+ * Dont use in IOThread out of co-routine context as
209
+ * it will block IOThread.
210
+ */
211
+ assert(qemu_in_coroutine() || !iothread);
212
+
213
+ /*
214
+ * Skip unlocking/locking iothread lock when the IOThread is running
215
+ * in co-routine context. Co-routine context is asserted above
216
+ * for IOThread case.
217
+ * Also skip lock handling while in a co-routine in the main context.
218
+ */
219
+ if (iolock && !iothread && !qemu_in_coroutine()) {
220
+ qemu_mutex_unlock_iothread();
221
+ }
222
+
223
+ if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send),
224
+ fds, nfds, errp)) {
225
+ ret = true;
226
+ } else {
227
+ trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds);
228
+ }
229
+
230
+ if (iolock && !iothread && !qemu_in_coroutine()) {
231
+ /* See above comment why skip locking here. */
232
+ qemu_mutex_lock_iothread();
233
+ }
234
+
235
+ return ret;
236
+}
237
+
238
+/*
239
+ * Read message from the ioc QIOChannel.
240
+ * This function is safe to call from:
241
+ * - From main loop in co-routine context. Will block the main loop if not in
242
+ * co-routine context;
243
+ * - From vCPU thread with no co-routine context and if the channel is not part
244
+ * of the main loop handling;
245
+ * - From IOThread within co-routine context, outside of co-routine context
246
+ * will block IOThread;
247
+ */
248
+static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
249
+ size_t *nfds, Error **errp)
250
+{
251
+ ERRP_GUARD();
252
+ struct iovec iov = { .iov_base = buf, .iov_len = len };
253
+ bool iolock = qemu_mutex_iothread_locked();
254
+ bool iothread = qemu_in_iothread();
255
+ int ret = -1;
256
+
257
+ /*
258
+ * Dont use in IOThread out of co-routine context as
259
+ * it will block IOThread.
260
+ */
261
+ assert(qemu_in_coroutine() || !iothread);
262
+
263
+ if (iolock && !iothread && !qemu_in_coroutine()) {
264
+ qemu_mutex_unlock_iothread();
265
+ }
266
+
267
+ ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
268
+
269
+ if (iolock && !iothread && !qemu_in_coroutine()) {
270
+ qemu_mutex_lock_iothread();
271
+ }
272
+
273
+ return (ret <= 0) ? ret : iov.iov_len;
274
+}
275
+
276
+bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
277
+{
278
+ ERRP_GUARD();
279
+ g_autofree int *fds = NULL;
280
+ size_t nfds = 0;
281
+ ssize_t len;
282
+ bool ret = false;
283
+
284
+ len = mpqemu_read(ioc, msg, MPQEMU_MSG_HDR_SIZE, &fds, &nfds, errp);
285
+ if (len <= 0) {
286
+ goto fail;
287
+ } else if (len != MPQEMU_MSG_HDR_SIZE) {
288
+ error_setg(errp, "Message header corrupted");
289
+ goto fail;
290
+ }
291
+
292
+ if (msg->size > sizeof(msg->data)) {
293
+ error_setg(errp, "Invalid size for message");
294
+ goto fail;
295
+ }
296
+
297
+ if (!msg->size) {
298
+ goto copy_fds;
299
+ }
300
+
301
+ len = mpqemu_read(ioc, &msg->data, msg->size, NULL, NULL, errp);
302
+ if (len <= 0) {
303
+ goto fail;
304
+ }
305
+ if (len != msg->size) {
306
+ error_setg(errp, "Unable to read full message");
307
+ goto fail;
308
+ }
309
+
310
+copy_fds:
311
+ msg->num_fds = nfds;
312
+ if (nfds > G_N_ELEMENTS(msg->fds)) {
313
+ error_setg(errp,
314
+ "Overflow error: received %zu fds, more than max of %d fds",
315
+ nfds, REMOTE_MAX_FDS);
316
+ goto fail;
317
+ }
318
+ if (nfds) {
319
+ memcpy(msg->fds, fds, nfds * sizeof(int));
320
+ }
321
+
322
+ ret = true;
323
+
324
+fail:
325
+ if (*errp) {
326
+ trace_mpqemu_recv_io_error(msg->cmd, msg->size, nfds);
327
+ }
328
+ while (*errp && nfds) {
329
+ close(fds[nfds - 1]);
330
+ nfds--;
331
+ }
332
+
333
+ return ret;
334
+}
335
+
336
+bool mpqemu_msg_valid(MPQemuMsg *msg)
337
+{
338
+ if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) {
339
+ return false;
340
+ }
341
+
342
+ /* Verify FDs. */
343
+ if (msg->num_fds >= REMOTE_MAX_FDS) {
344
+ return false;
345
+ }
346
+
347
+ if (msg->num_fds > 0) {
348
+ for (int i = 0; i < msg->num_fds; i++) {
349
+ if (fcntl(msg->fds[i], F_GETFL) == -1) {
350
+ return false;
351
+ }
352
+ }
353
+ }
354
+
355
+ return true;
356
+}
357
diff --git a/iothread.c b/iothread.c
358
index XXXXXXX..XXXXXXX 100644
359
--- a/iothread.c
360
+++ b/iothread.c
361
@@ -XXX,XX +XXX,XX @@ IOThread *iothread_by_id(const char *id)
362
{
363
return IOTHREAD(object_resolve_path_type(id, TYPE_IOTHREAD, NULL));
364
}
365
+
366
+bool qemu_in_iothread(void)
367
+{
368
+ return qemu_get_current_aio_context() == qemu_get_aio_context() ?
369
+ false : true;
370
+}
371
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
372
index XXXXXXX..XXXXXXX 100644
373
--- a/hw/remote/meson.build
374
+++ b/hw/remote/meson.build
375
@@ -XXX,XX +XXX,XX @@
376
remote_ss = ss.source_set()
377
378
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c'))
379
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
380
381
softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
382
diff --git a/hw/remote/trace-events b/hw/remote/trace-events
383
new file mode 100644
384
index XXXXXXX..XXXXXXX
385
--- /dev/null
386
+++ b/hw/remote/trace-events
387
@@ -XXX,XX +XXX,XX @@
388
+# multi-process trace events
389
+
390
+mpqemu_send_io_error(int cmd, int size, int nfds) "send command %d size %d, %d file descriptors to remote process"
391
+mpqemu_recv_io_error(int cmd, int size, int nfds) "failed to receive %d size %d, %d file descriptors to remote process"
392
--
393
2.29.2
394
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
Initializes the message handler function in the remote process. It is
4
called whenever there's an event pending on QIOChannel that registers
5
this function.
6
7
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: 99d38d8b93753a6409ac2340e858858cda59ab1b.1611938319.git.jag.raman@oracle.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
MAINTAINERS | 1 +
15
include/hw/remote/machine.h | 9 ++++++
16
hw/remote/message.c | 57 +++++++++++++++++++++++++++++++++++++
17
hw/remote/meson.build | 1 +
18
4 files changed, 68 insertions(+)
19
create mode 100644 hw/remote/message.c
20
21
diff --git a/MAINTAINERS b/MAINTAINERS
22
index XXXXXXX..XXXXXXX 100644
23
--- a/MAINTAINERS
24
+++ b/MAINTAINERS
25
@@ -XXX,XX +XXX,XX @@ F: hw/remote/machine.c
26
F: include/hw/remote/machine.h
27
F: hw/remote/mpqemu-link.c
28
F: include/hw/remote/mpqemu-link.h
29
+F: hw/remote/message.c
30
31
Build and test automation
32
-------------------------
33
diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h
34
index XXXXXXX..XXXXXXX 100644
35
--- a/include/hw/remote/machine.h
36
+++ b/include/hw/remote/machine.h
37
@@ -XXX,XX +XXX,XX @@
38
#include "qom/object.h"
39
#include "hw/boards.h"
40
#include "hw/pci-host/remote.h"
41
+#include "io/channel.h"
42
43
struct RemoteMachineState {
44
MachineState parent_obj;
45
@@ -XXX,XX +XXX,XX @@ struct RemoteMachineState {
46
RemotePCIHost *host;
47
};
48
49
+/* Used to pass to co-routine device and ioc. */
50
+typedef struct RemoteCommDev {
51
+ PCIDevice *dev;
52
+ QIOChannel *ioc;
53
+} RemoteCommDev;
54
+
55
#define TYPE_REMOTE_MACHINE "x-remote-machine"
56
OBJECT_DECLARE_SIMPLE_TYPE(RemoteMachineState, REMOTE_MACHINE)
57
58
+void coroutine_fn mpqemu_remote_msg_loop_co(void *data);
59
+
60
#endif
61
diff --git a/hw/remote/message.c b/hw/remote/message.c
62
new file mode 100644
63
index XXXXXXX..XXXXXXX
64
--- /dev/null
65
+++ b/hw/remote/message.c
66
@@ -XXX,XX +XXX,XX @@
67
+/*
68
+ * Copyright © 2020, 2021 Oracle and/or its affiliates.
69
+ *
70
+ * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
71
+ *
72
+ * See the COPYING file in the top-level directory.
73
+ *
74
+ */
75
+
76
+#include "qemu/osdep.h"
77
+#include "qemu-common.h"
78
+
79
+#include "hw/remote/machine.h"
80
+#include "io/channel.h"
81
+#include "hw/remote/mpqemu-link.h"
82
+#include "qapi/error.h"
83
+#include "sysemu/runstate.h"
84
+
85
+void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
86
+{
87
+ g_autofree RemoteCommDev *com = (RemoteCommDev *)data;
88
+ PCIDevice *pci_dev = NULL;
89
+ Error *local_err = NULL;
90
+
91
+ assert(com->ioc);
92
+
93
+ pci_dev = com->dev;
94
+ for (; !local_err;) {
95
+ MPQemuMsg msg = {0};
96
+
97
+ if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) {
98
+ break;
99
+ }
100
+
101
+ if (!mpqemu_msg_valid(&msg)) {
102
+ error_setg(&local_err, "Received invalid message from proxy"
103
+ "in remote process pid="FMT_pid"",
104
+ getpid());
105
+ break;
106
+ }
107
+
108
+ switch (msg.cmd) {
109
+ default:
110
+ error_setg(&local_err,
111
+ "Unknown command (%d) received for device %s"
112
+ " (pid="FMT_pid")",
113
+ msg.cmd, DEVICE(pci_dev)->id, getpid());
114
+ }
115
+ }
116
+
117
+ if (local_err) {
118
+ error_report_err(local_err);
119
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
120
+ } else {
121
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
122
+ }
123
+}
124
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
125
index XXXXXXX..XXXXXXX 100644
126
--- a/hw/remote/meson.build
127
+++ b/hw/remote/meson.build
128
@@ -XXX,XX +XXX,XX @@ remote_ss = ss.source_set()
129
130
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c'))
131
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
132
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
133
134
softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
135
--
136
2.29.2
137
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
Associate the file descriptor for a PCIDevice in remote process with
4
DeviceState object.
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: f405a2ed5d7518b87bea7c59cfdf334d67e5ee51.1611938319.git.jag.raman@oracle.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
MAINTAINERS | 1 +
14
hw/remote/remote-obj.c | 203 +++++++++++++++++++++++++++++++++++++++++
15
hw/remote/meson.build | 1 +
16
3 files changed, 205 insertions(+)
17
create mode 100644 hw/remote/remote-obj.c
18
19
diff --git a/MAINTAINERS b/MAINTAINERS
20
index XXXXXXX..XXXXXXX 100644
21
--- a/MAINTAINERS
22
+++ b/MAINTAINERS
23
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/machine.h
24
F: hw/remote/mpqemu-link.c
25
F: include/hw/remote/mpqemu-link.h
26
F: hw/remote/message.c
27
+F: hw/remote/remote-obj.c
28
29
Build and test automation
30
-------------------------
31
diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c
32
new file mode 100644
33
index XXXXXXX..XXXXXXX
34
--- /dev/null
35
+++ b/hw/remote/remote-obj.c
36
@@ -XXX,XX +XXX,XX @@
37
+/*
38
+ * Copyright © 2020, 2021 Oracle and/or its affiliates.
39
+ *
40
+ * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
41
+ *
42
+ * See the COPYING file in the top-level directory.
43
+ *
44
+ */
45
+
46
+#include "qemu/osdep.h"
47
+#include "qemu-common.h"
48
+
49
+#include "qemu/error-report.h"
50
+#include "qemu/notify.h"
51
+#include "qom/object_interfaces.h"
52
+#include "hw/qdev-core.h"
53
+#include "io/channel.h"
54
+#include "hw/qdev-core.h"
55
+#include "hw/remote/machine.h"
56
+#include "io/channel-util.h"
57
+#include "qapi/error.h"
58
+#include "sysemu/sysemu.h"
59
+#include "hw/pci/pci.h"
60
+#include "qemu/sockets.h"
61
+#include "monitor/monitor.h"
62
+
63
+#define TYPE_REMOTE_OBJECT "x-remote-object"
64
+OBJECT_DECLARE_TYPE(RemoteObject, RemoteObjectClass, REMOTE_OBJECT)
65
+
66
+struct RemoteObjectClass {
67
+ ObjectClass parent_class;
68
+
69
+ unsigned int nr_devs;
70
+ unsigned int max_devs;
71
+};
72
+
73
+struct RemoteObject {
74
+ /* private */
75
+ Object parent;
76
+
77
+ Notifier machine_done;
78
+
79
+ int32_t fd;
80
+ char *devid;
81
+
82
+ QIOChannel *ioc;
83
+
84
+ DeviceState *dev;
85
+ DeviceListener listener;
86
+};
87
+
88
+static void remote_object_set_fd(Object *obj, const char *str, Error **errp)
89
+{
90
+ RemoteObject *o = REMOTE_OBJECT(obj);
91
+ int fd = -1;
92
+
93
+ fd = monitor_fd_param(monitor_cur(), str, errp);
94
+ if (fd == -1) {
95
+ error_prepend(errp, "Could not parse remote object fd %s:", str);
96
+ return;
97
+ }
98
+
99
+ if (!fd_is_socket(fd)) {
100
+ error_setg(errp, "File descriptor '%s' is not a socket", str);
101
+ close(fd);
102
+ return;
103
+ }
104
+
105
+ o->fd = fd;
106
+}
107
+
108
+static void remote_object_set_devid(Object *obj, const char *str, Error **errp)
109
+{
110
+ RemoteObject *o = REMOTE_OBJECT(obj);
111
+
112
+ g_free(o->devid);
113
+
114
+ o->devid = g_strdup(str);
115
+}
116
+
117
+static void remote_object_unrealize_listener(DeviceListener *listener,
118
+ DeviceState *dev)
119
+{
120
+ RemoteObject *o = container_of(listener, RemoteObject, listener);
121
+
122
+ if (o->dev == dev) {
123
+ object_unref(OBJECT(o));
124
+ }
125
+}
126
+
127
+static void remote_object_machine_done(Notifier *notifier, void *data)
128
+{
129
+ RemoteObject *o = container_of(notifier, RemoteObject, machine_done);
130
+ DeviceState *dev = NULL;
131
+ QIOChannel *ioc = NULL;
132
+ Coroutine *co = NULL;
133
+ RemoteCommDev *comdev = NULL;
134
+ Error *err = NULL;
135
+
136
+ dev = qdev_find_recursive(sysbus_get_default(), o->devid);
137
+ if (!dev || !object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
138
+ error_report("%s is not a PCI device", o->devid);
139
+ return;
140
+ }
141
+
142
+ ioc = qio_channel_new_fd(o->fd, &err);
143
+ if (!ioc) {
144
+ error_report_err(err);
145
+ return;
146
+ }
147
+ qio_channel_set_blocking(ioc, false, NULL);
148
+
149
+ o->dev = dev;
150
+
151
+ o->listener.unrealize = remote_object_unrealize_listener;
152
+ device_listener_register(&o->listener);
153
+
154
+ /* co-routine should free this. */
155
+ comdev = g_new0(RemoteCommDev, 1);
156
+ *comdev = (RemoteCommDev) {
157
+ .ioc = ioc,
158
+ .dev = PCI_DEVICE(dev),
159
+ };
160
+
161
+ co = qemu_coroutine_create(mpqemu_remote_msg_loop_co, comdev);
162
+ qemu_coroutine_enter(co);
163
+}
164
+
165
+static void remote_object_init(Object *obj)
166
+{
167
+ RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj);
168
+ RemoteObject *o = REMOTE_OBJECT(obj);
169
+
170
+ if (k->nr_devs >= k->max_devs) {
171
+ error_report("Reached maximum number of devices: %u", k->max_devs);
172
+ return;
173
+ }
174
+
175
+ o->ioc = NULL;
176
+ o->fd = -1;
177
+ o->devid = NULL;
178
+
179
+ k->nr_devs++;
180
+
181
+ o->machine_done.notify = remote_object_machine_done;
182
+ qemu_add_machine_init_done_notifier(&o->machine_done);
183
+}
184
+
185
+static void remote_object_finalize(Object *obj)
186
+{
187
+ RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj);
188
+ RemoteObject *o = REMOTE_OBJECT(obj);
189
+
190
+ device_listener_unregister(&o->listener);
191
+
192
+ if (o->ioc) {
193
+ qio_channel_shutdown(o->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
194
+ qio_channel_close(o->ioc, NULL);
195
+ }
196
+
197
+ object_unref(OBJECT(o->ioc));
198
+
199
+ k->nr_devs--;
200
+ g_free(o->devid);
201
+}
202
+
203
+static void remote_object_class_init(ObjectClass *klass, void *data)
204
+{
205
+ RemoteObjectClass *k = REMOTE_OBJECT_CLASS(klass);
206
+
207
+ /*
208
+ * Limit number of supported devices to 1. This is done to avoid devices
209
+ * from one VM accessing the RAM of another VM. This is done until we
210
+ * start using separate address spaces for individual devices.
211
+ */
212
+ k->max_devs = 1;
213
+ k->nr_devs = 0;
214
+
215
+ object_class_property_add_str(klass, "fd", NULL, remote_object_set_fd);
216
+ object_class_property_add_str(klass, "devid", NULL,
217
+ remote_object_set_devid);
218
+}
219
+
220
+static const TypeInfo remote_object_info = {
221
+ .name = TYPE_REMOTE_OBJECT,
222
+ .parent = TYPE_OBJECT,
223
+ .instance_size = sizeof(RemoteObject),
224
+ .instance_init = remote_object_init,
225
+ .instance_finalize = remote_object_finalize,
226
+ .class_size = sizeof(RemoteObjectClass),
227
+ .class_init = remote_object_class_init,
228
+ .interfaces = (InterfaceInfo[]) {
229
+ { TYPE_USER_CREATABLE },
230
+ { }
231
+ }
232
+};
233
+
234
+static void register_types(void)
235
+{
236
+ type_register_static(&remote_object_info);
237
+}
238
+
239
+type_init(register_types);
240
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
241
index XXXXXXX..XXXXXXX 100644
242
--- a/hw/remote/meson.build
243
+++ b/hw/remote/meson.build
244
@@ -XXX,XX +XXX,XX @@ remote_ss = ss.source_set()
245
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c'))
246
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
247
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
248
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
249
250
softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
251
--
252
2.29.2
253
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
SyncSysMemMsg message format is defined. It is used to send
4
file descriptors of the RAM regions to remote device.
5
RAM on the remote device is configured with a set of file descriptors.
6
Old RAM regions are deleted and new regions, each with an fd, is
7
added to the RAM.
8
9
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
10
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
11
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: 7d2d1831d812e85f681e7a8ab99e032cf4704689.1611938319.git.jag.raman@oracle.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
MAINTAINERS | 2 +
17
include/hw/remote/memory.h | 19 ++++++++++
18
include/hw/remote/mpqemu-link.h | 10 +++++
19
hw/remote/memory.c | 65 +++++++++++++++++++++++++++++++++
20
hw/remote/mpqemu-link.c | 11 ++++++
21
hw/remote/meson.build | 2 +
22
6 files changed, 109 insertions(+)
23
create mode 100644 include/hw/remote/memory.h
24
create mode 100644 hw/remote/memory.c
25
26
diff --git a/MAINTAINERS b/MAINTAINERS
27
index XXXXXXX..XXXXXXX 100644
28
--- a/MAINTAINERS
29
+++ b/MAINTAINERS
30
@@ -XXX,XX +XXX,XX @@ F: hw/remote/mpqemu-link.c
31
F: include/hw/remote/mpqemu-link.h
32
F: hw/remote/message.c
33
F: hw/remote/remote-obj.c
34
+F: include/hw/remote/memory.h
35
+F: hw/remote/memory.c
36
37
Build and test automation
38
-------------------------
39
diff --git a/include/hw/remote/memory.h b/include/hw/remote/memory.h
40
new file mode 100644
41
index XXXXXXX..XXXXXXX
42
--- /dev/null
43
+++ b/include/hw/remote/memory.h
44
@@ -XXX,XX +XXX,XX @@
45
+/*
46
+ * Memory manager for remote device
47
+ *
48
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
49
+ *
50
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
51
+ * See the COPYING file in the top-level directory.
52
+ *
53
+ */
54
+
55
+#ifndef REMOTE_MEMORY_H
56
+#define REMOTE_MEMORY_H
57
+
58
+#include "exec/hwaddr.h"
59
+#include "hw/remote/mpqemu-link.h"
60
+
61
+void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp);
62
+
63
+#endif
64
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/hw/remote/mpqemu-link.h
67
+++ b/include/hw/remote/mpqemu-link.h
68
@@ -XXX,XX +XXX,XX @@
69
#include "qom/object.h"
70
#include "qemu/thread.h"
71
#include "io/channel.h"
72
+#include "exec/hwaddr.h"
73
74
#define REMOTE_MAX_FDS 8
75
76
@@ -XXX,XX +XXX,XX @@
77
*
78
*/
79
typedef enum {
80
+ MPQEMU_CMD_SYNC_SYSMEM,
81
MPQEMU_CMD_MAX,
82
} MPQemuCmd;
83
84
+typedef struct {
85
+ hwaddr gpas[REMOTE_MAX_FDS];
86
+ uint64_t sizes[REMOTE_MAX_FDS];
87
+ off_t offsets[REMOTE_MAX_FDS];
88
+} SyncSysmemMsg;
89
+
90
/**
91
* MPQemuMsg:
92
* @cmd: The remote command
93
@@ -XXX,XX +XXX,XX @@ typedef enum {
94
* MPQemuMsg Format of the message sent to the remote device from QEMU.
95
*
96
*/
97
+
98
typedef struct {
99
int cmd;
100
size_t size;
101
102
union {
103
uint64_t u64;
104
+ SyncSysmemMsg sync_sysmem;
105
} data;
106
107
int fds[REMOTE_MAX_FDS];
108
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
109
new file mode 100644
110
index XXXXXXX..XXXXXXX
111
--- /dev/null
112
+++ b/hw/remote/memory.c
113
@@ -XXX,XX +XXX,XX @@
114
+/*
115
+ * Memory manager for remote device
116
+ *
117
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
118
+ *
119
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
120
+ * See the COPYING file in the top-level directory.
121
+ *
122
+ */
123
+
124
+#include "qemu/osdep.h"
125
+#include "qemu-common.h"
126
+
127
+#include "hw/remote/memory.h"
128
+#include "exec/address-spaces.h"
129
+#include "exec/ram_addr.h"
130
+#include "qapi/error.h"
131
+
132
+static void remote_sysmem_reset(void)
133
+{
134
+ MemoryRegion *sysmem, *subregion, *next;
135
+
136
+ sysmem = get_system_memory();
137
+
138
+ QTAILQ_FOREACH_SAFE(subregion, &sysmem->subregions, subregions_link, next) {
139
+ if (subregion->ram) {
140
+ memory_region_del_subregion(sysmem, subregion);
141
+ object_unparent(OBJECT(subregion));
142
+ }
143
+ }
144
+}
145
+
146
+void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
147
+{
148
+ ERRP_GUARD();
149
+ SyncSysmemMsg *sysmem_info = &msg->data.sync_sysmem;
150
+ MemoryRegion *sysmem, *subregion;
151
+ static unsigned int suffix;
152
+ int region;
153
+
154
+ sysmem = get_system_memory();
155
+
156
+ remote_sysmem_reset();
157
+
158
+ for (region = 0; region < msg->num_fds; region++) {
159
+ g_autofree char *name;
160
+ subregion = g_new(MemoryRegion, 1);
161
+ name = g_strdup_printf("remote-mem-%u", suffix++);
162
+ memory_region_init_ram_from_fd(subregion, NULL,
163
+ name, sysmem_info->sizes[region],
164
+ true, msg->fds[region],
165
+ sysmem_info->offsets[region],
166
+ errp);
167
+
168
+ if (*errp) {
169
+ g_free(subregion);
170
+ remote_sysmem_reset();
171
+ return;
172
+ }
173
+
174
+ memory_region_add_subregion(sysmem, sysmem_info->gpas[region],
175
+ subregion);
176
+
177
+ }
178
+}
179
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
180
index XXXXXXX..XXXXXXX 100644
181
--- a/hw/remote/mpqemu-link.c
182
+++ b/hw/remote/mpqemu-link.c
183
@@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg)
184
}
185
}
186
187
+ /* Verify message specific fields. */
188
+ switch (msg->cmd) {
189
+ case MPQEMU_CMD_SYNC_SYSMEM:
190
+ if (msg->num_fds == 0 || msg->size != sizeof(SyncSysmemMsg)) {
191
+ return false;
192
+ }
193
+ break;
194
+ default:
195
+ break;
196
+ }
197
+
198
return true;
199
}
200
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
201
index XXXXXXX..XXXXXXX 100644
202
--- a/hw/remote/meson.build
203
+++ b/hw/remote/meson.build
204
@@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
205
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
206
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
207
208
+specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c'))
209
+
210
softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss)
211
--
212
2.29.2
213
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Defines a PCI Device proxy object as a child of TYPE_PCI_DEVICE.
4
5
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
6
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: b5186ebfedf8e557044d09a768846c59230ad3a7.1611938319.git.jag.raman@oracle.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
MAINTAINERS | 2 +
13
include/hw/remote/proxy.h | 33 +++++++++++++
14
hw/remote/proxy.c | 99 +++++++++++++++++++++++++++++++++++++++
15
hw/remote/meson.build | 1 +
16
4 files changed, 135 insertions(+)
17
create mode 100644 include/hw/remote/proxy.h
18
create mode 100644 hw/remote/proxy.c
19
20
diff --git a/MAINTAINERS b/MAINTAINERS
21
index XXXXXXX..XXXXXXX 100644
22
--- a/MAINTAINERS
23
+++ b/MAINTAINERS
24
@@ -XXX,XX +XXX,XX @@ F: hw/remote/message.c
25
F: hw/remote/remote-obj.c
26
F: include/hw/remote/memory.h
27
F: hw/remote/memory.c
28
+F: hw/remote/proxy.c
29
+F: include/hw/remote/proxy.h
30
31
Build and test automation
32
-------------------------
33
diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h
34
new file mode 100644
35
index XXXXXXX..XXXXXXX
36
--- /dev/null
37
+++ b/include/hw/remote/proxy.h
38
@@ -XXX,XX +XXX,XX @@
39
+/*
40
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
41
+ *
42
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
43
+ * See the COPYING file in the top-level directory.
44
+ *
45
+ */
46
+
47
+#ifndef PROXY_H
48
+#define PROXY_H
49
+
50
+#include "hw/pci/pci.h"
51
+#include "io/channel.h"
52
+
53
+#define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev"
54
+OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV)
55
+
56
+struct PCIProxyDev {
57
+ PCIDevice parent_dev;
58
+ char *fd;
59
+
60
+ /*
61
+ * Mutex used to protect the QIOChannel fd from
62
+ * the concurrent access by the VCPUs since proxy
63
+ * blocks while awaiting for the replies from the
64
+ * process remote.
65
+ */
66
+ QemuMutex io_mutex;
67
+ QIOChannel *ioc;
68
+ Error *migration_blocker;
69
+};
70
+
71
+#endif /* PROXY_H */
72
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
73
new file mode 100644
74
index XXXXXXX..XXXXXXX
75
--- /dev/null
76
+++ b/hw/remote/proxy.c
77
@@ -XXX,XX +XXX,XX @@
78
+/*
79
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
80
+ *
81
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
82
+ * See the COPYING file in the top-level directory.
83
+ *
84
+ */
85
+
86
+#include "qemu/osdep.h"
87
+#include "qemu-common.h"
88
+
89
+#include "hw/remote/proxy.h"
90
+#include "hw/pci/pci.h"
91
+#include "qapi/error.h"
92
+#include "io/channel-util.h"
93
+#include "hw/qdev-properties.h"
94
+#include "monitor/monitor.h"
95
+#include "migration/blocker.h"
96
+#include "qemu/sockets.h"
97
+
98
+static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
99
+{
100
+ ERRP_GUARD();
101
+ PCIProxyDev *dev = PCI_PROXY_DEV(device);
102
+ int fd;
103
+
104
+ if (!dev->fd) {
105
+ error_setg(errp, "fd parameter not specified for %s",
106
+ DEVICE(device)->id);
107
+ return;
108
+ }
109
+
110
+ fd = monitor_fd_param(monitor_cur(), dev->fd, errp);
111
+ if (fd == -1) {
112
+ error_prepend(errp, "proxy: unable to parse fd %s: ", dev->fd);
113
+ return;
114
+ }
115
+
116
+ if (!fd_is_socket(fd)) {
117
+ error_setg(errp, "proxy: fd %d is not a socket", fd);
118
+ close(fd);
119
+ return;
120
+ }
121
+
122
+ dev->ioc = qio_channel_new_fd(fd, errp);
123
+
124
+ error_setg(&dev->migration_blocker, "%s does not support migration",
125
+ TYPE_PCI_PROXY_DEV);
126
+ migrate_add_blocker(dev->migration_blocker, errp);
127
+
128
+ qemu_mutex_init(&dev->io_mutex);
129
+ qio_channel_set_blocking(dev->ioc, true, NULL);
130
+}
131
+
132
+static void pci_proxy_dev_exit(PCIDevice *pdev)
133
+{
134
+ PCIProxyDev *dev = PCI_PROXY_DEV(pdev);
135
+
136
+ if (dev->ioc) {
137
+ qio_channel_close(dev->ioc, NULL);
138
+ }
139
+
140
+ migrate_del_blocker(dev->migration_blocker);
141
+
142
+ error_free(dev->migration_blocker);
143
+}
144
+
145
+static Property proxy_properties[] = {
146
+ DEFINE_PROP_STRING("fd", PCIProxyDev, fd),
147
+ DEFINE_PROP_END_OF_LIST(),
148
+};
149
+
150
+static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
151
+{
152
+ DeviceClass *dc = DEVICE_CLASS(klass);
153
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
154
+
155
+ k->realize = pci_proxy_dev_realize;
156
+ k->exit = pci_proxy_dev_exit;
157
+ device_class_set_props(dc, proxy_properties);
158
+}
159
+
160
+static const TypeInfo pci_proxy_dev_type_info = {
161
+ .name = TYPE_PCI_PROXY_DEV,
162
+ .parent = TYPE_PCI_DEVICE,
163
+ .instance_size = sizeof(PCIProxyDev),
164
+ .class_init = pci_proxy_dev_class_init,
165
+ .interfaces = (InterfaceInfo[]) {
166
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
167
+ { },
168
+ },
169
+};
170
+
171
+static void pci_proxy_dev_register_types(void)
172
+{
173
+ type_register_static(&pci_proxy_dev_type_info);
174
+}
175
+
176
+type_init(pci_proxy_dev_register_types)
177
diff --git a/hw/remote/meson.build b/hw/remote/meson.build
178
index XXXXXXX..XXXXXXX 100644
179
--- a/hw/remote/meson.build
180
+++ b/hw/remote/meson.build
181
@@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c'))
182
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c'))
183
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c'))
184
remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c'))
185
+remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c'))
186
187
specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c'))
188
189
--
190
2.29.2
191
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
4
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
5
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-id: d54edb4176361eed86b903e8f27058363b6c83b3.1611938319.git.jag.raman@oracle.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
include/hw/remote/mpqemu-link.h | 4 ++++
11
hw/remote/mpqemu-link.c | 34 +++++++++++++++++++++++++++++++++
12
2 files changed, 38 insertions(+)
13
14
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/remote/mpqemu-link.h
17
+++ b/include/hw/remote/mpqemu-link.h
18
@@ -XXX,XX +XXX,XX @@
19
#include "qemu/thread.h"
20
#include "io/channel.h"
21
#include "exec/hwaddr.h"
22
+#include "io/channel-socket.h"
23
+#include "hw/remote/proxy.h"
24
25
#define REMOTE_MAX_FDS 8
26
27
@@ -XXX,XX +XXX,XX @@ typedef struct {
28
bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp);
29
bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp);
30
31
+uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
32
+ Error **errp);
33
bool mpqemu_msg_valid(MPQemuMsg *msg);
34
35
#endif
36
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/remote/mpqemu-link.c
39
+++ b/hw/remote/mpqemu-link.c
40
@@ -XXX,XX +XXX,XX @@ fail:
41
return ret;
42
}
43
44
+/*
45
+ * Send msg and wait for a reply with command code RET_MSG.
46
+ * Returns the message received of size u64 or UINT64_MAX
47
+ * on error.
48
+ * Called from VCPU thread in non-coroutine context.
49
+ * Used by the Proxy object to communicate to remote processes.
50
+ */
51
+uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
52
+ Error **errp)
53
+{
54
+ ERRP_GUARD();
55
+ MPQemuMsg msg_reply = {0};
56
+ uint64_t ret = UINT64_MAX;
57
+
58
+ assert(!qemu_in_coroutine());
59
+
60
+ QEMU_LOCK_GUARD(&pdev->io_mutex);
61
+ if (!mpqemu_msg_send(msg, pdev->ioc, errp)) {
62
+ return ret;
63
+ }
64
+
65
+ if (!mpqemu_msg_recv(&msg_reply, pdev->ioc, errp)) {
66
+ return ret;
67
+ }
68
+
69
+ if (!mpqemu_msg_valid(&msg_reply)) {
70
+ error_setg(errp, "ERROR: Invalid reply received for command %d",
71
+ msg->cmd);
72
+ return ret;
73
+ }
74
+
75
+ return msg_reply.data.u64;
76
+}
77
+
78
bool mpqemu_msg_valid(MPQemuMsg *msg)
79
{
80
if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) {
81
--
82
2.29.2
83
diff view generated by jsdifflib
Deleted patch
1
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
2
1
3
The Proxy Object sends the PCI config space accesses as messages
4
to the remote process over the communication channel
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
8
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: d3c94f4618813234655356c60e6f0d0362ff42d6.1611938319.git.jag.raman@oracle.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
include/hw/remote/mpqemu-link.h | 10 ++++++
14
hw/remote/message.c | 60 +++++++++++++++++++++++++++++++++
15
hw/remote/mpqemu-link.c | 8 ++++-
16
hw/remote/proxy.c | 55 ++++++++++++++++++++++++++++++
17
4 files changed, 132 insertions(+), 1 deletion(-)
18
19
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/remote/mpqemu-link.h
22
+++ b/include/hw/remote/mpqemu-link.h
23
@@ -XXX,XX +XXX,XX @@
24
*/
25
typedef enum {
26
MPQEMU_CMD_SYNC_SYSMEM,
27
+ MPQEMU_CMD_RET,
28
+ MPQEMU_CMD_PCI_CFGWRITE,
29
+ MPQEMU_CMD_PCI_CFGREAD,
30
MPQEMU_CMD_MAX,
31
} MPQemuCmd;
32
33
@@ -XXX,XX +XXX,XX @@ typedef struct {
34
off_t offsets[REMOTE_MAX_FDS];
35
} SyncSysmemMsg;
36
37
+typedef struct {
38
+ uint32_t addr;
39
+ uint32_t val;
40
+ int len;
41
+} PciConfDataMsg;
42
+
43
/**
44
* MPQemuMsg:
45
* @cmd: The remote command
46
@@ -XXX,XX +XXX,XX @@ typedef struct {
47
48
union {
49
uint64_t u64;
50
+ PciConfDataMsg pci_conf_data;
51
SyncSysmemMsg sync_sysmem;
52
} data;
53
54
diff --git a/hw/remote/message.c b/hw/remote/message.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/hw/remote/message.c
57
+++ b/hw/remote/message.c
58
@@ -XXX,XX +XXX,XX @@
59
#include "hw/remote/mpqemu-link.h"
60
#include "qapi/error.h"
61
#include "sysemu/runstate.h"
62
+#include "hw/pci/pci.h"
63
+
64
+static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
65
+ MPQemuMsg *msg, Error **errp);
66
+static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
67
+ MPQemuMsg *msg, Error **errp);
68
69
void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
70
{
71
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
72
}
73
74
switch (msg.cmd) {
75
+ case MPQEMU_CMD_PCI_CFGWRITE:
76
+ process_config_write(com->ioc, pci_dev, &msg, &local_err);
77
+ break;
78
+ case MPQEMU_CMD_PCI_CFGREAD:
79
+ process_config_read(com->ioc, pci_dev, &msg, &local_err);
80
+ break;
81
default:
82
error_setg(&local_err,
83
"Unknown command (%d) received for device %s"
84
@@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
85
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
86
}
87
}
88
+
89
+static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
90
+ MPQemuMsg *msg, Error **errp)
91
+{
92
+ ERRP_GUARD();
93
+ PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
94
+ MPQemuMsg ret = { 0 };
95
+
96
+ if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
97
+ error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
98
+ getpid());
99
+ ret.data.u64 = UINT64_MAX;
100
+ } else {
101
+ pci_default_write_config(dev, conf->addr, conf->val, conf->len);
102
+ }
103
+
104
+ ret.cmd = MPQEMU_CMD_RET;
105
+ ret.size = sizeof(ret.data.u64);
106
+
107
+ if (!mpqemu_msg_send(&ret, ioc, NULL)) {
108
+ error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
109
+ getpid());
110
+ }
111
+}
112
+
113
+static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
114
+ MPQemuMsg *msg, Error **errp)
115
+{
116
+ ERRP_GUARD();
117
+ PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
118
+ MPQemuMsg ret = { 0 };
119
+
120
+ if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
121
+ error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
122
+ getpid());
123
+ ret.data.u64 = UINT64_MAX;
124
+ } else {
125
+ ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
126
+ }
127
+
128
+ ret.cmd = MPQEMU_CMD_RET;
129
+ ret.size = sizeof(ret.data.u64);
130
+
131
+ if (!mpqemu_msg_send(&ret, ioc, NULL)) {
132
+ error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
133
+ getpid());
134
+ }
135
+}
136
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/hw/remote/mpqemu-link.c
139
+++ b/hw/remote/mpqemu-link.c
140
@@ -XXX,XX +XXX,XX @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
141
return ret;
142
}
143
144
- if (!mpqemu_msg_valid(&msg_reply)) {
145
+ if (!mpqemu_msg_valid(&msg_reply) || msg_reply.cmd != MPQEMU_CMD_RET) {
146
error_setg(errp, "ERROR: Invalid reply received for command %d",
147
msg->cmd);
148
return ret;
149
@@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg)
150
return false;
151
}
152
break;
153
+ case MPQEMU_CMD_PCI_CFGWRITE:
154
+ case MPQEMU_CMD_PCI_CFGREAD:
155
+ if (msg->size != sizeof(PciConfDataMsg)) {
156
+ return false;
157
+ }
158
+ break;
159
default:
160
break;
161
}
162
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/remote/proxy.c
165
+++ b/hw/remote/proxy.c
166
@@ -XXX,XX +XXX,XX @@
167
#include "monitor/monitor.h"
168
#include "migration/blocker.h"
169
#include "qemu/sockets.h"
170
+#include "hw/remote/mpqemu-link.h"
171
+#include "qemu/error-report.h"
172
173
static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
174
{
175
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev)
176
error_free(dev->migration_blocker);
177
}
178
179
+static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
180
+ int len, unsigned int op)
181
+{
182
+ MPQemuMsg msg = { 0 };
183
+ uint64_t ret = -EINVAL;
184
+ Error *local_err = NULL;
185
+
186
+ msg.cmd = op;
187
+ msg.data.pci_conf_data.addr = addr;
188
+ msg.data.pci_conf_data.val = (op == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0;
189
+ msg.data.pci_conf_data.len = len;
190
+ msg.size = sizeof(PciConfDataMsg);
191
+
192
+ ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
193
+ if (local_err) {
194
+ error_report_err(local_err);
195
+ }
196
+
197
+ if (ret == UINT64_MAX) {
198
+ error_report("Failed to perform PCI config %s operation",
199
+ (op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE");
200
+ }
201
+
202
+ if (op == MPQEMU_CMD_PCI_CFGREAD) {
203
+ *val = (uint32_t)ret;
204
+ }
205
+}
206
+
207
+static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len)
208
+{
209
+ uint32_t val;
210
+
211
+ config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD);
212
+
213
+ return val;
214
+}
215
+
216
+static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val,
217
+ int len)
218
+{
219
+ /*
220
+ * Some of the functions access the copy of remote device's PCI config
221
+ * space which is cached in the proxy device. Therefore, maintain
222
+ * it updated.
223
+ */
224
+ pci_default_write_config(d, addr, val, len);
225
+
226
+ config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE);
227
+}
228
+
229
static Property proxy_properties[] = {
230
DEFINE_PROP_STRING("fd", PCIProxyDev, fd),
231
DEFINE_PROP_END_OF_LIST(),
232
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
233
234
k->realize = pci_proxy_dev_realize;
235
k->exit = pci_proxy_dev_exit;
236
+ k->config_read = pci_proxy_read_config;
237
+ k->config_write = pci_proxy_write_config;
238
+
239
device_class_set_props(dc, proxy_properties);
240
}
241
242
--
243
2.29.2
244
diff view generated by jsdifflib
Deleted patch
1
From: Jagannathan Raman <jag.raman@oracle.com>
2
1
3
Retrieve PCI configuration info about the remote device and
4
configure the Proxy PCI object based on the returned information
5
6
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
7
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
8
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: 85ee367bbb993aa23699b44cfedd83b4ea6d5221.1611938319.git.jag.raman@oracle.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
hw/remote/proxy.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
14
1 file changed, 84 insertions(+)
15
16
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/remote/proxy.c
19
+++ b/hw/remote/proxy.c
20
@@ -XXX,XX +XXX,XX @@
21
#include "sysemu/kvm.h"
22
#include "util/event_notifier-posix.c"
23
24
+static void probe_pci_info(PCIDevice *dev, Error **errp);
25
+
26
static void proxy_intx_update(PCIDevice *pci_dev)
27
{
28
PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev);
29
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
30
{
31
ERRP_GUARD();
32
PCIProxyDev *dev = PCI_PROXY_DEV(device);
33
+ uint8_t *pci_conf = device->config;
34
int fd;
35
36
if (!dev->fd) {
37
@@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
38
qemu_mutex_init(&dev->io_mutex);
39
qio_channel_set_blocking(dev->ioc, true, NULL);
40
41
+ pci_conf[PCI_LATENCY_TIMER] = 0xff;
42
+ pci_conf[PCI_INTERRUPT_PIN] = 0x01;
43
+
44
proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc);
45
46
setup_irqfd(dev);
47
+
48
+ probe_pci_info(PCI_DEVICE(dev), errp);
49
}
50
51
static void pci_proxy_dev_exit(PCIDevice *pdev)
52
@@ -XXX,XX +XXX,XX @@ const MemoryRegionOps proxy_mr_ops = {
53
.max_access_size = 8,
54
},
55
};
56
+
57
+static void probe_pci_info(PCIDevice *dev, Error **errp)
58
+{
59
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
60
+ uint32_t orig_val, new_val, base_class, val;
61
+ PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
62
+ DeviceClass *dc = DEVICE_CLASS(pc);
63
+ uint8_t type;
64
+ int i, size;
65
+
66
+ config_op_send(pdev, PCI_VENDOR_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
67
+ pc->vendor_id = (uint16_t)val;
68
+
69
+ config_op_send(pdev, PCI_DEVICE_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
70
+ pc->device_id = (uint16_t)val;
71
+
72
+ config_op_send(pdev, PCI_CLASS_DEVICE, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
73
+ pc->class_id = (uint16_t)val;
74
+
75
+ config_op_send(pdev, PCI_SUBSYSTEM_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
76
+ pc->subsystem_id = (uint16_t)val;
77
+
78
+ base_class = pc->class_id >> 4;
79
+ switch (base_class) {
80
+ case PCI_BASE_CLASS_BRIDGE:
81
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
82
+ break;
83
+ case PCI_BASE_CLASS_STORAGE:
84
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
85
+ break;
86
+ case PCI_BASE_CLASS_NETWORK:
87
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
88
+ break;
89
+ case PCI_BASE_CLASS_INPUT:
90
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
91
+ break;
92
+ case PCI_BASE_CLASS_DISPLAY:
93
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
94
+ break;
95
+ case PCI_BASE_CLASS_PROCESSOR:
96
+ set_bit(DEVICE_CATEGORY_CPU, dc->categories);
97
+ break;
98
+ default:
99
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
100
+ break;
101
+ }
102
+
103
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
104
+ config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4,
105
+ MPQEMU_CMD_PCI_CFGREAD);
106
+ new_val = 0xffffffff;
107
+ config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4,
108
+ MPQEMU_CMD_PCI_CFGWRITE);
109
+ config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4,
110
+ MPQEMU_CMD_PCI_CFGREAD);
111
+ size = (~(new_val & 0xFFFFFFF0)) + 1;
112
+ config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4,
113
+ MPQEMU_CMD_PCI_CFGWRITE);
114
+ type = (new_val & 0x1) ?
115
+ PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
116
+
117
+ if (size) {
118
+ g_autofree char *name;
119
+ pdev->region[i].dev = pdev;
120
+ pdev->region[i].present = true;
121
+ if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
122
+ pdev->region[i].memory = true;
123
+ }
124
+ name = g_strdup_printf("bar-region-%d", i);
125
+ memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
126
+ &proxy_mr_ops, &pdev->region[i],
127
+ name, size);
128
+ pci_register_bar(dev, i, type, &pdev->region[i].mr);
129
+ }
130
+ }
131
+}
132
--
133
2.29.2
134
diff view generated by jsdifflib
Deleted patch
1
From: "Denis V. Lunev" <den@openvz.org>
2
1
3
Original specification says that l1 table size if 64 * l1_size, which
4
is obviously wrong. The size of the l1 entry is 64 _bits_, not bytes.
5
Thus 64 is to be replaces with 8 as specification says about bytes.
6
7
There is also minor tweak, field name is renamed from l1 to l1_table,
8
which matches with the later text.
9
10
Signed-off-by: Denis V. Lunev <den@openvz.org>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-id: 20210128171313.2210947-1-den@openvz.org
13
CC: Stefan Hajnoczi <stefanha@redhat.com>
14
CC: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
16
[Replace the original commit message "docs: fix mistake in dirty bitmap
17
feature description" as suggested by Eric Blake.
18
--Stefan]
19
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
---
22
docs/interop/parallels.txt | 2 +-
23
1 file changed, 1 insertion(+), 1 deletion(-)
24
25
diff --git a/docs/interop/parallels.txt b/docs/interop/parallels.txt
26
index XXXXXXX..XXXXXXX 100644
27
--- a/docs/interop/parallels.txt
28
+++ b/docs/interop/parallels.txt
29
@@ -XXX,XX +XXX,XX @@ of its data area are:
30
28 - 31: l1_size
31
The number of entries in the L1 table of the bitmap.
32
33
- variable: l1 (64 * l1_size bytes)
34
+ variable: l1_table (8 * l1_size bytes)
35
L1 offset table (in bytes)
36
37
A dirty bitmap is stored using a one-level structure for the mapping to host
38
--
39
2.29.2
40
diff view generated by jsdifflib