Skip to content

Commit dd9ada5

Browse files
jmberg-intelrichardweinberger
authored andcommitted
um: virtio: Implement VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS
Implement in-band notifications that are necessary for running vhost-user devices under externally synchronized time-travel mode (which is in a follow-up patch). This feature makes what usually should be eventfd notifications in-band messages. We'll prefer this feature, under the assumption that only a few (simulation) devices will ever support it, since it's not very efficient. Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 4b786e2 commit dd9ada5

File tree

2 files changed

+75
-22
lines changed

2 files changed

+75
-22
lines changed

arch/um/drivers/vhost_user.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
/* Feature bits */
1111
#define VHOST_USER_F_PROTOCOL_FEATURES 30
1212
/* Protocol feature bits */
13-
#define VHOST_USER_PROTOCOL_F_REPLY_ACK 3
14-
#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
15-
#define VHOST_USER_PROTOCOL_F_CONFIG 9
13+
#define VHOST_USER_PROTOCOL_F_REPLY_ACK 3
14+
#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
15+
#define VHOST_USER_PROTOCOL_F_CONFIG 9
16+
#define VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS 14
1617
/* Vring state index masks */
1718
#define VHOST_USER_VRING_INDEX_MASK 0xff
1819
#define VHOST_USER_VRING_POLL_MASK BIT(8)
@@ -24,7 +25,8 @@
2425
/* Supported protocol features */
2526
#define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \
2627
BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \
27-
BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG))
28+
BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG) | \
29+
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS))
2830

