1 #include "kvm/virtio-blk.h"
3 #include "kvm/virtio-pci-dev.h"
4 #include "kvm/disk-image.h"
9 #include "kvm/threadpool.h"
10 #include "kvm/ioeventfd.h"
11 #include "kvm/guest_compat.h"
12 #include "kvm/virtio-pci.h"
13 #include "kvm/virtio.h"
15 #include <linux/virtio_ring.h>
16 #include <linux/virtio_blk.h>
17 #include <linux/kernel.h>
18 #include <linux/list.h>
19 #include <linux/types.h>
22 #define VIRTIO_BLK_MAX_DEV 4
25 * the header and status consume too entries
27 #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2)
28 #define VIRTIO_BLK_QUEUE_SIZE 256
29 #define NUM_VIRT_QUEUES 1
32 struct virt_queue *vq;
34 struct iovec iov[VIRTIO_BLK_QUEUE_SIZE];
40 pthread_mutex_t mutex;
42 struct list_head list;
44 struct virtio_device vdev;
45 struct virtio_blk_config blk_config;
46 struct disk_image *disk;
49 struct virt_queue vqs[NUM_VIRT_QUEUES];
50 struct blk_dev_req reqs[VIRTIO_BLK_QUEUE_SIZE];
58 static LIST_HEAD(bdevs);
59 static int compat_id = -1;
61 void virtio_blk_complete(void *param, long len)
63 struct blk_dev_req *req = param;
64 struct blk_dev *bdev = req->bdev;
65 int queueid = req->vq - bdev->vqs;
69 status = req->iov[req->out + req->in - 1].iov_base;
70 *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
72 mutex_lock(&bdev->mutex);
73 virt_queue__set_used_elem(req->vq, req->head, len);
74 mutex_unlock(&bdev->mutex);
76 if (virtio_queue__should_signal(&bdev->vqs[queueid]))
77 bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid);
80 static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req)
82 struct virtio_blk_outhdr *req_hdr;
93 req_hdr = iov[0].iov_base;
95 switch (req_hdr->type) {
97 block_cnt = disk_image__read(bdev->disk, req_hdr->sector,
98 iov + 1, in + out - 2, req);
100 case VIRTIO_BLK_T_OUT:
101 block_cnt = disk_image__write(bdev->disk, req_hdr->sector,
102 iov + 1, in + out - 2, req);
104 case VIRTIO_BLK_T_FLUSH:
105 block_cnt = disk_image__flush(bdev->disk);
106 virtio_blk_complete(req, block_cnt);
108 case VIRTIO_BLK_T_GET_ID:
109 block_cnt = VIRTIO_BLK_ID_BYTES;
110 disk_image__get_serial(bdev->disk,
111 (iov + 1)->iov_base, &block_cnt);
112 virtio_blk_complete(req, block_cnt);
115 pr_warning("request type %d", req_hdr->type);
121 static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
123 struct blk_dev_req *req;
126 while (virt_queue__available(vq)) {
127 head = virt_queue__pop(vq);
128 req = &bdev->reqs[head];
129 req->head = virt_queue__get_head_iov(vq, req->iov, &req->out,
130 &req->in, head, kvm);
133 virtio_blk_do_io_request(kvm, req);
137 static u8 *get_config(struct kvm *kvm, void *dev)
139 struct blk_dev *bdev = dev;
141 return ((u8 *)(&bdev->blk_config));
144 static u32 get_host_features(struct kvm *kvm, void *dev)
146 return 1UL << VIRTIO_BLK_F_SEG_MAX
147 | 1UL << VIRTIO_BLK_F_FLUSH
148 | 1UL << VIRTIO_RING_F_EVENT_IDX
149 | 1UL << VIRTIO_RING_F_INDIRECT_DESC;
152 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
154 struct blk_dev *bdev = dev;
156 bdev->features = features;
159 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
161 struct blk_dev *bdev = dev;
162 struct virt_queue *queue;
165 compat__remove_message(compat_id);
167 queue = &bdev->vqs[vq];
169 p = guest_pfn_to_host(kvm, queue->pfn);
171 vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
176 static void *virtio_blk_thread(void *dev)
178 struct blk_dev *bdev = dev;
183 r = read(bdev->io_efd, &data, sizeof(u64));
186 virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev);
193 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
195 struct blk_dev *bdev = dev;
199 r = write(bdev->io_efd, &data, sizeof(data));
206 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
208 struct blk_dev *bdev = dev;
210 return bdev->vqs[vq].pfn;
213 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
216 return VIRTIO_BLK_QUEUE_SIZE;
219 static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
225 static struct virtio_ops blk_dev_virtio_ops = (struct virtio_ops) {
226 .get_config = get_config,
227 .get_host_features = get_host_features,
228 .set_guest_features = set_guest_features,
230 .notify_vq = notify_vq,
231 .get_pfn_vq = get_pfn_vq,
232 .get_size_vq = get_size_vq,
233 .set_size_vq = set_size_vq,
236 static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
238 struct blk_dev *bdev;
244 bdev = calloc(1, sizeof(struct blk_dev));
248 *bdev = (struct blk_dev) {
249 .mutex = PTHREAD_MUTEX_INITIALIZER,
251 .blk_config = (struct virtio_blk_config) {
252 .capacity = disk->size / SECTOR_SIZE,
253 .seg_max = DISK_SEG_MAX,
255 .io_efd = eventfd(0, 0),
259 virtio_init(kvm, bdev, &bdev->vdev, &blk_dev_virtio_ops,
260 VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK, PCI_CLASS_BLK);
262 list_add_tail(&bdev->list, &bdevs);
264 for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
265 bdev->reqs[i].bdev = bdev;
266 bdev->reqs[i].kvm = kvm;
269 disk_image__set_callback(bdev->disk, virtio_blk_complete);
271 pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev);
273 compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");
278 static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev)
280 list_del(&bdev->list);
286 int virtio_blk__init(struct kvm *kvm)
290 for (i = 0; i < kvm->nr_disks; i++) {
291 if (kvm->disks[i]->wwpn)
293 r = virtio_blk__init_one(kvm, kvm->disks[i]);
300 return virtio_blk__exit(kvm);
302 virtio_dev_init(virtio_blk__init);
304 int virtio_blk__exit(struct kvm *kvm)
306 while (!list_empty(&bdevs)) {
307 struct blk_dev *bdev;
309 bdev = list_first_entry(&bdevs, struct blk_dev, list);
310 virtio_blk__exit_one(kvm, bdev);
315 virtio_dev_exit(virtio_blk__exit);