From patchwork Wed Mar 24 20:27:31 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badari Pulavarty X-Patchwork-Id: 88027 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2OKRQ7i024497 for ; Wed, 24 Mar 2010 20:27:26 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756794Ab0CXU1Y (ORCPT ); Wed, 24 Mar 2010 16:27:24 -0400 Received: from e31.co.us.ibm.com ([32.97.110.149]:38684 "EHLO e31.co.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756774Ab0CXU1X (ORCPT ); Wed, 24 Mar 2010 16:27:23 -0400 Received: from d03relay03.boulder.ibm.com (d03relay03.boulder.ibm.com [9.17.195.228]) by e31.co.us.ibm.com (8.14.3/8.13.1) with ESMTP id o2OKIGYF019215 for ; Wed, 24 Mar 2010 14:18:16 -0600 Received: from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com [9.17.195.167]) by d03relay03.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o2OKRGSw142314 for ; Wed, 24 Mar 2010 14:27:16 -0600 Received: from d03av01.boulder.ibm.com (loopback [127.0.0.1]) by d03av01.boulder.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o2OKRFSh019697 for ; Wed, 24 Mar 2010 14:27:15 -0600 Received: from [127.0.0.1] (sig-9-65-56-99.mts.ibm.com [9.65.56.99]) by d03av01.boulder.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o2OKRDLC019556; Wed, 24 Mar 2010 14:27:15 -0600 Message-ID: <4BAA75B3.6040808@us.ibm.com> Date: Wed, 24 Mar 2010 13:27:31 -0700 From: Badari Pulavarty User-Agent: Thunderbird 2.0.0.24 (Windows/20100228) MIME-Version: 1.0 To: Christoph Hellwig CC: kvm@vger.kernel.org Subject: Re: [RFC] vhost-blk implementation References: <1269306023.7931.72.camel@badari-desktop> <20100324200402.GA22272@infradead.org> In-Reply-To: <20100324200402.GA22272@infradead.org> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 24 Mar 2010 20:27:26 +0000 (UTC) Index: vhost/hw/virtio-blk.c =================================================================== --- vhost.orig/hw/virtio-blk.c 2010-02-25 16:47:04.000000000 -0500 +++ vhost/hw/virtio-blk.c 2010-03-17 14:07:26.477430740 -0400 @@ -18,6 +18,7 @@ #ifdef __linux__ # include #endif +#include typedef struct VirtIOBlock { @@ -28,8 +29,13 @@ char serial_str[BLOCK_SERIAL_STRLEN + 1]; QEMUBH *bh; size_t config_size; + uint8_t vhost_started; } VirtIOBlock; +typedef struct BDRVRawState { + int fd; +} BDRVRawState; + static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) { return (VirtIOBlock *)vdev; @@ -501,6 +507,198 @@ return 0; } +#if 1 +#include "linux/vhost.h" +#include +#include +#include "vhost.h" + +int vhost_blk_fd; + +struct slot_info { + unsigned long phys_addr; + unsigned long len; + unsigned long userspace_addr; + unsigned flags; + int logging_count; +}; + +extern struct slot_info slots[KVM_MAX_NUM_MEM_REGIONS]; + +static int vhost_blk_start(struct VirtIODevice *vdev) +{ + target_phys_addr_t s, l, a; + int r, num, idx = 0; + struct vhost_vring_state state; + struct vhost_vring_file file; + struct vhost_vring_addr addr; + unsigned long long used_phys; + void *desc, *avail, *used; + int i, n =0; + struct VirtQueue *q = virtio_queue(vdev, idx); + VirtIOBlock *vb = to_virtio_blk(vdev); + struct vhost_memory *mem; + BDRVRawState *st = vb->bs->opaque; + + vhost_blk_fd = open("/dev/vhost-blk", O_RDWR); + if (vhost_blk_fd < 0) { + fprintf(stderr, "unable to open vhost-blk\n"); + return -errno; + } + + r = ioctl(vhost_blk_fd, VHOST_SET_OWNER, NULL); + if (r < 0) { + fprintf(stderr, "ioctl VHOST_SET_OWNER failed\n"); + return -errno; + } + + for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) { + if (!slots[i].len || + (slots[i].flags & KVM_MEM_LOG_DIRTY_PAGES)) { + continue; + } + ++n; + } + + mem = qemu_mallocz(offsetof(struct vhost_memory, regions) + + n * sizeof(struct vhost_memory_region)); + if (!mem) + return -ENOMEM; + + mem->nregions = n; + n = 0; + for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) { + if (!slots[i].len || (slots[i].flags & + KVM_MEM_LOG_DIRTY_PAGES)) { + continue; + } + mem->regions[n].guest_phys_addr = slots[i].phys_addr; + mem->regions[n].memory_size = slots[i].len; + mem->regions[n].userspace_addr = slots[i].userspace_addr; + ++n; + } + + r = ioctl(vhost_blk_fd, VHOST_SET_MEM_TABLE, mem); + if (r < 0) + return -errno; + + state.index = idx; + num = state.num = virtio_queue_get_num(vdev, idx); + r = ioctl(vhost_blk_fd, VHOST_SET_VRING_NUM, &state); + if (r) { + fprintf(stderr, "ioctl VHOST_SET_VRING_NUM failed\n"); + return -errno; + } + + state.num = virtio_queue_last_avail_idx(vdev, idx); + r = ioctl(vhost_blk_fd, VHOST_SET_VRING_BASE, &state); + if (r) { + fprintf(stderr, "ioctl VHOST_SET_VRING_BASE failed\n"); + return -errno; + } + + s = l = sizeof(struct vring_desc) * num; + a = virtio_queue_get_desc(vdev, idx); + desc = cpu_physical_memory_map(a, &l, 0); + if (!desc || l != s) { + r = -ENOMEM; + goto fail_alloc; + } + s = l = offsetof(struct vring_avail, ring) + + sizeof(u_int64_t) * num; + a = virtio_queue_get_avail(vdev, idx); + avail = cpu_physical_memory_map(a, &l, 0); + if (!avail || l != s) { + r = -ENOMEM; + goto fail_alloc; + } + s = l = offsetof(struct vring_used, ring) + + sizeof(struct vring_used_elem) * num; + used_phys = a = virtio_queue_get_used(vdev, idx); + used = cpu_physical_memory_map(a, &l, 1); + if (!used || l != s) { + r = -ENOMEM; + goto fail_alloc; + } + + addr.index = idx, + addr.desc_user_addr = (u_int64_t)(unsigned long)desc, + addr.avail_user_addr = (u_int64_t)(unsigned long)avail, + addr.used_user_addr = (u_int64_t)(unsigned long)used, + addr.log_guest_addr = used_phys, + addr.flags = 0; + r = ioctl(vhost_blk_fd, VHOST_SET_VRING_ADDR, &addr); + if (r < 0) { + fprintf(stderr, "ioctl VHOST_SET_VRING_ADDR failed\n"); + r = -errno; + goto fail_alloc; + } + if (!vdev->binding->guest_notifier || !vdev->binding->host_notifier) { + fprintf(stderr, "binding does not support irqfd/queuefd\n"); + r = -ENOSYS; + goto fail_alloc; + } + r = vdev->binding->guest_notifier(vdev->binding_opaque, idx, true); + if (r < 0) { + fprintf(stderr, "Error binding guest notifier: %d\n", -r); + goto fail_guest_notifier; + } + + r = vdev->binding->host_notifier(vdev->binding_opaque, idx, true); + if (r < 0) { + fprintf(stderr, "Error binding host notifier: %d\n", -r); + goto fail_host_notifier; + } + + file.index = idx; + file.fd = event_notifier_get_fd(virtio_queue_host_notifier(q)); + r = ioctl(vhost_blk_fd, VHOST_SET_VRING_KICK, &file); + if (r) { + goto fail_kick; + } + + file.fd = event_notifier_get_fd(virtio_queue_guest_notifier(q)); + r = ioctl(vhost_blk_fd, VHOST_SET_VRING_CALL, &file); + if (r) { + goto fail_call; + } + file.fd = st->fd; + r = ioctl(vhost_blk_fd, VHOST_NET_SET_BACKEND, &file); + if (r) { + r = -errno; + goto fail_call; + } + return 0; +fail_call: +fail_kick: + vdev->binding->host_notifier(vdev->binding_opaque, idx, false); +fail_host_notifier: + vdev->binding->guest_notifier(vdev->binding_opaque, idx, false); +fail_guest_notifier: +fail_alloc: + return r; +} + +static void virtio_blk_set_status(struct VirtIODevice *vdev) +{ + VirtIOBlock *s = to_virtio_blk(vdev); + + if (s->vhost_started) + return; + + if (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) { + int r = vhost_blk_start(vdev); + if (r < 0) { + fprintf(stderr, "unable to start vhost blk: %d\n", r); + } else { + s->vhost_started = 1; + } + } +} + +#endif + VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo) { VirtIOBlock *s; @@ -517,6 +715,7 @@