2931
enum vhost_user_request {
3032
VHOST_USER_GET_FEATURES = 1,
@@ -52,12 +54,14 @@ enum vhost_user_request {
5254
VHOST_USER_SET_VRING_ENDIAN = 23,
5355
VHOST_USER_GET_CONFIG = 24,
5456
VHOST_USER_SET_CONFIG = 25,
57+
VHOST_USER_VRING_KICK = 35,
5558
};
5659

5760
enum vhost_user_slave_request {
5861
VHOST_USER_SLAVE_IOTLB_MSG = 1,
5962
VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
6063
VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3,
64+
VHOST_USER_SLAVE_VRING_CALL = 4,
6165
};
6266

6367
struct vhost_user_header {

arch/um/drivers/virtio_uml.c

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct virtio_uml_device {
5353
struct virtio_device vdev;
5454
struct platform_device *pdev;
5555

56+
spinlock_t sock_lock;
5657
int sock, req_fd;
5758
u64 features;
5859
u64 protocol_features;
@@ -189,6 +190,7 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev,
189190
int *fds, size_t num_fds)
190191
{
191192
size_t size = sizeof(msg->header) + msg->header.size;
193+
unsigned long flags;
192194
bool request_ack;
193195
int rc;
194196

@@ -207,24 +209,28 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev,
207209
if (request_ack)
208210
msg->header.flags |= VHOST_USER_FLAG_NEED_REPLY;
209211

212+
spin_lock_irqsave(&vu_dev->sock_lock, flags);
210213
rc = full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds);
211214
if (rc < 0)
212-
return rc;
215+
goto out;
213216

214217
if (request_ack) {
215218
uint64_t status;
216219

217220
rc = vhost_user_recv_u64(vu_dev, &status);
218221
if (rc)
219-
return rc;
222+
goto out;
220223

221224
if (status) {
222225
vu_err(vu_dev, "slave reports error: %llu\n", status);
223-
return -EIO;
226+
rc = -EIO;
227+
goto out;
224228
}
225229
}
226230

227-
return 0;
231+
out:
232+
spin_unlock_irqrestore(&vu_dev->sock_lock, flags);
233+
return rc;
228234
}
229235

230236
static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev,
@@ -324,6 +330,7 @@ static void vhost_user_reply(struct virtio_uml_device *vu_dev,
324330
static irqreturn_t vu_req_interrupt(int irq, void *data)
325331
{
326332
struct virtio_uml_device *vu_dev = data;
333+
struct virtqueue *vq;
327334
int response = 1;
328335
struct {
329336
struct vhost_user_msg msg;
@@ -343,6 +350,15 @@ static irqreturn_t vu_req_interrupt(int irq, void *data)
343350
virtio_config_changed(&vu_dev->vdev);
344351
response = 0;
345352
break;
353+
case VHOST_USER_SLAVE_VRING_CALL:
354+
virtio_device_for_each_vq((&vu_dev->vdev), vq) {
355+
if (vq->index == msg.msg.payload.vring_state.index) {
356+
response = 0;
357+
vring_interrupt(0 /* ignored */, vq);
358+
break;
359+
}
360+
}
361+
break;
346362
case VHOST_USER_SLAVE_IOTLB_MSG:
347363
/* not supported - VIRTIO_F_IOMMU_PLATFORM */
348364
case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
@@ -684,6 +700,15 @@ static bool vu_notify(struct virtqueue *vq)
684700
const uint64_t n = 1;
685701
int rc;
686702

703+
if (info->kick_fd < 0) {
704+
struct virtio_uml_device *vu_dev;
705+
706+
vu_dev = to_virtio_uml_device(vq->vdev);
707+
708+
return vhost_user_set_vring_state(vu_dev, VHOST_USER_VRING_KICK,
709+
vq->index, 0) == 0;
710+
}
711+
687712
do {
688713
rc = os_write_file(info->kick_fd, &n, sizeof(n));
689714
} while (rc == -EINTR);
@@ -749,10 +774,13 @@ static void vu_del_vq(struct virtqueue *vq)
749774
{
750775
struct virtio_uml_vq_info *info = vq->priv;
751776

752-
um_free_irq(VIRTIO_IRQ, vq);
777+
if (info->call_fd >= 0) {
778+
um_free_irq(VIRTIO_IRQ, vq);
779+
os_close_file(info->call_fd);
780+
}
753781

754-
os_close_file(info->call_fd);
755-
os_close_file(info->kick_fd);
782+
if (info->kick_fd >= 0)
783+
os_close_file(info->kick_fd);
756784

757785
vring_del_virtqueue(vq);
758786
kfree(info);
@@ -782,6 +810,15 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev,
782810
int call_fds[2];
783811
int rc;
784812

813+
/* no call FD needed/desired in this case */
814+
if (vu_dev->protocol_features &
815+
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS) &&
816+
vu_dev->protocol_features &
817+
BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
818+
info->call_fd = -1;
819+
return 0;
820+
}
821+
785822
/* Use a pipe for call fd, since SIGIO is not supported for eventfd */
786823
rc = os_pipe(call_fds, true, true);
787824
if (rc < 0)
@@ -838,10 +875,15 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
838875
vq->priv = info;
839876
num = virtqueue_get_vring_size(vq);
840877

841-
rc = os_eventfd(0, 0);
842-
if (rc < 0)
843-
goto error_kick;
844-
info->kick_fd = rc;
878+
if (vu_dev->protocol_features &
879+
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)) {
880+
info->kick_fd = -1;
881+
} else {
882+
rc = os_eventfd(0, 0);
883+
if (rc < 0)
884+
goto error_kick;
885+
info->kick_fd = rc;
886+
}
845887

846888
rc = vu_setup_vq_call_fd(vu_dev, vq);
847889
if (rc)
@@ -866,10 +908,13 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
866908
return vq;
867909

868910
error_setup:
869-
um_free_irq(VIRTIO_IRQ, vq);
870-
os_close_file(info->call_fd);
911+
if (info->call_fd >= 0) {
912+
um_free_irq(VIRTIO_IRQ, vq);
913+
os_close_file(info->call_fd);
914+
}
871915
error_call:
872-
os_close_file(info->kick_fd);
916+
if (info->kick_fd >= 0)
917+
os_close_file(info->kick_fd);
873918
error_kick:
874919
vring_del_virtqueue(vq);
875920
error_create:
@@ -908,10 +953,12 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
908953
list_for_each_entry(vq, &vdev->vqs, list) {
909954
struct virtio_uml_vq_info *info = vq->priv;
910955

911-
rc = vhost_user_set_vring_kick(vu_dev, vq->index,
912-
info->kick_fd);
913-
if (rc)
914-
goto error_setup;
956+
if (info->kick_fd >= 0) {
957+
rc = vhost_user_set_vring_kick(vu_dev, vq->index,
958+
info->kick_fd);
959+
if (rc)
960+
goto error_setup;
961+
}
915962

916963
rc = vhost_user_set_vring_enable(vu_dev, vq->index, true);
917964
if (rc)
@@ -1008,6 +1055,8 @@ static int virtio_uml_probe(struct platform_device *pdev)
10081055
return rc;
10091056
vu_dev->sock = rc;
10101057

1058+
spin_lock_init(&vu_dev->sock_lock);
1059+
10111060
rc = vhost_user_init(vu_dev);
10121061
if (rc)
10131062
goto error_init;

0 commit comments

Comments
 (0)