]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/kvm/virtio/blk.c
Merge remote-tracking branch 'signal/for-next'
[karo-tx-linux.git] / tools / kvm / virtio / blk.c
1 #include "kvm/virtio-blk.h"
2
3 #include "kvm/virtio-pci-dev.h"
4 #include "kvm/disk-image.h"
5 #include "kvm/mutex.h"
6 #include "kvm/util.h"
7 #include "kvm/kvm.h"
8 #include "kvm/pci.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"
14
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>
20 #include <pthread.h>
21
22 #define VIRTIO_BLK_MAX_DEV              4
23
24 /*
25  * the header and status consume too entries
26  */
27 #define DISK_SEG_MAX                    (VIRTIO_BLK_QUEUE_SIZE - 2)
28 #define VIRTIO_BLK_QUEUE_SIZE           256
29 #define NUM_VIRT_QUEUES                 1
30
31 struct blk_dev_req {
32         struct virt_queue               *vq;
33         struct blk_dev                  *bdev;
34         struct iovec                    iov[VIRTIO_BLK_QUEUE_SIZE];
35         u16                             out, in, head;
36         struct kvm                      *kvm;
37 };
38
39 struct blk_dev {
40         pthread_mutex_t                 mutex;
41
42         struct list_head                list;
43
44         struct virtio_device            vdev;
45         struct virtio_blk_config        blk_config;
46         struct disk_image               *disk;
47         u32                             features;
48
49         struct virt_queue               vqs[NUM_VIRT_QUEUES];
50         struct blk_dev_req              reqs[VIRTIO_BLK_QUEUE_SIZE];
51
52         pthread_t                       io_thread;
53         int                             io_efd;
54
55         struct kvm                      *kvm;
56 };
57
58 static LIST_HEAD(bdevs);
59 static int compat_id = -1;
60
61 void virtio_blk_complete(void *param, long len)
62 {
63         struct blk_dev_req *req = param;
64         struct blk_dev *bdev = req->bdev;
65         int queueid = req->vq - bdev->vqs;
66         u8 *status;
67
68         /* status */
69         status  = req->iov[req->out + req->in - 1].iov_base;
70         *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
71
72         mutex_lock(&bdev->mutex);
73         virt_queue__set_used_elem(req->vq, req->head, len);
74         mutex_unlock(&bdev->mutex);
75
76         if (virtio_queue__should_signal(&bdev->vqs[queueid]))
77                 bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid);
78 }
79
80 static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req)
81 {
82         struct virtio_blk_outhdr *req_hdr;
83         ssize_t block_cnt;
84         struct blk_dev *bdev;
85         struct iovec *iov;
86         u16 out, in;
87
88         block_cnt       = -1;
89         bdev            = req->bdev;
90         iov             = req->iov;
91         out             = req->out;
92         in              = req->in;
93         req_hdr         = iov[0].iov_base;
94
95         switch (req_hdr->type) {
96         case VIRTIO_BLK_T_IN:
97                 block_cnt = disk_image__read(bdev->disk, req_hdr->sector,
98                                 iov + 1, in + out - 2, req);
99                 break;
100         case VIRTIO_BLK_T_OUT:
101                 block_cnt = disk_image__write(bdev->disk, req_hdr->sector,
102                                 iov + 1, in + out - 2, req);
103                 break;
104         case VIRTIO_BLK_T_FLUSH:
105                 block_cnt = disk_image__flush(bdev->disk);
106                 virtio_blk_complete(req, block_cnt);
107                 break;
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);
113                 break;
114         default:
115                 pr_warning("request type %d", req_hdr->type);
116                 block_cnt       = -1;
117                 break;
118         }
119 }
120
121 static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
122 {
123         struct blk_dev_req *req;
124         u16 head;
125
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);
131                 req->vq         = vq;
132
133                 virtio_blk_do_io_request(kvm, req);
134         }
135 }
136
137 static u8 *get_config(struct kvm *kvm, void *dev)
138 {
139         struct blk_dev *bdev = dev;
140
141         return ((u8 *)(&bdev->blk_config));
142 }
143
144 static u32 get_host_features(struct kvm *kvm, void *dev)
145 {
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;
150 }
151
152 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
153 {
154         struct blk_dev *bdev = dev;
155
156         bdev->features = features;
157 }
158
159 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
160 {
161         struct blk_dev *bdev = dev;
162         struct virt_queue *queue;
163         void *p;
164
165         compat__remove_message(compat_id);
166
167         queue           = &bdev->vqs[vq];
168         queue->pfn      = pfn;
169         p               = guest_pfn_to_host(kvm, queue->pfn);
170
171         vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
172
173         return 0;
174 }
175
176 static void *virtio_blk_thread(void *dev)
177 {
178         struct blk_dev *bdev = dev;
179         u64 data;
180         int r;
181
182         while (1) {
183                 r = read(bdev->io_efd, &data, sizeof(u64));
184                 if (r < 0)
185                         continue;
186                 virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev);
187         }
188
189         pthread_exit(NULL);
190         return NULL;
191 }
192
193 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
194 {
195         struct blk_dev *bdev = dev;
196         u64 data = 1;
197         int r;
198
199         r = write(bdev->io_efd, &data, sizeof(data));
200         if (r < 0)
201                 return r;
202
203         return 0;
204 }
205
206 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
207 {
208         struct blk_dev *bdev = dev;
209
210         return bdev->vqs[vq].pfn;
211 }
212
213 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
214 {
215         /* FIXME: dynamic */
216         return VIRTIO_BLK_QUEUE_SIZE;
217 }
218
219 static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
220 {
221         /* FIXME: dynamic */
222         return size;
223 }
224
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,
229         .init_vq                = init_vq,
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,
234 };
235
236 static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
237 {
238         struct blk_dev *bdev;
239         unsigned int i;
240
241         if (!disk)
242                 return -EINVAL;
243
244         bdev = calloc(1, sizeof(struct blk_dev));
245         if (bdev == NULL)
246                 return -ENOMEM;
247
248         *bdev = (struct blk_dev) {
249                 .mutex                  = PTHREAD_MUTEX_INITIALIZER,
250                 .disk                   = disk,
251                 .blk_config             = (struct virtio_blk_config) {
252                         .capacity       = disk->size / SECTOR_SIZE,
253                         .seg_max        = DISK_SEG_MAX,
254                 },
255                 .io_efd                 = eventfd(0, 0),
256                 .kvm                    = kvm,
257         };
258
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);
261
262         list_add_tail(&bdev->list, &bdevs);
263
264         for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
265                 bdev->reqs[i].bdev = bdev;
266                 bdev->reqs[i].kvm = kvm;
267         }
268
269         disk_image__set_callback(bdev->disk, virtio_blk_complete);
270
271         pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev);
272         if (compat_id == -1)
273                 compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");
274
275         return 0;
276 }
277
278 static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev)
279 {
280         list_del(&bdev->list);
281         free(bdev);
282
283         return 0;
284 }
285
286 int virtio_blk__init(struct kvm *kvm)
287 {
288         int i, r = 0;
289
290         for (i = 0; i < kvm->nr_disks; i++) {
291                 if (kvm->disks[i]->wwpn)
292                         continue;
293                 r = virtio_blk__init_one(kvm, kvm->disks[i]);
294                 if (r < 0)
295                         goto cleanup;
296         }
297
298         return 0;
299 cleanup:
300         return virtio_blk__exit(kvm);
301 }
302 virtio_dev_init(virtio_blk__init);
303
304 int virtio_blk__exit(struct kvm *kvm)
305 {
306         while (!list_empty(&bdevs)) {
307                 struct blk_dev *bdev;
308
309                 bdev = list_first_entry(&bdevs, struct blk_dev, list);
310                 virtio_blk__exit_one(kvm, bdev);
311         }
312
313         return 0;
314 }
315 virtio_dev_exit(virtio_blk__exit);