um: Implement time-travel=ext
This implements synchronized time-travel mode which - using a special application on a unix socket - lets multiple machines take part in a time-travelling simulation together. The protocol for the unix domain socket is defined in the new file include/uapi/linux/um_timetravel.h. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:

committed by
Richard Weinberger

parent
dd9ada5627
commit
88ce642492
@@ -26,6 +26,7 @@
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <linux/time-internal.h>
|
||||
#include <shared/as-layout.h>
|
||||
#include <irq_kern.h>
|
||||
#include <init.h>
|
||||
@@ -64,6 +65,11 @@ struct virtio_uml_device {
|
||||
struct virtio_uml_vq_info {
|
||||
int kick_fd, call_fd;
|
||||
char name[32];
|
||||
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
|
||||
struct virtqueue *vq;
|
||||
vq_callback_t *callback;
|
||||
struct time_travel_event defer;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern unsigned long long physmem_size, highmem;
|
||||
@@ -118,10 +124,27 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
|
||||
|
||||
static int vhost_user_recv(struct virtio_uml_device *vu_dev,
|
||||
int fd, struct vhost_user_msg *msg,
|
||||
size_t max_payload_size)
|
||||
size_t max_payload_size, bool wait)
|
||||
{
|
||||
size_t size;
|
||||
int rc = vhost_user_recv_header(fd, msg);
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* In virtio time-travel mode, we're handling all the vhost-user
|
||||
* FDs by polling them whenever appropriate. However, we may get
|
||||
* into a situation where we're sending out an interrupt message
|
||||
* to a device (e.g. a net device) and need to handle a simulation
|
||||
* time message while doing so, e.g. one that tells us to update
|
||||
* our idea of how long we can run without scheduling.
|
||||
*
|
||||
* Thus, we need to not just read() from the given fd, but need
|
||||
* to also handle messages for the simulation time - this function
|
||||
* does that for us while waiting for the given fd to be readable.
|
||||
*/
|
||||
if (wait)
|
||||
time_travel_wait_readable(fd);
|
||||
|
||||
rc = vhost_user_recv_header(fd, msg);
|
||||
|
||||
if (rc == -ECONNRESET && vu_dev->registered) {
|
||||
struct virtio_uml_platform_data *pdata;
|
||||
@@ -143,7 +166,8 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
|
||||
struct vhost_user_msg *msg,
|
||||
size_t max_payload_size)
|
||||
{
|
||||
int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size);
|
||||
int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg,
|
||||
max_payload_size, true);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -173,7 +197,8 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
|
||||
struct vhost_user_msg *msg,
|
||||
size_t max_payload_size)
|
||||
{
|
||||
int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, max_payload_size);
|
||||
int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg,
|
||||
max_payload_size, false);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -700,6 +725,8 @@ static bool vu_notify(struct virtqueue *vq)
|
||||
const uint64_t n = 1;
|
||||
int rc;
|
||||
|
||||
time_travel_propagate_time();
|
||||
|
||||
if (info->kick_fd < 0) {
|
||||
struct virtio_uml_device *vu_dev;
|
||||
|
||||
@@ -847,6 +874,23 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
|
||||
static void vu_defer_irq_handle(struct time_travel_event *d)
|
||||
{
|
||||
struct virtio_uml_vq_info *info;
|
||||
|
||||
info = container_of(d, struct virtio_uml_vq_info, defer);
|
||||
info->callback(info->vq);
|
||||
}
|
||||
|
||||
static void vu_defer_irq_callback(struct virtqueue *vq)
|
||||
{
|
||||
struct virtio_uml_vq_info *info = vq->priv;
|
||||
|
||||
time_travel_add_irq_event(&info->defer);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
|
||||
unsigned index, vq_callback_t *callback,
|
||||
const char *name, bool ctx)
|
||||
@@ -866,6 +910,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
|
||||
snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name,
|
||||
pdev->id, name);
|
||||
|
||||
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
|
||||
/*
|
||||
* When we get an interrupt, we must bounce it through the simulation
|
||||
* calendar (the simtime device), except for the simtime device itself
|
||||
* since that's part of the simulation control.
|
||||
*/
|
||||
if (time_travel_mode == TT_MODE_EXTERNAL && callback) {
|
||||
info->callback = callback;
|
||||
callback = vu_defer_irq_callback;
|
||||
time_travel_set_event_fn(&info->defer, vu_defer_irq_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true,
|
||||
ctx, vu_notify, callback, info->name);
|
||||
if (!vq) {
|
||||
@@ -874,6 +931,9 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
|
||||
}
|
||||
vq->priv = info;
|
||||
num = virtqueue_get_vring_size(vq);
|
||||
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
|
||||
info->vq = vq;
|
||||
#endif
|
||||
|
||||
if (vu_dev->protocol_features &
|
||||
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)) {
|
||||
|
Reference in New Issue
Block a user