Commit c6e84fbd authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging



virtio, vhost: fixes, features

IOTLB support in vhost-user.
A bunch of fixes all over the place.

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

# gpg: Signature made Fri 02 Jun 2017 17:33:25 BST
# gpg:                using RSA key 0x281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream:
  spec/vhost-user spec: Add IOMMU support
  vhost-user: add slave-req-fd support
  vhost-user: add vhost_user to hold the chr
  vhost: rework IOTLB messaging
  vhost: propagate errors in vhost_device_iotlb_miss()
  virtio-serial: fix segfault on disconnect
  virtio: add virtqueue_alloc_element tracepoint
  virtio-serial-bus: Unset hotplug handler when unrealize

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents e32fb6da 6dcdd06e
Loading
Loading
Loading
Loading
+114 −2
Original line number Diff line number Diff line
@@ -97,6 +97,25 @@ Depending on the request type, payload can be:
   log offset: offset from start of supplied file descriptor
       where logging starts (i.e. where guest address 0 would be logged)

 * An IOTLB message
   ---------------------------------------------------------
   | iova | size | user address | permissions flags | type |
   ---------------------------------------------------------

   IOVA: a 64-bit I/O virtual address programmed by the guest
   Size: a 64-bit size
   User address: a 64-bit user address
   Permissions: a 8-bit value:
    - 0: No access
    - 1: Read access
    - 2: Write access
    - 3: Read/Write access
   Type: a 8-bit IOTLB message type:
    - 1: IOTLB miss
    - 2: IOTLB update
    - 3: IOTLB invalidate
    - 4: IOTLB access fail

In QEMU the vhost-user message is implemented with the following struct:

typedef struct VhostUserMsg {
@@ -109,6 +128,7 @@ typedef struct VhostUserMsg {
        struct vhost_vring_addr addr;
        VhostUserMemory memory;
        VhostUserLog log;
        struct vhost_iotlb_msg iotlb;
    };
} QEMU_PACKED VhostUserMsg;

@@ -139,6 +159,7 @@ in the ancillary data:
 * VHOST_USER_SET_VRING_KICK
 * VHOST_USER_SET_VRING_CALL
 * VHOST_USER_SET_VRING_ERR
 * VHOST_USER_SET_SLAVE_REQ_FD

If Master is unable to send the full message or receives a wrong reply it will
close the connection. An optional reconnection mechanism can be implemented.
@@ -252,6 +273,50 @@ Once the source has finished migration, rings will be stopped by
the source. No further update must be done before rings are
restarted.

IOMMU support
-------------

When the VIRTIO_F_IOMMU_PLATFORM feature has been negotiated, the master
sends IOTLB entries update & invalidation by sending VHOST_USER_IOTLB_MSG
requests to the slave with a struct vhost_iotlb_msg as payload. For update
events, the iotlb payload has to be filled with the update message type (2),
the I/O virtual address, the size, the user virtual address, and the
permissions flags. Addresses and size must be within vhost memory regions set
via the VHOST_USER_SET_MEM_TABLE request. For invalidation events, the iotlb
payload has to be filled with the invalidation message type (3), the I/O virtual
address and the size. On success, the slave is expected to reply with a zero
payload, non-zero otherwise.

The slave relies on the slave communcation channel (see "Slave communication"
section below) to send IOTLB miss and access failure events, by sending
VHOST_USER_SLAVE_IOTLB_MSG requests to the master with a struct vhost_iotlb_msg
as payload. For miss events, the iotlb payload has to be filled with the miss
message type (1), the I/O virtual address and the permissions flags. For access
failure event, the iotlb payload has to be filled with the access failure
message type (4), the I/O virtual address and the permissions flags.
For synchronization purpose, the slave may rely on the reply-ack feature,
so the master may send a reply when operation is completed if the reply-ack
feature is negotiated and slaves requests a reply. For miss events, completed
operation means either master sent an update message containing the IOTLB entry
containing requested address and permission, or master sent nothing if the IOTLB
miss message is invalid (invalid IOVA or permission).

The master isn't expected to take the initiative to send IOTLB update messages,
as the slave sends IOTLB miss messages for the guest virtual memory areas it
needs to access.

Slave communication
-------------------

