postcopy+vhost-user/shared ram
v2 cover postcopy+vhost-user/shared ram
From: "Dr. David Alan Gilbert" <[email protected]>
Hi,
This is a RFC/WIP series that enables postcopy migration
with shared memory to a vhost-user process.
It's based off current-head + Alexey's bitmap series
It's tested with vhost-user-bridge and a dpdk (modified by Maxime that will get posted separately) - both very lightly.
It's still got a few very rough edges, but it succesfully migrates with both normal and huge pages (2M).
The major difference over v1 is that there's a set of code that merges vhost regions together on the qemu side so that we get a single hugepage region on the PC spanning the 640k hole (the hole hopefully isn't accessed by the client, but the client used to align around it anyway).
It's also got a lot of cleanups from the comments from v1 but there's still a few things that need work.
In particular, there's still the hack around qemu waiting for the set_mem_table to come back; I also worry what would happen if a set-mem-table was triggered during a migrate; I suspect it would break badly.
One problem that didn't cause a problem was madvises for hugepages; because we register userfault directly after mmap'ing the region in the client, we have no pages mapped and hence the madvise's/fallocate's are fortunately not compulsary. Still, I'd like a way to do it, it would feel safer.
A copy of this code, based off the current 2.10.0-rc4 together with Alexey's bitmap code is available here:
https://github.com/dagrh/qemu/tree/vhost-wipv2
Dave
Dr. David Alan Gilbert (32):
vhu: vu_queue_started
vhub: Only process received packets on started queues
migrate: Update ram_block_discard_range for shared qemu_ram_block_host_offset
migration/ram: ramblock_recv_bitmap_test_byte_offset
postcopy: use UFFDIO_ZEROPAGE only when available
postcopy: Add notifier chain
postcopy: Add vhost-user flag for postcopy and check it
vhost-user: Add 'VHOST_USER_POSTCOPY_ADVISE' message
vhub: Support sending fds back to qemu
vhub: Open userfaultfd
postcopy: Allow registering of fd handler vhost+postcopy: Register shared ufd with postcopy vhost+postcopy: Transmit 'listen' to client vhost+postcopy: Register new regions with the ufd vhost+postcopy: Send address back to qemu vhost+postcopy: Stash RAMBlock and offset vhost+postcopy: Send requests to source for shared pages vhost+postcopy: Resolve client address
postcopy: wake shared
postcopy: postcopy_notify_shared_wake vhost+postcopy: Add vhost waker
vhost+postcopy: Call wakeups
vub+postcopy: madvises
vhost+postcopy: Lock around set_mem_table
vhost: Add VHOST_USER_POSTCOPY_END message vhost+postcopy: Wire up POSTCOPY_END notify
postcopy: Allow shared memory
vhost-user: Claim support for postcopy
vhost: Merge neighbouring hugepage regions where appropriate
vhost: Don't break merged regions on small remove/non-adds postcopy shared docs
contrib/libvhost-user/libvhost-user.c | 226 ++++++++++++++++++++- contrib/libvhost-user/libvhost-user.h | 22 ++- docs/devel/migration.txt | 39 ++++ docs/interop/vhost-user.txt | 39 ++++ exec.c | 60 ++++-- hw/virtio/trace-events | 27 +++ hw/virtio/vhost-user.c | 326 +++++++++++++++++++++++++++++- hw/virtio/vhost.c | 121 +++++++++++- include/exec/cpu-common.h | 4 + migration/migration.c | 3 + migration/migration.h | 4 + migration/postcopy-ram.c | 359 +++++++++++++++++++++++++++------- migration/postcopy-ram.h | 69 +++++++ migration/ram.c | 5 + migration/ram.h | 1 + migration/savevm.c | 13 ++ migration/trace-events | 6 + tests/vhost-user-bridge.c | 1 + trace-events | 3 + vl.c | 2 + 20 files changed, 1241 insertions(+), 89 deletions(-)
Signature · 1 line
2.13.5
RFC v2 1/32 vhu: vu_queue_started
From: "Dr. David Alan Gilbert" <[email protected]>
Add a vu_queue_started method to complement vu_queue_enabled.
--- contrib/libvhost-user/libvhost-user.c | 6 ++++++ contrib/libvhost-user/libvhost-user.h | 9 +++++++++ 2 files changed, 15 insertions(+)
contrib/libvhost-user/libvhost-user.c +6 -0
@@ -930,6 +930,12 @@ vu_queue_enabled(VuDev *dev, VuVirtq *vq)return vq->enable; } +bool +vu_queue_started (VuDev *dev,VuVirtq *vq) +{ +return vq->started; +} +static inline uint16_t vring_avail_flags (VuVirtq *vq) {
contrib/libvhost-user/libvhost-user.h +9 -0
@@ -328,6 +328,15 @@ void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);bool vu_queue_enabled (VuDev *dev,VuVirtq *vq);/** +* vu_queue_started: +* @dev: a VuDev context +* @vq: a VuVirtq queue +* +* Returns: whether the queue is started. +*/ +bool vu_queue_started (VuDev *dev,VuVirtq *vq); + +/** * vu_queue_empty: * @dev: a VuDev context * @vq: a VuVirtq queue
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
Hi
Quoted 6 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Add a
vu_queue_startedmethod to complementvu_queue_enabled.Signed-off-by Dr. David Alan Gilbert <[email protected]>
Quoted 11 lines
--- contrib/libvhost-user/libvhost-user.c | 6 ++++++ contrib/libvhost-user/libvhost-user.h | 9 +++++++++ 2 files changed, 15 insertions(+)contrib/libvhost-user/libvhost-user.c +0
-0
contrib/libvhost-user/libvhost-user.c vu_queue_enabled(VuDev *dev, VuVirtq *vq) · line 935
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +2
-0@@ -930,6 +930,12 @@ vu_queue_enabled(VuDev *dev, VuVirtq *vq)return vq->enable; } +bool +vu_queue_started (VuDev *dev,VuVirtq *vq)
I guess we could make it const, but this is true for many other functions. Could be done later in one go.
Quoted 33 lines
contrib/libvhost-user/libvhost-user.c +4
-0+{ +return vq->started; +} +static inline uint16_t vring_avail_flags (VuVirtq *vq){
contrib/libvhost-user/libvhost-user.h +9
-0@@ -328,6 +328,15 @@ void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);bool vu_queue_enabled (VuDev *dev,VuVirtq *vq);/** +* vu_queue_started: +* @dev: a VuDev context +* @vq: a VuVirtq queue +* +* Returns: whether the queue is started. +*/ +bool vu_queue_started (VuDev *dev,VuVirtq *vq); + +/** * vu_queue_empty: * @dev: a VuDev context * @vq: a VuVirtq queue
--
2.13.5
Quoted 1 line
--
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
Quoted 5 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
On Thu, Aug 24, 2017 at 9:39 PM Dr. David Alan Gilbert (git) < [email protected]> wrote:
Quoted 8 lines
Quoted 6 lines
From: "Dr. David Alan Gilbert" <[email protected]>
Add a
vu_queue_startedmethod to complementvu_queue_enabled.Signed-off-by Dr. David Alan Gilbert <[email protected]>Reviewed-by Marc-André Lureau <[email protected]>
Thanks.
Quoted 15 lines
Quoted 15 lines
--- contrib/libvhost-user/libvhost-user.c | 6 ++++++ contrib/libvhost-user/libvhost-user.h | 9 +++++++++ 2 files changed, 15 insertions(+)contrib/libvhost-user/libvhost-user.c +0
-0@@ -930,6 +930,12 @@ vu_queue_enabled(VuDev *dev, VuVirtq *vq)return vq->enable; }
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c vu_queue_enabled(VuDev *dev, VuVirtq *vq)
Quoted 3 lines
contrib/libvhost-user/libvhost-user.c +2
-0+bool +vu_queue_started (VuDev *dev,VuVirtq *vq)I guess we could make it const, but this is true for many other functions. Could be done later in one go.
Thanks; I've added the consts.
Dave
Quoted 33 lines
Quoted 33 lines
contrib/libvhost-user/libvhost-user.c +4
-0+{ +return vq->started; +} +static inline uint16_t vring_avail_flags (VuVirtq *vq){
contrib/libvhost-user/libvhost-user.h +9
-0@@ -328,6 +328,15 @@ void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);bool vu_queue_enabled (VuDev *dev,VuVirtq *vq);/** +* vu_queue_started: +* @dev: a VuDev context +* @vq: a VuVirtq queue +* +* Returns: whether the queue is started. +*/ +bool vu_queue_started (VuDev *dev,VuVirtq *vq); + +/** * vu_queue_empty: * @dev: a VuDev context * @vq: a VuVirtq queue
--
2.13.5
Quoted 2 lines
Quoted 1 line
--
Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
In reply to Dr. David Alan Gilbert (git)Quoted 1 line
Subject: Re: [RFC v2 01/32] vhu:
vu_queue_started
I mean, how did we end up with "vhu"? I never meant that to happen :( It's merely in the commit title but maybe we can come up with a better-sounding way to abbreviate vhost user.
Signature · 1 line
MST
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
Hi
----- Original Message -----
Quoted 5 lines
Quoted 1 line
Subject: Re: [RFC v2 01/32] vhu:
vu_queue_startedI mean, how did we end up with "vhu"? I never meant that to happen :( It's merely in the commit title but maybe we can come up with a better-sounding way to abbreviate vhost user.
vhu, no idea :)
I would suggest to use libvhost-user: prefix in commit messages for contrib/libvhost-user changes.
vhost-user: for qemu vhost-user changes.
vhost-user-bridge: (or vub:), vhost-user-scsi: (or vus:) for those backends.
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
Quoted 9 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
----- Original Message -----
Quoted 5 lines
Quoted 1 line
Subject: Re: [RFC v2 01/32] vhu:
vu_queue_startedI mean, how did we end up with "vhu"? I never meant that to happen :( It's merely in the commit title but maybe we can come up with a better-sounding way to abbreviate vhost user.
Quoted 5 lines
vhu, no idea :)
I would suggest to use libvhost-user: prefix in commit messages for contrib/libvhost-user changes.
vhost-user: for qemu vhost-user changes.
Changed to vhost-user.
Dave
Quoted 1 line
vhost-user-bridge: (or vub:), vhost-user-scsi: (or vus:) for those backends.
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 01/32] vhu: vu_queue_started
Quoted 10 lines · * Dr. David Alan Gilbert ([email protected]) wrote:
Quoted 9 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
----- Original Message -----
Quoted 5 lines
Quoted 1 line
Subject: Re: [RFC v2 01/32] vhu:
vu_queue_startedI mean, how did we end up with "vhu"? I never meant that to happen :( It's merely in the commit title but maybe we can come up with a better-sounding way to abbreviate vhost user.
Quoted 7 lines
Quoted 5 lines
vhu, no idea :)
I would suggest to use libvhost-user: prefix in commit messages for contrib/libvhost-user changes.
vhost-user: for qemu vhost-user changes.
Changed to vhost-user.
oops, I mean changed to libvhost-user for this one.
Dave
Quoted 5 lines
Dave
Quoted 1 line
vhost-user-bridge: (or vub:), vhost-user-scsi: (or vus:) for those backends.
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 2/32 vhub: Only process received packets on started queues
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Only process received packets if the queue has been started.
--- tests/vhost-user-bridge.c | 1 + 1 file changed, 1 insertion(+)
tests/vhost-user-bridge.c +1 -0
@@ -277,6 +277,7 @@ vubr_backend_recv_cb(int sock, void *ctx)DPRINT (" hdrlen = %d\n" , hdrlen);if (!vu_queue_enabled (dev, vq) || + !vu_queue_started (dev, vq) || !vu_queue_avail_bytes (dev, vq, hdrlen,0 )) {DPRINT ("Got UDP packet, but no available descriptors on RX virtq.\n" );return ;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 02/32] vhub: Only process received packets on started queues
Quoted 14 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Only process received packets if the queue has been started.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- tests/vhost-user-bridge.c | 1 + 1 file changed, 1 insertion(+)tests/vhost-user-bridge.c +0
-0
tests/vhost-user-bridge.c vubr_backend_recv_cb(int sock, void *ctx) · line 283
Quoted 7 lines
tests/vhost-user-bridge.c +1
-0@@ -277,6 +277,7 @@ vubr_backend_recv_cb(int sock, void *ctx)DPRINT (" hdrlen = %d\n" , hdrlen);if (!vu_queue_enabled (dev, vq) || + !vu_queue_started (dev, vq) || !vu_queue_avail_bytes (dev, vq, hdrlen,0 )) {DPRINT ("Got UDP packet, but no available descriptors on RX virtq.\n" );return ;
Signature · 1 line
Marc-André Lureau
RFC v2 3/32 migrate: Update ram_block_discard_range for shared
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
The choice of call to discard a block is getting more complicated
for other cases. We use fallocate PUNCH_HOLE in any file cases;
it works for both hugepage and for tmpfs.
We use the DONTNEED for non-hugepage cases either where they're anonymous or where they're private.
Care should be taken when trying other backing files.
--- exec.c | 35 ++++++++++++++++++++++++----------- trace-events | 3 +++ 2 files changed, 27 insertions(+), 11 deletions(-)
exec.c +24 -11
@@ -3573,6 +3573,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) }if ((start + length) <= rb->used_length) { +bool need_madvise, need_fallocate;uint8_t *host_endaddr = host_startaddr + length;if ((uintptr_t )host_endaddr & (rb->page_size -1 )) { error_report("ram_block_discard_range: Unaligned end address: %p",
@@ -3582,23 +3583,35 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) errno =ENOTSUP ;/* If we are missing MADVISE etc */ -if (rb->page_size == qemu_host_page_size) { -#if defined(CONFIG_MADVISE ) -/* Note: We need the madvise MADV_DONTNEED behaviour of definitely -* freeing the page. -*/ - ret =madvise (host_startaddr, length,MADV_DONTNEED ); -#endif - }else { -/* Huge page case - unfortunately it can't do DONTNEED, but -* it can do the equivalent by FALLOC_FL_PUNCH_HOLE in the -* huge page file. +/* The logic here is messy; +* madvise DONTNEED fails for hugepages +* fallocate works on hugepages and shmem +*/ + need_madvise = (rb->page_size == qemu_host_page_size); + need_fallocate = rb->fd !=-1 ; +if (need_fallocate) { +/* For a file, this causes the area of the file to be zero'd +* if read, and for hugetlbfs also causes it to be unmapped +* so a userfault will trigger. */ #ifdef CONFIG_FALLOCATE_PUNCH_HOLE ret =fallocate (rb->fd,FALLOC_FL_PUNCH_HOLE |FALLOC_FL_KEEP_SIZE , start, length);#endif } +/* i.e. need madvise but skip it if the fallocate failed */ +if (need_madvise && (!need_fallocate || (ret ==0 ))) { +/* For normal RAM this causes it to be unmapped, +* for shared memory it causes the local mapping to disappear +* and to fall back on the file contents (which we just +* fallocate'd away). +*/ +#if defined(CONFIG_MADVISE ) + ret =madvise (host_startaddr, length,MADV_DONTNEED ); +#endif + } +trace_ram_block_discard_range (rb->idstr, host_startaddr, + need_madvise, need_fallocate, ret);if (ret) { ret = -errno; error_report("ram_block_discard_range: Failed to discard range "
trace-events +3 -0
@@ -55,6 +55,9 @@ dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p" dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d" dma_map_wait(void *dbs) "dbs=%p" +# exec.c +ram_block_discard_range(const char *rbname, void *hva, bool need_madvise, bool need_fallocate, int ret) "%s@%p: madvise: %d fallocate: %d ret: %d" + # memory.c memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 03/32] migrate: Update ram_block_discard_range for shared
Quoted 51 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
The choice of call to discard a block is getting more complicated
for other cases. We use fallocatePUNCH_HOLEin any file cases;
it works for both hugepage and for tmpfs.
We use the DONTNEED for non-hugepage cases either where they're anonymous or where they're private.Care should be taken when trying other backing files.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 35 ++++++++++++++++++++++++----------- trace-events | 3 +++ 2 files changed, 27 insertions(+), 11 deletions(-)exec.c +9
-11@@ -3573,6 +3573,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) }if ((start + length) <= rb->used_length) { +bool need_madvise, need_fallocate;uint8_t *host_endaddr = host_startaddr + length;if ((uintptr_t )host_endaddr & (rb->page_size -1 )) { error_report("ram_block_discard_range: Unaligned end address: %p",@@ -3582,23 +3583,35 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) errno =ENOTSUP ;/* If we are missing MADVISE etc */ -if (rb->page_size == qemu_host_page_size) { -#if defined(CONFIG_MADVISE ) -/* Note: We need the madvise MADV_DONTNEED behaviour of definitely -* freeing the page. -*/ - ret =madvise (host_startaddr, length,MADV_DONTNEED ); -#endif - }else { -/* Huge page case - unfortunately it can't do DONTNEED, but -* it can do the equivalent by FALLOC_FL_PUNCH_HOLE in the -* huge page file. +/* The logic here is messy; +* madvise DONTNEED fails for hugepages +* fallocate works on hugepages and shmem +*/ + need_madvise = (rb->page_size == qemu_host_page_size); + need_fallocate = rb->fd !=-1 ; +if (need_fallocate) { +/* For a file, this causes the area of the file to be zero'd
exec.c int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) · line 3603
Quoted 10 lines
exec.c +4
-0+* if read, and for hugetlbfs also causes it to be unmapped +* so a userfault will trigger. */ #ifdef CONFIG_FALLOCATE_PUNCH_HOLE ret =fallocate (rb->fd,FALLOC_FL_PUNCH_HOLE |FALLOC_FL_KEEP_SIZE , start, length);#endif } +/* i.e. need madvise but skip it if the fallocate failed */ +if (need_madvise && (!need_fallocate || (ret ==0 ))) {
I'll slightly prefer:
trace_ram_block_discard_range();
if (need_fallocate) {
ret = fallocate();
if (ret) {
error_report();
goto err;
}
}
if (need_madvise) {
ret = madvise();
if (ret) {
error_report();
goto err;
}
}But it is personal preference. For either way:
Quoted 31 lines
exec.c +11
-0+/* For normal RAM this causes it to be unmapped, +* for shared memory it causes the local mapping to disappear +* and to fall back on the file contents (which we just +* fallocate'd away). +*/ +#if defined(CONFIG_MADVISE ) + ret =madvise (host_startaddr, length,MADV_DONTNEED ); +#endif + } +trace_ram_block_discard_range (rb->idstr, host_startaddr, + need_madvise, need_fallocate, ret);if (ret) { ret = -errno; error_report("ram_block_discard_range: Failed to discard range "trace-events +3
-0@@ -55,6 +55,9 @@ dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p" dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d" dma_map_wait(void *dbs) "dbs=%p" +# exec.c +ram_block_discard_range(const char *rbname, void *hva, bool need_madvise, bool need_fallocate, int ret) "%s@%p: madvise: %d fallocate: %d ret: %d" + # memory.c memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 03/32] migrate: Update ram_block_discard_range for shared
Quoted 75 lines · * Peter Xu ([email protected]) wrote:
Quoted 51 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
The choice of call to discard a block is getting more complicated
for other cases. We use fallocatePUNCH_HOLEin any file cases;
it works for both hugepage and for tmpfs.
We use the DONTNEED for non-hugepage cases either where they're anonymous or where they're private.Care should be taken when trying other backing files.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 35 ++++++++++++++++++++++++----------- trace-events | 3 +++ 2 files changed, 27 insertions(+), 11 deletions(-)exec.c +9
-11@@ -3573,6 +3573,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) }if ((start + length) <= rb->used_length) { +bool need_madvise, need_fallocate;uint8_t *host_endaddr = host_startaddr + length;if ((uintptr_t )host_endaddr & (rb->page_size -1 )) { error_report("ram_block_discard_range: Unaligned end address: %p",@@ -3582,23 +3583,35 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) errno =ENOTSUP ;/* If we are missing MADVISE etc */ -if (rb->page_size == qemu_host_page_size) { -#if defined(CONFIG_MADVISE ) -/* Note: We need the madvise MADV_DONTNEED behaviour of definitely -* freeing the page. -*/ - ret =madvise (host_startaddr, length,MADV_DONTNEED ); -#endif - }else { -/* Huge page case - unfortunately it can't do DONTNEED, but -* it can do the equivalent by FALLOC_FL_PUNCH_HOLE in the -* huge page file. +/* The logic here is messy; +* madvise DONTNEED fails for hugepages +* fallocate works on hugepages and shmem +*/ + need_madvise = (rb->page_size == qemu_host_page_size); + need_fallocate = rb->fd !=-1 ; +if (need_fallocate) { +/* For a file, this causes the area of the file to be zero'd exec.c int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) · line 3603
Quoted 10 lines
exec.c +4
-0+* if read, and for hugetlbfs also causes it to be unmapped +* so a userfault will trigger. */ #ifdef CONFIG_FALLOCATE_PUNCH_HOLE ret =fallocate (rb->fd,FALLOC_FL_PUNCH_HOLE |FALLOC_FL_KEEP_SIZE , start, length);#endif } +/* i.e. need madvise but skip it if the fallocate failed */ +if (need_madvise && (!need_fallocate || (ret ==0 ))) {I'll slightly prefer:
trace_ram_block_discard_range(); if (need_fallocate) { ret = fallocate(); if (ret) { error_report(); goto err; } }
Quoted 7 lines
if (need_madvise) {
ret = madvise();
if (ret) {
error_report();
goto err;
}
}OK, I've reworked it more like that.
(It's a little more complex because of the ifdef's)
Dave
Quoted 26 lines
But it is personal preference. For either way:
Reviewed-by Peter Xu <[email protected]>Quoted 22 lines
exec.c +11
-0+/* For normal RAM this causes it to be unmapped, +* for shared memory it causes the local mapping to disappear +* and to fall back on the file contents (which we just +* fallocate'd away). +*/ +#if defined(CONFIG_MADVISE ) + ret =madvise (host_startaddr, length,MADV_DONTNEED ); +#endif + } +trace_ram_block_discard_range (rb->idstr, host_startaddr, + need_madvise, need_fallocate, ret);if (ret) { ret = -errno; error_report("ram_block_discard_range: Failed to discard range "trace-events +0
-0@@ -55,6 +55,9 @@ dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p" dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d" dma_map_wait(void *dbs) "dbs=%p"
Quoted 12 lines
Quoted 9 lines
trace-events +3
-0+# exec.c +ram_block_discard_range(const char *rbname, void *hva, bool need_madvise, bool need_fallocate, int ret) "%s@%p: madvise: %d fallocate: %d ret: %d" + # memory.c memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 4/32 qemu_ram_block_host_offset
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Utility to give the offset of a host pointer within a RAMBlock (assuming we already know it's in that RAMBlock)
--- exec.c | 10 ++++++++++ include/exec/cpu-common.h | 1 + 2 files changed, 11 insertions(+)
exec.c +10 -0
@@ -2231,6 +2231,16 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,return ramblock_ptr (block, addr); } +/* Return the offset of a hostpointer within a ramblock */ +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host) +{ +ram_addr_t res = (uint8_t *)host - (uint8_t *)rb->host; +assert ((uint8_t *)host >= (uint8_t *)rb->host); +assert (res < rb->max_length); + +return res; +} +/* * Translates a host ptr back to a RAMBlock, a ram_addr and an offset * in that RAMBlock.
include/exec/cpu-common.h +1 -0
@@ -68,6 +68,7 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr);RAMBlock *qemu_ram_block_by_name (const char *name);RAMBlock *qemu_ram_block_from_host (void *ptr,bool round_offset,ram_addr_t *offset); +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host);void qemu_ram_set_idstr (RAMBlock *block,const char *name,DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 04/32] qemu_ram_block_host_offset
Hi David,
Quoted 16 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Utility to give the offset of a host pointer within a RAMBlock (assuming we already know it's in that RAMBlock)
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 10 ++++++++++ include/exec/cpu-common.h | 1 + 2 files changed, 11 insertions(+)exec.c +0
-0
exec.c static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, · line 2237
Quoted 7 lines
exec.c +4
-0@@ -2231,6 +2231,16 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,return ramblock_ptr (block, addr); } +/* Return the offset of a hostpointer within a ramblock */ +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host) +{ +ram_addr_t res = (uint8_t *)host - (uint8_t *)rb->host;
What about using ptrdiff_t here,
exec.c static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, · line 2238
Quoted 1 line
exec.c +1
-0+assert ((uint8_t *)host >= (uint8_t *)rb->host);
and uintptr_t here?
Quoted 21 lines
exec.c +5
-0+assert (res < rb->max_length); + +return res; +} +/* * Translates a host ptr back to a RAMBlock, a ram_addr and an offset * in that RAMBlock. include/exec/cpu-common.h +1
-0@@ -68,6 +68,7 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr);RAMBlock *qemu_ram_block_by_name (const char *name);RAMBlock *qemu_ram_block_from_host (void *ptr,bool round_offset,ram_addr_t *offset); +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host);void qemu_ram_set_idstr (RAMBlock *block,const char *name,DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);
Re: [Qemu-devel] [RFC v2 04/32] qemu_ram_block_host_offset
Quoted 14 lines · * Philippe Mathieu-Daudé ([email protected]) wrote:
Hi David,
Quoted 11 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Utility to give the offset of a host pointer within a RAMBlock (assuming we already know it's in that RAMBlock)
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 10 ++++++++++ include/exec/cpu-common.h | 1 + 2 files changed, 11 insertions(+)
Quoted 13 lines
exec.c static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, · line 2236
Quoted 11 lines
exec.c +4
-0@@ -2231,6 +2231,16 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,return ramblock_ptr (block, addr); } +/* Return the offset of a hostpointer within a ramblock */ +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host) +{ +ram_addr_t res = (uint8_t *)host - (uint8_t *)rb->host;What about using
ptrdiff_there,
We tend to use ram_addr_t for offsets in RAM, and so that's the return type of the function, and we're also comparing this value to rb->max_length below which is also a ram_addr_t.
Quoted 3 lines
exec.c static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, · line 2238
Quoted 1 line
exec.c +1
-0+assert ((uint8_t *)host >= (uint8_t *)rb->host);and
uintptr_there?
Done.
Thanks,
Dave
Quoted 13 lines
Quoted 13 lines
exec.c +5
-0+assert (res < rb->max_length); + +return res; +} +/* * Translates a host ptr back to a RAMBlock, a ram_addr and an offset * in that RAMBlock. include/exec/cpu-common.h +0
-0@@ -68,6 +68,7 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr);
Quoted 8 lines
include/exec/cpu-common.h ram_addr_t qemu_ram_addr_from_host(void *ptr); · line 74
Quoted 8 lines
include/exec/cpu-common.h +1
-0RAMBlock *qemu_ram_block_by_name (const char *name);RAMBlock *qemu_ram_block_from_host (void *ptr,bool round_offset,ram_addr_t *offset); +ram_addr_t qemu_ram_block_host_offset (RAMBlock *rb,void *host);void qemu_ram_set_idstr (RAMBlock *block,const char *name,DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 04/32] qemu_ram_block_host_offset
In reply to Dr. David Alan Gilbert (git)Quoted 6 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Utility to give the offset of a host pointer within a RAMBlock (assuming we already know it's in that RAMBlock)
Signed-off-by Dr. David Alan Gilbert <[email protected]>
Signature · 1 line
Peter Xu
RFC v2 5/32 migration/ram: ramblock_recv_bitmap_test_byte_offset
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Utility for testing the map when you already know the offset in the RAMBlock.
--- migration/ram.c | 5 +++++ migration/ram.h | 1 + 2 files changed, 6 insertions(+)
migration/ram.c +5 -0
@@ -164,6 +164,11 @@ int ramblock_recv_bitmap_test(RAMBlock *rb, void *host_addr) rb->receivedmap); } +bool ramblock_recv_bitmap_test_byte_offset (RAMBlock *rb,uint64_t byte_offset) +{ +return test_bit (byte_offset >>TARGET_PAGE_BITS , rb->receivedmap); +} +void ramblock_recv_bitmap_set (RAMBlock *rb,void *host_addr) {set_bit_atomic (ramblock_recv_bitmap_offset (host_addr, rb), rb->receivedmap);
migration/ram.h +1 -0
@@ -54,6 +54,7 @@ int ram_postcopy_incoming_init(MigrationIncomingState *mis);void ram_handle_compressed (void *host,uint8_t ch,uint64_t size);int ramblock_recv_bitmap_test (RAMBlock *rb,void *host_addr); +bool ramblock_recv_bitmap_test_byte_offset (RAMBlock *rb,uint64_t byte_offset);void ramblock_recv_bitmap_set (RAMBlock *rb,void *host_addr);void ramblock_recv_bitmap_set_range (RAMBlock *rb,void *host_addr,size_t nr);void ramblock_recv_bitmap_clear (RAMBlock *rb,void *host_addr);
Signature · 1 line
2.13.5
RFC v2 6/32 postcopy: use UFFDIO_ZEROPAGE only when available
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Use a flag on the RAMBlock to state whether it has the UFFDIO_ZEROPAGE capability, use it when it's available.
This allows the use of postcopy on tmpfs as well as hugepage backed files.
--- exec.c | 15 +++++++++++++++ include/exec/cpu-common.h | 3 +++ migration/postcopy-ram.c | 14 +++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-)
exec.c +15 -0
@@ -103,6 +103,11 @@ static MemoryRegion io_mem_unassigned;*/ #define RAM_RESIZEABLE (1 << 2) +/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically +* zero the page and wake waiting processes. +* (Set during postcopy) +*/ +#define RAM_UF_ZEROPAGE (1 << 3)#endif #ifdef TARGET_PAGE_BITS_VARY
@@ -1705,6 +1710,16 @@ bool qemu_ram_is_shared(RAMBlock *rb)return rb->flags &RAM_SHARED ; } +bool qemu_ram_is_uf_zeroable (RAMBlock *rb) +{ +return rb->flags &RAM_UF_ZEROPAGE ; +} + +void qemu_ram_set_uf_zeroable (RAMBlock *rb) +{ + rb->flags |=RAM_UF_ZEROPAGE ; +} +/* Called with iothread lock held. */ void qemu_ram_set_idstr (RAMBlock *new_block,const char *name,DeviceState *dev) {
include/exec/cpu-common.h +3 -0
@@ -73,6 +73,9 @@ void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);bool qemu_ram_is_shared (RAMBlock *rb); +bool qemu_ram_is_uf_zeroable (RAMBlock *rb); +void qemu_ram_set_uf_zeroable (RAMBlock *rb); +size_t qemu_ram_pagesize (RAMBlock *block);size_t qemu_ram_pagesize_largest (void );
migration/postcopy-ram.c +11 -3
@@ -408,6 +408,11 @@ static int ram_block_enable_notify(const char *block_name, void *host_addr,error_report ("%s userfault: Region doesn't support COPY" , __func__);return -1 ; } +if (reg_struct.ioctls & ((__u64 )1 << _UFFDIO_ZEROPAGE)) { +RAMBlock *rb =qemu_ram_block_by_name (block_name); +qemu_ram_set_uf_zeroable (rb); + } +return 0 ; }
@@ -617,11 +622,14 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,int postcopy_place_page_zero (MigrationIncomingState *mis,void *host,RAMBlock *rb) { +size_t pagesize =qemu_ram_pagesize (rb);trace_postcopy_place_page_zero (host); -if (qemu_ram_pagesize (rb) ==getpagesize ()) { -if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL ,getpagesize (), - rb)) { +/* Normal RAMBlocks can zero a page using UFFDIO_ZEROPAGE +* but it's not available for everything (e.g. hugetlbpages) +*/ +if (qemu_ram_is_uf_zeroable (rb)) { +if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL , pagesize, rb)) {int e = errno;error_report ("%s: %s zero host: %p" , __func__,strerror (e), host);
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 06/32] postcopy: use UFFDIO_ZEROPAGE only when available
Hi
Quoted 67 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Use a flag on the RAMBlock to state whether it has the
UFFDIO_ZEROPAGEcapability, use it when it's available.This allows the use of postcopy on tmpfs as well as hugepage backed files.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 15 +++++++++++++++ include/exec/cpu-common.h | 3 +++ migration/postcopy-ram.c | 14 +++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-)exec.c +15
-0@@ -103,6 +103,11 @@ static MemoryRegion io_mem_unassigned;*/ #define RAM_RESIZEABLE (1 << 2) +/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically +* zero the page and wake waiting processes. +* (Set during postcopy) +*/ +#define RAM_UF_ZEROPAGE (1 << 3)#endif #ifdef TARGET_PAGE_BITS_VARY @@ -1705,6 +1710,16 @@ bool qemu_ram_is_shared(RAMBlock *rb)return rb->flags &RAM_SHARED ; } +bool qemu_ram_is_uf_zeroable (RAMBlock *rb) +{ +return rb->flags &RAM_UF_ZEROPAGE ; +} + +void qemu_ram_set_uf_zeroable (RAMBlock *rb) +{ + rb->flags |=RAM_UF_ZEROPAGE ; +} +/* Called with iothread lock held. */ void qemu_ram_set_idstr (RAMBlock *new_block,const char *name,DeviceState *dev) {include/exec/cpu-common.h +3
-0@@ -73,6 +73,9 @@ void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);bool qemu_ram_is_shared (RAMBlock *rb); +bool qemu_ram_is_uf_zeroable (RAMBlock *rb); +void qemu_ram_set_uf_zeroable (RAMBlock *rb); +size_t qemu_ram_pagesize (RAMBlock *block);size_t qemu_ram_pagesize_largest (void );migration/postcopy-ram.c +0
-0
migration/postcopy-ram.c static int ram_block_enable_notify(const char *block_name, void *host_addr, · line 416
Quoted 9 lines
migration/postcopy-ram.c +5
-0@@ -408,6 +408,11 @@ static int ram_block_enable_notify(const char *block_name, void *host_addr,error_report ("%s userfault: Region doesn't support COPY" , __func__);return -1 ; } +if (reg_struct.ioctls & ((__u64 )1 << _UFFDIO_ZEROPAGE)) { +RAMBlock *rb =qemu_ram_block_by_name (block_name); +qemu_ram_set_uf_zeroable (rb); + } +
extra empty line
migration/postcopy-ram.c int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, · line 622
Quoted 10 lines
migration/postcopy-ram.c +1
-1return 0 ; }@@ -617,11 +622,14 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,int postcopy_place_page_zero (MigrationIncomingState *mis,void *host,RAMBlock *rb) { +size_t pagesize =qemu_ram_pagesize (rb);trace_postcopy_place_page_zero (host); -if (qemu_ram_pagesize (rb) ==getpagesize ()) {
Is this check drop intentionally?
Quoted 14 lines
migration/postcopy-ram.c +5
-3-if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL ,getpagesize (), - rb)) { +/* Normal RAMBlocks can zero a page using UFFDIO_ZEROPAGE +* but it's not available for everything (e.g. hugetlbpages) +*/ +if (qemu_ram_is_uf_zeroable (rb)) { +if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL , pagesize, rb)) {int e = errno;error_report ("%s: %s zero host: %p" , __func__,strerror (e), host); --2.13.5
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 06/32] postcopy: use UFFDIO_ZEROPAGE only when available
Quoted 66 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
Quoted 62 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Use a flag on the RAMBlock to state whether it has the
UFFDIO_ZEROPAGEcapability, use it when it's available.This allows the use of postcopy on tmpfs as well as hugepage backed files.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- exec.c | 15 +++++++++++++++ include/exec/cpu-common.h | 3 +++ migration/postcopy-ram.c | 14 +++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-)exec.c +15
-0@@ -103,6 +103,11 @@ static MemoryRegion io_mem_unassigned;*/ #define RAM_RESIZEABLE (1 << 2) +/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically +* zero the page and wake waiting processes. +* (Set during postcopy) +*/ +#define RAM_UF_ZEROPAGE (1 << 3)#endif #ifdef TARGET_PAGE_BITS_VARY @@ -1705,6 +1710,16 @@ bool qemu_ram_is_shared(RAMBlock *rb)return rb->flags &RAM_SHARED ; } +bool qemu_ram_is_uf_zeroable (RAMBlock *rb) +{ +return rb->flags &RAM_UF_ZEROPAGE ; +} + +void qemu_ram_set_uf_zeroable (RAMBlock *rb) +{ + rb->flags |=RAM_UF_ZEROPAGE ; +} +/* Called with iothread lock held. */ void qemu_ram_set_idstr (RAMBlock *new_block,const char *name,DeviceState *dev) {include/exec/cpu-common.h +3
-0@@ -73,6 +73,9 @@ void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev);void qemu_ram_unset_idstr (RAMBlock *block);const char *qemu_ram_get_idstr (RAMBlock *rb);bool qemu_ram_is_shared (RAMBlock *rb); +bool qemu_ram_is_uf_zeroable (RAMBlock *rb); +void qemu_ram_set_uf_zeroable (RAMBlock *rb); +size_t qemu_ram_pagesize (RAMBlock *block);size_t qemu_ram_pagesize_largest (void );
Quoted 16 lines
Quoted 5 lines
migration/postcopy-ram.c +0
-0migration/postcopy-ram.c static int ram_block_enable_notify(const char *block_name, void *host_addr, · line 416
Quoted 9 lines
migration/postcopy-ram.c +5
-0@@ -408,6 +408,11 @@ static int ram_block_enable_notify(const char *block_name, void *host_addr,error_report ("%s userfault: Region doesn't support COPY" , __func__);return -1 ; } +if (reg_struct.ioctls & ((__u64 )1 << _UFFDIO_ZEROPAGE)) { +RAMBlock *rb =qemu_ram_block_by_name (block_name); +qemu_ram_set_uf_zeroable (rb); + } +extra empty line
Thanks, gone.
Quoted 9 lines
Quoted 9 lines
migration/postcopy-ram.c +1
-0return 0 ; }@@ -617,11 +622,14 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,int postcopy_place_page_zero (MigrationIncomingState *mis,void *host,RAMBlock *rb) { +size_t pagesize =qemu_ram_pagesize (rb);trace_postcopy_place_page_zero (host);
Quoted 3 lines
migration/postcopy-ram.c int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, · line 622
Quoted 1 line
migration/postcopy-ram.c +0
-1-if (qemu_ram_pagesize (rb) ==getpagesize ()) {Is this check drop intentionally?
Yes, it used to be the case that we knew that for hugepages we couldn't
do zeroing and that was the rule we used. Now we're using the
capability flag returned from the uffdio registration on this RAMBlock and it tells us if we can use the ZERO ioctl on this block.
Dave
Quoted 6 lines
Quoted 6 lines
migration/postcopy-ram.c +4
-2-if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL ,getpagesize (), - rb)) { +/* Normal RAMBlocks can zero a page using UFFDIO_ZEROPAGE +* but it's not available for everything (e.g. hugetlbpages) +*/ +if (qemu_ram_is_uf_zeroable (rb)) {
Quoted 13 lines
Quoted 8 lines
migration/postcopy-ram.c +1
-1+if (qemu_ufd_copy_ioctl (mis->userfault_fd, host,NULL , pagesize, rb)) {int e = errno;error_report ("%s: %s zero host: %p" , __func__,strerror (e), host); --2.13.5
Signature · 1 line
Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 7/32 postcopy: Add notifier chain
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Add a notifier chain for postcopy with a 'reason' flag and an opportunity for a notifier member to return an error.
Call it when enabling postcopy.
This will initially used to enable devices to declare they're unable to postcopy and later to notify of devices of stages within postcopy.
--- migration/postcopy-ram.c | 41 +++++++++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 26 ++++++++++++++++++++++++++ vl.c | 2 ++ 3 files changed, 69 insertions(+)
migration/postcopy-ram.c +41 -0
@@ -23,6 +23,8 @@#include "savevm.h" #include "postcopy-ram.h" #include "ram.h" +#include "qapi/error.h" +#include "qemu/notify.h" #include "sysemu/sysemu.h" #include "sysemu/balloon.h" #include "qemu/error-report.h"
@@ -45,6 +47,38 @@ struct PostcopyDiscardState {unsigned int nsentcmds; }; +/* A notifier chain for postcopy +* The notifier should return 0 if it's OK, or a +* -errno on error. +* The notifier should expect an Error ** as it's data +*/ +static NotifierWithReturnList postcopy_notifier_list; + +void postcopy_infrastructure_init (void ) +{ +notifier_with_return_list_init (&postcopy_notifier_list); +} + +void postcopy_add_notifier (NotifierWithReturn *nn) +{ +notifier_with_return_list_add (&postcopy_notifier_list, nn); +} + +void postcopy_remove_notifier (NotifierWithReturn *n) +{ +notifier_with_return_remove (n); +} + +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp) +{ +struct PostcopyNotifyData pnd; + pnd.reason = reason; + pnd.errp = errp; + +return notifier_with_return_list_notify (&postcopy_notifier_list, + &pnd); +} +/* Postcopy needs to detect accesses to pages that haven't yet been copied * across, and efficiently map new pages in, the techniques for doing this * are target OS specific.
@@ -133,6 +167,7 @@ bool postcopy_ram_supported_by_host(void)struct uffdio_register reg_struct;struct uffdio_range range_struct;uint64_t feature_mask; +Error *local_err =NULL ;if (qemu_target_page_size () > pagesize) {error_report ("Target page size bigger than host page size" );
@@ -146,6 +181,12 @@ bool postcopy_ram_supported_by_host(void) goto out; } +/* Give devices a chance to object */ +if (postcopy_notify (POSTCOPY_NOTIFY_PROBE , &local_err)) { +error_report_err (local_err); + goto out; + } +/* Version and features check */ if (!ufd_version_check (ufd)) { goto out;
migration/postcopy-ram.h +26 -0
@@ -114,4 +114,30 @@ PostcopyState postcopy_state_get(void);/* Set the state and return the old state */ PostcopyState postcopy_state_set (PostcopyState new_state); +/* +* To be called once at the start before any device initialisation +*/ +void postcopy_infrastructure_init (void ); + +/* Add a notifier to a list to be called when checking whether the devices +* can support postcopy. +* It's data is a *PostcopyNotifyData +* It should return 0 if OK, or a negative value on failure. +* On failure it must set the data->errp to an error. +* +*/ +enum PostcopyNotifyReason { +POSTCOPY_NOTIFY_PROBE =0 , +}; + +struct PostcopyNotifyData { +enum PostcopyNotifyReason reason; +Error **errp; +}; + +void postcopy_add_notifier (NotifierWithReturn *nn); +void postcopy_remove_notifier (NotifierWithReturn *n); +/* Call the notifier list set by postcopy_add_start_notifier */ +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp); +#endif
vl.c +2 -0
@@ -95,6 +95,7 @@ int main(int argc, char **argv)#include "audio/audio.h" #include "sysemu/cpus.h" #include "migration/colo.h" +#include "migration/postcopy-ram.h" #include "sysemu/kvm.h" #include "sysemu/hax.h" #include "qapi/qobject-input-visitor.h"
@@ -3082,6 +3083,7 @@ int main(int argc, char **argv, char **envp)module_call_init (MODULE_INIT_OPTS );runstate_init (); +postcopy_infrastructure_init ();if (qcrypto_init (&err) <0 ) {error_reportf_err (err,"cannot initialize crypto: " );
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 07/32] postcopy: Add notifier chain
Quoted 31 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Add a notifier chain for postcopy with a 'reason' flag and an opportunity for a notifier member to return an error.
Call it when enabling postcopy.
This will initially used to enable devices to declare they're unable to postcopy and later to notify of devices of stages within postcopy.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- migration/postcopy-ram.c | 41 +++++++++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 26 ++++++++++++++++++++++++++ vl.c | 2 ++ 3 files changed, 69 insertions(+)migration/postcopy-ram.c +2
-0@@ -23,6 +23,8 @@#include "savevm.h" #include "postcopy-ram.h" #include "ram.h" +#include "qapi/error.h" +#include "qemu/notify.h" #include "sysemu/sysemu.h" #include "sysemu/balloon.h" #include "qemu/error-report.h"
migration/postcopy-ram.c struct PostcopyDiscardState { · line 53
Quoted 7 lines
migration/postcopy-ram.c +4
-0@@ -45,6 +47,38 @@ struct PostcopyDiscardState {unsigned int nsentcmds; }; +/* A notifier chain for postcopy +* The notifier should return 0 if it's OK, or a +* -errno on error. +* The notifier should expect an Error ** as it's data
"PostcopyNotifyData *" but not "Error **"?
Maybe we can just remove this block of comment since there is a similar one in the header below.
Besides:
Quoted 110 lines
migration/postcopy-ram.c +35
-0+*/ +static NotifierWithReturnList postcopy_notifier_list; + +void postcopy_infrastructure_init (void ) +{ +notifier_with_return_list_init (&postcopy_notifier_list); +} + +void postcopy_add_notifier (NotifierWithReturn *nn) +{ +notifier_with_return_list_add (&postcopy_notifier_list, nn); +} + +void postcopy_remove_notifier (NotifierWithReturn *n) +{ +notifier_with_return_remove (n); +} + +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp) +{ +struct PostcopyNotifyData pnd; + pnd.reason = reason; + pnd.errp = errp; + +return notifier_with_return_list_notify (&postcopy_notifier_list, + &pnd); +} +/* Postcopy needs to detect accesses to pages that haven't yet been copied * across, and efficiently map new pages in, the techniques for doing this * are target OS specific. @@ -133,6 +167,7 @@ bool postcopy_ram_supported_by_host(void)struct uffdio_register reg_struct;struct uffdio_range range_struct;uint64_t feature_mask; +Error *local_err =NULL ;if (qemu_target_page_size () > pagesize) {error_report ("Target page size bigger than host page size" );@@ -146,6 +181,12 @@ bool postcopy_ram_supported_by_host(void) goto out; } +/* Give devices a chance to object */ +if (postcopy_notify (POSTCOPY_NOTIFY_PROBE , &local_err)) { +error_report_err (local_err); + goto out; + } +/* Version and features check */ if (!ufd_version_check (ufd)) { goto out;migration/postcopy-ram.h +26
-0@@ -114,4 +114,30 @@ PostcopyState postcopy_state_get(void);/* Set the state and return the old state */ PostcopyState postcopy_state_set (PostcopyState new_state); +/* +* To be called once at the start before any device initialisation +*/ +void postcopy_infrastructure_init (void ); + +/* Add a notifier to a list to be called when checking whether the devices +* can support postcopy. +* It's data is a *PostcopyNotifyData +* It should return 0 if OK, or a negative value on failure. +* On failure it must set the data->errp to an error. +* +*/ +enum PostcopyNotifyReason { +POSTCOPY_NOTIFY_PROBE =0 , +}; + +struct PostcopyNotifyData { +enum PostcopyNotifyReason reason; +Error **errp; +}; + +void postcopy_add_notifier (NotifierWithReturn *nn); +void postcopy_remove_notifier (NotifierWithReturn *n); +/* Call the notifier list set by postcopy_add_start_notifier */ +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp); +#endif vl.c +2
-0@@ -95,6 +95,7 @@ int main(int argc, char **argv)#include "audio/audio.h" #include "sysemu/cpus.h" #include "migration/colo.h" +#include "migration/postcopy-ram.h" #include "sysemu/kvm.h" #include "sysemu/hax.h" #include "qapi/qobject-input-visitor.h" @@ -3082,6 +3083,7 @@ int main(int argc, char **argv, char **envp)module_call_init (MODULE_INIT_OPTS );runstate_init (); +postcopy_infrastructure_init ();if (qcrypto_init (&err) <0 ) {error_reportf_err (err,"cannot initialize crypto: " );Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 07/32] postcopy: Add notifier chain
Quoted 35 lines · * Peter Xu ([email protected]) wrote:
Quoted 34 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Add a notifier chain for postcopy with a 'reason' flag and an opportunity for a notifier member to return an error.
Call it when enabling postcopy.
This will initially used to enable devices to declare they're unable to postcopy and later to notify of devices of stages within postcopy.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- migration/postcopy-ram.c | 41 +++++++++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 26 ++++++++++++++++++++++++++ vl.c | 2 ++ 3 files changed, 69 insertions(+)migration/postcopy-ram.c +2
-0@@ -23,6 +23,8 @@#include "savevm.h" #include "postcopy-ram.h" #include "ram.h" +#include "qapi/error.h" +#include "qemu/notify.h" #include "sysemu/sysemu.h" #include "sysemu/balloon.h" #include "qemu/error-report.h" @@ -45,6 +47,38 @@ struct PostcopyDiscardState {unsigned int nsentcmds; };
Quoted 6 lines
migration/postcopy-ram.c struct PostcopyDiscardState { · line 53
Quoted 4 lines
migration/postcopy-ram.c +4
-0+/* A notifier chain for postcopy +* The notifier should return 0 if it's OK, or a +* -errno on error. +* The notifier should expect an Error ** as it's data "PostcopyNotifyData *" but not "Error **"?
Ah well spotted.
Quoted 2 lines
Maybe we can just remove this block of comment since there is a similar one in the header below.
Yes, that's what I've done.
Quoted 3 lines
Besides:
Reviewed-by Peter Xu <[email protected]>
Thanks.
Dave
Quoted 103 lines
Quoted 103 lines
migration/postcopy-ram.c +35
-0+*/ +static NotifierWithReturnList postcopy_notifier_list; + +void postcopy_infrastructure_init (void ) +{ +notifier_with_return_list_init (&postcopy_notifier_list); +} + +void postcopy_add_notifier (NotifierWithReturn *nn) +{ +notifier_with_return_list_add (&postcopy_notifier_list, nn); +} + +void postcopy_remove_notifier (NotifierWithReturn *n) +{ +notifier_with_return_remove (n); +} + +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp) +{ +struct PostcopyNotifyData pnd; + pnd.reason = reason; + pnd.errp = errp; + +return notifier_with_return_list_notify (&postcopy_notifier_list, + &pnd); +} +/* Postcopy needs to detect accesses to pages that haven't yet been copied * across, and efficiently map new pages in, the techniques for doing this * are target OS specific. @@ -133,6 +167,7 @@ bool postcopy_ram_supported_by_host(void)struct uffdio_register reg_struct;struct uffdio_range range_struct;uint64_t feature_mask; +Error *local_err =NULL ;if (qemu_target_page_size () > pagesize) {error_report ("Target page size bigger than host page size" );@@ -146,6 +181,12 @@ bool postcopy_ram_supported_by_host(void) goto out; } +/* Give devices a chance to object */ +if (postcopy_notify (POSTCOPY_NOTIFY_PROBE , &local_err)) { +error_report_err (local_err); + goto out; + } +/* Version and features check */ if (!ufd_version_check (ufd)) { goto out;migration/postcopy-ram.h +26
-0@@ -114,4 +114,30 @@ PostcopyState postcopy_state_get(void);/* Set the state and return the old state */ PostcopyState postcopy_state_set (PostcopyState new_state); +/* +* To be called once at the start before any device initialisation +*/ +void postcopy_infrastructure_init (void ); + +/* Add a notifier to a list to be called when checking whether the devices +* can support postcopy. +* It's data is a *PostcopyNotifyData +* It should return 0 if OK, or a negative value on failure. +* On failure it must set the data->errp to an error. +* +*/ +enum PostcopyNotifyReason { +POSTCOPY_NOTIFY_PROBE =0 , +}; + +struct PostcopyNotifyData { +enum PostcopyNotifyReason reason; +Error **errp; +}; + +void postcopy_add_notifier (NotifierWithReturn *nn); +void postcopy_remove_notifier (NotifierWithReturn *n); +/* Call the notifier list set by postcopy_add_start_notifier */ +int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp); +#endif vl.c +1
-0@@ -95,6 +95,7 @@ int main(int argc, char **argv)#include "audio/audio.h" #include "sysemu/cpus.h" #include "migration/colo.h" +#include "migration/postcopy-ram.h" #include "sysemu/kvm.h" #include "sysemu/hax.h" #include "qapi/qobject-input-visitor.h" @@ -3082,6 +3083,7 @@ int main(int argc, char **argv, char **envp)module_call_init (MODULE_INIT_OPTS );
Quoted 11 lines
Quoted 8 lines
vl.c +1
-0runstate_init (); +postcopy_infrastructure_init ();if (qcrypto_init (&err) <0 ) {error_reportf_err (err,"cannot initialize crypto: " );Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 8/32 postcopy: Add vhost-user flag for postcopy and check it
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Add a vhost feature flag for postcopy support, and use the postcopy notifier to check it before allowing postcopy.
--- contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 10 +++++++++ hw/virtio/vhost-user.c | 40 ++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-)
contrib/libvhost-user/libvhost-user.h +1 -0
@@ -34,6 +34,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_MQ =0 ,VHOST_USER_PROTOCOL_F_LOG_SHMFD =1 ,VHOST_USER_PROTOCOL_F_RARP =2 , +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };
docs/interop/vhost-user.txt +10 -0
@@ -273,6 +273,15 @@ Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. +In postcopy migration the slave is started before all the memory has been +received from the source host, and care must be taken to avoid accessing pages +that have yet to be received. The slave opens a 'userfault'-fd and registers +the memory with it; this fd is then passed back over to the master. +The master services requests on the userfaultfd for pages that are accessed +and when the page is available it performs WAKE ioctl's on the userfaultfd +to wake the stalled slave. The client indicates support for this via the +VHOST_USER_PROTOCOL_F_PAGEFAULT feature. + IOMMU support -------------
@@ -327,6 +336,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_MTU 4 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 +#define VHOST_USER_PROTOCOL_F_PAGEFAULT 7 Master message types --------------------
hw/virtio/vhost-user.c +39 -1
@@ -17,6 +17,8 @@#include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" +#include "migration/migration.h" +#include "migration/postcopy-ram.h" #include <sys/ioctl.h> #include <sys/socket.h>
@@ -34,7 +36,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_NET_MTU =4 ,VHOST_USER_PROTOCOL_F_SLAVE_REQ =5 ,VHOST_USER_PROTOCOL_F_CROSS_ENDIAN =6 , - +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };
@@ -123,8 +125,10 @@ static VhostUserMsg m __attribute__ ((unused));#define VHOST_USER_VERSION (0x1)struct vhost_user { +struct vhost_dev *dev;CharBackend *chr;int slave_fd; +NotifierWithReturn postcopy_notifier; };static bool ioeventfd_enabled (void )
@@ -720,6 +724,33 @@ out:return ret; } +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier, +void *opaque) +{ +struct PostcopyNotifyData *pnd = opaque; + struct vhost_user *u = container_of(notifier, struct vhost_user, + postcopy_notifier); +struct vhost_dev *dev = u->dev; + +switch (pnd->reason) { +case POSTCOPY_NOTIFY_PROBE : +if (!virtio_has_feature (dev->protocol_features, +VHOST_USER_PROTOCOL_F_PAGEFAULT )) { +/* TODO: Get the device name into this error somehow */ +error_setg (pnd->errp, +"vhost-user backend not capable of postcopy" ); +return -ENOENT ; + } +break ; + +default : +/* We ignore notifications we don't know */ +break ; + } + +return 0 ; +} +static int vhost_user_init (struct vhost_dev *dev,void *opaque) {uint64_t features, protocol_features;
@@ -731,6 +762,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) u = g_new0(struct vhost_user, 1); u->chr = opaque; u->slave_fd =-1 ; + u->dev = dev; dev->opaque = u; err =vhost_user_get_features (dev, &features);
@@ -787,6 +819,9 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)return err; } + u->postcopy_notifier.notify = vhost_user_postcopy_notifier; +postcopy_add_notifier (&u->postcopy_notifier); +return 0 ; }
@@ -797,6 +832,9 @@ static int vhost_user_cleanup(struct vhost_dev *dev)assert (dev->vhost_ops->backend_type ==VHOST_BACKEND_TYPE_USER ); u = dev->opaque; +if (u->postcopy_notifier.notify) { +postcopy_remove_notifier (&u->postcopy_notifier); + }if (u->slave_fd >=0 ) {qemu_set_fd_handler (u->slave_fd,NULL ,NULL ,NULL );close (u->slave_fd);
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 08/32] postcopy: Add vhost-user flag for postcopy and check it
Quoted 138 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Add a vhost feature flag for postcopy support, and use the postcopy notifier to check it before allowing postcopy.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 10 +++++++++ hw/virtio/vhost-user.c | 40 ++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-)contrib/libvhost-user/libvhost-user.h +1
-0@@ -34,6 +34,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_MQ =0 ,VHOST_USER_PROTOCOL_F_LOG_SHMFD =1 ,VHOST_USER_PROTOCOL_F_RARP =2 , +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };docs/interop/vhost-user.txt +10
-0@@ -273,6 +273,15 @@ Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. +In postcopy migration the slave is started before all the memory has been +received from the source host, and care must be taken to avoid accessing pages +that have yet to be received. The slave opens a 'userfault'-fd and registers +the memory with it; this fd is then passed back over to the master. +The master services requests on the userfaultfd for pages that are accessed +and when the page is available it performs WAKE ioctl's on the userfaultfd +to wake the stalled slave. The client indicates support for this via the +VHOST_USER_PROTOCOL_F_PAGEFAULT feature. + IOMMU support -------------@@ -327,6 +336,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_MTU 4 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 +#define VHOST_USER_PROTOCOL_F_PAGEFAULT 7 Master message types --------------------hw/virtio/vhost-user.c +36
-1@@ -17,6 +17,8 @@#include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" +#include "migration/migration.h" +#include "migration/postcopy-ram.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -34,7 +36,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_NET_MTU =4 ,VHOST_USER_PROTOCOL_F_SLAVE_REQ =5 ,VHOST_USER_PROTOCOL_F_CROSS_ENDIAN =6 , - +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };@@ -123,8 +125,10 @@ static VhostUserMsg m __attribute__ ((unused));#define VHOST_USER_VERSION (0x1)struct vhost_user { +struct vhost_dev *dev;CharBackend *chr;int slave_fd; +NotifierWithReturn postcopy_notifier; };static bool ioeventfd_enabled (void )@@ -720,6 +724,33 @@ out:return ret; } +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier, +void *opaque) +{ +struct PostcopyNotifyData *pnd = opaque; + struct vhost_user *u = container_of(notifier, struct vhost_user, + postcopy_notifier); +struct vhost_dev *dev = u->dev; + +switch (pnd->reason) { +case POSTCOPY_NOTIFY_PROBE : +if (!virtio_has_feature (dev->protocol_features, +VHOST_USER_PROTOCOL_F_PAGEFAULT )) { +/* TODO: Get the device name into this error somehow */ +error_setg (pnd->errp, +"vhost-user backend not capable of postcopy" ); +return -ENOENT ; + } +break ; + +default : +/* We ignore notifications we don't know */ +break ; + } + +return 0 ; +} +static int vhost_user_init (struct vhost_dev *dev,void *opaque) {uint64_t features, protocol_features;@@ -731,6 +762,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) u = g_new0(struct vhost_user, 1); u->chr = opaque; u->slave_fd =-1 ; + u->dev = dev; dev->opaque = u; err =vhost_user_get_features (dev, &features);@@ -787,6 +819,9 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)return err; } + u->postcopy_notifier.notify = vhost_user_postcopy_notifier; +postcopy_add_notifier (&u->postcopy_notifier); +return 0 ; }
hw/virtio/vhost-user.c static int vhost_user_cleanup(struct vhost_dev *dev) · line 835
Quoted 4 lines
hw/virtio/vhost-user.c +1
-0@@ -797,6 +832,9 @@ static int vhost_user_cleanup(struct vhost_dev *dev)assert (dev->vhost_ops->backend_type ==VHOST_BACKEND_TYPE_USER ); u = dev->opaque; +if (u->postcopy_notifier.notify) {
Detecting init using the notify hook is slightly strange here for me... If so, not sure whether we also need:
u->postcopy_notifier.notify = NULL;
Or I'm not sure whether a 2nd call to vhost_user_cleanup() can be dangerous since postcopy_remove_notifier() will be called twice.
Besides that, the patch looks good to me. Thanks,
Quoted 8 lines
hw/virtio/vhost-user.c +2
-0+postcopy_remove_notifier (&u->postcopy_notifier); + }if (u->slave_fd >=0 ) {qemu_set_fd_handler (u->slave_fd,NULL ,NULL ,NULL );close (u->slave_fd);Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 08/32] postcopy: Add vhost-user flag for postcopy and check it
Quoted 147 lines · * Peter Xu ([email protected]) wrote:
Quoted 138 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Add a vhost feature flag for postcopy support, and use the postcopy notifier to check it before allowing postcopy.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 10 +++++++++ hw/virtio/vhost-user.c | 40 ++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-)contrib/libvhost-user/libvhost-user.h +1
-0@@ -34,6 +34,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_MQ =0 ,VHOST_USER_PROTOCOL_F_LOG_SHMFD =1 ,VHOST_USER_PROTOCOL_F_RARP =2 , +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };docs/interop/vhost-user.txt +10
-0@@ -273,6 +273,15 @@ Once the source has finished migration, rings will be stopped by the source. No further update must be done before rings are restarted. +In postcopy migration the slave is started before all the memory has been +received from the source host, and care must be taken to avoid accessing pages +that have yet to be received. The slave opens a 'userfault'-fd and registers +the memory with it; this fd is then passed back over to the master. +The master services requests on the userfaultfd for pages that are accessed +and when the page is available it performs WAKE ioctl's on the userfaultfd +to wake the stalled slave. The client indicates support for this via the +VHOST_USER_PROTOCOL_F_PAGEFAULT feature. + IOMMU support -------------@@ -327,6 +336,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_MTU 4 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 +#define VHOST_USER_PROTOCOL_F_PAGEFAULT 7 Master message types --------------------hw/virtio/vhost-user.c +36
-1@@ -17,6 +17,8 @@#include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" +#include "migration/migration.h" +#include "migration/postcopy-ram.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -34,7 +36,7 @@ enum VhostUserProtocolFeature {VHOST_USER_PROTOCOL_F_NET_MTU =4 ,VHOST_USER_PROTOCOL_F_SLAVE_REQ =5 ,VHOST_USER_PROTOCOL_F_CROSS_ENDIAN =6 , - +VHOST_USER_PROTOCOL_F_PAGEFAULT =7 , VHOST_USER_PROTOCOL_F_MAX };@@ -123,8 +125,10 @@ static VhostUserMsg m __attribute__ ((unused));#define VHOST_USER_VERSION (0x1)struct vhost_user { +struct vhost_dev *dev;CharBackend *chr;int slave_fd; +NotifierWithReturn postcopy_notifier; };static bool ioeventfd_enabled (void )@@ -720,6 +724,33 @@ out:return ret; } +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier, +void *opaque) +{ +struct PostcopyNotifyData *pnd = opaque; + struct vhost_user *u = container_of(notifier, struct vhost_user, + postcopy_notifier); +struct vhost_dev *dev = u->dev; + +switch (pnd->reason) { +case POSTCOPY_NOTIFY_PROBE : +if (!virtio_has_feature (dev->protocol_features, +VHOST_USER_PROTOCOL_F_PAGEFAULT )) { +/* TODO: Get the device name into this error somehow */ +error_setg (pnd->errp, +"vhost-user backend not capable of postcopy" ); +return -ENOENT ; + } +break ; + +default : +/* We ignore notifications we don't know */ +break ; + } + +return 0 ; +} +static int vhost_user_init (struct vhost_dev *dev,void *opaque) {uint64_t features, protocol_features;@@ -731,6 +762,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) u = g_new0(struct vhost_user, 1); u->chr = opaque; u->slave_fd =-1 ; + u->dev = dev; dev->opaque = u; err =vhost_user_get_features (dev, &features);@@ -787,6 +819,9 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque)return err; } + u->postcopy_notifier.notify = vhost_user_postcopy_notifier; +postcopy_add_notifier (&u->postcopy_notifier); +return 0 ; }hw/virtio/vhost-user.c static int vhost_user_cleanup(struct vhost_dev *dev) · line 835
Quoted 4 lines
hw/virtio/vhost-user.c +1
-0@@ -797,6 +832,9 @@ static int vhost_user_cleanup(struct vhost_dev *dev)assert (dev->vhost_ops->backend_type ==VHOST_BACKEND_TYPE_USER ); u = dev->opaque; +if (u->postcopy_notifier.notify) {Detecting init using the notify hook is slightly strange here for me... If so, not sure whether we also need:
Quoted 4 lines
u->postcopy_notifier.notify = NULL;Or I'm not sure whether a 2nd call to
vhost_user_cleanup()can be dangerous sincepostcopy_remove_notifier()will be called twice.
I've added the NULL assignment; I think I'd assumed that the notifier remove also did that.
Dave
Quoted 14 lines
Besides that, the patch looks good to me. Thanks,
Quoted 8 lines
hw/virtio/vhost-user.c +2
-0+postcopy_remove_notifier (&u->postcopy_notifier); + }if (u->slave_fd >=0 ) {qemu_set_fd_handler (u->slave_fd,NULL ,NULL ,NULL );close (u->slave_fd);Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 9/32 vhost-user: Add 'VHOST_USER_POSTCOPY_ADVISE' message
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Wire up a notifier to send a VHOST_USER_POSTCOPY_ADVISE message on an incoming advise.
Later patches will fill in the behaviour/contents of the message.
--- contrib/libvhost-user/libvhost-user.c | 21 ++++++++++++--- contrib/libvhost-user/libvhost-user.h | 6 ++++- docs/interop/vhost-user.txt | 9 +++++++ hw/virtio/vhost-user.c | 48 +++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 6 +++++ 6 files changed, 86 insertions(+), 5 deletions(-)
contrib/libvhost-user/libvhost-user.c +17 -4
@@ -42,9 +42,6 @@ vu_request_to_string(int req)REQ (VHOST_USER_NONE ),REQ (VHOST_USER_GET_FEATURES ),REQ (VHOST_USER_SET_FEATURES ), -REQ (VHOST_USER_NONE ), -REQ (VHOST_USER_GET_FEATURES ), -REQ (VHOST_USER_SET_FEATURES ),REQ (VHOST_USER_SET_OWNER ),REQ (VHOST_USER_RESET_OWNER ), REQ(VHOST_USER_SET_MEM_TABLE),
@@ -62,7 +59,10 @@ vu_request_to_string(int req)REQ (VHOST_USER_GET_QUEUE_NUM ),REQ (VHOST_USER_SET_VRING_ENABLE ),REQ (VHOST_USER_SEND_RARP ), -REQ (VHOST_USER_INPUT_GET_CONFIG ), +REQ (VHOST_USER_SET_SLAVE_REQ_FD ), +REQ (VHOST_USER_IOTLB_MSG ), +REQ (VHOST_USER_SET_VRING_ENDIAN ), +REQ (VHOST_USER_POSTCOPY_ADVISE ), REQ(VHOST_USER_MAX), };#undef REQ
@@ -744,6 +744,17 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) }static bool +vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) +{ +/* TODO: Open ufd, pass it back in the request +* TODO: Add addresses +*/ + vmsg->payload.u64 =0xcafe ; + vmsg->size =sizeof (vmsg->payload.u64); +return true;/* = send a reply */ +} + +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;
@@ -808,6 +819,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_vring_enable_exec (dev, vmsg);case VHOST_USER_NONE :break ; +case VHOST_USER_POSTCOPY_ADVISE : +return vu_set_postcopy_advise (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);
contrib/libvhost-user/libvhost-user.h +5 -1
@@ -62,7 +62,11 @@ typedef enum VhostUserRequest {VHOST_USER_GET_QUEUE_NUM =17 ,VHOST_USER_SET_VRING_ENABLE =18 ,VHOST_USER_SEND_RARP =19 , -VHOST_USER_INPUT_GET_CONFIG =20 , +VHOST_USER_NET_SET_MTU =20 , +VHOST_USER_SET_SLAVE_REQ_FD =21 , +VHOST_USER_IOTLB_MSG =22 , +VHOST_USER_SET_VRING_ENDIAN =23 , +VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_MAX } VhostUserRequest;
docs/interop/vhost-user.txt +9 -0
@@ -606,6 +606,15 @@ Master message types and expect this message once (per VQ) during device configuration (ie. before the master starts the VQ). + * VHOST_USER_POSTCOPY_ADVISE + Id: 24 + Master payload: N/A + Slave payload: userfault fd + u64 + + Master advises slave that a migration with postcopy enabled is underway, + the slave must open a userfaultfd for later use. + Note that at this stage the migration is still in precopy mode. + Slave message types -------------------
hw/virtio/vhost-user.c +48 -0
66 lines not on this page · raw message
migration/postcopy-ram.h +1 -0
@@ -128,6 +128,7 @@ void postcopy_infrastructure_init(void);*/ enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 , +POSTCOPY_NOTIFY_INBOUND_ADVISE , };struct PostcopyNotifyData {
migration/savevm.c +6 -0
@@ -1343,6 +1343,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_ADVISE );uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; +Error *local_err =NULL ;trace_loadvm_postcopy_handle_advise ();if (ps !=POSTCOPY_INCOMING_NONE ) {
@@ -1390,6 +1391,11 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)return -1 ; } +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_ADVISE , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (ram_postcopy_incoming_init (mis)) {return -1 ; }
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 09/32] vhost-user: Add 'VHOST_USER_POSTCOPY_ADVISE' message
Hi
Quoted 23 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Wire up a notifier to send a
VHOST_USER_POSTCOPY_ADVISEmessage on an incoming advise.Later patches will fill in the behaviour/contents of the message.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 21 ++++++++++++--- contrib/libvhost-user/libvhost-user.h | 6 ++++- docs/interop/vhost-user.txt | 9 +++++++ hw/virtio/vhost-user.c | 48 +++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 6 +++++ 6 files changed, 86 insertions(+), 5 deletions(-)contrib/libvhost-user/libvhost-user.c +0
-0
contrib/libvhost-user/libvhost-user.c vu_request_to_string(int req) · line 47
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +0
-3@@ -42,9 +42,6 @@ vu_request_to_string(int req)REQ (VHOST_USER_NONE ),REQ (VHOST_USER_GET_FEATURES ), REQ(VHOST_USER_SET_FEATURES), -REQ (VHOST_USER_NONE ), -REQ (VHOST_USER_GET_FEATURES ), - REQ(VHOST_USER_SET_FEATURES),
nice cleanup ;)
Quoted 16 lines
contrib/libvhost-user/libvhost-user.c +4
-1REQ (VHOST_USER_SET_OWNER ),REQ (VHOST_USER_RESET_OWNER ), REQ(VHOST_USER_SET_MEM_TABLE),@@ -62,7 +59,10 @@ vu_request_to_string(int req)REQ (VHOST_USER_GET_QUEUE_NUM ),REQ (VHOST_USER_SET_VRING_ENABLE ),REQ (VHOST_USER_SEND_RARP ), -REQ (VHOST_USER_INPUT_GET_CONFIG ), +REQ (VHOST_USER_SET_SLAVE_REQ_FD ), +REQ (VHOST_USER_IOTLB_MSG ), +REQ (VHOST_USER_SET_VRING_ENDIAN ), +REQ (VHOST_USER_POSTCOPY_ADVISE ), REQ(VHOST_USER_MAX), };#undef REQ
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 750
Quoted 7 lines
contrib/libvhost-user/libvhost-user.c +4
-0@@ -744,6 +744,17 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) }static bool +vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) +{ +/* TODO: Open ufd, pass it back in the request +* TODO: Add addresses
Extra EOL space
Quoted 166 lines
contrib/libvhost-user/libvhost-user.c +9
-0+*/ + vmsg->payload.u64 =0xcafe ; + vmsg->size =sizeof (vmsg->payload.u64); +return true;/* = send a reply */ +} + +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;@@ -808,6 +819,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_vring_enable_exec (dev, vmsg);case VHOST_USER_NONE :break ; +case VHOST_USER_POSTCOPY_ADVISE : +return vu_set_postcopy_advise (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +5
-1@@ -62,7 +62,11 @@ typedef enum VhostUserRequest {VHOST_USER_GET_QUEUE_NUM =17 ,VHOST_USER_SET_VRING_ENABLE =18 ,VHOST_USER_SEND_RARP =19 , -VHOST_USER_INPUT_GET_CONFIG =20 , +VHOST_USER_NET_SET_MTU =20 , +VHOST_USER_SET_SLAVE_REQ_FD =21 , +VHOST_USER_IOTLB_MSG =22 , +VHOST_USER_SET_VRING_ENDIAN =23 , +VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_MAX } VhostUserRequest;docs/interop/vhost-user.txt +9
-0@@ -606,6 +606,15 @@ Master message types and expect this message once (per VQ) during device configuration (ie. before the master starts the VQ). + * VHOST_USER_POSTCOPY_ADVISE + Id: 24 + Master payload: N/A + Slave payload: userfault fd + u64 + + Master advises slave that a migration with postcopy enabled is underway, + the slave must open a userfaultfd for later use. + Note that at this stage the migration is still in precopy mode. + Slave message types -------------------hw/virtio/vhost-user.c +48
-0@@ -67,6 +67,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_SLAVE_REQ_FD =21 ,VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 , +VHOST_USER_POSTCOPY_ADVISE =24 , VHOST_USER_MAX } VhostUserRequest;@@ -724,6 +725,50 @@ out:return ret; } +/* +* Called at the start of an inbound postcopy on reception of the +* 'advise' command. +*/ +static int vhost_user_postcopy_advise (struct vhost_dev *dev,Error **errp) +{ +struct vhost_user *u = dev->opaque; +CharBackend *chr = u->chr; +int ufd; +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_ADVISE , + .flags =VHOST_USER_VERSION , + }; + +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_advise to vhost" ); +return -1 ; + } + +if (vhost_user_read (dev, &msg) <0 ) { +error_setg (errp,"Failed to get postcopy_advise reply from vhost" ); +return -1 ; + } + +if (msg.request !=VHOST_USER_POSTCOPY_ADVISE ) { +error_setg (errp,"Unexpected msg type. Expected %d received %d" , +VHOST_USER_POSTCOPY_ADVISE , msg.request); +return -1 ; + } + +if (msg.size !=sizeof (msg.payload.u64)) { +error_setg (errp,"Received bad msg size." ); +return -1 ; + } + ufd =qemu_chr_fe_get_msgfd (chr); +if (ufd <0 ) { +error_setg (errp,"%s: Failed to get ufd" , __func__); +return -1 ; + } + +/* TODO: register ufd with userfault thread */ +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {@@ -743,6 +788,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, }break ; +case POSTCOPY_NOTIFY_INBOUND_ADVISE : +return vhost_user_postcopy_advise (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;migration/postcopy-ram.h +1
-0@@ -128,6 +128,7 @@ void postcopy_infrastructure_init(void);*/ enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 , +POSTCOPY_NOTIFY_INBOUND_ADVISE , };struct PostcopyNotifyData {migration/savevm.c +6
-1@@ -1343,6 +1343,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_ADVISE );uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; +Error *local_err =NULL ;trace_loadvm_postcopy_handle_advise ();if (ps !=POSTCOPY_INCOMING_NONE ) {@@ -1390,6 +1391,11 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)return -1 ; } +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_ADVISE , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (ram_postcopy_incoming_init (mis)) {return -1 ; } --
Quoted 3 lines
2.13.5
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 09/32] vhost-user: Add 'VHOST_USER_POSTCOPY_ADVISE' message
Quoted 54 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
Quoted 23 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Wire up a notifier to send a
VHOST_USER_POSTCOPY_ADVISEmessage on an incoming advise.Later patches will fill in the behaviour/contents of the message.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 21 ++++++++++++--- contrib/libvhost-user/libvhost-user.h | 6 ++++- docs/interop/vhost-user.txt | 9 +++++++ hw/virtio/vhost-user.c | 48 +++++++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 6 +++++ 6 files changed, 86 insertions(+), 5 deletions(-)contrib/libvhost-user/libvhost-user.c +0
-0contrib/libvhost-user/libvhost-user.c vu_request_to_string(int req) · line 47
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +0
-3@@ -42,9 +42,6 @@ vu_request_to_string(int req)REQ (VHOST_USER_NONE ),REQ (VHOST_USER_GET_FEATURES ), REQ(VHOST_USER_SET_FEATURES), -REQ (VHOST_USER_NONE ), -REQ (VHOST_USER_GET_FEATURES ), - REQ(VHOST_USER_SET_FEATURES),nice cleanup ;)
Quoted 18 lines
contrib/libvhost-user/libvhost-user.c +4
-1REQ (VHOST_USER_SET_OWNER ),REQ (VHOST_USER_RESET_OWNER ), REQ(VHOST_USER_SET_MEM_TABLE),@@ -62,7 +59,10 @@ vu_request_to_string(int req)REQ (VHOST_USER_GET_QUEUE_NUM ),REQ (VHOST_USER_SET_VRING_ENABLE ),REQ (VHOST_USER_SEND_RARP ), -REQ (VHOST_USER_INPUT_GET_CONFIG ), +REQ (VHOST_USER_SET_SLAVE_REQ_FD ), +REQ (VHOST_USER_IOTLB_MSG ), +REQ (VHOST_USER_SET_VRING_ENDIAN ), +REQ (VHOST_USER_POSTCOPY_ADVISE ), REQ(VHOST_USER_MAX), };#undef REQ@@ -744,6 +744,17 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) }
Quoted 7 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 750
Quoted 5 lines
contrib/libvhost-user/libvhost-user.c +4
-0static bool +vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) +{ +/* TODO: Open ufd, pass it back in the request +* TODO: Add addresses Extra EOL space
Gone.
Quoted 157 lines
Quoted 157 lines
contrib/libvhost-user/libvhost-user.c +9
-0+*/ + vmsg->payload.u64 =0xcafe ; + vmsg->size =sizeof (vmsg->payload.u64); +return true;/* = send a reply */ +} + +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;@@ -808,6 +819,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_vring_enable_exec (dev, vmsg);case VHOST_USER_NONE :break ; +case VHOST_USER_POSTCOPY_ADVISE : +return vu_set_postcopy_advise (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +5
-1@@ -62,7 +62,11 @@ typedef enum VhostUserRequest {VHOST_USER_GET_QUEUE_NUM =17 ,VHOST_USER_SET_VRING_ENABLE =18 ,VHOST_USER_SEND_RARP =19 , -VHOST_USER_INPUT_GET_CONFIG =20 , +VHOST_USER_NET_SET_MTU =20 , +VHOST_USER_SET_SLAVE_REQ_FD =21 , +VHOST_USER_IOTLB_MSG =22 , +VHOST_USER_SET_VRING_ENDIAN =23 , +VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_MAX } VhostUserRequest;docs/interop/vhost-user.txt +9
-0@@ -606,6 +606,15 @@ Master message types and expect this message once (per VQ) during device configuration (ie. before the master starts the VQ). + * VHOST_USER_POSTCOPY_ADVISE + Id: 24 + Master payload: N/A + Slave payload: userfault fd + u64 + + Master advises slave that a migration with postcopy enabled is underway, + the slave must open a userfaultfd for later use. + Note that at this stage the migration is still in precopy mode. + Slave message types -------------------hw/virtio/vhost-user.c +48
-0@@ -67,6 +67,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_SLAVE_REQ_FD =21 ,VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 , +VHOST_USER_POSTCOPY_ADVISE =24 , VHOST_USER_MAX } VhostUserRequest;@@ -724,6 +725,50 @@ out:return ret; } +/* +* Called at the start of an inbound postcopy on reception of the +* 'advise' command. +*/ +static int vhost_user_postcopy_advise (struct vhost_dev *dev,Error **errp) +{ +struct vhost_user *u = dev->opaque; +CharBackend *chr = u->chr; +int ufd; +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_ADVISE , + .flags =VHOST_USER_VERSION , + }; + +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_advise to vhost" ); +return -1 ; + } + +if (vhost_user_read (dev, &msg) <0 ) { +error_setg (errp,"Failed to get postcopy_advise reply from vhost" ); +return -1 ; + } + +if (msg.request !=VHOST_USER_POSTCOPY_ADVISE ) { +error_setg (errp,"Unexpected msg type. Expected %d received %d" , +VHOST_USER_POSTCOPY_ADVISE , msg.request); +return -1 ; + } + +if (msg.size !=sizeof (msg.payload.u64)) { +error_setg (errp,"Received bad msg size." ); +return -1 ; + } + ufd =qemu_chr_fe_get_msgfd (chr); +if (ufd <0 ) { +error_setg (errp,"%s: Failed to get ufd" , __func__); +return -1 ; + } + +/* TODO: register ufd with userfault thread */ +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {@@ -743,6 +788,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, }break ; +case POSTCOPY_NOTIFY_INBOUND_ADVISE : +return vhost_user_postcopy_advise (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;migration/postcopy-ram.h +1
-0@@ -128,6 +128,7 @@ void postcopy_infrastructure_init(void);*/ enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 , +POSTCOPY_NOTIFY_INBOUND_ADVISE , };struct PostcopyNotifyData {migration/savevm.c +1
-0@@ -1343,6 +1343,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_ADVISE );uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; +Error *local_err =NULL ;trace_loadvm_postcopy_handle_advise ();if (ps !=POSTCOPY_INCOMING_NONE ) {@@ -1390,6 +1391,11 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)return -1 ; }
Quoted 14 lines
Quoted 9 lines
migration/savevm.c +5
-1+if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_ADVISE , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (ram_postcopy_incoming_init (mis)) {return -1 ; } --Quoted 3 lines
2.13.5
Reviewed-by Marc-André Lureau <[email protected]>
Thanks.
Dave
Quoted 6 lines
Signature · 2 lines
-- Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 10/32 vhub: Support sending fds back to qemu
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Allow replies with fds (for postcopy)
--- contrib/libvhost-user/libvhost-user.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
contrib/libvhost-user/libvhost-user.c +28 -1
@@ -213,6 +213,30 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) {int rc;uint8_t *p = (uint8_t *)vmsg; +char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS *sizeof (int ))] = { }; +struct iovec iov = { + .iov_base = (char *)vmsg, + .iov_len =VHOST_USER_HDR_SIZE , + }; +struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen =1 , + .msg_control = control, + }; +struct cmsghdr *cmsg; + +memset (control,0 ,sizeof (control)); +if (vmsg->fds) { +size_t fdsize = vmsg->fd_num *sizeof (int ); + msg.msg_controllen =CMSG_SPACE (fdsize); + cmsg =CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len =CMSG_LEN (fdsize); + cmsg->cmsg_level =SOL_SOCKET ; + cmsg->cmsg_type =SCM_RIGHTS ; +memcpy (CMSG_DATA (cmsg), vmsg->fds, fdsize); + }else { + msg.msg_controllen =0 ; + }/* Set the version in the flags when sending the reply */ vmsg->flags &= ~VHOST_USER_VERSION_MASK ;
@@ -220,7 +244,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) vmsg->flags |=VHOST_USER_REPLY_MASK ;do { - rc =write (conn_fd, p,VHOST_USER_HDR_SIZE ); + rc =sendmsg (conn_fd, &msg,0 ); }while (rc <0 && (errno ==EINTR || errno ==EAGAIN )); do {
@@ -313,6 +337,7 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg) } vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;DPRINT ("Sending back to guest u64: 0x%016" PRIx64"\n" , vmsg->payload.u64);
@@ -454,6 +479,7 @@ vu_set_log_base_exec(VuDev *dev, VhostUserMsg *vmsg) dev->log_size = log_mmap_size; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; }
@@ -698,6 +724,7 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 = features; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; }
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 10/32] vhub: Support sending fds back to qemu
Hi
Quoted 21 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Allow replies with fds (for postcopy)
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)contrib/libvhost-user/libvhost-user.c +4
-0@@ -213,6 +213,30 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) {int rc;uint8_t *p = (uint8_t *)vmsg; +char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS *sizeof (int ))] = { }; +struct iovec iov = { + .iov_base = (char *)vmsg, + .iov_len =VHOST_USER_HDR_SIZE ,
contrib/libvhost-user/libvhost-user.c vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) · line 229
Quoted 10 lines
contrib/libvhost-user/libvhost-user.c +10
-0+ }; +struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen =1 , + .msg_control = control, + }; +struct cmsghdr *cmsg; + +memset (control,0 ,sizeof (control)); +if (vmsg->fds) {
This is going to be always true, right? Check vmsg->fd_num > 0 instead?
I would also add check or assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS)
Quoted 47 lines
contrib/libvhost-user/libvhost-user.c +14
-2+size_t fdsize = vmsg->fd_num *sizeof (int ); + msg.msg_controllen =CMSG_SPACE (fdsize); + cmsg =CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len =CMSG_LEN (fdsize); + cmsg->cmsg_level =SOL_SOCKET ; + cmsg->cmsg_type =SCM_RIGHTS ; +memcpy (CMSG_DATA (cmsg), vmsg->fds, fdsize); + }else { + msg.msg_controllen =0 ; + }/* Set the version in the flags when sending the reply */ vmsg->flags &= ~VHOST_USER_VERSION_MASK ;@@ -220,7 +244,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) vmsg->flags |=VHOST_USER_REPLY_MASK ;do { - rc =write (conn_fd, p,VHOST_USER_HDR_SIZE ); + rc =sendmsg (conn_fd, &msg,0 ); }while (rc <0 && (errno ==EINTR || errno ==EAGAIN )); do {@@ -313,6 +337,7 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg) } vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;DPRINT ("Sending back to guest u64: 0x%016" PRIx64"\n" , vmsg->payload.u64);@@ -454,6 +479,7 @@ vu_set_log_base_exec(VuDev *dev, VhostUserMsg *vmsg) dev->log_size = log_mmap_size; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; }@@ -698,6 +724,7 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 = features; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; } --
Quoted 3 lines
2.13.5
other than that
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 10/32] vhub: Support sending fds back to qemu
Quoted 29 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
Quoted 25 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Allow replies with fds (for postcopy)
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)contrib/libvhost-user/libvhost-user.c +8
-0@@ -213,6 +213,30 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) {int rc;uint8_t *p = (uint8_t *)vmsg; +char control[CMSG_SPACE (VHOST_MEMORY_MAX_NREGIONS *sizeof (int ))] = { }; +struct iovec iov = { + .iov_base = (char *)vmsg, + .iov_len =VHOST_USER_HDR_SIZE , + }; +struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen =1 ,
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) · line 229
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +6
-0+ .msg_control = control, + }; +struct cmsghdr *cmsg; + +memset (control,0 ,sizeof (control)); +if (vmsg->fds) {This is going to be always true, right? Check
vmsg->fd_num> 0 instead?
Ah yes, thanks.
Quoted 1 line
I would also add check or
assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS)
- if (vmsg->fds) {
+ assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS);
+ if (vmsg->fd_num > 0) {Quoted 53 lines
Quoted 48 lines
contrib/libvhost-user/libvhost-user.c +14
-2+size_t fdsize = vmsg->fd_num *sizeof (int ); + msg.msg_controllen =CMSG_SPACE (fdsize); + cmsg =CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len =CMSG_LEN (fdsize); + cmsg->cmsg_level =SOL_SOCKET ; + cmsg->cmsg_type =SCM_RIGHTS ; +memcpy (CMSG_DATA (cmsg), vmsg->fds, fdsize); + }else { + msg.msg_controllen =0 ; + }/* Set the version in the flags when sending the reply */ vmsg->flags &= ~VHOST_USER_VERSION_MASK ;@@ -220,7 +244,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) vmsg->flags |=VHOST_USER_REPLY_MASK ;do { - rc =write (conn_fd, p,VHOST_USER_HDR_SIZE ); + rc =sendmsg (conn_fd, &msg,0 ); }while (rc <0 && (errno ==EINTR || errno ==EAGAIN )); do {@@ -313,6 +337,7 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg) } vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;DPRINT ("Sending back to guest u64: 0x%016" PRIx64"\n" , vmsg->payload.u64);@@ -454,6 +479,7 @@ vu_set_log_base_exec(VuDev *dev, VhostUserMsg *vmsg) dev->log_size = log_mmap_size; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; }@@ -698,6 +724,7 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 = features; vmsg->size =sizeof (vmsg->payload.u64); + vmsg->fd_num =0 ;return true; } --Quoted 3 lines
2.13.5
other than that
Quoted 1 line
Reviewed-by Marc-André Lureau <[email protected]>
Thanks.
Dave
Quoted 4 lines
Signature · 2 lines
-- Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 11/32 vhub: Open userfaultfd
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Open a userfaultfd (on a postcopy_advise) and send it back in the reply to the qemu for it to monitor.
--- contrib/libvhost-user/libvhost-user.c | 26 +++++++++++++++++++++++--- contrib/libvhost-user/libvhost-user.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-)
contrib/libvhost-user/libvhost-user.c +23 -3
@@ -15,6 +15,7 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/syscall.h> #include <linux/vhost.h> #include "qemu/atomic.h"
@@ -773,11 +774,30 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)static bool vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) { -/* TODO: Open ufd, pass it back in the request -* TODO: Add addresses -*/ +struct uffdio_api api_struct; + + dev->postcopy_ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK ); +/* TODO: Add addresses */ vmsg->payload.u64 =0xcafe ; vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->postcopy_ufd ==-1 ) { +vu_panic (dev,"Userfaultfd not available: %s" ,strerror (errno)); + goto out; + } + api_struct.api =UFFD_API ; + api_struct.features =0 ; +if (ioctl (dev->postcopy_ufd,UFFDIO_API , &api_struct)) { +vu_panic (dev,"Failed UFFDIO_API: %s" ,strerror (errno)); +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; + goto out; + } +/* TODO: Stash feature flags somewhere */ +out: +/* Return a ufd to the QEMU */ + vmsg->fd_num =1 ; + vmsg->fds[0 ] = dev->postcopy_ufd;return true;/* = send a reply */ }
contrib/libvhost-user/libvhost-user.h +3 -0
@@ -234,6 +234,9 @@ struct VuDev {* re-initialize */ vu_panic_cb panic;const VuDevIface *iface; + +/* Postcopy data */ +int postcopy_ufd; }; typedef struct VuVirtqElement {
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 11/32] vhub: Open userfaultfd
Quoted 30 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Open a userfaultfd (on a
postcopy_advise) and send it back in the reply to the qemu for it to monitor.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 26 +++++++++++++++++++++++--- contrib/libvhost-user/libvhost-user.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-)contrib/libvhost-user/libvhost-user.c +1
-3@@ -15,6 +15,7 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/syscall.h> #include <linux/vhost.h> #include "qemu/atomic.h" @@ -773,11 +774,30 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)static bool vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) { -/* TODO: Open ufd, pass it back in the request -* TODO: Add addresses -*/
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 786
Quoted 10 lines
contrib/libvhost-user/libvhost-user.c +8
-0+struct uffdio_api api_struct; + + dev->postcopy_ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK ); +/* TODO: Add addresses */ vmsg->payload.u64 =0xcafe ; vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->postcopy_ufd ==-1 ) { +vu_panic (dev,"Userfaultfd not available: %s" ,strerror (errno)); + goto out;
We got error but still goto out? I feel like we should reply with some kind of error code when any error happens.
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 794
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c +8
-0+ } + api_struct.api =UFFD_API ; + api_struct.features =0 ; +if (ioctl (dev->postcopy_ufd,UFFDIO_API , &api_struct)) { +vu_panic (dev,"Failed UFFDIO_API: %s" ,strerror (errno)); +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; + goto out;
Same here.
Quoted 26 lines
contrib/libvhost-user/libvhost-user.c +6
-0+ } +/* TODO: Stash feature flags somewhere */ +out: +/* Return a ufd to the QEMU */ + vmsg->fd_num =1 ; + vmsg->fds[0 ] = dev->postcopy_ufd;return true;/* = send a reply */ }contrib/libvhost-user/libvhost-user.h +3
-0@@ -234,6 +234,9 @@ struct VuDev {* re-initialize */ vu_panic_cb panic;const VuDevIface *iface; + +/* Postcopy data */ +int postcopy_ufd; }; typedef struct VuVirtqElement {Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 11/32] vhub: Open userfaultfd
Quoted 36 lines · * Peter Xu ([email protected]) wrote:
Quoted 35 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Open a userfaultfd (on a
postcopy_advise) and send it back in the reply to the qemu for it to monitor.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 26 +++++++++++++++++++++++--- contrib/libvhost-user/libvhost-user.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-)contrib/libvhost-user/libvhost-user.c +5
-3@@ -15,6 +15,7 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/syscall.h> #include <linux/vhost.h> #include "qemu/atomic.h" @@ -773,11 +774,30 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)static bool vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) { -/* TODO: Open ufd, pass it back in the request -* TODO: Add addresses -*/ +struct uffdio_api api_struct; + + dev->postcopy_ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK ); +/* TODO: Add addresses */ vmsg->payload.u64 =0xcafe ;
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 786
Quoted 5 lines
contrib/libvhost-user/libvhost-user.c +4
-0vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->postcopy_ufd ==-1 ) { +vu_panic (dev,"Userfaultfd not available: %s" ,strerror (errno)); + goto out;We got error but still goto out? I feel like we should reply with some kind of error code when any error happens.
See that the out: code returns the dev->postcopy_ufd to qemu and in this case it's -1 so it is already flagged as an error.
Quoted 10 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 794
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c +8
-0+ } + api_struct.api =UFFD_API ; + api_struct.features =0 ; +if (ioctl (dev->postcopy_ufd,UFFDIO_API , &api_struct)) { +vu_panic (dev,"Failed UFFDIO_API: %s" ,strerror (errno)); +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; + goto out;Same here.
And there we explicitly set dev->postcopy_ufd = -1 before going to out so it's sent as the error value.
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 800
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +6
-0+ } +/* TODO: Stash feature flags somewhere */ +out: +/* Return a ufd to the QEMU */ + vmsg->fd_num =1 ; + vmsg->fds[0 ] = dev->postcopy_ufd;
^^^ see that's where the -1's end up.
Quoted 2 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 802
Quoted 2 lines
contrib/libvhost-user/libvhost-user.c +0
-0return true;/* = send a reply */ }
Dave
Quoted 14 lines
Quoted 14 lines
contrib/libvhost-user/libvhost-user.h +3
-0@@ -234,6 +234,9 @@ struct VuDev {* re-initialize */ vu_panic_cb panic;const VuDevIface *iface; + +/* Postcopy data */ +int postcopy_ufd; };
Quoted 7 lines
Quoted 4 lines
contrib/libvhost-user/libvhost-user.h +0
-0typedef struct VuVirtqElement {Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 11/32] vhub: Open userfaultfd
In reply to Dr. David Alan Gilbert (git)I would rather use libvhost-user: message prefix (same for similar libvhost-user patches)
Quoted 24 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Open a userfaultfd (on a
postcopy_advise) and send it back in the reply to the qemu for it to monitor.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 26 +++++++++++++++++++++++--- contrib/libvhost-user/libvhost-user.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-)contrib/libvhost-user/libvhost-user.c +1
-0@@ -15,6 +15,7 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/syscall.h> #include <linux/vhost.h> #include "qemu/atomic.h"
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 779
Quoted 9 lines
contrib/libvhost-user/libvhost-user.c +3
-3@@ -773,11 +774,30 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)static bool vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) { -/* TODO: Open ufd, pass it back in the request -* TODO: Add addresses -*/ +struct uffdio_api api_struct; + + dev->postcopy_ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK );
This will likely fail to compile on !Linux, could you add some appropriate #ifdef?
Quoted 42 lines
contrib/libvhost-user/libvhost-user.c +19
-0+/* TODO: Add addresses */ vmsg->payload.u64 =0xcafe ; vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->postcopy_ufd ==-1 ) { +vu_panic (dev,"Userfaultfd not available: %s" ,strerror (errno)); + goto out; + } + api_struct.api =UFFD_API ; + api_struct.features =0 ; +if (ioctl (dev->postcopy_ufd,UFFDIO_API , &api_struct)) { +vu_panic (dev,"Failed UFFDIO_API: %s" ,strerror (errno)); +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; + goto out; + } +/* TODO: Stash feature flags somewhere */ +out: +/* Return a ufd to the QEMU */ + vmsg->fd_num =1 ; + vmsg->fds[0 ] = dev->postcopy_ufd;return true;/* = send a reply */ }contrib/libvhost-user/libvhost-user.h +3
-1@@ -234,6 +234,9 @@ struct VuDev {* re-initialize */ vu_panic_cb panic;const VuDevIface *iface; + +/* Postcopy data */ +int postcopy_ufd; }; typedef struct VuVirtqElement { --2.13.5
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 11/32] vhub: Open userfaultfd
Quoted 2 lines · * Marc-André Lureau ([email protected]) wrote:
I would rather use libvhost-user: message prefix (same for similar libvhost-user patches)
Done.
Quoted 24 lines
Quoted 22 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Open a userfaultfd (on a
postcopy_advise) and send it back in the reply to the qemu for it to monitor.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 26 +++++++++++++++++++++++--- contrib/libvhost-user/libvhost-user.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-)contrib/libvhost-user/libvhost-user.c +1
-0@@ -15,6 +15,7 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/syscall.h> #include <linux/vhost.h>
Quoted 14 lines
contrib/libvhost-user/libvhost-user.c vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) · line 779
Quoted 11 lines
contrib/libvhost-user/libvhost-user.c +3
-3#include "qemu/atomic.h" @@ -773,11 +774,30 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)static bool vu_set_postcopy_advise (VuDev *dev,VhostUserMsg *vmsg) { -/* TODO: Open ufd, pass it back in the request -* TODO: Add addresses -*/ +struct uffdio_api api_struct; + + dev->postcopy_ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK );This will likely fail to compile on !Linux, could you add some appropriate #ifdef?
Note that we already #include <linux/vhost.h> so this file only builds on Linux anyway before I came along, however I'll add some ifdef's for my new code.
Dave
Quoted 37 lines
Quoted 37 lines
contrib/libvhost-user/libvhost-user.c +19
-0+/* TODO: Add addresses */ vmsg->payload.u64 =0xcafe ; vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->postcopy_ufd ==-1 ) { +vu_panic (dev,"Userfaultfd not available: %s" ,strerror (errno)); + goto out; + } + api_struct.api =UFFD_API ; + api_struct.features =0 ; +if (ioctl (dev->postcopy_ufd,UFFDIO_API , &api_struct)) { +vu_panic (dev,"Failed UFFDIO_API: %s" ,strerror (errno)); +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; + goto out; + } +/* TODO: Stash feature flags somewhere */ +out: +/* Return a ufd to the QEMU */ + vmsg->fd_num =1 ; + vmsg->fds[0 ] = dev->postcopy_ufd;return true;/* = send a reply */ }contrib/libvhost-user/libvhost-user.h +3
-0@@ -234,6 +234,9 @@ struct VuDev {* re-initialize */ vu_panic_cb panic;const VuDevIface *iface; + +/* Postcopy data */ +int postcopy_ufd; };
Quoted 10 lines
Quoted 5 lines
contrib/libvhost-user/libvhost-user.h +0
-1typedef struct VuVirtqElement { --2.13.5
Signature · 1 line
Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 12/32 postcopy: Allow registering of fd handler
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Allow other userfaultfd's to be registered into the fault thread so that handlers for shared memory can get responses.
--- migration/migration.c | 3 + migration/migration.h | 2 + migration/postcopy-ram.c | 212 +++++++++++++++++++++++++++++++++++------------ migration/postcopy-ram.h | 21 +++++ migration/trace-events | 2 + 5 files changed, 186 insertions(+), 54 deletions(-)
migration/migration.c +3 -0
@@ -144,6 +144,8 @@ MigrationIncomingState *migration_incoming_get_current(void)if (!once) { mis_current.state =MIGRATION_STATUS_NONE ;memset (&mis_current,0 ,sizeof (MigrationIncomingState)); + mis_current.postcopy_remote_fds =g_array_new (FALSE, TRUE, +sizeof (struct PostCopyFD ));qemu_mutex_init (&mis_current.rp_mutex);qemu_event_init (&mis_current.main_thread_load_event, false); once = true;
@@ -166,6 +168,7 @@ void migration_incoming_state_destroy(void)qemu_fclose (mis->from_src_file); mis->from_src_file =NULL ; } +g_array_free (mis->postcopy_remote_fds, TRUE);qemu_event_destroy (&mis->main_thread_load_event); }
migration/migration.h +2 -0
@@ -48,6 +48,8 @@ struct MigrationIncomingState {QemuMutex rp_mutex;/* We send replies from multiple threads */ void *postcopy_tmp_page;void *postcopy_tmp_zero_page; +/* PostCopyFD's for external userfaultfds & handlers of shared memory */ +GArray *postcopy_remote_fds;QEMUBH *bh;
migration/postcopy-ram.c +158 -54
247 lines not on this page · raw message
migration/postcopy-ram.h +21 -0
@@ -141,4 +141,25 @@ void postcopy_remove_notifier(NotifierWithReturn *n);/* Call the notifier list set by postcopy_add_start_notifier */ int postcopy_notify (enum PostcopyNotifyReason reason,Error **errp); +struct PostCopyFD ; + +/* ufd is a pointer to the struct uffd_msg *TODO: more Portable! */ +typedef int (*pcfdhandler )(struct PostCopyFD *pcfd,void *ufd); + +struct PostCopyFD { +int fd; +/* Data to pass to handler */ +void *data; +/* Handler to be called whenever we get a poll event */ +pcfdhandler handler; +/* A string to use in error messages */ +char *idstr; +}; + +/* Register a userfaultfd owned by an external process for +* shared memory. +*/ +void postcopy_register_shared_ufd (struct PostCopyFD *pcfd); +void postcopy_unregister_shared_ufd (struct PostCopyFD *pcfd); +#endif
migration/trace-events +2 -0
@@ -189,6 +189,8 @@ postcopy_place_page_zero(void *host_addr) "host=%p" postcopy_ram_enable_notify(void) "" postcopy_ram_fault_thread_entry(void) "" postcopy_ram_fault_thread_exit(void) "" +postcopy_ram_fault_thread_fds_core(int baseufd, int quitfd) "ufd: %d quitfd: %d" +postcopy_ram_fault_thread_fds_extra(size_t index, const char *name, int fd) "%zd/%s: %d" postcopy_ram_fault_thread_quit(void) "" postcopy_ram_fault_thread_request(uint64_t hostaddr, const char *ramblock, size_t offset) "Request for HVA=0x%" PRIx64 " rb=%s offset=0x%zx" postcopy_ram_incoming_cleanup_closeuf(void) ""
Signature · 1 line
2.13.5
RFC v2 13/32 vhost+postcopy: Register shared ufd with postcopy
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Register the UFD that comes in as the response to the 'advise' method with the postcopy code.
--- hw/virtio/vhost-user.c | 21 ++++++++++++++++++++- migration/postcopy-ram.h | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-)
hw/virtio/vhost-user.c +20 -1
@@ -24,6 +24,7 @@#include <sys/socket.h> #include <sys/un.h> #include <linux/vhost.h> +#include <linux/userfaultfd.h> #define VHOST_MEMORY_MAX_NREGIONS 8#define VHOST_USER_F_PROTOCOL_FEATURES 30
@@ -130,6 +131,7 @@ struct vhost_user {CharBackend *chr;int slave_fd;NotifierWithReturn postcopy_notifier; +struct PostCopyFD postcopy_fd; };static bool ioeventfd_enabled (void )
@@ -726,6 +728,17 @@ out: }/* +* Called back from the postcopy fault thread when a fault is received on our +* ufd. +* TODO: This is Linux specific +*/ +static int vhost_user_postcopy_fault_handler (struct PostCopyFD *pcfd, +void *ufd) +{ +return 0 ; +} + +/* * Called at the start of an inbound postcopy on reception of the * 'advise' command. */
@@ -764,8 +777,14 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)error_setg (errp,"%s: Failed to get ufd" , __func__);return -1 ; } +fcntl (ufd,F_SETFL ,O_NONBLOCK ); -/* TODO: register ufd with userfault thread */ +/* register ufd with userfault thread */ + u->postcopy_fd.fd = ufd; + u->postcopy_fd.data = dev; + u->postcopy_fd.handler = vhost_user_postcopy_fault_handler; + u->postcopy_fd.idstr ="vhost-user" ;/* Need to find unique name */ +postcopy_register_shared_ufd (&u->postcopy_fd);return 0 ; }
migration/postcopy-ram.h +1 -1
@@ -153,7 +153,7 @@ struct PostCopyFD {/* Handler to be called whenever we get a poll event */ pcfdhandler handler;/* A string to use in error messages */ -char *idstr; +const char *idstr; };/* Register a userfaultfd owned by an external process for
Signature · 1 line
2.13.5
RFC v2 14/32 vhost+postcopy: Transmit 'listen' to client
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Notify the vhost-user client on reception of the 'postcopy-listen' event from the source.
--- contrib/libvhost-user/libvhost-user.c | 21 +++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 2 ++ docs/interop/vhost-user.txt | 6 ++++++ hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 7 +++++++ 7 files changed, 70 insertions(+)
contrib/libvhost-user/libvhost-user.c +21 -0
@@ -15,7 +15,9 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/ioctl.h> #include <sys/syscall.h> +#include <linux/userfaultfd.h> #include <linux/vhost.h> #include "qemu/atomic.h"
@@ -64,6 +66,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_IOTLB_MSG ),REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ), +REQ (VHOST_USER_POSTCOPY_LISTEN ), REQ(VHOST_USER_MAX), };#undef REQ
@@ -802,6 +805,22 @@ out: }static bool +vu_set_postcopy_listen (VuDev *dev,VhostUserMsg *vmsg) +{ + vmsg->payload.u64 =-1 ; + vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->nregions) { +vu_panic (dev,"Regions already registered at postcopy-listen" ); +return true; + } + dev->postcopy_listening = true; + + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; + vmsg->payload.u64 =0 ;/* Success */ +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;
@@ -868,6 +887,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)break ;case VHOST_USER_POSTCOPY_ADVISE :return vu_set_postcopy_advise (dev, vmsg); +case VHOST_USER_POSTCOPY_LISTEN : +return vu_set_postcopy_listen (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);
contrib/libvhost-user/libvhost-user.h +2 -0
@@ -67,6 +67,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;
@@ -237,6 +238,7 @@ struct VuDev {/* Postcopy data */ int postcopy_ufd; +bool postcopy_listening; }; typedef struct VuVirtqElement {
docs/interop/vhost-user.txt +6 -0
@@ -615,6 +615,12 @@ Master message types the slave must open a userfaultfd for later use. Note that at this stage the migration is still in precopy mode. + * VHOST_USER_POSTCOPY_LISTEN + Id: 25 + Master payload: N/A + + Master advises slave that a transition to postcopy mode has happened. + Slave message types -------------------
hw/virtio/trace-events +3 -0
@@ -1,5 +1,8 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost-user.c +vhost_user_postcopy_listen(void) "" + # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
hw/virtio/vhost-user.c +30 -0
@@ -69,6 +69,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;
@@ -788,6 +789,32 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)return 0 ; } +/* +* Called at the switch to postcopy on reception of the 'listen' command. +*/ +static int vhost_user_postcopy_listen (struct vhost_dev *dev,Error **errp) +{ +int ret; +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_LISTEN , + .flags =VHOST_USER_VERSION |VHOST_USER_NEED_REPLY_MASK , + }; + +trace_vhost_user_postcopy_listen (); +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_listen to vhost" ); +return -1 ; + } + + ret =process_message_reply (dev, &msg); +if (ret) { +error_setg (errp,"Failed to receive reply to postcopy_listen" ); +return ret; + } + +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {
@@ -810,6 +837,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,case POSTCOPY_NOTIFY_INBOUND_ADVISE :return vhost_user_postcopy_advise (dev, pnd->errp); +case POSTCOPY_NOTIFY_INBOUND_LISTEN : +return vhost_user_postcopy_listen (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;
migration/postcopy-ram.h +1 -0
@@ -129,6 +129,7 @@ void postcopy_infrastructure_init(void);enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 ,POSTCOPY_NOTIFY_INBOUND_ADVISE , +POSTCOPY_NOTIFY_INBOUND_LISTEN , };struct PostcopyNotifyData {
migration/savevm.c +7 -0
@@ -1557,6 +1557,8 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_LISTENING );trace_loadvm_postcopy_handle_listen (); +Error *local_err =NULL ; +if (ps !=POSTCOPY_INCOMING_ADVISE && ps !=POSTCOPY_INCOMING_DISCARD ) {error_report ("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)" , ps);return -1 ;
@@ -1578,6 +1580,11 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)return -1 ; } +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_LISTEN , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (mis->have_listen_thread) {error_report ("CMD_POSTCOPY_RAM_LISTEN already has a listen thread" );return -1 ;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 14/32] vhost+postcopy: Transmit 'listen' to client
Quoted 21 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Notify the vhost-user client on reception of the 'postcopy-listen' event from the source.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 21 +++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 2 ++ docs/interop/vhost-user.txt | 6 ++++++ hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 7 +++++++ 7 files changed, 70 insertions(+)contrib/libvhost-user/libvhost-user.c +0
-0
contrib/libvhost-user/libvhost-user.c line 22
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c +2
-0@@ -15,7 +15,9 @@#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/ioctl.h> #include <sys/syscall.h> +#include <linux/userfaultfd.h> #include <linux/vhost.h>
Belong to an earlier patch
Quoted 184 lines
contrib/libvhost-user/libvhost-user.c +19
-0#include "qemu/atomic.h" @@ -64,6 +66,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_IOTLB_MSG ),REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ), +REQ (VHOST_USER_POSTCOPY_LISTEN ), REQ(VHOST_USER_MAX), };#undef REQ@@ -802,6 +805,22 @@ out: }static bool +vu_set_postcopy_listen (VuDev *dev,VhostUserMsg *vmsg) +{ + vmsg->payload.u64 =-1 ; + vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->nregions) { +vu_panic (dev,"Regions already registered at postcopy-listen" ); +return true; + } + dev->postcopy_listening = true; + + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; + vmsg->payload.u64 =0 ;/* Success */ +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;@@ -868,6 +887,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)break ;case VHOST_USER_POSTCOPY_ADVISE :return vu_set_postcopy_advise (dev, vmsg); +case VHOST_USER_POSTCOPY_LISTEN : +return vu_set_postcopy_listen (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +2
-0@@ -67,6 +67,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;@@ -237,6 +238,7 @@ struct VuDev {/* Postcopy data */ int postcopy_ufd; +bool postcopy_listening; }; typedef struct VuVirtqElement {docs/interop/vhost-user.txt +6
-0@@ -615,6 +615,12 @@ Master message types the slave must open a userfaultfd for later use. Note that at this stage the migration is still in precopy mode. + * VHOST_USER_POSTCOPY_LISTEN + Id: 25 + Master payload: N/A + + Master advises slave that a transition to postcopy mode has happened. + Slave message types -------------------hw/virtio/trace-events +3
-0@@ -1,5 +1,8 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost-user.c +vhost_user_postcopy_listen(void) "" + # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"hw/virtio/vhost-user.c +30
-0@@ -69,6 +69,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;@@ -788,6 +789,32 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)return 0 ; } +/* +* Called at the switch to postcopy on reception of the 'listen' command. +*/ +static int vhost_user_postcopy_listen (struct vhost_dev *dev,Error **errp) +{ +int ret; +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_LISTEN , + .flags =VHOST_USER_VERSION |VHOST_USER_NEED_REPLY_MASK , + }; + +trace_vhost_user_postcopy_listen (); +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_listen to vhost" ); +return -1 ; + } + + ret =process_message_reply (dev, &msg); +if (ret) { +error_setg (errp,"Failed to receive reply to postcopy_listen" ); +return ret; + } + +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {@@ -810,6 +837,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,case POSTCOPY_NOTIFY_INBOUND_ADVISE :return vhost_user_postcopy_advise (dev, pnd->errp); +case POSTCOPY_NOTIFY_INBOUND_LISTEN : +return vhost_user_postcopy_listen (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;migration/postcopy-ram.h +1
-0@@ -129,6 +129,7 @@ void postcopy_infrastructure_init(void);enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 ,POSTCOPY_NOTIFY_INBOUND_ADVISE , +POSTCOPY_NOTIFY_INBOUND_LISTEN , };struct PostcopyNotifyData {migration/savevm.c +7
-1@@ -1557,6 +1557,8 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_LISTENING );trace_loadvm_postcopy_handle_listen (); +Error *local_err =NULL ; +if (ps !=POSTCOPY_INCOMING_ADVISE && ps !=POSTCOPY_INCOMING_DISCARD ) {error_report ("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)" , ps);return -1 ;@@ -1578,6 +1580,11 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)return -1 ; } +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_LISTEN , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (mis->have_listen_thread) {error_report ("CMD_POSTCOPY_RAM_LISTEN already has a listen thread" );return -1 ; --
Quoted 3 lines
2.13.5
Looks good to me otherwise,
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 14/32] vhost+postcopy: Transmit 'listen' to client
Quoted 24 lines · * Marc-André Lureau ([email protected]) wrote:
Quoted 22 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Notify the vhost-user client on reception of the 'postcopy-listen' event from the source.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 21 +++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 2 ++ docs/interop/vhost-user.txt | 6 ++++++ hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ migration/postcopy-ram.h | 1 + migration/savevm.c | 7 +++++++ 7 files changed, 70 insertions(+)contrib/libvhost-user/libvhost-user.c +0
-0@@ -15,7 +15,9 @@
Quoted 9 lines
contrib/libvhost-user/libvhost-user.c line 22
Quoted 7 lines
contrib/libvhost-user/libvhost-user.c +2
-0#include <qemu/osdep.h> #include <sys/eventfd.h> +#include <sys/ioctl.h> #include <sys/syscall.h> +#include <linux/userfaultfd.h> #include <linux/vhost.h> Belong to an earlier patch
oops, thanks.
Quoted 190 lines
Quoted 184 lines
contrib/libvhost-user/libvhost-user.c +19
-0#include "qemu/atomic.h" @@ -64,6 +66,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_IOTLB_MSG ),REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ), +REQ (VHOST_USER_POSTCOPY_LISTEN ), REQ(VHOST_USER_MAX), };#undef REQ@@ -802,6 +805,22 @@ out: }static bool +vu_set_postcopy_listen (VuDev *dev,VhostUserMsg *vmsg) +{ + vmsg->payload.u64 =-1 ; + vmsg->size =sizeof (vmsg->payload.u64); + +if (dev->nregions) { +vu_panic (dev,"Regions already registered at postcopy-listen" ); +return true; + } + dev->postcopy_listening = true; + + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; + vmsg->payload.u64 =0 ;/* Success */ +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {int do_reply =0 ;@@ -868,6 +887,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)break ;case VHOST_USER_POSTCOPY_ADVISE :return vu_set_postcopy_advise (dev, vmsg); +case VHOST_USER_POSTCOPY_LISTEN : +return vu_set_postcopy_listen (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +2
-0@@ -67,6 +67,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;@@ -237,6 +238,7 @@ struct VuDev {/* Postcopy data */ int postcopy_ufd; +bool postcopy_listening; }; typedef struct VuVirtqElement {docs/interop/vhost-user.txt +6
-0@@ -615,6 +615,12 @@ Master message types the slave must open a userfaultfd for later use. Note that at this stage the migration is still in precopy mode. + * VHOST_USER_POSTCOPY_LISTEN + Id: 25 + Master payload: N/A + + Master advises slave that a transition to postcopy mode has happened. + Slave message types -------------------hw/virtio/trace-events +3
-0@@ -1,5 +1,8 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost-user.c +vhost_user_postcopy_listen(void) "" + # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"hw/virtio/vhost-user.c +30
-0@@ -69,6 +69,7 @@ typedef enum VhostUserRequest {VHOST_USER_IOTLB_MSG =22 ,VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 , +VHOST_USER_POSTCOPY_LISTEN =25 , VHOST_USER_MAX } VhostUserRequest;@@ -788,6 +789,32 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)return 0 ; } +/* +* Called at the switch to postcopy on reception of the 'listen' command. +*/ +static int vhost_user_postcopy_listen (struct vhost_dev *dev,Error **errp) +{ +int ret; +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_LISTEN , + .flags =VHOST_USER_VERSION |VHOST_USER_NEED_REPLY_MASK , + }; + +trace_vhost_user_postcopy_listen (); +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_listen to vhost" ); +return -1 ; + } + + ret =process_message_reply (dev, &msg); +if (ret) { +error_setg (errp,"Failed to receive reply to postcopy_listen" ); +return ret; + } + +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {@@ -810,6 +837,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,case POSTCOPY_NOTIFY_INBOUND_ADVISE :return vhost_user_postcopy_advise (dev, pnd->errp); +case POSTCOPY_NOTIFY_INBOUND_LISTEN : +return vhost_user_postcopy_listen (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;migration/postcopy-ram.h +1
-0@@ -129,6 +129,7 @@ void postcopy_infrastructure_init(void);enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 ,POSTCOPY_NOTIFY_INBOUND_ADVISE , +POSTCOPY_NOTIFY_INBOUND_LISTEN , };struct PostcopyNotifyData {migration/savevm.c +7
-1@@ -1557,6 +1557,8 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) {PostcopyState ps =postcopy_state_set (POSTCOPY_INCOMING_LISTENING );trace_loadvm_postcopy_handle_listen (); +Error *local_err =NULL ; +if (ps !=POSTCOPY_INCOMING_ADVISE && ps !=POSTCOPY_INCOMING_DISCARD ) {error_report ("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)" , ps);return -1 ;@@ -1578,6 +1580,11 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)return -1 ; } +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_LISTEN , &local_err)) { +error_report_err (local_err); +return -1 ; + } +if (mis->have_listen_thread) {error_report ("CMD_POSTCOPY_RAM_LISTEN already has a listen thread" );return -1 ; --Quoted 3 lines
2.13.5
Looks good to me otherwise,
Quoted 1 line
Reviewed-by Marc-André Lureau <[email protected]>
Thanks.
Dave
Quoted 3 lines
Signature · 2 lines
-- Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 15/32 vhost+postcopy: Register new regions with the ufd
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
When new regions are sent to the client using SET_MEM_TABLE, register them with the userfaultfd.
--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
contrib/libvhost-user/libvhost-user.c +32 -0
@@ -449,6 +449,38 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) dev_region->mmap_addr); } +if (dev->postcopy_listening) { +/* We should already have an open ufd need to mark each memory +* range as ufd. +* Note: Do we need any madvises? Well it's not been accessed +* yet, still probably need no THP to be safe, discard to be safe? +*/ +struct uffdio_register reg_struct; + reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; + reg_struct.range.len = dev_region->size + dev_region->mmap_offset; + reg_struct.mode =UFFDIO_REGISTER_MODE_MISSING ; + +if (ioctl (dev->postcopy_ufd,UFFDIO_REGISTER , ®_struct)) { +vu_panic (dev,"%s: Failed to userfault region %d " +"@%p + %zx: (ufd=%d)%s\n" , + __func__, i, + dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + dev->postcopy_ufd,strerror (errno)); +continue ; + } +if (!(reg_struct.ioctls & ((__u64 )1 << _UFFDIO_COPY))) { +vu_panic (dev,"%s Region (%d) doesn't support COPY" , + __func__, i); +continue ; + } +DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , + __func__, i, reg_struct.range.start, reg_struct.range.len); +/* TODO: Stash 'zero' support flags somewhere */ +/* TODO: Get address back to QEMU */ + + } +close (vmsg->fds[i]); }
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 15/32] vhost+postcopy: Register new regions with the ufd
Use "libvhost-user: " commit title tag/prefix?
Quoted 27 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
When new regions are sent to the client using
SET_MEM_TABLE, register them with the userfaultfd.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)contrib/libvhost-user/libvhost-user.c +9
-0@@ -449,6 +449,38 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) dev_region->mmap_addr); } +if (dev->postcopy_listening) { +/* We should already have an open ufd need to mark each memory +* range as ufd. +* Note: Do we need any madvises? Well it's not been accessed +* yet, still probably need no THP to be safe, discard to be safe? +*/ +struct uffdio_register reg_struct; + reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; + reg_struct.range.len = dev_region->size + dev_region->mmap_offset;
contrib/libvhost-user/libvhost-user.c vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) · line 470
Quoted 10 lines
contrib/libvhost-user/libvhost-user.c +10
-0+ reg_struct.mode =UFFDIO_REGISTER_MODE_MISSING ; + +if (ioctl (dev->postcopy_ufd,UFFDIO_REGISTER , ®_struct)) { +vu_panic (dev,"%s: Failed to userfault region %d " +"@%p + %zx: (ufd=%d)%s\n" , + __func__, i, + dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + dev->postcopy_ufd,strerror (errno)); +continue ;
panic is supposed to be unrecoverable errors, so I would suggest to return here
Quoted 5 lines
contrib/libvhost-user/libvhost-user.c +5
-0+ } +if (!(reg_struct.ioctls & ((__u64 )1 << _UFFDIO_COPY))) { +vu_panic (dev,"%s Region (%d) doesn't support COPY" , + __func__, i); +continue ;
contrib/libvhost-user/libvhost-user.c vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) · line 485
Quoted 10 lines
contrib/libvhost-user/libvhost-user.c +8
-0+ } +DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , + __func__, i, reg_struct.range.start, reg_struct.range.len); +/* TODO: Stash 'zero' support flags somewhere */ +/* TODO: Get address back to QEMU */ + + } +close (vmsg->fds[i]); }
This patch would be nicer if it compiles on !Linux / without userfault.
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 15/32] vhost+postcopy: Register new regions with the ufd
Quoted 35 lines · * Marc-André Lureau ([email protected]) wrote:
Use "libvhost-user: " commit title tag/prefix?
Quoted 31 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
When new regions are sent to the client using
SET_MEM_TABLE, register them with the userfaultfd.Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)contrib/libvhost-user/libvhost-user.c +13
-0@@ -449,6 +449,38 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) dev_region->mmap_addr); } +if (dev->postcopy_listening) { +/* We should already have an open ufd need to mark each memory +* range as ufd. +* Note: Do we need any madvises? Well it's not been accessed +* yet, still probably need no THP to be safe, discard to be safe? +*/ +struct uffdio_register reg_struct; + reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; + reg_struct.range.len = dev_region->size + dev_region->mmap_offset; + reg_struct.mode =UFFDIO_REGISTER_MODE_MISSING ; + +if (ioctl (dev->postcopy_ufd,UFFDIO_REGISTER , ®_struct)) { + vu_panic(dev, "%s: Failed to userfault region %d "
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) · line 470
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +6
-0+"@%p + %zx: (ufd=%d)%s\n" , + __func__, i, + dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, + dev->postcopy_ufd, strerror(errno)); +continue ;panic is supposed to be unrecoverable errors, so I would suggest to return here
Done.
Quoted 9 lines
Quoted 9 lines
contrib/libvhost-user/libvhost-user.c +9
-0+ } +if (!(reg_struct.ioctls & ((__u64 )1 << _UFFDIO_COPY))) { +vu_panic (dev,"%s Region (%d) doesn't support COPY" , + __func__, i); +continue ; + } +DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , + __func__, i, reg_struct.range.start, reg_struct.range.len); +/* TODO: Stash 'zero' support flags somewhere */
Quoted 8 lines
contrib/libvhost-user/libvhost-user.c vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) · line 485
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +4
-0+/* TODO: Get address back to QEMU */ + + } +close (vmsg->fds[i]); }This patch would be nicer if it compiles on !Linux / without userfault.
Done; I've just ifdef UFFDIO_REGISTER the inside of this if; I'll add other code that makes sure it doesn't get as far as setting postcopy_listening either.
Dave
Quoted 2 lines
Signature · 1 line
Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 16/32 vhost+postcopy: Send address back to qemu
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)
contrib/libvhost-user/libvhost-user.c +14 -1
@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }
docs/interop/vhost-user.txt +6 -0
@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6
hw/virtio/trace-events +1 -0
@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
hw/virtio/vhost-user.c +56 -1
85 lines not on this page · raw message
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 105 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, static int vhost_user_set_mem_table(struct vhost_dev *dev,
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 10 lines
hw/virtio/vhost-user.c +3
-1struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;
(indent)
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {
It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe vhost_user_postcopy_end?)
Quoted 23 lines
hw/virtio/vhost-user.c +23
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS );
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 10 lines
hw/virtio/vhost-user.c +10
-0+ +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's +*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==
^^^^^^^^
should this be reply_i?
(And maybe we can use pointers for the regions for better readability?)
Quoted 23 lines
hw/virtio/vhost-user.c +17
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; +trace_vhost_user_set_mem_table_postcopy ( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr, + reply_i, region_i); + reply_i++; + } + } +if (reply_i != fd_num) { +error_report ("%s: postcopy reply not fully consumed " +"%d vs %zd" , + __func__, reply_i, fd_num); +return -1 ; + } + }if (reply_supported) {return process_message_reply (dev, &msg); }Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };
Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)
Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's
Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?
Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
I'm nervous of doing that since VhostUserMsg is 'packed' - and I'm not convinced it's legal to take a pointer to a member (although I think we do it in a whole bunch of places and clang moans about it).
Quoted 6 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 396
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,
^^^^^^^
and I think this one is region_i
Dave
Quoted 9 lines
Quoted 9 lines
hw/virtio/vhost-user.c +9
-0+ reply_i, region_i); + reply_i++; + } + } +if (reply_i != fd_num) { +error_report ("%s: postcopy reply not fully consumed " +"%d vs %zd" , + __func__, reply_i, fd_num); +return -1 ;
Quoted 11 lines
Quoted 8 lines
hw/virtio/vhost-user.c +2
-0+ } + }if (reply_supported) {return process_message_reply (dev, &msg); }Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 172 lines · Dr. David Alan Gilbert
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?
Quoted 7 lines
Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
I'm nervous of doing that since VhostUserMsg is 'packed' - and I'm not convinced it's legal to take a pointer to a member (although I think we do it in a whole bunch of places and clang moans about it).
Could I ask why packed struct is not suitable for taking field pointers out of the structs? I hardly use clang, and I feel like there is something I may have missed in C programming...
Quoted 9 lines
Quoted 7 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 396
Quoted 7 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,^^^^^^^
and I think this one isregion_i
Hmm... shouldn't msg.payload.memory.regions[] defined with size VHOST_MEMORY_MAX_NREGIONS as well?
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 177 lines · * Peter Xu ([email protected]) wrote:
Quoted 176 lines · Dr. David Alan Gilbert
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
Quoted 7 lines
Quoted 3 lines
I'm nervous of doing that since VhostUserMsg is 'packed' - and I'm not convinced it's legal to take a pointer to a member (although I think we do it in a whole bunch of places and clang moans about it).
Could I ask why packed struct is not suitable for taking field pointers out of the structs? I hardly use clang, and I feel like there is something I may have missed in C programming...
The problem is that when you 'pack' a structure all the alignment rules you normally have go away; when the compiler knows it's accessing a packed structure that's OK because the compiler knows not to rely on those alignments; however if I took a pointer to the regions table in the msg I'd end up with a VhostUserMemoryRegion* and a pointer like that carries nothing to tell the compiler to take care about alignment.
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,
Quoted 5 lines
Quoted 2 lines
^^^^^^^
and I think this one isregion_iHmm... shouldn't msg.payload.memory.regions[] defined with size
VHOST_MEMORY_MAX_NREGIONSas well?
Yes, it already is; msg is a VhostUserMsg, payload.memory is a VhostUserMemory and it has:
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
Dave
Quoted 2 lines
Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 186 lines · Dr. David Alan Gilbert
Quoted 177 lines · * Peter Xu ([email protected]) wrote:
Quoted 176 lines · Dr. David Alan Gilbert
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
Quoted 7 lines
Quoted 3 lines
I'm nervous of doing that since VhostUserMsg is 'packed' - and I'm not convinced it's legal to take a pointer to a member (although I think we do it in a whole bunch of places and clang moans about it).
Could I ask why packed struct is not suitable for taking field pointers out of the structs? I hardly use clang, and I feel like there is something I may have missed in C programming...
Quoted 7 lines
The problem is that when you 'pack' a structure all the alignment rules you normally have go away; when the compiler knows it's accessing a packed structure that's OK because the compiler knows not to rely on those alignments; however if I took a pointer to the regions table in the msg I'd end up with a VhostUserMemoryRegion* and a pointer like that carries nothing to tell the compiler to take care about alignment.
Ah I see.
I did a test with gcc:
#include <stdio.h>
struct test {
unsigned short a;
unsigned long b;
};struct test2 {
struct test c;
} __attribute__ ((packed));int main(void)
{
printf("test is %lu, test2 is %lu\n",
sizeof(struct test), sizeof(struct test2));
return 0;
}This outputs:
test is 16, test2 is 16
So I think even if test2 is marked as packed, it'll still keep how test is defined (or I would expect test be 16B while test2 be 10B)? I tried with clang and got the same result.
gcc version 6.1.1 20160621 (Red Hat 6.1.1-3) (GCC) clang version 3.8.1 (tags/RELEASE_381/final)
Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 396
Quoted 8 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,^^^^^^^
and I think this one isregion_i
Quoted 6 lines
Quoted 2 lines
Hmm... shouldn't msg.payload.memory.regions[] defined with size
VHOST_MEMORY_MAX_NREGIONSas well?Yes, it already is; msg is a VhostUserMsg, payload.memory is a VhostUserMemory and it has:
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
Sorry I mis-expressed. I mean, then we should still use reply_i here, right? Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
Quoted 219 lines · * Peter Xu ([email protected]) wrote:
Quoted 186 lines · Dr. David Alan Gilbert
Quoted 177 lines · * Peter Xu ([email protected]) wrote:
Quoted 176 lines · Dr. David Alan Gilbert
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
Quoted 7 lines
Quoted 3 lines
I'm nervous of doing that since VhostUserMsg is 'packed' - and I'm not convinced it's legal to take a pointer to a member (although I think we do it in a whole bunch of places and clang moans about it).
Could I ask why packed struct is not suitable for taking field pointers out of the structs? I hardly use clang, and I feel like there is something I may have missed in C programming...
Quoted 7 lines
The problem is that when you 'pack' a structure all the alignment rules you normally have go away; when the compiler knows it's accessing a packed structure that's OK because the compiler knows not to rely on those alignments; however if I took a pointer to the regions table in the msg I'd end up with a VhostUserMemoryRegion* and a pointer like that carries nothing to tell the compiler to take care about alignment.
Ah I see.
I did a test with gcc:
#include <
stdio.h>struct test { unsigned short a; unsigned long b; };struct test2 { struct test c; } __attribute__ ((packed));int main(void)
{ printf("test is %lu, test2 is %lu\n", sizeof(struct test), sizeof(struct test2)); return 0; }This outputs:
Quoted 8 lines
test is 16, test2 is 16
So I think even if test2 is marked as packed, it'll still keep how test is defined (or I would expect test be 16B while test2 be 10B)? I tried with clang and got the same result.
gcc version 6.1.1 20160621 (Red Hat 6.1.1-3) (GCC) clang version 3.8.1 (tags/RELEASE_381/final)
Note it's alignment not size that's the problem (and any portability test is always wrong on one compiler!)
#include <stdio.h>
#include <stddef.h>
struct test {
unsigned long c;
unsigned short d;
};struct test2 {
unsigned short a;
struct test b;
} __attribute__ ((packed));int main(void)
{
struct test2 t2;
struct test *tp=&t2.b;
unsigned long *tpc=&tp->c;
printf("t2 at %p t2.b at %p tp->c at %p\n", &t2, tp, tpc);
return 0;
}t2 at 0x7ffe7a235a30 t2.b at 0x7ffe7a235a32 tp->c at 0x7ffe7a235a32
so you see that the 'unsigned long * tpc' is unaligned as is the 'struct test *tp' - those are both unaligned but there's nothing in the type that tells you that.
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
Quoted 10 lines
Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 396
Quoted 8 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,^^^^^^^
and I think this one isregion_iHmm... shouldn't msg.payload.memory.regions[] defined with size
VHOST_MEMORY_MAX_NREGIONSas well?
Quoted 6 lines
Quoted 3 lines
Yes, it already is; msg is a VhostUserMsg, payload.memory is a VhostUserMemory and it has:
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];Sorry I mis-expressed. I mean, then we should still use
reply_ihere, right? Thanks,
Why? Aren't we indexing msg_reply by reply_i and msg by region_i ?
Dave
Quoted 2 lines
Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 16/32] vhost+postcopy: Send address back to qemu
In reply to Peter XuQuoted 179 lines · * Peter Xu ([email protected]) wrote:
Quoted 178 lines · Dr. David Alan Gilbert
Quoted 177 lines · * Peter Xu ([email protected]) wrote:
Quoted 176 lines · Dr. David Alan Gilbert
Quoted 103 lines · * Peter Xu ([email protected]) wrote:
Quoted 102 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
We need a better way, but at the moment we need the address of the mappings sent back to qemu so it can interpret the messages on the userfaultfd it reads.
Note: We don't ask for the default 'ack' reply since we've got our own.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 15 ++++++++- docs/interop/vhost-user.txt | 6 ++++ hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 57 ++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +14
-1@@ -477,13 +477,26 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)DPRINT ("%s: region %d: Registered userfault for %llx + %llx\n" , __func__, i, reg_struct.range.start, reg_struct.range.len);/* TODO: Stash 'zero' support flags somewhere */ -/* TODO: Get address back to QEMU */ +/* TODO: We need to find a way for the qemu not to see the virtual +* addresses of the clients, so as to keep better separation. +*/ +/* Return the address to QEMU so that it can translate the ufd +* fault addresses back. +*/ + msg_region->userspace_addr = (uintptr_t )(mmap_addr + + dev_region->mmap_offset); }close (vmsg->fds[i]); } +if (dev->postcopy_listening) { +/* Need to return the addresses - send the updated message back */ + vmsg->fd_num =0 ; +return true; + } +return false; }docs/interop/vhost-user.txt +6
-0@@ -413,12 +413,18 @@ Master message types Id: 5 Equivalent ioctl: VHOST_SET_MEM_TABLE Master payload: memory regions description + Slave payload: (postcopy only) memory regions description Sets the memory map regions on the slave so it can translate the vring addresses. In the ancillary data there is an array of file descriptors for each memory mapped region. The size and ordering of the fds matches the number and ordering of memory regions. + When postcopy-listening has been received, SET_MEM_TABLE replies with + the bases of the memory mapped regions to the master. It must have mmap'd + the regions and enabled userfaultfd on them. Note NEED_REPLY_MASK + is not set in this case. + * VHOST_USER_SET_LOG_BASE Id: 6hw/virtio/trace-events +1
-0@@ -2,6 +2,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" +vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +2
-0@@ -19,6 +19,7 @@#include "qemu/sockets.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" +#include "trace.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -133,6 +134,7 @@ struct vhost_user {int slave_fd;NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd; +uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; };Quoted 15 lines
hw/virtio/vhost-user.c static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, · line 311
Quoted 13 lines
hw/virtio/vhost-user.c +3
-1static bool ioeventfd_enabled (void )@@ -300,11 +302,13 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,static int vhost_user_set_mem_table (struct vhost_dev *dev,struct vhost_memory *mem) { +struct vhost_user *u = dev->opaque;int fds[VHOST_MEMORY_MAX_NREGIONS ];int i, fd;size_t fd_num =0 ;bool reply_supported =virtio_has_feature (dev->protocol_features, -VHOST_USER_PROTOCOL_F_REPLY_ACK ); +VHOST_USER_PROTOCOL_F_REPLY_ACK ) && + !u->postcopy_fd.handler;(indent)
Fixed
Quoted 11 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 357
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0VhostUserMsg msg = { .request =VHOST_USER_SET_MEM_TABLE ,@@ -350,6 +354,57 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,return -1 ; } +if (u->postcopy_fd.handler) {It seems that after this handler is set, we never clean it up. Do we need to unset it somewhere? (maybe
vhost_user_postcopy_end?)Hmm yes I'll have a look at that.
Quoted 27 lines
Quoted 27 lines
hw/virtio/vhost-user.c +27
-0+VhostUserMsg msg_reply; +int region_i, reply_i; +if (vhost_user_read (dev, &msg_reply) <0 ) { +return -1 ; + } + +if (msg_reply.request !=VHOST_USER_SET_MEM_TABLE ) { +error_report ("%s: Received unexpected msg type." +"Expected %d received %d" , __func__, +VHOST_USER_SET_MEM_TABLE , msg_reply.request); +return -1 ; + } +/* We're using the same structure, just reusing one of the +* fields, so it should be the same size. +*/ +if (msg_reply.size != msg.size) { +error_report ("%s: Unexpected size for postcopy reply " +"%d vs %d" , __func__, msg_reply.size, msg.size); +return -1 ; + } + +memset (u->postcopy_client_bases,0 , +sizeof (uint64_t ) *VHOST_MEMORY_MAX_NREGIONS ); + +/* They're in the same order as the regions that were sent +* but some of the regions were skipped (above) if they +* didn't have fd's Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 390
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+*/ + for (reply_i = 0, region_i = 0; + region_i < dev->mem->nregions; + region_i++) { + if (reply_i < fd_num && + msg_reply.payload.memory.regions[region_i].guest_phys_addr ==^^^^^^^^
should this bereply_i?Yes it should - nicely spotted
Quoted 1 line
(And maybe we can use pointers for the regions for better readability?)
<snip>
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 396
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+ dev->mem->regions[region_i].guest_phys_addr) { + u->postcopy_client_bases[region_i] = + msg_reply.payload.memory.regions[reply_i].userspace_addr; + trace_vhost_user_set_mem_table_postcopy( + msg_reply.payload.memory.regions[reply_i].userspace_addr, + msg.payload.memory.regions[reply_i].userspace_addr,^^^^^^^
and I think this one isregion_iHmm... shouldn't msg.payload.memory.regions[] defined with size
VHOST_MEMORY_MAX_NREGIONSas well?
Quoted 6 lines
Quoted 3 lines
Yes, it already is; msg is a VhostUserMsg, payload.memory is a VhostUserMemory and it has:
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];Sorry I mis-expressed. I mean, then we should still use
reply_ihere, right? Thanks,
You're right! I've renamed 'reply_i' to 'msg_i' - it's always an index into the messages (either of them).
Dave
Quoted 2 lines
Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 17/32 vhost+postcopy: Stash RAMBlock and offset
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Stash the RAMBlock and offset for later use looking up addresses.
--- hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+)
hw/virtio/trace-events +1 -0
@@ -3,6 +3,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" +vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
hw/virtio/vhost-user.c +30 -0
@@ -135,6 +135,14 @@ struct vhost_user {NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd;uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; +/* Length of the region_rb and region_rb_offset arrays */ +size_t region_rb_len; +/* RAMBlock associated with a given region */ +RAMBlock **region_rb; +/* The offset from the start of the RAMBlock to the start of the +* vhost region. +*/ +ram_addr_t *region_rb_offset; };static bool ioeventfd_enabled (void )
@@ -319,6 +327,17 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.flags |=VHOST_USER_NEED_REPLY_MASK ; } +if (u->region_rb_len < dev->mem->nregions) { + u->region_rb = g_renew(RAMBlock*, u->region_rb, dev->mem->nregions); + u->region_rb_offset =g_renew (ram_addr_t, u->region_rb_offset, + dev->mem->nregions); +memset (&(u->region_rb[u->region_rb_len]),'\0' , +sizeof (RAMBlock *) * (dev->mem->nregions - u->region_rb_len)); +memset (&(u->region_rb_offset[u->region_rb_len]),'\0' , +sizeof (ram_addr_t) * (dev->mem->nregions - u->region_rb_len)); + u->region_rb_len = dev->mem->nregions; + } +for (i =0 ; i < dev->mem->nregions; ++i) {struct vhost_memory_region *reg = dev->mem->regions + i;ram_addr_t offset;
@@ -327,8 +346,14 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,assert ((uintptr_t )reg->userspace_addr == reg->userspace_addr); mr =memory_region_from_host ((void *)(uintptr_t )reg->userspace_addr, &offset); + u->region_rb_offset[i] = offset; + u->region_rb[i] = mr->ram_block; fd =memory_region_get_fd (mr);if (fd >0 ) { +trace_vhost_user_set_mem_table_withfd (fd_num, mr->name, + reg->memory_size, + reg->guest_phys_addr, + reg->userspace_addr, offset); msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
@@ -992,6 +1017,11 @@ static int vhost_user_cleanup(struct vhost_dev *dev)close (u->slave_fd); u->slave_fd =-1 ; } +g_free (u->region_rb); + u->region_rb =NULL ; +g_free (u->region_rb_offset); + u->region_rb_offset =NULL ; + u->region_rb_len =0 ;g_free (u); dev->opaque =0 ;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 17/32] vhost+postcopy: Stash RAMBlock and offset
Quoted 61 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Stash the RAMBlock and offset for later use looking up addresses.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+)hw/virtio/trace-events +1
-0@@ -3,6 +3,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" +vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +19
-0@@ -135,6 +135,14 @@ struct vhost_user {NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd;uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; +/* Length of the region_rb and region_rb_offset arrays */ +size_t region_rb_len; +/* RAMBlock associated with a given region */ +RAMBlock **region_rb; +/* The offset from the start of the RAMBlock to the start of the +* vhost region. +*/ +ram_addr_t *region_rb_offset; };static bool ioeventfd_enabled (void )@@ -319,6 +327,17 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.flags |=VHOST_USER_NEED_REPLY_MASK ; } +if (u->region_rb_len < dev->mem->nregions) { + u->region_rb = g_renew(RAMBlock*, u->region_rb, dev->mem->nregions); + u->region_rb_offset =g_renew (ram_addr_t, u->region_rb_offset, + dev->mem->nregions); +memset (&(u->region_rb[u->region_rb_len]),'\0' , +sizeof (RAMBlock *) * (dev->mem->nregions - u->region_rb_len)); +memset (&(u->region_rb_offset[u->region_rb_len]),'\0' , +sizeof (ram_addr_t) * (dev->mem->nregions - u->region_rb_len)); + u->region_rb_len = dev->mem->nregions; + } +for (i =0 ; i < dev->mem->nregions; ++i) {struct vhost_memory_region *reg = dev->mem->regions + i;ram_addr_t offset;
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 350
Quoted 5 lines
hw/virtio/vhost-user.c +2
-0@@ -327,8 +346,14 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,assert ((uintptr_t )reg->userspace_addr == reg->userspace_addr); mr =memory_region_from_host ((void *)(uintptr_t )reg->userspace_addr, &offset); + u->region_rb_offset[i] = offset; + u->region_rb[i] = mr->ram_block;
Do we need to record these info even if fd <= 0?
Quoted 24 lines
hw/virtio/vhost-user.c +9
-0fd =memory_region_get_fd (mr);if (fd >0 ) { +trace_vhost_user_set_mem_table_withfd (fd_num, mr->name, + reg->memory_size, + reg->guest_phys_addr, + reg->userspace_addr, offset); msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;@@ -992,6 +1017,11 @@ static int vhost_user_cleanup(struct vhost_dev *dev)close (u->slave_fd); u->slave_fd =-1 ; } +g_free (u->region_rb); + u->region_rb =NULL ; +g_free (u->region_rb_offset); + u->region_rb_offset =NULL ; + u->region_rb_len =0 ;g_free (u); dev->opaque =0 ;Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 17/32] vhost+postcopy: Stash RAMBlock and offset
Quoted 61 lines · * Peter Xu ([email protected]) wrote:
Quoted 60 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Stash the RAMBlock and offset for later use looking up addresses.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+)hw/virtio/trace-events +1
-0@@ -3,6 +3,7 @@ # hw/virtio/vhost-user.c vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" +vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +19
-0@@ -135,6 +135,14 @@ struct vhost_user {NotifierWithReturn postcopy_notifier;struct PostCopyFD postcopy_fd;uint64_t postcopy_client_bases[VHOST_MEMORY_MAX_NREGIONS ]; +/* Length of the region_rb and region_rb_offset arrays */ +size_t region_rb_len; +/* RAMBlock associated with a given region */ +RAMBlock **region_rb; +/* The offset from the start of the RAMBlock to the start of the +* vhost region. +*/ +ram_addr_t *region_rb_offset; };static bool ioeventfd_enabled (void )@@ -319,6 +327,17 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.flags |=VHOST_USER_NEED_REPLY_MASK ; } +if (u->region_rb_len < dev->mem->nregions) { + u->region_rb = g_renew(RAMBlock*, u->region_rb, dev->mem->nregions); + u->region_rb_offset =g_renew (ram_addr_t, u->region_rb_offset, + dev->mem->nregions); +memset (&(u->region_rb[u->region_rb_len]),'\0' , +sizeof (RAMBlock *) * (dev->mem->nregions - u->region_rb_len)); +memset (&(u->region_rb_offset[u->region_rb_len]),'\0' , +sizeof (ram_addr_t) * (dev->mem->nregions - u->region_rb_len)); + u->region_rb_len = dev->mem->nregions; + } +for (i =0 ; i < dev->mem->nregions; ++i) {struct vhost_memory_region *reg = dev->mem->regions + i;ram_addr_t offset;
Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_set_mem_table(struct vhost_dev *dev, · line 350
Quoted 6 lines
hw/virtio/vhost-user.c +2
-0@@ -327,8 +346,14 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,assert ((uintptr_t )reg->userspace_addr == reg->userspace_addr); mr =memory_region_from_host ((void *)(uintptr_t )reg->userspace_addr, &offset); + u->region_rb_offset[i] = offset; + u->region_rb[i] = mr->ram_block;Do we need to record these info even if fd <= 0?
Hmm no we don't; I've moved them down into the if block and 0 initialised them in the non-fd case just to make sure we don't use them accidentally.
Dave
Quoted 21 lines
Quoted 21 lines
hw/virtio/vhost-user.c +9
-0fd =memory_region_get_fd (mr);if (fd >0 ) { +trace_vhost_user_set_mem_table_withfd (fd_num, mr->name, + reg->memory_size, + reg->guest_phys_addr, + reg->userspace_addr, offset); msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;@@ -992,6 +1017,11 @@ static int vhost_user_cleanup(struct vhost_dev *dev)close (u->slave_fd); u->slave_fd =-1 ; } +g_free (u->region_rb); + u->region_rb =NULL ; +g_free (u->region_rb_offset); + u->region_rb_offset =NULL ; + u->region_rb_len =0 ;g_free (u); dev->opaque =0 ;
Quoted 6 lines
Quoted 3 lines
Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 18/32 vhost+postcopy: Send requests to source for shared pages
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Send requests back to the source for shared page requests.
--- migration/migration.h | 2 ++ migration/postcopy-ram.c | 31 ++++++++++++++++++++++++++++--- migration/postcopy-ram.h | 3 +++ migration/trace-events | 2 ++ 4 files changed, 35 insertions(+), 3 deletions(-)
migration/migration.h +2 -0
@@ -46,6 +46,8 @@ struct MigrationIncomingState {int userfault_quit_fd;QEMUFile *to_src_file;QemuMutex rp_mutex;/* We send replies from multiple threads */ +/* RAMBlock of last request sent to source */ +RAMBlock *last_rb;void *postcopy_tmp_page;void *postcopy_tmp_zero_page;/* PostCopyFD's for external userfaultfds & handlers of shared memory */
migration/postcopy-ram.c +28 -3
@@ -459,6 +459,31 @@ static int ram_block_enable_notify(const char *block_name, void *host_addr, }/* +* Callback from shared fault handlers to ask for a page, +* the page must be specified by a RAMBlock and an offset in that rb +*/ +int postcopy_request_shared_page (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t client_addr,uint64_t rb_offset) +{ +size_t pagesize =qemu_ram_pagesize (rb); +uint64_t aligned_rbo = rb_offset & ~(pagesize -1 ); +MigrationIncomingState *mis =migration_incoming_get_current (); + +trace_postcopy_request_shared_page (pcfd->idstr,qemu_ram_get_idstr (rb), + rb_offset); +/* TODO: Check bitmap to see if we already have the page */ +if (rb != mis->last_rb) { + mis->last_rb = rb; +migrate_send_rp_req_pages (mis,qemu_ram_get_idstr (rb), + aligned_rbo, pagesize); + }else { +/* Save some space */ +migrate_send_rp_req_pages (mis,NULL , aligned_rbo, pagesize); + } +return 0 ; +} + +/* * Handle faults detected by the USERFAULT markings */ static void *postcopy_ram_fault_thread (void *opaque)
@@ -468,9 +493,9 @@ static void *postcopy_ram_fault_thread(void *opaque)int ret;size_t index;RAMBlock *rb =NULL ; -RAMBlock *last_rb =NULL ;/* last RAMBlock we sent part of */ trace_postcopy_ram_fault_thread_entry (); + mis->last_rb =NULL ;/* last RAMBlock we sent part of */ qemu_sem_post (&mis->fault_thread_sem);struct pollfd *pfd;
@@ -559,8 +584,8 @@ static void *postcopy_ram_fault_thread(void *opaque)* Send the request to the source - we want to request one * of our host page sizes (which is >= TPS) */ -if (rb != last_rb) { - last_rb = rb; +if (rb != mis->last_rb) { + mis->last_rb = rb;migrate_send_rp_req_pages (mis,qemu_ram_get_idstr (rb), rb_offset,qemu_ram_pagesize (rb)); }else {
migration/postcopy-ram.h +3 -0
@@ -162,5 +162,8 @@ struct PostCopyFD {*/ void postcopy_register_shared_ufd (struct PostCopyFD *pcfd);void postcopy_unregister_shared_ufd (struct PostCopyFD *pcfd); +/* Callback from shared fault handlers to ask for a page */ +int postcopy_request_shared_page (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t client_addr,uint64_t offset);#endif
migration/trace-events +2 -0
@@ -197,6 +197,8 @@ postcopy_ram_incoming_cleanup_closeuf(void) "" postcopy_ram_incoming_cleanup_entry(void) "" postcopy_ram_incoming_cleanup_exit(void) "" postcopy_ram_incoming_cleanup_join(void) "" +postcopy_request_shared_page(const char *sharer, const char *rb, uint64_t rb_offset) "for %s in %s offset 0x%"PRIx64 + save_xbzrle_page_skipping(void) "" save_xbzrle_page_overflow(void) "" ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRIu64 " milliseconds, %d iterations"
Signature · 1 line
2.13.5
RFC v2 19/32 vhost+postcopy: Resolve client address
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Resolve fault addresses read off the clients UFD into RAMBlock and offset, and call back to the postcopy code to ask for the page.
--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-)
hw/virtio/trace-events +3 -0
@@ -1,6 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" +vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 +vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64 vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64
hw/virtio/vhost-user.c +29 -1
@@ -816,7 +816,35 @@ out:static int vhost_user_postcopy_fault_handler (struct PostCopyFD *pcfd,void *ufd) { -return 0 ; +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +struct uffd_msg *msg = ufd; +uint64_t faultaddr = msg->arg.pagefault.address; +RAMBlock *rb =NULL ; +uint64_t rb_offset; +int i; + +trace_vhost_user_postcopy_fault_handler (pcfd->idstr, faultaddr, + dev->mem->nregions); +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) { +trace_vhost_user_postcopy_fault_handler_loop (i, + u->postcopy_client_bases[i], dev->mem->regions[i].memory_size); +if (faultaddr >= u->postcopy_client_bases[i]) { +/* Ofset of the fault address in the vhost region */ +uint64_t region_offset = faultaddr - u->postcopy_client_bases[i]; +if (region_offset <= dev->mem->regions[i].memory_size) { + rb_offset = region_offset + u->region_rb_offset[i]; +trace_vhost_user_postcopy_fault_handler_found (i, + region_offset, rb_offset); + rb = u->region_rb[i]; +return postcopy_request_shared_page (pcfd, rb, faultaddr, + rb_offset); + } + } + } +error_report ("%s: Failed to find region for fault %" PRIx64, + __func__, faultaddr); +return -1 ; }/*
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 19/32] vhost+postcopy: Resolve client address
Quoted 35 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Resolve fault addresses read off the clients UFD into RAMBlock and offset, and call back to the postcopy code to ask for the page.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-)hw/virtio/trace-events +3
-0@@ -1,6 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" +vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 +vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64 vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64hw/virtio/vhost-user.c +1
-1@@ -816,7 +816,35 @@ out:static int vhost_user_postcopy_fault_handler (struct PostCopyFD *pcfd,void *ufd) { -return 0 ; +struct vhost_dev *dev = pcfd->data;
hw/virtio/vhost-user.c out: · line 829
Quoted 10 lines
hw/virtio/vhost-user.c +10
-0+struct vhost_user *u = dev->opaque; +struct uffd_msg *msg = ufd; +uint64_t faultaddr = msg->arg.pagefault.address; +RAMBlock *rb =NULL ; +uint64_t rb_offset; +int i; + +trace_vhost_user_postcopy_fault_handler (pcfd->idstr, faultaddr, + dev->mem->nregions); +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) {
Should dev->mem->nregions always the same as u->region_rb_len?
hw/virtio/vhost-user.c out: · line 835
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+trace_vhost_user_postcopy_fault_handler_loop (i, + u->postcopy_client_bases[i], dev->mem->regions[i].memory_size); +if (faultaddr >= u->postcopy_client_bases[i]) { +/* Ofset of the fault address in the vhost region */ +uint64_t region_offset = faultaddr - u->postcopy_client_bases[i]; +if (region_offset <= dev->mem->regions[i].memory_size) {
Should be "<" rather than "<="? Say:
Region 1: [0, 1M), size 1M
Region 2: [1M, 2M), size 1M
Looks like otherwise faultaddr=1M will fall into region 1, while it should be region 2?
hw/virtio/vhost-user.c out: · line 839
Quoted 4 lines
hw/virtio/vhost-user.c +4
-0+ rb_offset = region_offset + u->region_rb_offset[i]; +trace_vhost_user_postcopy_fault_handler_found (i, + region_offset, rb_offset); + rb = u->region_rb[i];
Nit: this "rb" might be avoided if only used once.
Quoted 14 lines
hw/virtio/vhost-user.c +8
-0+return postcopy_request_shared_page (pcfd, rb, faultaddr, + rb_offset); + } + } + } +error_report ("%s: Failed to find region for fault %" PRIx64, + __func__, faultaddr); +return -1 ; }/* Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 19/32] vhost+postcopy: Resolve client address
Quoted 40 lines · * Peter Xu ([email protected]) wrote:
Quoted 39 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Resolve fault addresses read off the clients UFD into RAMBlock and offset, and call back to the postcopy code to ask for the page.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-)hw/virtio/trace-events +3
-0@@ -1,6 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" +vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 +vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64 vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64hw/virtio/vhost-user.c +5
-1@@ -816,7 +816,35 @@ out:static int vhost_user_postcopy_fault_handler (struct PostCopyFD *pcfd,void *ufd) { -return 0 ; +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +struct uffd_msg *msg = ufd; +uint64_t faultaddr = msg->arg.pagefault.address; +RAMBlock *rb =NULL ;
Quoted 8 lines
hw/virtio/vhost-user.c out: · line 829
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+uint64_t rb_offset; +int i; + +trace_vhost_user_postcopy_fault_handler (pcfd->idstr, faultaddr, + dev->mem->nregions); +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) {Should
dev->mem->nregionsalways the same asu->region_rb_len?
u->region_rb_len only gets updated when vhost_user_set_mem_table is called, so I think there are short periods of time when they don't quite match.
(We do have to take some more care than we are at the moment during updates, because this address resolution happens off the postcopy thread)
Quoted 7 lines
hw/virtio/vhost-user.c out: · line 835
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+trace_vhost_user_postcopy_fault_handler_loop (i, + u->postcopy_client_bases[i], dev->mem->regions[i].memory_size); +if (faultaddr >= u->postcopy_client_bases[i]) { +/* Ofset of the fault address in the vhost region */ +uint64_t region_offset = faultaddr - u->postcopy_client_bases[i]; +if (region_offset <= dev->mem->regions[i].memory_size) {
Quoted 7 lines
Should be "<" rather than "<="? Say:
Region 1: [0, 1M), size 1M
Region 2: [1M, 2M), size 1MLooks like otherwise faultaddr=1M will fall into region 1, while it should be region 2?
Fixed; thanks.
Quoted 7 lines
hw/virtio/vhost-user.c out: · line 839
Quoted 5 lines
hw/virtio/vhost-user.c +4
-0+ rb_offset = region_offset + u->region_rb_offset[i]; +trace_vhost_user_postcopy_fault_handler_found (i, + region_offset, rb_offset); + rb = u->region_rb[i];Nit: this "rb" might be avoided if only used once.
It's only a local, ok if it makes it a little more readable.
Dave
Quoted 10 lines
Quoted 10 lines
hw/virtio/vhost-user.c +8
-0+return postcopy_request_shared_page (pcfd, rb, faultaddr, + rb_offset); + } + } + } +error_report ("%s: Failed to find region for fault %" PRIx64, + __func__, faultaddr); +return -1 ; }
Quoted 7 lines
Quoted 4 lines
hw/virtio/vhost-user.c +0
-0/* Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 19/32] vhost+postcopy: Resolve client address
Quoted 50 lines · Dr. David Alan Gilbert
Quoted 40 lines · * Peter Xu ([email protected]) wrote:
Quoted 39 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Resolve fault addresses read off the clients UFD into RAMBlock and offset, and call back to the postcopy code to ask for the page.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-)hw/virtio/trace-events +3
-0@@ -1,6 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" +vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 +vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64 vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64hw/virtio/vhost-user.c +5
-1@@ -816,7 +816,35 @@ out:static int vhost_user_postcopy_fault_handler (struct PostCopyFD *pcfd,void *ufd) { -return 0 ; +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +struct uffd_msg *msg = ufd; +uint64_t faultaddr = msg->arg.pagefault.address; +RAMBlock *rb =NULL ;Quoted 8 lines
hw/virtio/vhost-user.c out: · line 829
Quoted 6 lines
hw/virtio/vhost-user.c +6
-0+uint64_t rb_offset; +int i; + +trace_vhost_user_postcopy_fault_handler (pcfd->idstr, faultaddr, + dev->mem->nregions); +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) {Should
dev->mem->nregionsalways the same asu->region_rb_len?
Quoted 6 lines
u->region_rb_lenonly gets updated whenvhost_user_set_mem_tableis called, so I think there are short periods of time when they don't quite match.
(We do have to take some more care than we are at the moment during updates, because this address resolution happens off the postcopy thread)
I see, so memory layout can change along the way...
But I still doubt whether this single MIN() can work.
Say, we have these arrays already:
- array A: dev->mem->regions[]
- array B: u->region_rb[]
- array C: u->postcopy_client_bases[]
These arrays should always be aligned with each other (index "i" of array "A/B/C" will always describe the same memory region). But since we can change the memory layout dynamically during postcopy, then array A can grow/shrink/change in following path:
vhost_region_{add|delete}
updates array A (1)
vhost_region_{add|delete}
updates array A (2)
vhost_region_{add|delete}
updates array A (3)
...
vhost_commit
vhost_set_mem_table
align arrays B/C with A (4)
IMHO array A may not really match B/C during step (1)-(3), until step
(4) to re-align them? And if they are not aligned with each other, I guess a single MIN() won't help much? (Since the indexing below would be problematic?)
(Hmm, can we just disallow memory change during postcopy for now?)
Quoted 4 lines
Quoted 4 lines
hw/virtio/vhost-user.c out: · line 832
Quoted 4 lines
hw/virtio/vhost-user.c +3
-0+trace_vhost_user_postcopy_fault_handler_loop (i, + u->postcopy_client_bases[i], dev->mem->regions[i].memory_size); +if (faultaddr >= u->postcopy_client_bases[i]) {
Ah, wait...
postcopy_client_bases[] is now defined with static size VHOST_MEMORY_MAX_NREGIONS. Shouldn't it be dynamically allocated as well with dev->mem->nregions, just like vhost_user.region_rb[]?
Maybe we want to leave the postcopy_client_bases[i] be zeros when dev->mem->regions[i] it's not a vhost-user supported region (without "fd")?
Quoted 45 lines
Quoted 11 lines
hw/virtio/vhost-user.c out: · line 835
Quoted 3 lines
hw/virtio/vhost-user.c +3
-0+/* Ofset of the fault address in the vhost region */ +uint64_t region_offset = faultaddr - u->postcopy_client_bases[i]; +if (region_offset <= dev->mem->regions[i].memory_size) {Should be "<" rather than "<="? Say:
Region 1: [0, 1M), size 1M
Region 2: [1M, 2M), size 1MLooks like otherwise faultaddr=1M will fall into region 1, while it should be region 2?
Fixed; thanks.
Quoted 7 lines
hw/virtio/vhost-user.c out: · line 839
Quoted 5 lines
hw/virtio/vhost-user.c +4
-0+ rb_offset = region_offset + u->region_rb_offset[i]; +trace_vhost_user_postcopy_fault_handler_found (i, + region_offset, rb_offset); + rb = u->region_rb[i];Nit: this "rb" might be avoided if only used once.
It's only a local, ok if it makes it a little more readable.
Dave
Quoted 10 lines
Quoted 10 lines
hw/virtio/vhost-user.c +8
-0+return postcopy_request_shared_page (pcfd, rb, faultaddr, + rb_offset); + } + } + } +error_report ("%s: Failed to find region for fault %" PRIx64, + __func__, faultaddr); +return -1 ; }Quoted 7 lines
Quoted 4 lines
hw/virtio/vhost-user.c +0
-0/* Signature · 1 line
2.13.5Signature · 1 line
Peter Xu--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Signature · 1 line
Peter Xu
RFC v2 20/32 postcopy: wake shared
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Send a 'wake' request on a userfaultfd for a shared process. The address in the clients address space is specified together with the RAMBlock it was resolved to.
--- migration/postcopy-ram.c | 26 ++++++++++++++++++++++++++ migration/postcopy-ram.h | 6 ++++++ migration/trace-events | 1 + 3 files changed, 33 insertions(+)
migration/postcopy-ram.c +26 -0
@@ -458,6 +458,25 @@ static int ram_block_enable_notify(const char *block_name, void *host_addr,return 0 ; } +int postcopy_wake_shared (struct PostCopyFD *pcfd, +uint64_t client_addr, +RAMBlock *rb) +{ +size_t pagesize =qemu_ram_pagesize (rb); +struct uffdio_range range; +int ret; +trace_postcopy_wake_shared (client_addr,qemu_ram_get_idstr (rb)); + range.start = client_addr & ~(pagesize -1 ); + range.len = pagesize; + ret =ioctl (pcfd->fd,UFFDIO_WAKE , &range); +if (ret) { +error_report ("%s: Failed to wake: %zx in %s (%s)" , + __func__, client_addr,qemu_ram_get_idstr (rb), +strerror (errno)); + } +return ret; +} +/* * Callback from shared fault handlers to ask for a page, * the page must be specified by a RAMBlock and an offset in that rb
@@ -876,6 +895,13 @@ void *postcopy_get_tmp_page(MigrationIncomingState *mis) return NULL; } +int postcopy_wake_shared (struct PostCopyFD *pcfd, +uint64_t client_addr, +RAMBlock *rb) +{ +assert (0 ); +return -1 ; +}#endif /* ------------------------------------------------------------------------- */
migration/postcopy-ram.h +6 -0
@@ -162,6 +162,12 @@ struct PostCopyFD {*/ void postcopy_register_shared_ufd (struct PostCopyFD *pcfd);void postcopy_unregister_shared_ufd (struct PostCopyFD *pcfd); +/* Notify a client ufd that a page is available +* Note: The 'client_address' is in the address space of the client +* program not QEMU +*/ +int postcopy_wake_shared (struct PostCopyFD *pcfd,uint64_t client_addr, +RAMBlock *rb);/* Callback from shared fault handlers to ask for a page */ int postcopy_request_shared_page (struct PostCopyFD *pcfd,RAMBlock *rb,uint64_t client_addr,uint64_t offset);
migration/trace-events +1 -0
@@ -198,6 +198,7 @@ postcopy_ram_incoming_cleanup_entry(void) "" postcopy_ram_incoming_cleanup_exit(void) "" postcopy_ram_incoming_cleanup_join(void) "" postcopy_request_shared_page(const char *sharer, const char *rb, uint64_t rb_offset) "for %s in %s offset 0x%"PRIx64 +postcopy_wake_shared(uint64_t client_addr, const char *rb) "at 0x%"PRIx64" in %s" save_xbzrle_page_skipping(void) "" save_xbzrle_page_overflow(void) ""
Signature · 1 line
2.13.5
RFC v2 21/32 postcopy: postcopy_notify_shared_wake
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Add a hook to allow a client userfaultfd to be 'woken' when a page arrives, and a walker that calls that hook for relevant clients given a RAMBlock and offset.
--- migration/postcopy-ram.c | 16 ++++++++++++++++ migration/postcopy-ram.h | 10 ++++++++++ 2 files changed, 26 insertions(+)
migration/postcopy-ram.c +16 -0
@@ -749,6 +749,22 @@ static int qemu_ufd_copy_ioctl(int userfault_fd, void *host_addr,return ret; } +int postcopy_notify_shared_wake (RAMBlock *rb,uint64_t offset) +{ +int i; +MigrationIncomingState *mis =migration_incoming_get_current (); +GArray *pcrfds = mis->postcopy_remote_fds; + +for (i =0 ; i < pcrfds->len; i++) { + struct PostCopyFD *cur = &g_array_index(pcrfds, struct PostCopyFD, i); +int ret = cur->waker (cur, rb, offset); +if (ret) { +return ret; + } + } +return 0 ; +} +/* * Place a host page (from) at (host) atomically * returns 0 on success
migration/postcopy-ram.h +10 -0
@@ -146,6 +146,10 @@ struct PostCopyFD;/* ufd is a pointer to the struct uffd_msg *TODO: more Portable! */ typedef int (*pcfdhandler )(struct PostCopyFD *pcfd,void *ufd); +/* Notification to wake, either on place or on reception of +* a fault on something that's already arrived (race) +*/ +typedef int (*pcfdwake )(struct PostCopyFD *pcfd,RAMBlock *rb,uint64_t offset);struct PostCopyFD {int fd;
@@ -153,6 +157,8 @@ struct PostCopyFD {void *data;/* Handler to be called whenever we get a poll event */ pcfdhandler handler; +/* Notification to wake shared client */ +pcfdwake waker;/* A string to use in error messages */ const char *idstr; };
@@ -162,6 +168,10 @@ struct PostCopyFD {*/ void postcopy_register_shared_ufd (struct PostCopyFD *pcfd);void postcopy_unregister_shared_ufd (struct PostCopyFD *pcfd); +/* Call each of the shared 'waker's registerd telling them of +* availability of a block. +*/ +int postcopy_notify_shared_wake (RAMBlock *rb,uint64_t offset);/* Notify a client ufd that a page is available * Note: The 'client_address' is in the address space of the client * program not QEMU
Signature · 1 line
2.13.5
RFC v2 22/32 vhost+postcopy: Add vhost waker
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Register a waker function in vhost-user code to be notified when pages arrive or requests to previously mapped pages get requested.
--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)
hw/virtio/trace-events +3 -0
@@ -7,6 +7,9 @@ vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 +vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 +vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
hw/virtio/vhost-user.c +26 -0
@@ -847,6 +847,31 @@ static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd,return -1 ; } +static int vhost_user_postcopy_waker (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t offset) +{ +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +int i; + +trace_vhost_user_postcopy_waker (qemu_ram_get_idstr (rb), offset); +/* Translate the offset into an address in the clients address space */ +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) { +if (u->region_rb[i] == rb && + offset >= u->region_rb_offset[i] && + offset < (u->region_rb_offset[i] + + dev->mem->regions[i].memory_size)) { +uint64_t client_addr = (offset - u->region_rb_offset[i]) + + u->postcopy_client_bases[i]; +trace_vhost_user_postcopy_waker_found (client_addr); +return postcopy_wake_shared (pcfd, client_addr, rb); + } + } + +trace_vhost_user_postcopy_waker_nomatch (qemu_ram_get_idstr (rb), offset); +return 0 ; +} +/* * Called at the start of an inbound postcopy on reception of the * 'advise' command.
@@ -892,6 +917,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) u->postcopy_fd.fd = ufd; u->postcopy_fd.data = dev; u->postcopy_fd.handler = vhost_user_postcopy_fault_handler; + u->postcopy_fd.waker = vhost_user_postcopy_waker; u->postcopy_fd.idstr ="vhost-user" ;/* Need to find unique name */ postcopy_register_shared_ufd (&u->postcopy_fd);return 0 ;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 22/32] vhost+postcopy: Add vhost waker
Quoted 37 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Register a waker function in vhost-user code to be notified when pages arrive or requests to previously mapped pages get requested.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)hw/virtio/trace-events +3
-0@@ -7,6 +7,9 @@ vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 +vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 +vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +4
-0@@ -847,6 +847,31 @@ static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd,return -1 ; } +static int vhost_user_postcopy_waker (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t offset) +{ +struct vhost_dev *dev = pcfd->data;
hw/virtio/vhost-user.c static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd, · line 863
Quoted 10 lines
hw/virtio/vhost-user.c +10
-0+struct vhost_user *u = dev->opaque; +int i; + +trace_vhost_user_postcopy_waker (qemu_ram_get_idstr (rb), offset); +/* Translate the offset into an address in the clients address space */ +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) { +if (u->region_rb[i] == rb && + offset >= u->region_rb_offset[i] && + offset < (u->region_rb_offset[i] + + dev->mem->regions[i].memory_size)) {
Just curious: checks against offset should only be for safety, right? Is there valid case that even rb is correct but the offset gets out of the range of that RAMBlock?
Quoted 25 lines
hw/virtio/vhost-user.c +12
-0+uint64_t client_addr = (offset - u->region_rb_offset[i]) + + u->postcopy_client_bases[i]; +trace_vhost_user_postcopy_waker_found (client_addr); +return postcopy_wake_shared (pcfd, client_addr, rb); + } + } + +trace_vhost_user_postcopy_waker_nomatch (qemu_ram_get_idstr (rb), offset); +return 0 ; +} +/* * Called at the start of an inbound postcopy on reception of the * 'advise' command. @@ -892,6 +917,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) u->postcopy_fd.fd = ufd; u->postcopy_fd.data = dev; u->postcopy_fd.handler = vhost_user_postcopy_fault_handler; + u->postcopy_fd.waker = vhost_user_postcopy_waker; u->postcopy_fd.idstr ="vhost-user" ;/* Need to find unique name */ postcopy_register_shared_ufd (&u->postcopy_fd);return 0 ;Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 22/32] vhost+postcopy: Add vhost waker
Quoted 44 lines · * Peter Xu ([email protected]) wrote:
Quoted 43 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Register a waker function in vhost-user code to be notified when pages arrive or requests to previously mapped pages get requested.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)hw/virtio/trace-events +3
-0@@ -7,6 +7,9 @@ vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 +vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 +vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +10
-0@@ -847,6 +847,31 @@ static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd,return -1 ; } +static int vhost_user_postcopy_waker (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t offset) +{ +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +int i; + +trace_vhost_user_postcopy_waker (qemu_ram_get_idstr (rb), offset); +/* Translate the offset into an address in the clients address space */ +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) {
Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd, · line 863
Quoted 4 lines
hw/virtio/vhost-user.c +4
-0+if (u->region_rb[i] == rb && + offset >= u->region_rb_offset[i] && + offset < (u->region_rb_offset[i] + + dev->mem->regions[i].memory_size)) {Just curious: checks against offset should only be for safety, right? Is there valid case that even rb is correct but the offset gets out of the range of that RAMBlock?
Yes, I think that case does exist.
'regions' are mapping regions as visible from the guest, but there may be two regions that are mapped to the same RAMBlock. In our world the cleanest example of that is an x86 guest with 8GB of RAM; it has a single pc.ram RAMBlock of 8GB in size, but that's mapped in two chunks, a 3GB chunk at the bottom of physical address space and a 5GB chunk that starts on the 4GB boundary - i.e. leaving a 1GB hole.
In this structure that appears as two regions each with the same rb and different offsets.
Dave
Quoted 17 lines
Quoted 17 lines
hw/virtio/vhost-user.c +11
-0+uint64_t client_addr = (offset - u->region_rb_offset[i]) + + u->postcopy_client_bases[i]; +trace_vhost_user_postcopy_waker_found (client_addr); +return postcopy_wake_shared (pcfd, client_addr, rb); + } + } + +trace_vhost_user_postcopy_waker_nomatch (qemu_ram_get_idstr (rb), offset); +return 0 ; +} +/* * Called at the start of an inbound postcopy on reception of the * 'advise' command. @@ -892,6 +917,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) u->postcopy_fd.fd = ufd; u->postcopy_fd.data = dev;
Quoted 11 lines
Quoted 8 lines
hw/virtio/vhost-user.c +1
-0u->postcopy_fd.handler = vhost_user_postcopy_fault_handler; + u->postcopy_fd.waker = vhost_user_postcopy_waker; u->postcopy_fd.idstr ="vhost-user" ;/* Need to find unique name */ postcopy_register_shared_ufd (&u->postcopy_fd);return 0 ;Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 22/32] vhost+postcopy: Add vhost waker
Quoted 56 lines · Dr. David Alan Gilbert
Quoted 44 lines · * Peter Xu ([email protected]) wrote:
Quoted 43 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Register a waker function in vhost-user code to be notified when pages arrive or requests to previously mapped pages get requested.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- hw/virtio/trace-events | 3 +++ hw/virtio/vhost-user.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)hw/virtio/trace-events +3
-0@@ -7,6 +7,9 @@ vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t vhost_user_postcopy_listen(void) "" vhost_user_set_mem_table_postcopy(uint64_t client_addr, uint64_t qhva, int reply_i, int region_i) "client:0x%"PRIx64" for hva: 0x%"PRIx64" reply %d region %d" vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_size, uint64_t guest_phys_addr, uint64_t userspace_addr, uint64_t offset) "%d:%s: size:0x%"PRIx64" GPA:0x%"PRIx64" QVA/userspace:0x%"PRIx64" RB offset:0x%"PRIx64 +vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 +vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"hw/virtio/vhost-user.c +10
-0@@ -847,6 +847,31 @@ static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd,return -1 ; } +static int vhost_user_postcopy_waker (struct PostCopyFD *pcfd,RAMBlock *rb, +uint64_t offset) +{ +struct vhost_dev *dev = pcfd->data; +struct vhost_user *u = dev->opaque; +int i; + +trace_vhost_user_postcopy_waker (qemu_ram_get_idstr (rb), offset); +/* Translate the offset into an address in the clients address space */ +for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) {Quoted 8 lines
hw/virtio/vhost-user.c static int vhost_user_postcopy_fault_handler(struct PostCopyFD *pcfd, · line 863
Quoted 4 lines
hw/virtio/vhost-user.c +4
-0+if (u->region_rb[i] == rb && + offset >= u->region_rb_offset[i] && + offset < (u->region_rb_offset[i] + + dev->mem->regions[i].memory_size)) {Just curious: checks against offset should only be for safety, right? Is there valid case that even rb is correct but the offset gets out of the range of that RAMBlock?
Yes, I think that case does exist.
Quoted 9 lines
'regions' are mapping regions as visible from the guest, but there may be two regions that are mapped to the same RAMBlock. In our world the cleanest example of that is an x86 guest with 8GB of RAM; it has a single pc.ram RAMBlock of 8GB in size, but that's mapped in two chunks, a 3GB chunk at the bottom of physical address space and a 5GB chunk that starts on the 4GB boundary - i.e. leaving a 1GB hole.
In this structure that appears as two regions each with the same rb and different offsets.
Yeah I missed that. Thanks!
Signature · 1 line
Peter Xu
RFC v2 23/32 vhost+postcopy: Call wakeups
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Cause the vhost-user client to be woken up whenever:
a) We place a page in postcopy mode
b) We get a fault and the page has already been received
--- migration/postcopy-ram.c | 14 ++++++++++---- migration/trace-events | 1 + 2 files changed, 11 insertions(+), 4 deletions(-)
migration/postcopy-ram.c +10 -4
@@ -490,7 +490,11 @@ int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb,trace_postcopy_request_shared_page (pcfd->idstr,qemu_ram_get_idstr (rb), rb_offset); -/* TODO: Check bitmap to see if we already have the page */ +if (ramblock_recv_bitmap_test_byte_offset (rb, aligned_rbo)) { +trace_postcopy_request_shared_page_present (pcfd->idstr, +qemu_ram_get_idstr (rb), rb_offset); +return postcopy_wake_shared (pcfd, client_addr, rb); + }if (rb != mis->last_rb) { mis->last_rb = rb; migrate_send_rp_req_pages(mis, qemu_ram_get_idstr(rb),
@@ -788,7 +792,8 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from, }trace_postcopy_place_page (host); -return 0 ; +return postcopy_notify_shared_wake (rb, +qemu_ram_block_host_offset (rb, host)); }/*
@@ -812,6 +817,9 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host,return -e; } +return postcopy_notify_shared_wake (rb, +qemu_ram_block_host_offset (rb, + host)); }else {/* The kernel can't use UFFDIO_ZEROPAGE for hugepages */ if (!mis->postcopy_tmp_zero_page) {
@@ -831,8 +839,6 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host,return postcopy_place_page (mis, host, mis->postcopy_tmp_zero_page, rb); } - -return 0 ; }/*
migration/trace-events +1 -0
@@ -198,6 +198,7 @@ postcopy_ram_incoming_cleanup_entry(void) "" postcopy_ram_incoming_cleanup_exit(void) "" postcopy_ram_incoming_cleanup_join(void) "" postcopy_request_shared_page(const char *sharer, const char *rb, uint64_t rb_offset) "for %s in %s offset 0x%"PRIx64 +postcopy_request_shared_page_present(const char *sharer, const char *rb, uint64_t rb_offset) "%s already %s offset 0x%"PRIx64 postcopy_wake_shared(uint64_t client_addr, const char *rb) "at 0x%"PRIx64" in %s" save_xbzrle_page_skipping(void) ""
Signature · 1 line
2.13.5
RFC v2 24/32 vub+postcopy: madvises
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Clear the area and turn off THP.
--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
contrib/libvhost-user/libvhost-user.c +30 -2
@@ -450,11 +450,39 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) }if (dev->postcopy_listening) { +int ret;/* We should already have an open ufd need to mark each memory * range as ufd. -* Note: Do we need any madvises? Well it's not been accessed -* yet, still probably need no THP to be safe, discard to be safe? */ + +/* Discard any mapping we have here; note I can't use MADV_REMOVE +* or fallocate to make the hole since I don't want to lose +* data that's already arrived in the shared process. +* TODO: How to do hugepage +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_DONTNEED ); +if (ret) { +fprintf (stderr, +"%s: Failed to madvise(DONTNEED) region %d: %s\n" , + __func__, i,strerror (errno)); + } +/* Turn off transparent hugepages so we dont get lose wakeups +* in neighbouring pages. +* TODO: Turn this backon later. +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_NOHUGEPAGE ); +if (ret) { +/* Note: This can happen legally on kernels that are configured +* without madvise'able hugepages +*/ +fprintf (stderr, +"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n" , + __func__, i,strerror (errno)); + }struct uffdio_register reg_struct; reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; reg_struct.range.len = dev_region->size + dev_region->mmap_offset;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 24/32] vub+postcopy: madvises
Hi
"libvhost-user: madvises for postcopy" for ex, would be nicer imho
Quoted 56 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Clear the area and turn off THP.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +30
-3@@ -450,11 +450,39 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) }if (dev->postcopy_listening) { +int ret;/* We should already have an open ufd need to mark each memory * range as ufd. -* Note: Do we need any madvises? Well it's not been accessed -* yet, still probably need no THP to be safe, discard to be safe? */ + +/* Discard any mapping we have here; note I can't use MADV_REMOVE +* or fallocate to make the hole since I don't want to lose +* data that's already arrived in the shared process. +* TODO: How to do hugepage +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_DONTNEED ); +if (ret) { +fprintf (stderr, +"%s: Failed to madvise(DONTNEED) region %d: %s\n" , + __func__, i,strerror (errno)); + } +/* Turn off transparent hugepages so we dont get lose wakeups +* in neighbouring pages. +* TODO: Turn this backon later. +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_NOHUGEPAGE ); +if (ret) { +/* Note: This can happen legally on kernels that are configured +* without madvise'able hugepages +*/ +fprintf (stderr, +"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n" , + __func__, i,strerror (errno)); + }struct uffdio_register reg_struct; reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; reg_struct.range.len = dev_region->size + dev_region->mmap_offset; --
Quoted 2 lines
2.13.5
Errors are non-fatal? patch looks ok to me, despite the TODOs :).
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 24/32] vub+postcopy: madvises
Quoted 3 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
"libvhost-user: madvises for postcopy" for ex, would be nicer imho
Done.
Quoted 54 lines
Quoted 52 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Clear the area and turn off THP.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)contrib/libvhost-user/libvhost-user.c +30
-2@@ -450,11 +450,39 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) }if (dev->postcopy_listening) { +int ret;/* We should already have an open ufd need to mark each memory * range as ufd. -* Note: Do we need any madvises? Well it's not been accessed -* yet, still probably need no THP to be safe, discard to be safe? */ + +/* Discard any mapping we have here; note I can't use MADV_REMOVE +* or fallocate to make the hole since I don't want to lose +* data that's already arrived in the shared process. +* TODO: How to do hugepage +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_DONTNEED ); +if (ret) { +fprintf (stderr, +"%s: Failed to madvise(DONTNEED) region %d: %s\n" , + __func__, i,strerror (errno)); + } +/* Turn off transparent hugepages so we dont get lose wakeups +* in neighbouring pages. +* TODO: Turn this backon later. +*/ + ret =madvise ((void *)dev_region->mmap_addr, + dev_region->size + dev_region->mmap_offset, +MADV_NOHUGEPAGE ); +if (ret) { +/* Note: This can happen legally on kernels that are configured +* without madvise'able hugepages +*/ +fprintf (stderr, +"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n" , + __func__, i,strerror (errno)); + }
Quoted 8 lines
Quoted 6 lines
contrib/libvhost-user/libvhost-user.c +0
-1struct uffdio_register reg_struct; reg_struct.range.start = (uintptr_t )dev_region->mmap_addr; reg_struct.range.len = dev_region->size + dev_region->mmap_offset; --2.13.5
Errors are non-fatal? patch looks ok to me, despite the TODOs :).
The DONTNEED is actually not critical in this case; since we've only just mmap'd it there should be nothing mapped in there that needs clearing with DONTNEED; however it's a good safe guard. There's no equivalent syscall we can make for postcopy.
The madvise(NOHUGEPAGE) can fail on a kernel that's configured without CONFIG_TRANSPARENT_HUGEPAGE_MADVISE if TRANSPARENT_HUGEPAGE=n then that's OK since it just means we don't have transparent hugepages and thus we can't turn them off (I think we saw this on s390 or aarch64)
if CONFIG_TRANSAPRENT_HUGEPAGE_ALWAYS is set then things get messy. IMHO there's way too many kernel config flags for transparent hugepages!
Quoted 1 line
Reviewed-by Marc-André Lureau <[email protected]>
Thanks,
Dave
Quoted 6 lines
Signature · 2 lines
-- Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 25/32 vhost+postcopy: Lock around set_mem_table
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
**HACK - better solution needed **
We have the situation where:
qemu bridge
send set_mem_table
map memory
a) mark area with UFD
send reply with map addresses
b) start using
c) receive reply
As soon as (a) happens qemu might start seeing faults
from memory accesses (but doesn't until b); but it can't process those faults until (c) when it's received the mmap addresses.
Make the fault handler spin until it gets the reply in (c).
At the very least this needs some proper locks, but preferably we need to split the message.
--- hw/virtio/trace-events | 1 + hw/virtio/vhost-user.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-)
hw/virtio/trace-events +1 -0
@@ -10,6 +10,7 @@ vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_siz vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 +vhost_user_postcopy_waker_spin(const char *rb) "%s" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
hw/virtio/vhost-user.c +16 -1
@@ -143,6 +143,7 @@ struct vhost_user {* vhost region. */ ram_addr_t *region_rb_offset; +uint64_t in_set_mem_table;/*Hack! 1 while waiting for set_mem_table reply */ };static bool ioeventfd_enabled (void )
@@ -338,6 +339,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, u->region_rb_len = dev->mem->nregions; } +atomic_set (&u->in_set_mem_table, true);for (i =0 ; i < dev->mem->nregions; ++i) {struct vhost_memory_region *reg = dev->mem->regions + i;ram_addr_t offset;
@@ -368,14 +370,15 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,if (!fd_num) {error_report ("Failed initializing vhost-user memory map, " "consider using -object memory-backend-file share=on" ); +atomic_set (&u->in_set_mem_table, false);return -1 ; } msg.size =sizeof (msg.payload.memory.nregions); msg.size +=sizeof (msg.payload.memory.padding); msg.size += fd_num *sizeof (VhostUserMemoryRegion); -if (vhost_user_write (dev, &msg, fds, fd_num) <0 ) { +atomic_set (&u->in_set_mem_table, false);return -1 ; }
@@ -390,6 +393,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,error_report ("%s: Received unexpected msg type." "Expected %d received %d" , __func__,VHOST_USER_SET_MEM_TABLE , msg_reply.request); +atomic_set (&u->in_set_mem_table, false);return -1 ; }/* We're using the same structure, just reusing one of the
@@ -398,6 +402,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,if (msg_reply.size != msg.size) {error_report ("%s: Unexpected size for postcopy reply " "%d vs %d" , __func__, msg_reply.size, msg.size); +atomic_set (&u->in_set_mem_table, false);return -1 ; }
@@ -427,9 +432,11 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,error_report ("%s: postcopy reply not fully consumed " "%d vs %zd" , __func__, reply_i, fd_num); +atomic_set (&u->in_set_mem_table, false);return -1 ; } } +atomic_set (&u->in_set_mem_table, false);if (reply_supported) {return process_message_reply (dev, &msg); }
@@ -855,6 +862,14 @@ static int vhost_user_postcopy_waker(struct PostCopyFD *pcfd, RAMBlock *rb,int i;trace_vhost_user_postcopy_waker (qemu_ram_get_idstr (rb), offset); +if (!u) { +return 0 ; + } +while (atomic_mb_read (&u->in_set_mem_table)) { +trace_vhost_user_postcopy_waker_spin (qemu_ram_get_idstr (rb)); +usleep (1000 *100 ); + } +/* Translate the offset into an address in the clients address space */ for (i =0 ; i <MIN (dev->mem->nregions, u->region_rb_len); i++) { if (u->region_rb[i] == rb &&
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 25/32] vhost+postcopy: Lock around set_mem_table
Quoted 19 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
**HACK - better solution needed **
We have the situation where:qemu bridge
send
set_mem_table
map memory
a) mark area with UFD
send reply with map addresses
b) start using
c) receive replyAs soon as (a) happens qemu might start seeing faults
from memory accesses (but doesn't until b); but it can't process those faults until (c) when it's received the mmap addresses.
Quoted 4 lines
Make the fault handler spin until it gets the reply in (c).
At the very least this needs some proper locks, but preferably we need to split the message.
I see discussions about slave channel and ack mechanism in previous post. So it's still not adopted (which looks doable)? What's our further plan?
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 25/32] vhost+postcopy: Lock around set_mem_table
Quoted 20 lines · * Peter Xu ([email protected]) wrote:
Quoted 19 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
**HACK - better solution needed **
We have the situation where:qemu bridge
send
set_mem_table
map memory
a) mark area with UFD
send reply with map addresses
b) start using
c) receive replyAs soon as (a) happens qemu might start seeing faults
from memory accesses (but doesn't until b); but it can't process those faults until (c) when it's received the mmap addresses.
Quoted 8 lines
Quoted 4 lines
Make the fault handler spin until it gets the reply in (c).
At the very least this needs some proper locks, but preferably we need to split the message.
I see discussions about slave channel and ack mechanism in previous post. So it's still not adopted (which looks doable)? What's our further plan?
Yep I'm going to look at the slave channel stuff.
Dave
Quoted 2 lines
Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 26/32 vhost: Add VHOST_USER_POSTCOPY_END message
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
This message is sent just before the end of postcopy to get the client to stop using userfault since we wont respond to any more requests. It should close userfaultfd so that any other pages get mapped to the backing file automatically by the kernel, since at this point we know we've received everything.
--- contrib/libvhost-user/libvhost-user.c | 23 +++++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 8 ++++++++ hw/virtio/vhost-user.c | 1 + 4 files changed, 33 insertions(+)
contrib/libvhost-user/libvhost-user.c +23 -0
@@ -67,6 +67,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ),REQ (VHOST_USER_POSTCOPY_LISTEN ), +REQ (VHOST_USER_POSTCOPY_END ), REQ(VHOST_USER_MAX), };#undef REQ
@@ -893,6 +894,26 @@ vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 =0 ;/* Success */ return true; } + +static bool +vu_set_postcopy_end (VuDev *dev,VhostUserMsg *vmsg) +{ +DPRINT ("%s: Entry\n" , __func__); + dev->postcopy_listening = false; +if (dev->postcopy_ufd >0 ) { +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; +DPRINT ("%s: Done close\n" , __func__); + } + + vmsg->fd_num =0 ; + vmsg->payload.u64 =0 ; + vmsg->size =sizeof (vmsg->payload.u64); + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; +DPRINT ("%s: exit\n" , __func__); +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {
@@ -962,6 +983,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_postcopy_advise (dev, vmsg);case VHOST_USER_POSTCOPY_LISTEN :return vu_set_postcopy_listen (dev, vmsg); +case VHOST_USER_POSTCOPY_END : +return vu_set_postcopy_end (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);
contrib/libvhost-user/libvhost-user.h +1 -0
@@ -68,6 +68,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;
docs/interop/vhost-user.txt +8 -0
@@ -627,6 +627,14 @@ Master message types Master advises slave that a transition to postcopy mode has happened. + * VHOST_USER_POSTCOPY_END + Id: 26 + Slave payload: u64 + + Master advises that postcopy migration has now completed. The + slave must disable the userfaultfd. The response is an acknowledgement + only. + Slave message types -------------------
hw/virtio/vhost-user.c +1 -0
@@ -71,6 +71,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 26/32] vhost: Add VHOST_USER_POSTCOPY_END message
Quoted 9 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
This message is sent just before the end of postcopy to get the client to stop using userfault since we wont respond to any more requests. It should close userfaultfd so that any other pages get mapped to the backing file automatically by the kernel, since at this point we know we've received everything.
Signed-off-by Dr. David Alan Gilbert <[email protected]>
(I feel like the title should be for "vub", not "vhost"?)
Quoted 101 lines
--- contrib/libvhost-user/libvhost-user.c | 23 +++++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 8 ++++++++ hw/virtio/vhost-user.c | 1 + 4 files changed, 33 insertions(+)contrib/libvhost-user/libvhost-user.c +23
-0@@ -67,6 +67,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ),REQ (VHOST_USER_POSTCOPY_LISTEN ), +REQ (VHOST_USER_POSTCOPY_END ), REQ(VHOST_USER_MAX), };#undef REQ@@ -893,6 +894,26 @@ vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 =0 ;/* Success */ return true; } + +static bool +vu_set_postcopy_end (VuDev *dev,VhostUserMsg *vmsg) +{ +DPRINT ("%s: Entry\n" , __func__); + dev->postcopy_listening = false; +if (dev->postcopy_ufd >0 ) { +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; +DPRINT ("%s: Done close\n" , __func__); + } + + vmsg->fd_num =0 ; + vmsg->payload.u64 =0 ; + vmsg->size =sizeof (vmsg->payload.u64); + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; +DPRINT ("%s: exit\n" , __func__); +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {@@ -962,6 +983,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_postcopy_advise (dev, vmsg);case VHOST_USER_POSTCOPY_LISTEN :return vu_set_postcopy_listen (dev, vmsg); +case VHOST_USER_POSTCOPY_END : +return vu_set_postcopy_end (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +1
-0@@ -68,6 +68,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;docs/interop/vhost-user.txt +8
-0@@ -627,6 +627,14 @@ Master message types Master advises slave that a transition to postcopy mode has happened. + * VHOST_USER_POSTCOPY_END + Id: 26 + Slave payload: u64 + + Master advises that postcopy migration has now completed. The + slave must disable the userfaultfd. The response is an acknowledgement + only. + Slave message types -------------------hw/virtio/vhost-user.c +1
-0@@ -71,6 +71,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [RFC v2 26/32] vhost: Add VHOST_USER_POSTCOPY_END message
Quoted 9 lines · * Peter Xu ([email protected]) wrote:
Quoted 8 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
This message is sent just before the end of postcopy to get the client to stop using userfault since we wont respond to any more requests. It should close userfaultfd so that any other pages get mapped to the backing file automatically by the kernel, since at this point we know we've received everything.
Quoted 3 lines
Quoted 1 line
Signed-off-by Dr. David Alan Gilbert <[email protected]>(I feel like the title should be for "vub", not "vhost"?)
I've changed it to vhost-user.
Quoted 1 line
Reviewed-by Peter Xu <[email protected]>
Thanks.
Dave
Quoted 99 lines
Quoted 99 lines
--- contrib/libvhost-user/libvhost-user.c | 23 +++++++++++++++++++++++ contrib/libvhost-user/libvhost-user.h | 1 + docs/interop/vhost-user.txt | 8 ++++++++ hw/virtio/vhost-user.c | 1 + 4 files changed, 33 insertions(+)contrib/libvhost-user/libvhost-user.c +23
-0@@ -67,6 +67,7 @@ vu_request_to_string(int req)REQ (VHOST_USER_SET_VRING_ENDIAN ),REQ (VHOST_USER_POSTCOPY_ADVISE ),REQ (VHOST_USER_POSTCOPY_LISTEN ), +REQ (VHOST_USER_POSTCOPY_END ), REQ(VHOST_USER_MAX), };#undef REQ@@ -893,6 +894,26 @@ vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg) vmsg->payload.u64 =0 ;/* Success */ return true; } + +static bool +vu_set_postcopy_end (VuDev *dev,VhostUserMsg *vmsg) +{ +DPRINT ("%s: Entry\n" , __func__); + dev->postcopy_listening = false; +if (dev->postcopy_ufd >0 ) { +close (dev->postcopy_ufd); + dev->postcopy_ufd =-1 ; +DPRINT ("%s: Done close\n" , __func__); + } + + vmsg->fd_num =0 ; + vmsg->payload.u64 =0 ; + vmsg->size =sizeof (vmsg->payload.u64); + vmsg->flags =VHOST_USER_VERSION |VHOST_USER_REPLY_MASK ; +DPRINT ("%s: exit\n" , __func__); +return true; +} +static bool vu_process_message (VuDev *dev,VhostUserMsg *vmsg) {@@ -962,6 +983,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)return vu_set_postcopy_advise (dev, vmsg);case VHOST_USER_POSTCOPY_LISTEN :return vu_set_postcopy_listen (dev, vmsg); +case VHOST_USER_POSTCOPY_END : +return vu_set_postcopy_end (dev, vmsg);default :vmsg_close_fds (vmsg);vu_panic (dev,"Unhandled request: %d" , vmsg->request);contrib/libvhost-user/libvhost-user.h +1
-0@@ -68,6 +68,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;docs/interop/vhost-user.txt +8
-0@@ -627,6 +627,14 @@ Master message types Master advises slave that a transition to postcopy mode has happened. + * VHOST_USER_POSTCOPY_END + Id: 26 + Slave payload: u64 + + Master advises that postcopy migration has now completed. The + slave must disable the userfaultfd. The response is an acknowledgement + only. + Slave message types -------------------hw/virtio/vhost-user.c +1
-0@@ -71,6 +71,7 @@ typedef enum VhostUserRequest {VHOST_USER_SET_VRING_ENDIAN =23 ,VHOST_USER_POSTCOPY_ADVISE =24 ,VHOST_USER_POSTCOPY_LISTEN =25 , +VHOST_USER_POSTCOPY_END =26 , VHOST_USER_MAX } VhostUserRequest;
Quoted 6 lines
Quoted 3 lines
Signature · 1 line
2.13.5Signature · 1 line
Peter Xu
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 27/32 vhost+postcopy: Wire up POSTCOPY_END notify
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Wire up a call to VHOST_USER_POSTCOPY_END message to the vhost clients right before we ask the listener thread to shutdown.
--- hw/virtio/trace-events | 2 ++ hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ migration/postcopy-ram.c | 5 +++++ migration/postcopy-ram.h | 1 + 4 files changed, 38 insertions(+)
hw/virtio/trace-events +2 -0
@@ -1,6 +1,8 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_end_entry(void) "" +vhost_user_postcopy_end_exit(void) "" vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64
hw/virtio/vhost-user.c +30 -0
@@ -965,6 +965,33 @@ static int vhost_user_postcopy_listen(struct vhost_dev *dev, Error **errp)return 0 ; } +/* +* Called at the end of postcopy +*/ +static int vhost_user_postcopy_end (struct vhost_dev *dev,Error **errp) +{ +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_END , + .flags =VHOST_USER_VERSION |VHOST_USER_NEED_REPLY_MASK , + }; +int ret; + +trace_vhost_user_postcopy_end_entry (); +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_end to vhost" ); +return -1 ; + } + + ret =process_message_reply (dev, &msg); +if (ret) { +error_setg (errp,"Failed to receive reply to postcopy_end" ); +return ret; + } +trace_vhost_user_postcopy_end_exit (); + +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {
@@ -990,6 +1017,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,case POSTCOPY_NOTIFY_INBOUND_LISTEN :return vhost_user_postcopy_listen (dev, pnd->errp); +case POSTCOPY_NOTIFY_INBOUND_END : +return vhost_user_postcopy_end (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;
migration/postcopy-ram.c +5 -0
@@ -337,7 +337,12 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)if (mis->have_fault_thread) {uint64_t tmp64; +Error *local_err =NULL ; +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_END , &local_err)) { +error_report_err (local_err); +return -1 ; + }if (qemu_ram_foreach_block (cleanup_range, mis)) {return -1 ; }
migration/postcopy-ram.h +1 -0
@@ -130,6 +130,7 @@ enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 ,POSTCOPY_NOTIFY_INBOUND_ADVISE ,POSTCOPY_NOTIFY_INBOUND_LISTEN , + POSTCOPY_NOTIFY_INBOUND_END, }; struct PostcopyNotifyData {
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 27/32] vhost+postcopy: Wire up POSTCOPY_END notify
Quoted 6 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Wire up a call to
VHOST_USER_POSTCOPY_ENDmessage to the vhost clients right before we ask the listener thread to shutdown.Signed-off-by Dr. David Alan Gilbert <[email protected]>
Quoted 100 lines
--- hw/virtio/trace-events | 2 ++ hw/virtio/vhost-user.c | 30 ++++++++++++++++++++++++++++++ migration/postcopy-ram.c | 5 +++++ migration/postcopy-ram.h | 1 + 4 files changed, 38 insertions(+)hw/virtio/trace-events +2
-0@@ -1,6 +1,8 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost-user.c +vhost_user_postcopy_end_entry(void) "" +vhost_user_postcopy_end_exit(void) "" vhost_user_postcopy_fault_handler(const char *name, uint64_t fault_address, int nregions) "%s: @0x%"PRIx64" nregions:%d" vhost_user_postcopy_fault_handler_loop(int i, uint64_t client_base, uint64_t size) "%d: client 0x%"PRIx64" +0x%"PRIx64 vhost_user_postcopy_fault_handler_found(int i, uint64_t region_offset, uint64_t rb_offset) "%d: region_offset: 0x%"PRIx64" rb_offset:0x%"PRIx64hw/virtio/vhost-user.c +30
-0@@ -965,6 +965,33 @@ static int vhost_user_postcopy_listen(struct vhost_dev *dev, Error **errp)return 0 ; } +/* +* Called at the end of postcopy +*/ +static int vhost_user_postcopy_end (struct vhost_dev *dev,Error **errp) +{ +VhostUserMsg msg = { + .request =VHOST_USER_POSTCOPY_END , + .flags =VHOST_USER_VERSION |VHOST_USER_NEED_REPLY_MASK , + }; +int ret; + +trace_vhost_user_postcopy_end_entry (); +if (vhost_user_write (dev, &msg,NULL ,0 ) <0 ) { +error_setg (errp,"Failed to send postcopy_end to vhost" ); +return -1 ; + } + + ret =process_message_reply (dev, &msg); +if (ret) { +error_setg (errp,"Failed to receive reply to postcopy_end" ); +return ret; + } +trace_vhost_user_postcopy_end_exit (); + +return 0 ; +} +static int vhost_user_postcopy_notifier (NotifierWithReturn *notifier,void *opaque) {@@ -990,6 +1017,9 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,case POSTCOPY_NOTIFY_INBOUND_LISTEN :return vhost_user_postcopy_listen (dev, pnd->errp); +case POSTCOPY_NOTIFY_INBOUND_END : +return vhost_user_postcopy_end (dev, pnd->errp); +default :/* We ignore notifications we don't know */ break ;migration/postcopy-ram.c +5
-0@@ -337,7 +337,12 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)if (mis->have_fault_thread) {uint64_t tmp64; +Error *local_err =NULL ; +if (postcopy_notify (POSTCOPY_NOTIFY_INBOUND_END , &local_err)) { +error_report_err (local_err); +return -1 ; + }if (qemu_ram_foreach_block (cleanup_range, mis)) {return -1 ; }migration/postcopy-ram.h +1
-0@@ -130,6 +130,7 @@ enum PostcopyNotifyReason {POSTCOPY_NOTIFY_PROBE =0 ,POSTCOPY_NOTIFY_INBOUND_ADVISE ,POSTCOPY_NOTIFY_INBOUND_LISTEN , + POSTCOPY_NOTIFY_INBOUND_END, }; struct PostcopyNotifyData {Signature · 1 line
2.13.5
Signature · 1 line
Peter Xu
RFC v2 28/32 postcopy: Allow shared memory
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Now that we have the mechanisms in here, allow shared memory in a postcopy.
Note that QEMU can't tell who all the users of shared regions are and thus can't tell whether all the users of the shared regions have appropriate support for postcopy. Those devices that explicitly support shared memory (e.g. vhost-user) must check, but it doesn't stop weirder configurations causing problems.
--- migration/postcopy-ram.c | 6 ------ 1 file changed, 6 deletions(-)
migration/postcopy-ram.c +0 -6
@@ -138,12 +138,6 @@ static int test_ramblock_postcopiable(const char *block_name, void *host_addr,RAMBlock *rb =qemu_ram_block_by_name (block_name);size_t pagesize =qemu_ram_pagesize (rb); -if (qemu_ram_is_shared (rb)) { -error_report ("Postcopy on shared RAM (%s) is not yet supported" , - block_name); -return 1 ; - } -if (length % pagesize) {error_report ("Postcopy requires RAM blocks to be a page size multiple," " block %s is 0x" RAM_ADDR_FMT " bytes with a "
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 28/32] postcopy: Allow shared memory
Hi
Quoted 11 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Now that we have the mechanisms in here, allow shared memory in a postcopy.
Note that QEMU can't tell who all the users of shared regions are and thus can't tell whether all the users of the shared regions have appropriate support for postcopy. Those devices that explicitly support shared memory (e.g. vhost-user) must check, but it doesn't stop weirder configurations causing problems.
Other users should have their own migration blocker, I guess.
Quoted 1 line
Signed-off-by Dr. David Alan Gilbert <[email protected]>
Quoted 25 lines
--- migration/postcopy-ram.c | 6 ------ 1 file changed, 6 deletions(-)migration/postcopy-ram.c +0
-7@@ -138,12 +138,6 @@ static int test_ramblock_postcopiable(const char *block_name, void *host_addr,RAMBlock *rb =qemu_ram_block_by_name (block_name);size_t pagesize =qemu_ram_pagesize (rb); -if (qemu_ram_is_shared (rb)) { -error_report ("Postcopy on shared RAM (%s) is not yet supported" , - block_name); -return 1 ; - } -if (length % pagesize) {error_report ("Postcopy requires RAM blocks to be a page size multiple," " block %s is 0x" RAM_ADDR_FMT " bytes with a " --2.13.5
Signature · 1 line
Marc-André Lureau
Re: [Qemu-devel] [RFC v2 28/32] postcopy: Allow shared memory
Quoted 9 lines · * Marc-André Lureau ([email protected]) wrote:
Hi
Quoted 5 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Now that we have the mechanisms in here, allow shared memory in a postcopy.
Quoted 8 lines
Quoted 6 lines
Note that QEMU can't tell who all the users of shared regions are and thus can't tell whether all the users of the shared regions have appropriate support for postcopy. Those devices that explicitly support shared memory (e.g. vhost-user) must check, but it doesn't stop weirder configurations causing problems.
Other users should have their own migration blocker, I guess.
Yes, the ones that know about it.
The tricky thing is you can add a shared=on to any memory object you add; I don't know that the reason it's shared is purely because it's used by vhost-user - for all qemu knows it could be shared with 5 other things as well.
Quoted 3 lines
Quoted 1 line
Signed-off-by Dr. David Alan Gilbert <[email protected]>Reviewed-by Marc-André Lureau <[email protected]>
Thanks.
Dave
Quoted 14 lines
Quoted 14 lines
--- migration/postcopy-ram.c | 6 ------ 1 file changed, 6 deletions(-)migration/postcopy-ram.c +0
-0@@ -138,12 +138,6 @@ static int test_ramblock_postcopiable(const char *block_name, void *host_addr,RAMBlock *rb =qemu_ram_block_by_name (block_name);size_t pagesize =qemu_ram_pagesize (rb);
Quoted 18 lines
Quoted 13 lines
migration/postcopy-ram.c +0
-7-if (qemu_ram_is_shared (rb)) { -error_report ("Postcopy on shared RAM (%s) is not yet supported" , - block_name); -return 1 ; - } -if (length % pagesize) {error_report ("Postcopy requires RAM blocks to be a page size multiple," " block %s is 0x" RAM_ADDR_FMT " bytes with a " --2.13.5
Signature · 1 line
Marc-André Lureau
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 29/32 vhost-user: Claim support for postcopy
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Tell QEMU we understand the protocol features needed for postcopy.
--- contrib/libvhost-user/libvhost-user.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
contrib/libvhost-user/libvhost-user.c +33 -0
@@ -144,6 +144,35 @@ vmsg_close_fds(VhostUserMsg *vmsg) } } +/* A test to see if we have userfault available */ +static bool +have_userfault (void ) +{ +#if defined(__linux__) && defined(__NR_userfaultfd) &&\ + defined(UFFD_FEATURE_MISSING_SHMEM ) &&\ + defined(UFFD_FEATURE_MISSING_HUGETLBFS ) +/* Now test the kernel we're running on really has the features */ +int ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK ); +struct uffdio_api api_struct; +if (ufd <0 ) { +return false; + } + + api_struct.api =UFFD_API ; + api_struct.features =UFFD_FEATURE_MISSING_SHMEM | +UFFD_FEATURE_MISSING_HUGETLBFS ; +if (ioctl (ufd,UFFDIO_API , &api_struct)) { +close (ufd); +return false; + } +close (ufd); +return true; + +#else +return false; +#endif +} +static bool vu_message_read (VuDev *dev,int conn_fd,VhostUserMsg *vmsg) {
@@ -796,6 +825,10 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) {uint64_t features =1ULL <<VHOST_USER_PROTOCOL_F_LOG_SHMFD ; +if (have_userfault ()) { + features |=1ULL <<VHOST_USER_PROTOCOL_F_PAGEFAULT ; + } +if (dev->iface->get_protocol_features) { features |= dev->iface->get_protocol_features (dev); }
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 29/32] vhost-user: Claim support for postcopy
Hi
Use "libvhost-user: ", so we don't confuse with qemu own vhost-user code.
Quoted 61 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Tell QEMU we understand the protocol features needed for postcopy.
Signed-off-by Dr. David Alan Gilbert <[email protected]>--- contrib/libvhost-user/libvhost-user.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)contrib/libvhost-user/libvhost-user.c +33
-1@@ -144,6 +144,35 @@ vmsg_close_fds(VhostUserMsg *vmsg) } } +/* A test to see if we have userfault available */ +static bool +have_userfault (void ) +{ +#if defined(__linux__) && defined(__NR_userfaultfd) &&\ + defined(UFFD_FEATURE_MISSING_SHMEM ) &&\ + defined(UFFD_FEATURE_MISSING_HUGETLBFS ) +/* Now test the kernel we're running on really has the features */ +int ufd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK ); +struct uffdio_api api_struct; +if (ufd <0 ) { +return false; + } + + api_struct.api =UFFD_API ; + api_struct.features =UFFD_FEATURE_MISSING_SHMEM | +UFFD_FEATURE_MISSING_HUGETLBFS ; +if (ioctl (ufd,UFFDIO_API , &api_struct)) { +close (ufd); +return false; + } +close (ufd); +return true; + +#else +return false; +#endif +} +static bool vu_message_read (VuDev *dev,int conn_fd,VhostUserMsg *vmsg) {@@ -796,6 +825,10 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) {uint64_t features =1ULL <<VHOST_USER_PROTOCOL_F_LOG_SHMFD ; +if (have_userfault ()) { + features |=1ULL <<VHOST_USER_PROTOCOL_F_PAGEFAULT ; + } +if (dev->iface->get_protocol_features) { features |= dev->iface->get_protocol_features (dev); } --
Quoted 3 lines
2.13.5
Signature · 1 line
Marc-André Lureau
RFC v2 30/32 vhost: Merge neighbouring hugepage regions where appropriate
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Where two regions are created with a gap such that when aligned to hugepage boundaries, the two regions overlap, merge them.
I also add quite a few trace events to see what's going on.
Note: This doesn't handle all the cases, but does handle the common case on a PC due to the 640k hole.
--- hw/virtio/trace-events | 11 +++++++ hw/virtio/vhost.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-)
hw/virtio/trace-events +11 -0
@@ -1,5 +1,16 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost.c +vhost_dev_assign_memory_merged(int from, int to, uint64_t size, uint64_t start_addr, uint64_t uaddr) "f/t=%d/%d 0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_not_merged(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_entry(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_exit(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_entry(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_can(void) "" +vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" + # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) "" vhost_user_postcopy_end_exit(void) ""
hw/virtio/vhost.c +78 -1
133 lines not on this page · raw message
Signature · 1 line
2.13.5
Re: [Qemu-devel] [RFC v2 30/32] vhost: Merge neighbouring hugepage regions where appropriate
Quoted 4 lines · On Thu, 24 Aug 2017 20:27:28 +0100 "Dr. David Alan Gilbert (git)"…
From: "Dr. David Alan Gilbert" <[email protected]>
Where two regions are created with a gap such that when aligned to hugepage boundaries, the two regions overlap, merge them.
why only hugepage boundaries, it should be applicable any alignment
I'd say the patch isn't what I've had in mind when we discussed issue, it builds on already existing merging code and complicates code even more.
Have you looked into possibility to rebuild memory map from scratch every time vhost_region_add/vhost_region_del is called or even at vhost_commit() time to reduce rebuild from a set of memory sections that vhost tracks?
That should simplify algorithm a lot as memory sections are coming from flat view and never overlap compared to current merged memory map in vhost_dev::mem, so it won't have to deal with first splitting and then merging back every time flatview changes.
Quoted 178 lines
I also add quite a few trace events to see what's going on.
Note: This doesn't handle all the cases, but does handle the common case on a PC due to the 640k hole.
Signed-off-by Dr. David Alan Gilbert <[email protected]>Signed-off-by Maxime Coquelin <[email protected]>--- hw/virtio/trace-events | 11 +++++++ hw/virtio/vhost.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-)hw/virtio/trace-events +11
-0@@ -1,5 +1,16 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost.c +vhost_dev_assign_memory_merged(int from, int to, uint64_t size, uint64_t start_addr, uint64_t uaddr) "f/t=%d/%d 0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_not_merged(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_entry(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_exit(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_entry(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_can(void) "" +vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" + # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) "" vhost_user_postcopy_end_exit(void) ""hw/virtio/vhost.c +78
-1@@ -27,6 +27,7 @@#include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1@@ -250,6 +251,8 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, {int from, to;struct vhost_memory_region *merged =NULL ; +trace_vhost_dev_assign_memory_entry (size, start_addr, uaddr); +for (from =0 , to =0 ; from < dev->mem->nregions; ++from, ++to) {struct vhost_memory_region *reg = dev->mem->regions + to;uint64_t prlast, urlast;@@ -293,11 +296,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, uaddr = merged->userspace_addr = u; start_addr = merged->guest_phys_addr = s; size = merged->memory_size = e - s +1 ; +trace_vhost_dev_assign_memory_merged (from, to, size, start_addr, uaddr);assert (merged->memory_size); }if (!merged) {struct vhost_memory_region *reg = dev->mem->regions + to; +trace_vhost_dev_assign_memory_not_merged (size, start_addr, uaddr);memset (reg,0 ,sizeof *reg); reg->memory_size = size;assert (reg->memory_size);@@ -307,6 +312,7 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, }assert (to <= dev->mem->nregions +1 ); dev->mem->nregions = to; +trace_vhost_dev_assign_memory_exit (to); }static uint64_t vhost_get_log_size (struct vhost_dev *dev)@@ -610,8 +616,12 @@ static void vhost_set_memory(MemoryListener *listener,static bool vhost_section (MemoryRegionSection *section) { -return memory_region_is_ram (section->mr) && +bool result; + result =memory_region_is_ram (section->mr) && !memory_region_is_rom (section->mr); + +trace_vhost_section (section->mr->name, result); +return result; }static void vhost_begin (MemoryListener *listener)@@ -622,6 +632,68 @@ static void vhost_begin(MemoryListener *listener) dev->mem_changed_start_addr =-1 ; } +/* Look for regions that are hugepage backed but not aligned +* and fix them up to be aligned. +* TODO: For now this is just enough to deal with the 640k hole +*/ +static bool vhost_huge_page_stretch_and_merge (struct vhost_dev *dev) +{ +int i, j; +bool result = true; +trace_vhost_huge_page_stretch_and_merge_entry (dev->mem->nregions); + +for (i =0 ; i < dev->mem->nregions; i++) { +struct vhost_memory_region *reg = dev->mem->regions + i; +ram_addr_t offset; +RAMBlock *rb =qemu_ram_block_from_host ((void *)reg->userspace_addr, + false, &offset); +size_t pagesize =qemu_ram_pagesize (rb); +uint64_t alignage; + alignage = reg->guest_phys_addr & (pagesize -1 ); +if (alignage) { + +trace_vhost_huge_page_stretch_and_merge_start_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +for (j =0 ; j < dev->mem->nregions; j++) { +struct vhost_memory_region *oreg = dev->mem->regions + j; +if (j == i) { +continue ; + } + +if (oreg->guest_phys_addr == + (reg->guest_phys_addr - alignage) && + oreg->userspace_addr == + (reg->userspace_addr - alignage)) { +struct vhost_memory_region treg = *reg; +trace_vhost_huge_page_stretch_and_merge_can (); +vhost_dev_unassign_memory (dev, oreg->guest_phys_addr, + oreg->memory_size); +vhost_dev_unassign_memory (dev, treg.guest_phys_addr, + treg.memory_size); +vhost_dev_assign_memory (dev, + treg.guest_phys_addr - alignage, + treg.memory_size + alignage, + treg.userspace_addr - alignage); +return vhost_huge_page_stretch_and_merge (dev); + } + } + } + alignage = reg->memory_size & (pagesize -1 ); +if (alignage) { +trace_vhost_huge_page_stretch_and_merge_size_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +/* We ignore this if we find something else to merge, +* so we only return false if we're left with this +*/ + result = false; + } + } + +return result; +} +static void vhost_commit (MemoryListener *listener) { struct vhost_dev *dev = container_of(listener, struct vhost_dev,@@ -641,6 +713,7 @@ static void vhost_commit(MemoryListener *listener)return ; } +vhost_huge_page_stretch_and_merge (dev);if (dev->started) { start_addr = dev->mem_changed_start_addr; size = dev->mem_changed_end_addr - dev->mem_changed_start_addr +1 ;@@ -1512,6 +1585,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_features; } +if (!vhost_huge_page_stretch_and_merge (hdev)) { +VHOST_OPS_DEBUG ("vhost_huge_page_stretch_and_merge failed" ); + goto fail_mem; + }if (vhost_dev_has_iommu (hdev)) {memory_listener_register (&hdev->iommu_listener, vdev->dma_as); }
Re: [Qemu-devel] [RFC v2 30/32] vhost: Merge neighbouring hugepage regions where appropriate
Quoted 8 lines · * Igor Mammedov ([email protected]) wrote:
Quoted 4 lines · On Thu, 24 Aug 2017 20:27:28 +0100 "Dr. David Alan Gilbert (git)"…
From: "Dr. David Alan Gilbert" <[email protected]>
Where two regions are created with a gap such that when aligned to hugepage boundaries, the two regions overlap, merge them.
why only hugepage boundaries, it should be applicable any alignment
Actually this patch isn't huge-page specific - it just aligns to the pagesize; but do we ever hit a case where a region is smaller than a normal page and thus is changed by this?
Quoted 1 line
I'd say the patch isn't what I've had in mind when we discussed issue,
Ah
Quoted 2 lines
it builds on already existing merging code and complicates code even more.
Yes it is a little complex.
Quoted 8 lines
Have you looked into possibility to rebuild memory map from scratch every time vhost_region_add/vhost_region_del is called or even at
vhost_commit()time to reduce rebuild from a set of memory sections that vhost tracks?
That should simplify algorithm a lot as memory sections are coming from flat view and never overlap compared to current merged memory map invhost_dev::mem, so it won't have to deal with first splitting and then merging back every time flatview changes.
I hadn't; I was concentrating on changing the existing code rather than reworking it - especially since I don't/didn't know much about the notifiers.
Are you suggesting that basically vhost_region_add/del do nothing (except maybe set a flag) and the real work gets done in vhost_commit()? (I also found I had to call the merge from vhost_dev_start as well as vhost_commit - I guess from the first use?)
If I just did everything in vhost_commit where do I start - is that using something like address_space_to_flatview(address_space_memory) to get the main FlatView and somehow walk that?
Dave
Quoted 171 lines
Quoted 171 lines
I also add quite a few trace events to see what's going on.
Note: This doesn't handle all the cases, but does handle the common case on a PC due to the 640k hole.
Signed-off-by Dr. David Alan Gilbert <[email protected]>Signed-off-by Maxime Coquelin <[email protected]>--- hw/virtio/trace-events | 11 +++++++ hw/virtio/vhost.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-)hw/virtio/trace-events +11
-0@@ -1,5 +1,16 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost.c +vhost_dev_assign_memory_merged(int from, int to, uint64_t size, uint64_t start_addr, uint64_t uaddr) "f/t=%d/%d 0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_not_merged(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_entry(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_exit(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_entry(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_can(void) "" +vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" + # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) "" vhost_user_postcopy_end_exit(void) ""hw/virtio/vhost.c +74
-1@@ -27,6 +27,7 @@#include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1@@ -250,6 +251,8 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, {int from, to;struct vhost_memory_region *merged =NULL ; +trace_vhost_dev_assign_memory_entry (size, start_addr, uaddr); +for (from =0 , to =0 ; from < dev->mem->nregions; ++from, ++to) {struct vhost_memory_region *reg = dev->mem->regions + to;uint64_t prlast, urlast;@@ -293,11 +296,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, uaddr = merged->userspace_addr = u; start_addr = merged->guest_phys_addr = s; size = merged->memory_size = e - s +1 ; +trace_vhost_dev_assign_memory_merged (from, to, size, start_addr, uaddr);assert (merged->memory_size); }if (!merged) {struct vhost_memory_region *reg = dev->mem->regions + to; +trace_vhost_dev_assign_memory_not_merged (size, start_addr, uaddr);memset (reg,0 ,sizeof *reg); reg->memory_size = size;assert (reg->memory_size);@@ -307,6 +312,7 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, }assert (to <= dev->mem->nregions +1 ); dev->mem->nregions = to; +trace_vhost_dev_assign_memory_exit (to); }static uint64_t vhost_get_log_size (struct vhost_dev *dev)@@ -610,8 +616,12 @@ static void vhost_set_memory(MemoryListener *listener,static bool vhost_section (MemoryRegionSection *section) { -return memory_region_is_ram (section->mr) && +bool result; + result =memory_region_is_ram (section->mr) && !memory_region_is_rom (section->mr); + +trace_vhost_section (section->mr->name, result); +return result; }static void vhost_begin (MemoryListener *listener)@@ -622,6 +632,68 @@ static void vhost_begin(MemoryListener *listener) dev->mem_changed_start_addr =-1 ; } +/* Look for regions that are hugepage backed but not aligned +* and fix them up to be aligned. +* TODO: For now this is just enough to deal with the 640k hole +*/ +static bool vhost_huge_page_stretch_and_merge (struct vhost_dev *dev) +{ +int i, j; +bool result = true; +trace_vhost_huge_page_stretch_and_merge_entry (dev->mem->nregions); + +for (i =0 ; i < dev->mem->nregions; i++) { +struct vhost_memory_region *reg = dev->mem->regions + i; +ram_addr_t offset; +RAMBlock *rb =qemu_ram_block_from_host ((void *)reg->userspace_addr, + false, &offset); +size_t pagesize =qemu_ram_pagesize (rb); +uint64_t alignage; + alignage = reg->guest_phys_addr & (pagesize -1 ); +if (alignage) { + +trace_vhost_huge_page_stretch_and_merge_start_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +for (j =0 ; j < dev->mem->nregions; j++) { +struct vhost_memory_region *oreg = dev->mem->regions + j; +if (j == i) { +continue ; + } + +if (oreg->guest_phys_addr == + (reg->guest_phys_addr - alignage) && + oreg->userspace_addr == + (reg->userspace_addr - alignage)) { +struct vhost_memory_region treg = *reg; +trace_vhost_huge_page_stretch_and_merge_can (); +vhost_dev_unassign_memory (dev, oreg->guest_phys_addr, + oreg->memory_size); +vhost_dev_unassign_memory (dev, treg.guest_phys_addr, + treg.memory_size); +vhost_dev_assign_memory (dev, + treg.guest_phys_addr - alignage, + treg.memory_size + alignage, + treg.userspace_addr - alignage); +return vhost_huge_page_stretch_and_merge (dev); + } + } + } + alignage = reg->memory_size & (pagesize -1 ); +if (alignage) { +trace_vhost_huge_page_stretch_and_merge_size_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +/* We ignore this if we find something else to merge, +* so we only return false if we're left with this +*/ + result = false; + } + } + +return result; +} +static void vhost_commit (MemoryListener *listener) { struct vhost_dev *dev = container_of(listener, struct vhost_dev,@@ -641,6 +713,7 @@ static void vhost_commit(MemoryListener *listener)return ; } +vhost_huge_page_stretch_and_merge (dev);if (dev->started) { start_addr = dev->mem_changed_start_addr; size = dev->mem_changed_end_addr - dev->mem_changed_start_addr +1 ;@@ -1512,6 +1585,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_features; }
Quoted 8 lines
hw/virtio/vhost.c int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) · line 1594
Quoted 7 lines
hw/virtio/vhost.c +4
-0+if (!vhost_huge_page_stretch_and_merge (hdev)) { +VHOST_OPS_DEBUG ("vhost_huge_page_stretch_and_merge failed" ); + goto fail_mem; + }if (vhost_dev_has_iommu (hdev)) {memory_listener_register (&hdev->iommu_listener, vdev->dma_as); }
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [RFC v2 30/32] vhost: Merge neighbouring hugepage regions where appropriate
Quoted 32 lines · On Mon, 25 Sep 2017 12:19:55 +0100 "Dr. David Alan Gilbert"…
Quoted 8 lines · * Igor Mammedov ([email protected]) wrote:
Quoted 4 lines · On Thu, 24 Aug 2017 20:27:28 +0100 "Dr. David Alan Gilbert (git)"…
From: "Dr. David Alan Gilbert" <[email protected]>
Where two regions are created with a gap such that when aligned to hugepage boundaries, the two regions overlap, merge them.
why only hugepage boundaries, it should be applicable any alignment
Actually this patch isn't huge-page specific - it just aligns to the pagesize; but do we ever hit a case where a region is smaller than a normal page and thus is changed by this?
Quoted 1 line
I'd say the patch isn't what I've had in mind when we discussed issue,
Ah
Quoted 2 lines
it builds on already existing merging code and complicates code even more.
Yes it is a little complex.
Quoted 8 lines
Have you looked into possibility to rebuild memory map from scratch every time vhost_region_add/vhost_region_del is called or even at
vhost_commit()time to reduce rebuild from a set of memory sections that vhost tracks?
That should simplify algorithm a lot as memory sections are coming from flat view and never overlap compared to current merged memory map invhost_dev::mem, so it won't have to deal with first splitting and then merging back every time flatview changes.
Quoted 8 lines
I hadn't; I was concentrating on changing the existing code rather than reworking it - especially since I don't/didn't know much about the notifiers.
Are you suggesting that basically vhost_region_add/del do nothing (except maybe set a flag) and the real work gets done in
vhost_commit()? (I also found I had to call the merge fromvhost_dev_startas well asvhost_commit- I guess from the first use?)
yep, i.e. build memmap on request.
Quoted 3 lines
If I just did everything in
vhost_commitwhere do I start - is that using something likeaddress_space_to_flatview(address_space_memory)to get the main FlatView and somehow walk that?
vhost already tracks flat view with vhost_region_add/vhost_region_del notifiers by saving references to MemoryRegionSection-s. Memory sections have following properties/behavior:
1. they never overlap
2. when we map something over existing memory section. notifier first removes former section and then gets several region_add calls that add newly split non overlaping sections.
#2 happens multiple times when we start VM (before machine_done)
and several times during firmware boot when some registers are (un)mapped during chip-set initialization.
so currently vhost_set_memory() is called uselessly multiple times before memmap is actually need/used and it maintains essentially optimized/sorted version of mem_sections[].
What I suggest is to
1. stop rebuilding memap in vhost_set_memory on 'every' flatview change and do it only when memmap is actually used
2. get rid of duplicate data kept in regions[]/complex code that
maintains it and
2.1 use mem_sections[] directly to build memap on request.
2.2 sorting mem_sections[] by start_addr when memmap is
build could help to merge neighboring/mergable sections on the fly
without need to resplit/merge regions[] in internally maintained
memmap.implementing both points would allow to drop a bunch of complex code that sort of duplicates what flatview already does and I'd guess this patch would be much simpler as result.
Optionally there is an idea to allow merging neighboring sections even if there are gaps between them provided that GVA->HVA distance for merging sections is the same (i.e sections belong to the same MR with some holes in flatview punched by MMIO),
it should allow for better memmap compression then we have now.
PS:
refactoring probably should be split into separate series, that should go in first.
Quoted 184 lines
Dave
Quoted 171 lines
Quoted 171 lines
I also add quite a few trace events to see what's going on.
Note: This doesn't handle all the cases, but does handle the common case on a PC due to the 640k hole.
Signed-off-by Dr. David Alan Gilbert <[email protected]>Signed-off-by Maxime Coquelin <[email protected]>--- hw/virtio/trace-events | 11 +++++++ hw/virtio/vhost.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-)hw/virtio/trace-events +11
-0@@ -1,5 +1,16 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost.c +vhost_dev_assign_memory_merged(int from, int to, uint64_t size, uint64_t start_addr, uint64_t uaddr) "f/t=%d/%d 0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_not_merged(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_entry(uint64_t size, uint64_t start_addr, uint64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_exit(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_entry(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_can(void) "" +vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" + # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) "" vhost_user_postcopy_end_exit(void) ""hw/virtio/vhost.c +74
-1@@ -27,6 +27,7 @@#include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1@@ -250,6 +251,8 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, {int from, to;struct vhost_memory_region *merged =NULL ; +trace_vhost_dev_assign_memory_entry (size, start_addr, uaddr); +for (from =0 , to =0 ; from < dev->mem->nregions; ++from, ++to) {struct vhost_memory_region *reg = dev->mem->regions + to;uint64_t prlast, urlast;@@ -293,11 +296,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, uaddr = merged->userspace_addr = u; start_addr = merged->guest_phys_addr = s; size = merged->memory_size = e - s +1 ; +trace_vhost_dev_assign_memory_merged (from, to, size, start_addr, uaddr);assert (merged->memory_size); }if (!merged) {struct vhost_memory_region *reg = dev->mem->regions + to; +trace_vhost_dev_assign_memory_not_merged (size, start_addr, uaddr);memset (reg,0 ,sizeof *reg); reg->memory_size = size;assert (reg->memory_size);@@ -307,6 +312,7 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, }assert (to <= dev->mem->nregions +1 ); dev->mem->nregions = to; +trace_vhost_dev_assign_memory_exit (to); }static uint64_t vhost_get_log_size (struct vhost_dev *dev)@@ -610,8 +616,12 @@ static void vhost_set_memory(MemoryListener *listener,static bool vhost_section (MemoryRegionSection *section) { -return memory_region_is_ram (section->mr) && +bool result; + result =memory_region_is_ram (section->mr) && !memory_region_is_rom (section->mr); + +trace_vhost_section (section->mr->name, result); +return result; }static void vhost_begin (MemoryListener *listener)@@ -622,6 +632,68 @@ static void vhost_begin(MemoryListener *listener) dev->mem_changed_start_addr =-1 ; } +/* Look for regions that are hugepage backed but not aligned +* and fix them up to be aligned. +* TODO: For now this is just enough to deal with the 640k hole +*/ +static bool vhost_huge_page_stretch_and_merge (struct vhost_dev *dev) +{ +int i, j; +bool result = true; +trace_vhost_huge_page_stretch_and_merge_entry (dev->mem->nregions); + +for (i =0 ; i < dev->mem->nregions; i++) { +struct vhost_memory_region *reg = dev->mem->regions + i; +ram_addr_t offset; +RAMBlock *rb =qemu_ram_block_from_host ((void *)reg->userspace_addr, + false, &offset); +size_t pagesize =qemu_ram_pagesize (rb); +uint64_t alignage; + alignage = reg->guest_phys_addr & (pagesize -1 ); +if (alignage) { + +trace_vhost_huge_page_stretch_and_merge_start_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +for (j =0 ; j < dev->mem->nregions; j++) { +struct vhost_memory_region *oreg = dev->mem->regions + j; +if (j == i) { +continue ; + } + +if (oreg->guest_phys_addr == + (reg->guest_phys_addr - alignage) && + oreg->userspace_addr == + (reg->userspace_addr - alignage)) { +struct vhost_memory_region treg = *reg; +trace_vhost_huge_page_stretch_and_merge_can (); +vhost_dev_unassign_memory (dev, oreg->guest_phys_addr, + oreg->memory_size); +vhost_dev_unassign_memory (dev, treg.guest_phys_addr, + treg.memory_size); +vhost_dev_assign_memory (dev, + treg.guest_phys_addr - alignage, + treg.memory_size + alignage, + treg.userspace_addr - alignage); +return vhost_huge_page_stretch_and_merge (dev); + } + } + } + alignage = reg->memory_size & (pagesize -1 ); +if (alignage) { +trace_vhost_huge_page_stretch_and_merge_size_align (i, + (uint64_t )reg->guest_phys_addr, + alignage); +/* We ignore this if we find something else to merge, +* so we only return false if we're left with this +*/ + result = false; + } + } + +return result; +} +static void vhost_commit (MemoryListener *listener) { struct vhost_dev *dev = container_of(listener, struct vhost_dev,@@ -641,6 +713,7 @@ static void vhost_commit(MemoryListener *listener)return ; } +vhost_huge_page_stretch_and_merge (dev);if (dev->started) { start_addr = dev->mem_changed_start_addr; size = dev->mem_changed_end_addr - dev->mem_changed_start_addr +1 ;@@ -1512,6 +1585,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_features; }Quoted 8 lines
hw/virtio/vhost.c int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) · line 1594
Quoted 7 lines
hw/virtio/vhost.c +4
-0+if (!vhost_huge_page_stretch_and_merge (hdev)) { +VHOST_OPS_DEBUG ("vhost_huge_page_stretch_and_merge failed" ); + goto fail_mem; + }if (vhost_dev_has_iommu (hdev)) {memory_listener_register (&hdev->iommu_listener, vdev->dma_as); }--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
RFC v2 31/32 vhost: Don't break merged regions on small remove/non-adds
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
The previous patch merges hugepage regions with small gaps back into one; this patch stops some of the cases that split them up again.
vhost_set_memory avoids adding small regions that are being dirty-monitored (typically VGA regions), but vhost_set_memory does remove these regions from any region they overlap.
Avoid doing that removal if we'll just merge them again.
The typical case is where the VGA regions dynamically change at run time after we've done the merge; although the merge works, the result is that the memory is marked as having changed and a set_mem_table message is transmitted. By avoiding the split we avoid the join and we avoid marking the regions as having changed, and thus avoid sending the set_mem_table.
--- hw/virtio/trace-events | 2 ++ hw/virtio/vhost.c | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)
hw/virtio/trace-events +2 -0
@@ -10,6 +10,8 @@ vhost_huge_page_stretch_and_merge_can(void) "" vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 vhost_section(const char *name, int r) "%s:%d" +vhost_dev_would_remerge_no(uint64_t start_addr, uint64_t size) "0x%"PRIx64" + 0x%"PRIx64 +vhost_dev_would_remerge_yes(uint64_t start_addr, uint64_t size) "0x%"PRIx64" + 0x%"PRIx64 # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) ""
hw/virtio/vhost.c +41 -1
54 lines not on this page · raw message
Signature · 1 line
2.13.5
RFC v2 32/32 postcopy shared docs
In reply to Dr. David Alan Gilbert (git)From: "Dr. David Alan Gilbert" <[email protected]>
Add some notes to the migration documentation for shared memory postcopy.
--- docs/devel/migration.txt | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
docs/devel/migration.txt +39 -0
@@ -553,3 +553,42 @@ Postcopy now works with hugetlbfs backed memory: hugepages works well, however 1GB hugepages are likely to be problematic since it takes ~1 second to transfer a 1GB hugepage across a 10Gbps link, and until the full page is transferred the destination thread is blocked. + +=== Postcopy with shared memory === + +Postcopy migration with shared memory needs explicit support from the other +processes that share memory and from QEMU. There are restrictions on the type of +memory that userfault can support shared. + +The Linux kernel userfault support works on /dev/shm memory and on hugetlbfs +(although the kernel doesn't provide an equivalent to madvise(MADV_DONTNEED) +for hugetlbfs which may be a problem in some configurations). + +The vhost-user code in QEMU supports clients that have Postcopy support, +and the vhost-user-bridge (in tests/) and the DPDK package have changes +to support postcopy. + +The client needs to open a userfaultfd and register the areas +of memory that it maps with userfault. The client must then pass the +userfaultfd back to QEMU together with a mapping table that allows +fault addresses in the clients address space to be converted back to +RAMBlock/offsets. The client's userfaultfd is added to the postcopy +fault-thread and page requests are made on behalf of the client by QEMU. +QEMU performs 'wake' operations on the client's userfaultfd to allow it +to continue after a page has arrived. + + Note: There are two future improvements that would be nice: + a) Some way to make QEMU ignorant of the addresses in the clients + address space + b) Avoiding the need for QEMU to perform ufd-wake calls after the + pages have arrived + +Retro-fitting postcopy to existing clients is possible: + a) A mechanism is needed for the registration with userfault as above, + and the registration needs to be coordinated with the phases of + postcopy. In vhost-user extra messages are added to the existing + control channel. + b) Any thread that can block due to guest memory accesses must be + identified and the implication understood; for example if the + guest memory access is made while holding a lock then all other + threads waiting for that lock will also be blocked.
Signature · 1 line
2.13.5
Hello David,
You wrote in previous version:
Quoted 3 lines
We've had a postcopy migrate work now, with a few hacks we're still cleaning up, both on vhost-user-bridge and dpdk; so I'll get this updated and reposted.
I want to know more about DPDK work, do you know, is somebody assigned to that task?
Quoted 94 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Hi,
This is a RFC/WIP series that enables postcopy migration
with shared memory to a vhost-user process.
It's based off current-head + Alexey's bitmap seriesIt's tested with vhost-user-bridge and a dpdk (modified by Maxime that will get posted separately) - both very lightly.
It's still got a few very rough edges, but it succesfully migrates with both normal and huge pages (2M).
The major difference over v1 is that there's a set of code that merges vhost regions together on the qemu side so that we get a single hugepage region on the PC spanning the 640k hole (the hole hopefully isn't accessed by the client, but the client used to align around it anyway).
It's also got a lot of cleanups from the comments from v1 but there's still a few things that need work.
In particular, there's still the hack around qemu waiting for theset_mem_tableto come back; I also worry what would happen if a set-mem-table was triggered during a migrate; I suspect it would break badly.One problem that didn't cause a problem was madvises for hugepages; because we register userfault directly after mmap'ing the region in the client, we have no pages mapped and hence the madvise's/fallocate's are fortunately not compulsary. Still, I'd like a way to do it, it would feel safer.
A copy of this code, based off the current 2.10.0-rc4 together with Alexey's bitmap code is available here:
https://github.com/dagrh/qemu/tree/vhost-wipv2Dave
Dr. David Alan Gilbert (32):
vhu:vu_queue_started
vhub: Only process received packets on started queues
migrate: Updateram_block_discard_rangefor sharedqemu_ram_block_host_offset
migration/ram:ramblock_recv_bitmap_test_byte_offset
postcopy: useUFFDIO_ZEROPAGEonly when available
postcopy: Add notifier chain
postcopy: Add vhost-user flag for postcopy and check it
vhost-user: Add 'VHOST_USER_POSTCOPY_ADVISE' message
vhub: Support sending fds back to qemu
vhub: Open userfaultfd
postcopy: Allow registering of fd handler vhost+postcopy: Register shared ufd with postcopy vhost+postcopy: Transmit 'listen' to client vhost+postcopy: Register new regions with the ufd vhost+postcopy: Send address back to qemu vhost+postcopy: Stash RAMBlock and offset vhost+postcopy: Send requests to source for shared pages vhost+postcopy: Resolve client address
postcopy: wake shared
postcopy:postcopy_notify_shared_wakevhost+postcopy: Add vhost waker
vhost+postcopy: Call wakeups
vub+postcopy: madvises
vhost+postcopy: Lock aroundset_mem_table
vhost: AddVHOST_USER_POSTCOPY_ENDmessage vhost+postcopy: Wire upPOSTCOPY_ENDnotify
postcopy: Allow shared memory
vhost-user: Claim support for postcopy
vhost: Merge neighbouring hugepage regions where appropriate
vhost: Don't break merged regions on small remove/non-adds postcopy shared docscontrib/libvhost-user/libvhost-user.c | 226 ++++++++++++++++++++- contrib/libvhost-user/libvhost-user.h | 22 ++- docs/devel/migration.txt | 39 ++++ docs/interop/vhost-user.txt | 39 ++++ exec.c | 60 ++++-- hw/virtio/trace-events | 27 +++ hw/virtio/vhost-user.c | 326 +++++++++++++++++++++++++++++- hw/virtio/vhost.c | 121 +++++++++++- include/exec/cpu-common.h | 4 + migration/migration.c | 3 + migration/migration.h | 4 + migration/postcopy-ram.c | 359 +++++++++++++++++++++++++++------- migration/postcopy-ram.h | 69 +++++++ migration/ram.c | 5 + migration/ram.h | 1 + migration/savevm.c | 13 ++ migration/trace-events | 6 + tests/vhost-user-bridge.c | 1 + trace-events | 3 + vl.c | 2 + 20 files changed, 1241 insertions(+), 89 deletions(-)
Signature · 2 lines
Best regards, Alexey Perevalov
Hello Alexey,
Quoted 9 lines · Alexey Perevalov
Hello David,
You wrote in previous version:
Quoted 3 lines
We've had a postcopy migrate work now, with a few hacks we're still cleaning up, both on vhost-user-bridge and dpdk; so I'll get this updated and reposted.
I want to know more about DPDK work, do you know, is somebody assigned to that task?
I did the DPDK (rough) prototype, you may find it here:
https://gitlab.com/mcoquelin/dpdk-next-virtio/commits/postcopy_proto_v1
Cheers,
Maxime
Hello Maxime
Quoted 7 lines · Maxime Coquelin
Hello Alexey,
Quoted 4 lines · Alexey Perevalov
Hello David,
You wrote in previous version:
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
We've had a postcopy migrate work now, with a few hacks we're still cleaning up, both on vhost-user-bridge and dpdk; so I'll get this updated and reposted.
I want to know more about DPDK work, do you know, is somebody assigned to that task?
I did the DPDK (rough) prototype, you may find it here:
https://gitlab.com/mcoquelin/dpdk-next-virtio/commits/postcopy_proto_v1
I found it is for previous version of the patchset. Do you have any updates?
Quoted 6 lines
Cheers,
Maxime
Signature · 2 lines
Best regards, Alexey Perevalov