aboutsummaryrefslogtreecommitdiff
path: root/hw/virtio/vhost-user.c
diff options
context:
space:
mode:
authorDr. David Alan Gilbert <dgilbert@redhat.com>2018-03-12 17:21:13 +0000
committerMichael S. Tsirkin <mst@redhat.com>2018-03-20 16:40:19 +0200
commit375318d03f3f3fca72606eea71240cb6a3536314 (patch)
tree0c9810c5b631264129cf159e2f158af209c447d5 /hw/virtio/vhost-user.c
parentc188c539275bbdc221c325ae9bc1c407353c4130 (diff)
vhost+postcopy: Resolve client address
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 <dgilbert@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/virtio/vhost-user.c')
-rw-r--r--hw/virtio/vhost-user.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index b47de62c47..6dee1b565c 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -26,6 +26,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
@@ -974,7 +975,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;
}
/*