aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2019-09-11 08:51:22 -0400
committerRichard Weinberger <richard@nod.at>2019-09-15 15:37:16 -0400
commit27eca5c474f8c669fec3079db652df7533d83b55 (patch)
treeaba9928f3ab92d792845fdcd7cc0d661a97c5a82 /arch/um/drivers
parent2cd097ba8c05c8d06f8a28daf400303ad0e75e41 (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.h5
-rw-r--r--arch/um/drivers/virtio_uml.c97
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
26enum vhost_user_request { 29enum 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
169static int vhost_user_send(struct virtio_uml_device *vu_dev, 170static 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
179static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev, 213static 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
189static int vhost_user_send_no_payload_fd(struct virtio_uml_device *vu_dev, 223static 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
199static int vhost_user_send_u64(struct virtio_uml_device *vu_dev, 233static 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
211static int vhost_user_set_owner(struct virtio_uml_device *vu_dev) 245static 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
216static int vhost_user_get_features(struct virtio_uml_device *vu_dev, 250static 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,
232static int vhost_user_get_protocol_features(struct virtio_uml_device *vu_dev, 267static 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
285static 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
250static irqreturn_t vu_req_interrupt(int irq, void *data) 307static 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
512static int vhost_user_set_vring_state(struct virtio_uml_device *vu_dev, 575static 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
525static int vhost_user_set_vring_num(struct virtio_uml_device *vu_dev, 588static 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
556static int vhost_user_set_vring_fd(struct virtio_uml_device *vu_dev, 619static 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
574static int vhost_user_set_vring_call(struct virtio_uml_device *vu_dev, 637static int vhost_user_set_vring_call(struct virtio_uml_device *vu_dev,