diff options
author | Johannes Berg <johannes.berg@intel.com> | 2019-09-11 08:51:22 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2019-09-15 15:37:16 -0400 |
commit | 27eca5c474f8c669fec3079db652df7533d83b55 (patch) | |
tree | aba9928f3ab92d792845fdcd7cc0d661a97c5a82 /arch/um/drivers | |
parent | 2cd097ba8c05c8d06f8a28daf400303ad0e75e41 (diff) |
um: virtio: Implement VHOST_USER_PROTOCOL_F_REPLY_ACK
Implement the VHOST_USER_PROTOCOL_F_REPLY_ACK extension for both
slave requests (previous patch) where we have to reply and our
own requests where it helps understand if the slave failed.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/drivers')
-rw-r--r-- | arch/um/drivers/vhost_user.h | 5 | ||||
-rw-r--r-- | arch/um/drivers/virtio_uml.c | 97 |
2 files changed, 84 insertions, 18 deletions
diff --git a/arch/um/drivers/vhost_user.h b/arch/um/drivers/vhost_user.h index 8aee9919581e..45ff5ea22fea 100644 --- a/arch/um/drivers/vhost_user.h +++ b/arch/um/drivers/vhost_user.h | |||
@@ -6,9 +6,11 @@ | |||
6 | 6 | ||
7 | /* Message flags */ | 7 | /* Message flags */ |
8 | #define VHOST_USER_FLAG_REPLY BIT(2) | 8 | #define VHOST_USER_FLAG_REPLY BIT(2) |
9 | #define VHOST_USER_FLAG_NEED_REPLY BIT(3) | ||
9 | /* Feature bits */ | 10 | /* Feature bits */ |
10 | #define VHOST_USER_F_PROTOCOL_FEATURES 30 | 11 | #define VHOST_USER_F_PROTOCOL_FEATURES 30 |
11 | /* Protocol feature bits */ | 12 | /* Protocol feature bits */ |
13 | #define VHOST_USER_PROTOCOL_F_REPLY_ACK 3 | ||
12 | #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 | 14 | #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 |
13 | #define VHOST_USER_PROTOCOL_F_CONFIG 9 | 15 | #define VHOST_USER_PROTOCOL_F_CONFIG 9 |
14 | /* Vring state index masks */ | 16 | /* Vring state index masks */ |
@@ -20,7 +22,8 @@ | |||
20 | /* Supported transport features */ | 22 | /* Supported transport features */ |
21 | #define VHOST_USER_SUPPORTED_F BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES) | 23 | #define VHOST_USER_SUPPORTED_F BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES) |
22 | /* Supported protocol features */ | 24 | /* Supported protocol features */ |
23 | #define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \ | 25 | #define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \ |
26 | BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \ | ||
24 | BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)) | 27 | BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)) |
25 | 28 | ||
26 | enum vhost_user_request { | 29 | enum vhost_user_request { |
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index ea4d9c1784d2..fc8c52cff5aa 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c | |||
@@ -160,30 +160,64 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev, | |||
160 | if (rc) | 160 | if (rc) |
161 | return rc; | 161 | return rc; |
162 | 162 | ||
163 | if (msg->header.flags != VHOST_USER_VERSION) | 163 | if ((msg->header.flags & ~VHOST_USER_FLAG_NEED_REPLY) != |
164 | VHOST_USER_VERSION) | ||
164 | return -EPROTO; | 165 | return -EPROTO; |
165 | 166 | ||
166 | return 0; | 167 | return 0; |
167 | } | 168 | } |
168 | 169 | ||
169 | static int vhost_user_send(struct virtio_uml_device *vu_dev, | 170 | static int vhost_user_send(struct virtio_uml_device *vu_dev, |
170 | struct vhost_user_msg *msg, | 171 | bool need_response, struct vhost_user_msg *msg, |
171 | int *fds, size_t num_fds) | 172 | int *fds, size_t num_fds) |
172 | { | 173 | { |
173 | size_t size = sizeof(msg->header) + msg->header.size; | 174 | size_t size = sizeof(msg->header) + msg->header.size; |
175 | bool request_ack; | ||
176 | int rc; | ||
174 | 177 | ||
175 | msg->header.flags |= VHOST_USER_VERSION; | 178 | msg->header.flags |= VHOST_USER_VERSION; |
176 | return full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds); | 179 | |
180 | /* | ||
181 | * The need_response flag indicates that we already need a response, | ||
182 | * e.g. to read the features. In these cases, don't request an ACK as | ||
183 | * it is meaningless. Also request an ACK only if supported. | ||
184 | */ | ||
185 | request_ack = !need_response; | ||
186 | if (!(vu_dev->protocol_features & | ||
187 | BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK))) | ||
188 | request_ack = false; | ||
189 | |||
190 | if (request_ack) | ||
191 | msg->header.flags |= VHOST_USER_FLAG_NEED_REPLY; | ||
192 | |||
193 | rc = full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds); | ||
194 | if (rc < 0) | ||
195 | return rc; | ||
196 | |||
197 | if (request_ack) { | ||
198 | uint64_t status; | ||
199 | |||
200 | rc = vhost_user_recv_u64(vu_dev, &status); | ||
201 | if (rc) | ||
202 | return rc; | ||
203 | |||
204 | if (status) { | ||
205 | vu_err(vu_dev, "slave reports error: %llu\n", status); | ||
206 | return -EIO; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return 0; | ||
177 | } | 211 | } |
178 | 212 | ||
179 | static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev, | 213 | static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev, |
180 | u32 request) | 214 | bool need_response, u32 request) |
181 | { | 215 | { |
182 | struct vhost_user_msg msg = { | 216 | struct vhost_user_msg msg = { |
183 | .header.request = request, | 217 | .header.request = request, |
184 | }; | 218 | }; |
185 | 219 | ||
186 | return vhost_user_send(vu_dev, &msg, NULL, 0); | 220 | return vhost_user_send(vu_dev, need_response, &msg, NULL, 0); |
187 | } | 221 | } |
188 | 222 | ||
189 | static int vhost_user_send_no_payload_fd(struct virtio_uml_device *vu_dev, | 223 | static int vhost_user_send_no_payload_fd(struct virtio_uml_device *vu_dev, |
@@ -193,7 +227,7 @@ static int vhost_user_send_no_payload_fd(struct virtio_uml_device *vu_dev, | |||
193 | .header.request = request, | 227 | .header.request = request, |
194 | }; | 228 | }; |
195 | 229 | ||
196 | return vhost_user_send(vu_dev, &msg, &fd, 1); | 230 | return vhost_user_send(vu_dev, false, &msg, &fd, 1); |
197 | } | 231 | } |
198 | 232 | ||
199 | static int vhost_user_send_u64(struct virtio_uml_device *vu_dev, | 233 | static int vhost_user_send_u64(struct virtio_uml_device *vu_dev, |
@@ -205,18 +239,19 @@ static int vhost_user_send_u64(struct virtio_uml_device *vu_dev, | |||
205 | .payload.integer = value, | 239 | .payload.integer = value, |
206 | }; | 240 | }; |
207 | 241 | ||
208 | return vhost_user_send(vu_dev, &msg, NULL, 0); | 242 | return vhost_user_send(vu_dev, false, &msg, NULL, 0); |
209 | } | 243 | } |
210 | 244 | ||
211 | static int vhost_user_set_owner(struct virtio_uml_device *vu_dev) | 245 | static int vhost_user_set_owner(struct virtio_uml_device *vu_dev) |
212 | { | 246 | { |
213 | return vhost_user_send_no_payload(vu_dev, VHOST_USER_SET_OWNER); | 247 | return vhost_user_send_no_payload(vu_dev, false, VHOST_USER_SET_OWNER); |
214 | } | 248 | } |
215 | 249 | ||
216 | static int vhost_user_get_features(struct virtio_uml_device *vu_dev, | 250 | static int vhost_user_get_features(struct virtio_uml_device *vu_dev, |
217 | u64 *features) | 251 | u64 *features) |
218 | { | 252 | { |
219 | int rc = vhost_user_send_no_payload(vu_dev, VHOST_USER_GET_FEATURES); | 253 | int rc = vhost_user_send_no_payload(vu_dev, true, |
254 | VHOST_USER_GET_FEATURES); | ||
220 | 255 | ||
221 | if (rc) | 256 | if (rc) |
222 | return rc; | 257 | return rc; |
@@ -232,7 +267,7 @@ static int vhost_user_set_features(struct virtio_uml_device *vu_dev, | |||
232 | static int vhost_user_get_protocol_features(struct virtio_uml_device *vu_dev, | 267 | static int vhost_user_get_protocol_features(struct virtio_uml_device *vu_dev, |
233 | u64 *protocol_features) | 268 | u64 *protocol_features) |
234 | { | 269 | { |
235 | int rc = vhost_user_send_no_payload(vu_dev, | 270 | int rc = vhost_user_send_no_payload(vu_dev, true, |
236 | VHOST_USER_GET_PROTOCOL_FEATURES); | 271 | VHOST_USER_GET_PROTOCOL_FEATURES); |
237 | 272 | ||
238 | if (rc) | 273 | if (rc) |
@@ -247,9 +282,32 @@ static int vhost_user_set_protocol_features(struct virtio_uml_device *vu_dev, | |||
247 | protocol_features); | 282 | protocol_features); |
248 | } | 283 | } |
249 | 284 | ||
285 | static void vhost_user_reply(struct virtio_uml_device *vu_dev, | ||
286 | struct vhost_user_msg *msg, int response) | ||
287 | { | ||
288 | struct vhost_user_msg reply = { | ||
289 | .payload.integer = response, | ||
290 | }; | ||
291 | size_t size = sizeof(reply.header) + sizeof(reply.payload.integer); | ||
292 | int rc; | ||
293 | |||
294 | reply.header = msg->header; | ||
295 | reply.header.flags &= ~VHOST_USER_FLAG_NEED_REPLY; | ||
296 | reply.header.flags |= VHOST_USER_FLAG_REPLY; | ||
297 | reply.header.size = sizeof(reply.payload.integer); | ||
298 | |||
299 | rc = full_sendmsg_fds(vu_dev->req_fd, &reply, size, NULL, 0); | ||
300 | |||
301 | if (rc) | ||
302 | vu_err(vu_dev, | ||
303 | "sending reply to slave request failed: %d (size %zu)\n", | ||
304 | rc, size); | ||
305 | } | ||
306 | |||
250 | static irqreturn_t vu_req_interrupt(int irq, void *data) | 307 | static irqreturn_t vu_req_interrupt(int irq, void *data) |
251 | { | 308 | { |
252 | struct virtio_uml_device *vu_dev = data; | 309 | struct virtio_uml_device *vu_dev = data; |
310 | int response = 1; | ||
253 | struct { | 311 | struct { |
254 | struct vhost_user_msg msg; | 312 | struct vhost_user_msg msg; |
255 | u8 extra_payload[512]; | 313 | u8 extra_payload[512]; |
@@ -266,6 +324,7 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) | |||
266 | switch (msg.msg.header.request) { | 324 | switch (msg.msg.header.request) { |
267 | case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG: | 325 | case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG: |
268 | virtio_config_changed(&vu_dev->vdev); | 326 | virtio_config_changed(&vu_dev->vdev); |
327 | response = 0; | ||
269 | break; | 328 | break; |
270 | case VHOST_USER_SLAVE_IOTLB_MSG: | 329 | case VHOST_USER_SLAVE_IOTLB_MSG: |
271 | /* not supported - VIRTIO_F_IOMMU_PLATFORM */ | 330 | /* not supported - VIRTIO_F_IOMMU_PLATFORM */ |
@@ -276,6 +335,9 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) | |||
276 | msg.msg.header.request); | 335 | msg.msg.header.request); |
277 | } | 336 | } |
278 | 337 | ||
338 | if (msg.msg.header.flags & VHOST_USER_FLAG_NEED_REPLY) | ||
339 | vhost_user_reply(vu_dev, &msg.msg, response); | ||
340 | |||
279 | return IRQ_HANDLED; | 341 | return IRQ_HANDLED; |
280 | } | 342 | } |
281 | 343 | ||
@@ -365,7 +427,7 @@ static void vhost_user_get_config(struct virtio_uml_device *vu_dev, | |||
365 | msg->payload.config.offset = 0; | 427 | msg->payload.config.offset = 0; |
366 | msg->payload.config.size = cfg_size; | 428 | msg->payload.config.size = cfg_size; |
367 | 429 | ||
368 | rc = vhost_user_send(vu_dev, msg, NULL, 0); | 430 | rc = vhost_user_send(vu_dev, true, msg, NULL, 0); |
369 | if (rc) { | 431 | if (rc) { |
370 | vu_err(vu_dev, "sending VHOST_USER_GET_CONFIG failed: %d\n", | 432 | vu_err(vu_dev, "sending VHOST_USER_GET_CONFIG failed: %d\n", |
371 | rc); | 433 | rc); |
@@ -416,7 +478,7 @@ static void vhost_user_set_config(struct virtio_uml_device *vu_dev, | |||
416 | msg->payload.config.size = len; | 478 | msg->payload.config.size = len; |
417 | memcpy(msg->payload.config.payload, buf, len); | 479 | memcpy(msg->payload.config.payload, buf, len); |
418 | 480 | ||
419 | rc = vhost_user_send(vu_dev, msg, NULL, 0); | 481 | rc = vhost_user_send(vu_dev, false, msg, NULL, 0); |
420 | if (rc) | 482 | if (rc) |
421 | vu_err(vu_dev, "sending VHOST_USER_SET_CONFIG failed: %d\n", | 483 | vu_err(vu_dev, "sending VHOST_USER_SET_CONFIG failed: %d\n", |
422 | rc); | 484 | rc); |
@@ -506,7 +568,8 @@ static int vhost_user_set_mem_table(struct virtio_uml_device *vu_dev) | |||
506 | return rc; | 568 | return rc; |
507 | } | 569 | } |
508 | 570 | ||
509 | return vhost_user_send(vu_dev, &msg, fds, msg.payload.mem_regions.num); | 571 | return vhost_user_send(vu_dev, false, &msg, fds, |
572 | msg.payload.mem_regions.num); | ||
510 | } | 573 | } |
511 | 574 | ||
512 | static int vhost_user_set_vring_state(struct virtio_uml_device *vu_dev, | 575 | static int vhost_user_set_vring_state(struct virtio_uml_device *vu_dev, |
@@ -519,7 +582,7 @@ static int vhost_user_set_vring_state(struct virtio_uml_device *vu_dev, | |||
519 | .payload.vring_state.num = num, | 582 | .payload.vring_state.num = num, |
520 | }; | 583 | }; |
521 | 584 | ||
522 | return vhost_user_send(vu_dev, &msg, NULL, 0); | 585 | return vhost_user_send(vu_dev, false, &msg, NULL, 0); |
523 | } | 586 | } |
524 | 587 | ||
525 | static int vhost_user_set_vring_num(struct virtio_uml_device *vu_dev, | 588 | static int vhost_user_set_vring_num(struct virtio_uml_device *vu_dev, |
@@ -550,7 +613,7 @@ static int vhost_user_set_vring_addr(struct virtio_uml_device *vu_dev, | |||
550 | .payload.vring_addr.log = log, | 613 | .payload.vring_addr.log = log, |
551 | }; | 614 | }; |
552 | 615 | ||
553 | return vhost_user_send(vu_dev, &msg, NULL, 0); | 616 | return vhost_user_send(vu_dev, false, &msg, NULL, 0); |
554 | } | 617 | } |
555 | 618 | ||
556 | static int vhost_user_set_vring_fd(struct virtio_uml_device *vu_dev, | 619 | static int vhost_user_set_vring_fd(struct virtio_uml_device *vu_dev, |
@@ -566,9 +629,9 @@ static int vhost_user_set_vring_fd(struct virtio_uml_device *vu_dev, | |||
566 | return -EINVAL; | 629 | return -EINVAL; |
567 | if (fd < 0) { | 630 | if (fd < 0) { |
568 | msg.payload.integer |= VHOST_USER_VRING_POLL_MASK; | 631 | msg.payload.integer |= VHOST_USER_VRING_POLL_MASK; |
569 | return vhost_user_send(vu_dev, &msg, NULL, 0); | 632 | return vhost_user_send(vu_dev, false, &msg, NULL, 0); |
570 | } | 633 | } |
571 | return vhost_user_send(vu_dev, &msg, &fd, 1); | 634 | return vhost_user_send(vu_dev, false, &msg, &fd, 1); |
572 | } | 635 | } |
573 | 636 | ||
574 | static int vhost_user_set_vring_call(struct virtio_uml_device *vu_dev, | 637 | static int vhost_user_set_vring_call(struct virtio_uml_device *vu_dev, |