An optional communication channel is provided if the slave declares
VHOST_USER_PROTOCOL_F_SLAVE_REQ protocol feature, to allow the slave to make
requests to the master.

The fd is provided via VHOST_USER_SET_SLAVE_REQ_FD ancillary data.

A slave may then send VHOST_USER_SLAVE_* messages to the master
using this fd communication channel.

Protocol features
-----------------

@@ -260,9 +325,10 @@ Protocol features
#define VHOST_USER_PROTOCOL_F_RARP           2
#define VHOST_USER_PROTOCOL_F_REPLY_ACK      3
#define VHOST_USER_PROTOCOL_F_MTU            4
#define VHOST_USER_PROTOCOL_F_SLAVE_REQ      5

Message types
-------------
Master message types
--------------------

 * VHOST_USER_GET_FEATURES

@@ -486,6 +552,52 @@ Message types
      If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
      with zero in case the specified MTU is valid, or non-zero otherwise.

 * VHOST_USER_SET_SLAVE_REQ_FD

      Id: 21
      Equivalent ioctl: N/A
      Master payload: N/A

      Set the socket file descriptor for slave initiated requests. It is passed
      in the ancillary data.
      This request should be sent only when VHOST_USER_F_PROTOCOL_FEATURES
      has been negotiated, and protocol feature bit VHOST_USER_PROTOCOL_F_SLAVE_REQ
      bit is present in VHOST_USER_GET_PROTOCOL_FEATURES.
      If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
      with zero for success, non-zero otherwise.

 * VHOST_USER_IOTLB_MSG

      Id: 22
      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
      Master payload: struct vhost_iotlb_msg
      Slave payload: u64

      Send IOTLB messages with struct vhost_iotlb_msg as payload.
      Master sends such requests to update and invalidate entries in the device
      IOTLB. The slave has to acknowledge the request with sending zero as u64
      payload for success, non-zero otherwise.
      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
      has been successfully negotiated.

Slave message types
-------------------

 * VHOST_USER_SLAVE_IOTLB_MSG

      Id: 1
      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
      Slave payload: struct vhost_iotlb_msg
      Master payload: N/A

      Send IOTLB messages with struct vhost_iotlb_msg as payload.
      Slave sends such requests to notify of an IOTLB miss, or an IOTLB
      access failure. If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated,
      and slave set the VHOST_USER_NEED_REPLY flag, master must respond with
      zero when operation is successfully completed, or non-zero otherwise.
      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
      has been successfully negotiated.

VHOST_USER_PROTOCOL_F_REPLY_ACK:
-------------------------------
The original vhost-user specification only demands replies for certain
+6 −0
Original line number Diff line number Diff line
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                  port->elem->out_sg[i].iov_base
                                  + port->iov_offset,
                                  buf_size);
            if (!port->elem) { /* bail if we got disconnected */
                return;
            }
            if (port->throttled) {
                port->iov_idx = i;
                if (ret > 0) {
@@ -1121,6 +1124,9 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
        timer_free(vser->post_load->timer);
        g_free(vser->post_load);
    }

    qbus_set_hotplug_handler(BUS(&vser->bus), NULL, errp);

    virtio_cleanup(vdev);
}

+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ static const int user_feature_bits[] = {
    VIRTIO_NET_F_HOST_UFO,
    VIRTIO_NET_F_MRG_RXBUF,
    VIRTIO_NET_F_MTU,
    VIRTIO_F_IOMMU_PLATFORM,

    /* This bit implies RARP isn't sent by QEMU out of band */
    VIRTIO_NET_F_GUEST_ANNOUNCE,
+1 −0
Original line number Diff line number Diff line
# See docs/tracing.txt for syntax documentation.

# hw/virtio/virtio.c
virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
+73 −57
Original line number Diff line number Diff line
@@ -192,7 +192,6 @@ static void vhost_kernel_iotlb_read(void *opaque)
    ssize_t len;

    while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
        struct vhost_iotlb_msg *imsg = &msg.iotlb;
        if (len < sizeof msg) {
            error_report("Wrong vhost message len: %d", (int)len);
            break;
@@ -201,70 +200,21 @@ static void vhost_kernel_iotlb_read(void *opaque)
            error_report("Unknown vhost iotlb message type");
            break;
        }
        switch (imsg->type) {
        case VHOST_IOTLB_MISS:
            vhost_device_iotlb_miss(dev, imsg->iova,
                                    imsg->perm != VHOST_ACCESS_RO);
            break;
        case VHOST_IOTLB_UPDATE:
        case VHOST_IOTLB_INVALIDATE:
            error_report("Unexpected IOTLB message type");
            break;
        case VHOST_IOTLB_ACCESS_FAIL:
            /* FIXME: report device iotlb error */
            break;
        default:
            break;
        }
    }
}

