26
26
#include <linux/virtio.h>
27
27
#include <linux/virtio_config.h>
28
28
#include <linux/virtio_ring.h>
29
+ #include <linux/time-internal.h>
29
30
#include <shared/as-layout.h>
30
31
#include <irq_kern.h>
31
32
#include <init.h>
@@ -64,6 +65,11 @@ struct virtio_uml_device {
64
65
struct virtio_uml_vq_info {
65
66
int kick_fd , call_fd ;
66
67
char name [32 ];
68
+ #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
69
+ struct virtqueue * vq ;
70
+ vq_callback_t * callback ;
71
+ struct time_travel_event defer ;
72
+ #endif
67
73
};
68
74
69
75
extern unsigned long long physmem_size , highmem ;
@@ -118,10 +124,27 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
118
124
119
125
static int vhost_user_recv (struct virtio_uml_device * vu_dev ,
120
126
int fd , struct vhost_user_msg * msg ,
121
- size_t max_payload_size )
127
+ size_t max_payload_size , bool wait )
122
128
{
123
129
size_t size ;
124
- int rc = vhost_user_recv_header (fd , msg );
130
+ int rc ;
131
+
132
+ /*
133
+ * In virtio time-travel mode, we're handling all the vhost-user
134
+ * FDs by polling them whenever appropriate. However, we may get
135
+ * into a situation where we're sending out an interrupt message
136
+ * to a device (e.g. a net device) and need to handle a simulation
137
+ * time message while doing so, e.g. one that tells us to update
138
+ * our idea of how long we can run without scheduling.
139
+ *
140
+ * Thus, we need to not just read() from the given fd, but need
141
+ * to also handle messages for the simulation time - this function
142
+ * does that for us while waiting for the given fd to be readable.
143
+ */
144
+ if (wait )
145
+ time_travel_wait_readable (fd );
146
+
147
+ rc = vhost_user_recv_header (fd , msg );
125
148
126
149
if (rc == - ECONNRESET && vu_dev -> registered ) {
127
150
struct virtio_uml_platform_data * pdata ;
@@ -143,7 +166,8 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
143
166
struct vhost_user_msg * msg ,
144
167
size_t max_payload_size )
145
168
{
146
- int rc = vhost_user_recv (vu_dev , vu_dev -> sock , msg , max_payload_size );
169
+ int rc = vhost_user_recv (vu_dev , vu_dev -> sock , msg ,
170
+ max_payload_size , true);
147
171
148
172
if (rc )
149
173
return rc ;
@@ -173,7 +197,8 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
173
197
struct vhost_user_msg * msg ,
174
198
size_t max_payload_size )
175
199
{
176
- int rc = vhost_user_recv (vu_dev , vu_dev -> req_fd , msg , max_payload_size );
200
+ int rc = vhost_user_recv (vu_dev , vu_dev -> req_fd , msg ,
201
+ max_payload_size , false);
177
202
178
203
if (rc )
179
204
return rc ;
@@ -700,6 +725,8 @@ static bool vu_notify(struct virtqueue *vq)
700
725
const uint64_t n = 1 ;
701
726
int rc ;
702
727
728
+ time_travel_propagate_time ();
729
+
703
730
if (info -> kick_fd < 0 ) {
704
731
struct virtio_uml_device * vu_dev ;
705
732
@@ -847,6 +874,23 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev,
847
874
return rc ;
848
875
}
849
876
877
+ #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
878
+ static void vu_defer_irq_handle (struct time_travel_event * d )
879
+ {
880
+ struct virtio_uml_vq_info * info ;
881
+
882
+ info = container_of (d , struct virtio_uml_vq_info , defer );
883
+ info -> callback (info -> vq );
884
+ }
885
+
886
+ static void vu_defer_irq_callback (struct virtqueue * vq )
887
+ {
888
+ struct virtio_uml_vq_info * info = vq -> priv ;
889
+
890
+ time_travel_add_irq_event (& info -> defer );
891
+ }
892
+ #endif
893
+
850
894
static struct virtqueue * vu_setup_vq (struct virtio_device * vdev ,
851
895
unsigned index , vq_callback_t * callback ,
852
896
const char * name , bool ctx )
@@ -866,6 +910,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
866
910
snprintf (info -> name , sizeof (info -> name ), "%s.%d-%s" , pdev -> name ,
867
911
pdev -> id , name );
868
912
913
+ #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
914
+ /*
915
+ * When we get an interrupt, we must bounce it through the simulation
916
+ * calendar (the simtime device), except for the simtime device itself
917
+ * since that's part of the simulation control.
918
+ */
919
+ if (time_travel_mode == TT_MODE_EXTERNAL && callback ) {
920
+ info -> callback = callback ;
921
+ callback = vu_defer_irq_callback ;
922
+ time_travel_set_event_fn (& info -> defer , vu_defer_irq_handle );
923
+ }
924
+ #endif
925
+
869
926
vq = vring_create_virtqueue (index , num , PAGE_SIZE , vdev , true, true,
870
927
ctx , vu_notify , callback , info -> name );
871
928
if (!vq ) {
@@ -874,6 +931,9 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
874
931
}
875
932
vq -> priv = info ;
876
933
num = virtqueue_get_vring_size (vq );
934
+ #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
935
+ info -> vq = vq ;
936
+ #endif
877
937
878
938
if (vu_dev -> protocol_features &
879
939
BIT_ULL (VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS )) {
0 commit comments