Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

virtio: allow extra context per descriptor

Allow extra context per descriptor. To avoid slow down for data path,
this disables use of indirect descriptors for this vq.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

+66 -13
+57 -13
drivers/virtio/virtio_ring.c
··· 263 263 unsigned int out_sgs, 264 264 unsigned int in_sgs, 265 265 void *data, 266 + void *ctx, 266 267 gfp_t gfp) 267 268 { 268 269 struct vring_virtqueue *vq = to_vvq(_vq); ··· 276 275 START_USE(vq); 277 276 278 277 BUG_ON(data == NULL); 278 + BUG_ON(ctx && vq->indirect); 279 279 280 280 if (unlikely(vq->broken)) { 281 281 END_USE(vq); ··· 391 389 vq->desc_state[head].data = data; 392 390 if (indirect) 393 391 vq->desc_state[head].indir_desc = desc; 392 + if (ctx) 393 + vq->desc_state[head].indir_desc = ctx; 394 394 395 395 /* Put entry in available array (but don't update avail->idx until they 396 396 * do sync). */ ··· 465 461 for (sg = sgs[i]; sg; sg = sg_next(sg)) 466 462 total_sg++; 467 463 } 468 - return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs, data, gfp); 464 + return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs, 465 + data, NULL, gfp); 469 466 } 470 467 EXPORT_SYMBOL_GPL(virtqueue_add_sgs); 471 468 ··· 488 483 void *data, 489 484 gfp_t gfp) 490 485 { 491 - return virtqueue_add(vq, &sg, num, 1, 0, data, gfp); 486 + return virtqueue_add(vq, &sg, num, 1, 0, data, NULL, gfp); 492 487 } 493 488 EXPORT_SYMBOL_GPL(virtqueue_add_outbuf); 494 489 ··· 510 505 void *data, 511 506 gfp_t gfp) 512 507 { 513 - return virtqueue_add(vq, &sg, num, 0, 1, data, gfp); 508 + return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, gfp); 514 509 } 515 510 EXPORT_SYMBOL_GPL(virtqueue_add_inbuf); 511 + 512 + /** 513 + * virtqueue_add_inbuf_ctx - expose input buffers to other end 514 + * @vq: the struct virtqueue we're talking about. 515 + * @sg: scatterlist (must be well-formed and terminated!) 516 + * @num: the number of entries in @sg writable by other side 517 + * @data: the token identifying the buffer. 518 + * @ctx: extra context for the token 519 + * @gfp: how to do memory allocations (if necessary). 520 + * 521 + * Caller must ensure we don't call this with other virtqueue operations 522 + * at the same time (except where noted). 523 + * 524 + * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO). 525 + */ 526 + int virtqueue_add_inbuf_ctx(struct virtqueue *vq, 527 + struct scatterlist *sg, unsigned int num, 528 + void *data, 529 + void *ctx, 530 + gfp_t gfp) 531 + { 532 + return virtqueue_add(vq, &sg, num, 0, 1, data, ctx, gfp); 533 + } 534 + EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_ctx); 516 535 517 536 /** 518 537 * virtqueue_kick_prepare - first half of split virtqueue_kick call. ··· 627 598 } 628 599 EXPORT_SYMBOL_GPL(virtqueue_kick); 629 600 630 - static void detach_buf(struct vring_virtqueue *vq, unsigned int head) 601 + static void detach_buf(struct vring_virtqueue *vq, unsigned int head, 602 + void **ctx) 631 603 { 632 604 unsigned int i, j; 633 605 __virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); ··· 652 622 /* Plus final descriptor */ 653 623 vq->vq.num_free++; 654 624 655 - /* Free the indirect table, if any, now that it's unmapped. */ 656 - if (vq->desc_state[head].indir_desc) { 625 + if (vq->indirect) { 657 626 struct vring_desc *indir_desc = vq->desc_state[head].indir_desc; 658 - u32 len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len); 627 + u32 len; 628 + 629 + /* Free the indirect table, if any, now that it's unmapped. */ 630 + if (!indir_desc) 631 + return; 632 + 633 + len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len); 659 634 660 635 BUG_ON(!(vq->vring.desc[head].flags & 661 636 cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))); ··· 669 634 for (j = 0; j < len / sizeof(struct vring_desc); j++) 670 635 vring_unmap_one(vq, &indir_desc[j]); 671 636 672 - kfree(vq->desc_state[head].indir_desc); 637 + kfree(indir_desc); 673 638 vq->desc_state[head].indir_desc = NULL; 639 + } else if (ctx) { 640 + *ctx = vq->desc_state[head].indir_desc; 674 641 } 675 642 } 676 643 ··· 697 660 * Returns NULL if there are no used buffers, or the "data" token 698 661 * handed to virtqueue_add_*(). 699 662 */ 700 - void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) 663 + void *virtqueue_get_buf_ctx(struct virtqueue *_vq, unsigned int *len, 664 + void **ctx) 701 665 { 702 666 struct vring_virtqueue *vq = to_vvq(_vq); 703 667 void *ret; ··· 736 698 737 699 /* detach_buf clears data, so grab it now. */ 738 700 ret = vq->desc_state[i].data; 739 - detach_buf(vq, i); 701 + detach_buf(vq, i, ctx); 740 702 vq->last_used_idx++; 741 703 /* If we expect an interrupt for the next entry, tell host 742 704 * by writing event index and flush out the write before ··· 753 715 END_USE(vq); 754 716 return ret; 755 717 } 756 - EXPORT_SYMBOL_GPL(virtqueue_get_buf); 718 + EXPORT_SYMBOL_GPL(virtqueue_get_buf_ctx); 757 719 720 + void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) 721 + { 722 + return virtqueue_get_buf_ctx(_vq, len, NULL); 723 + } 724 + EXPORT_SYMBOL_GPL(virtqueue_get_buf); 758 725 /** 759 726 * virtqueue_disable_cb - disable callbacks 760 727 * @vq: the struct virtqueue we're talking about. ··· 921 878 continue; 922 879 /* detach_buf clears data, so grab it now. */ 923 880 buf = vq->desc_state[i].data; 924 - detach_buf(vq, i); 881 + detach_buf(vq, i, NULL); 925 882 vq->avail_idx_shadow--; 926 883 vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); 927 884 END_USE(vq); ··· 994 951 vq->last_add_time_valid = false; 995 952 #endif 996 953 997 - vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC); 954 + vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) && 955 + !context; 998 956 vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); 999 957 1000 958 /* No callback? Tell other side not to bother us. */
+9
include/linux/virtio.h
··· 44 44 void *data, 45 45 gfp_t gfp); 46 46 47 + int virtqueue_add_inbuf_ctx(struct virtqueue *vq, 48 + struct scatterlist sg[], unsigned int num, 49 + void *data, 50 + void *ctx, 51 + gfp_t gfp); 52 + 47 53 int virtqueue_add_sgs(struct virtqueue *vq, 48 54 struct scatterlist *sgs[], 49 55 unsigned int out_sgs, ··· 64 58 bool virtqueue_notify(struct virtqueue *vq); 65 59 66 60 void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); 61 + 62 + void *virtqueue_get_buf_ctx(struct virtqueue *vq, unsigned int *len, 63 + void **ctx); 67 64 68 65 void virtqueue_disable_cb(struct virtqueue *vq); 69 66