1 #include "kvm/virtio-blk.h"
3 #include "kvm/virtio-pci-dev.h"
4 #include "kvm/disk-image.h"
5 #include "kvm/virtio.h"
10 #include "kvm/threadpool.h"
11 #include "kvm/ioeventfd.h"
12 #include "kvm/guest_compat.h"
13 #include "kvm/virtio-pci.h"
15 #include <linux/virtio_ring.h>
16 #include <linux/virtio_blk.h>
18 #include <linux/kernel.h>
19 #include <linux/list.h>
20 #include <linux/types.h>
23 #define VIRTIO_BLK_MAX_DEV 4
24 #define NUM_VIRT_QUEUES 1
26 #define VIRTIO_BLK_QUEUE_SIZE 128
28 * the header and status consume too entries
30 #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2)
33 struct virt_queue
*vq
;
35 struct iovec iov
[VIRTIO_BLK_QUEUE_SIZE
];
37 struct thread_pool__job job_id
;
41 pthread_mutex_t mutex
;
42 struct list_head list
;
44 struct virtio_pci vpci
;
45 struct virtio_blk_config blk_config
;
46 struct disk_image
*disk
;
50 struct virt_queue vqs
[NUM_VIRT_QUEUES
];
51 struct blk_dev_job jobs
[VIRTIO_BLK_QUEUE_SIZE
];
55 static LIST_HEAD(bdevs
);
57 static void virtio_blk_do_io_request(struct kvm
*kvm
, void *param
)
59 struct virtio_blk_outhdr
*req
;
62 struct blk_dev_job
*job
;
64 struct virt_queue
*queue
;
76 req
= iov
[0].iov_base
;
80 block_cnt
= disk_image__read(bdev
->disk
, req
->sector
, iov
+ 1, in
+ out
- 2);
82 case VIRTIO_BLK_T_OUT
:
83 block_cnt
= disk_image__write(bdev
->disk
, req
->sector
, iov
+ 1, in
+ out
- 2);
85 case VIRTIO_BLK_T_FLUSH
:
86 block_cnt
= disk_image__flush(bdev
->disk
);
88 case VIRTIO_BLK_T_GET_ID
:
89 block_cnt
= VIRTIO_BLK_ID_BYTES
;
90 disk_image__get_serial(bdev
->disk
, (iov
+ 1)->iov_base
, &block_cnt
);
93 pr_warning("request type %d", req
->type
);
99 status
= iov
[out
+ in
- 1].iov_base
;
100 *status
= (block_cnt
< 0) ? VIRTIO_BLK_S_IOERR
: VIRTIO_BLK_S_OK
;
102 mutex_lock(&bdev
->mutex
);
103 virt_queue__set_used_elem(queue
, head
, block_cnt
);
104 mutex_unlock(&bdev
->mutex
);
106 virtio_pci__signal_vq(kvm
, &bdev
->vpci
, queue
- bdev
->vqs
);
109 static void virtio_blk_do_io(struct kvm
*kvm
, struct virt_queue
*vq
, struct blk_dev
*bdev
)
111 while (virt_queue__available(vq
)) {
112 struct blk_dev_job
*job
= &bdev
->jobs
[bdev
->job_idx
++ % VIRTIO_BLK_QUEUE_SIZE
];
114 *job
= (struct blk_dev_job
) {
118 job
->head
= virt_queue__get_iov(vq
, job
->iov
, &job
->out
, &job
->in
, kvm
);
120 thread_pool__init_job(&job
->job_id
, kvm
, virtio_blk_do_io_request
, job
);
121 thread_pool__do_job(&job
->job_id
);
125 static void set_config(struct kvm
*kvm
, void *dev
, u8 data
, u32 offset
)
127 struct blk_dev
*bdev
= dev
;
129 ((u8
*)(&bdev
->blk_config
))[offset
] = data
;
132 static u8
get_config(struct kvm
*kvm
, void *dev
, u32 offset
)
134 struct blk_dev
*bdev
= dev
;
136 return ((u8
*)(&bdev
->blk_config
))[offset
];
139 static u32
get_host_features(struct kvm
*kvm
, void *dev
)
141 return 1UL << VIRTIO_BLK_F_SEG_MAX
| 1UL << VIRTIO_BLK_F_FLUSH
;
144 static void set_guest_features(struct kvm
*kvm
, void *dev
, u32 features
)
146 struct blk_dev
*bdev
= dev
;
148 bdev
->features
= features
;
151 static int init_vq(struct kvm
*kvm
, void *dev
, u32 vq
, u32 pfn
)
153 struct blk_dev
*bdev
= dev
;
154 struct virt_queue
*queue
;
157 compat__remove_message(bdev
->compat_id
);
159 queue
= &bdev
->vqs
[vq
];
161 p
= guest_pfn_to_host(kvm
, queue
->pfn
);
163 vring_init(&queue
->vring
, VIRTIO_BLK_QUEUE_SIZE
, p
, VIRTIO_PCI_VRING_ALIGN
);
168 static int notify_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
170 struct blk_dev
*bdev
= dev
;
172 virtio_blk_do_io(kvm
, &bdev
->vqs
[vq
], bdev
);
177 static int get_pfn_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
179 struct blk_dev
*bdev
= dev
;
181 return bdev
->vqs
[vq
].pfn
;
184 static int get_size_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
186 return VIRTIO_BLK_QUEUE_SIZE
;
189 void virtio_blk__init(struct kvm
*kvm
, struct disk_image
*disk
)
191 struct blk_dev
*bdev
;
196 bdev
= calloc(1, sizeof(struct blk_dev
));
198 die("Failed allocating bdev");
200 *bdev
= (struct blk_dev
) {
201 .mutex
= PTHREAD_MUTEX_INITIALIZER
,
203 .blk_config
= (struct virtio_blk_config
) {
204 .capacity
= disk
->size
/ SECTOR_SIZE
,
205 .seg_max
= DISK_SEG_MAX
,
209 virtio_pci__init(kvm
, &bdev
->vpci
, bdev
, PCI_DEVICE_ID_VIRTIO_BLK
, VIRTIO_ID_BLOCK
);
210 bdev
->vpci
.ops
= (struct virtio_pci_ops
) {
211 .set_config
= set_config
,
212 .get_config
= get_config
,
213 .get_host_features
= get_host_features
,
214 .set_guest_features
= set_guest_features
,
216 .notify_vq
= notify_vq
,
217 .get_pfn_vq
= get_pfn_vq
,
218 .get_size_vq
= get_size_vq
,
221 list_add_tail(&bdev
->list
, &bdevs
);
223 bdev
->compat_id
= compat__add_message("virtio-blk device was not detected",
224 "While you have requested a virtio-blk device, "
225 "the guest kernel didn't seem to detect it.\n"
226 "Please make sure that the kernel was compiled"
227 "with CONFIG_VIRTIO_BLK.");
230 void virtio_blk__init_all(struct kvm
*kvm
)
234 for (i
= 0; i
< kvm
->nr_disks
; i
++)
235 virtio_blk__init(kvm
, kvm
->disks
[i
]);
238 void virtio_blk__delete_all(struct kvm
*kvm
)
240 while (!list_empty(&bdevs
)) {
241 struct blk_dev
*bdev
;
243 bdev
= list_first_entry(&bdevs
, struct blk_dev
, list
);
244 list_del(&bdev
->list
);