static int vhost_kernel_update_device_iotlb(struct vhost_dev *dev,
                                            uint64_t iova, uint64_t uaddr,
                                            uint64_t len,
                                            IOMMUAccessFlags perm)
{
    struct vhost_msg msg;
    msg.type = VHOST_IOTLB_MSG;
    msg.iotlb.iova =  iova;
    msg.iotlb.uaddr = uaddr;
    msg.iotlb.size = len;
    msg.iotlb.type = VHOST_IOTLB_UPDATE;

    switch (perm) {
    case IOMMU_RO:
        msg.iotlb.perm = VHOST_ACCESS_RO;
        break;
    case IOMMU_WO:
        msg.iotlb.perm = VHOST_ACCESS_WO;
        break;
    case IOMMU_RW:
        msg.iotlb.perm = VHOST_ACCESS_RW;
        break;
    default:
        g_assert_not_reached();
        vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
    }

    if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
        error_report("Fail to update device iotlb");
        return -EFAULT;
    }

    return 0;
}

static int vhost_kernel_invalidate_device_iotlb(struct vhost_dev *dev,
                                                uint64_t iova, uint64_t len)
static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev,
                                              struct vhost_iotlb_msg *imsg)
{
    struct vhost_msg msg;

    msg.type = VHOST_IOTLB_MSG;
    msg.iotlb.iova = iova;
    msg.iotlb.size = len;
    msg.iotlb.type = VHOST_IOTLB_INVALIDATE;
    msg.iotlb = *imsg;

    if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
        error_report("Fail to invalidate device iotlb");
        error_report("Fail to update device iotlb");
        return -EFAULT;
    }

@@ -311,8 +261,7 @@ static const VhostOps kernel_ops = {
        .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
#endif /* CONFIG_VHOST_VSOCK */
        .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
        .vhost_update_device_iotlb = vhost_kernel_update_device_iotlb,
        .vhost_invalidate_device_iotlb = vhost_kernel_invalidate_device_iotlb,
        .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
};

int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
@@ -333,3 +282,70 @@ int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)

    return r;
}

int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
                                             uint64_t iova, uint64_t uaddr,
                                             uint64_t len,
                                             IOMMUAccessFlags perm)
{
    struct vhost_iotlb_msg imsg;

    imsg.iova =  iova;
    imsg.uaddr = uaddr;
    imsg.size = len;
    imsg.type = VHOST_IOTLB_UPDATE;

    switch (perm) {
    case IOMMU_RO:
        imsg.perm = VHOST_ACCESS_RO;
        break;
    case IOMMU_WO:
        imsg.perm = VHOST_ACCESS_WO;
        break;
    case IOMMU_RW:
        imsg.perm = VHOST_ACCESS_RW;
        break;
    default:
        return -EINVAL;
    }

    return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
}

int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev,
                                                 uint64_t iova, uint64_t len)
{
    struct vhost_iotlb_msg imsg;

    imsg.iova = iova;
    imsg.size = len;
    imsg.type = VHOST_IOTLB_INVALIDATE;

    return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
}

int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev,
                                          struct vhost_iotlb_msg *imsg)
{
    int ret = 0;

    switch (imsg->type) {
    case VHOST_IOTLB_MISS:
        ret = vhost_device_iotlb_miss(dev, imsg->iova,
                                      imsg->perm != VHOST_ACCESS_RO);
        break;
    case VHOST_IOTLB_ACCESS_FAIL:
        /* FIXME: report device iotlb error */
        error_report("Access failure IOTLB message type not supported");
        ret = -ENOTSUP;
        break;
    case VHOST_IOTLB_UPDATE:
    case VHOST_IOTLB_INVALIDATE:
    default:
        error_report("Unexpected IOTLB message type");
        ret = -EINVAL;
        break;
    }

    return ret;
}
Loading