xref: /kvmtool/virtio/blk.c (revision 74af1456dfa0c3fb1c79529450c6130b54fd1c83)
1416b2c2dSAsias He #include "kvm/virtio-blk.h"
2b30d05adSPekka Enberg 
331638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h"
45a24a9f2SPekka Enberg #include "kvm/disk-image.h"
548427891SJean-Philippe Brucker #include "kvm/iovec.h"
64ef0f4d6SPekka Enberg #include "kvm/mutex.h"
7fe99fd4eSPekka Enberg #include "kvm/util.h"
88b1ff07eSPekka Enberg #include "kvm/kvm.h"
9b30d05adSPekka Enberg #include "kvm/pci.h"
10fb0957f2SSasha Levin #include "kvm/threadpool.h"
11ec75b82fSSasha Levin #include "kvm/ioeventfd.h"
12404d164bSSasha Levin #include "kvm/guest_compat.h"
13427948d5SSasha Levin #include "kvm/virtio-pci.h"
14f41a132bSSasha Levin #include "kvm/virtio.h"
15b30d05adSPekka Enberg 
1620c64ecaSPekka Enberg #include <linux/virtio_ring.h>
1720c64ecaSPekka Enberg #include <linux/virtio_blk.h>
18427948d5SSasha Levin #include <linux/kernel.h>
19ebe9ac19SSasha Levin #include <linux/list.h>
203fdf659dSSasha Levin #include <linux/types.h>
210528c2a7SPekka Enberg #include <pthread.h>
224155ba8cSPekka Enberg 
234749e795SSasha Levin #define VIRTIO_BLK_MAX_DEV		4
2410eca11dSPekka Enberg 
253d7831a1SAsias He /*
263d7831a1SAsias He  * the header and status consume too entries
273d7831a1SAsias He  */
283d7831a1SAsias He #define DISK_SEG_MAX			(VIRTIO_BLK_QUEUE_SIZE - 2)
294059ad8bSAsias He #define VIRTIO_BLK_QUEUE_SIZE		256
30f41a132bSSasha Levin #define NUM_VIRT_QUEUES			1
3110eca11dSPekka Enberg 
328b52f877SSasha Levin struct blk_dev_req {
334749e795SSasha Levin 	struct virt_queue		*vq;
34fe2a70d1SSasha Levin 	struct blk_dev			*bdev;
3569971b13SSasha Levin 	struct iovec			iov[VIRTIO_BLK_QUEUE_SIZE];
3669971b13SSasha Levin 	u16				out, in, head;
3748427891SJean-Philippe Brucker 	u8				*status;
388b52f877SSasha Levin 	struct kvm			*kvm;
394749e795SSasha Levin };
404749e795SSasha Levin 
41fe2a70d1SSasha Levin struct blk_dev {
42d3476f7dSSasha Levin 	struct mutex			mutex;
438b52f877SSasha Levin 
44ebe9ac19SSasha Levin 	struct list_head		list;
450528c2a7SPekka Enberg 
4602eca50cSAsias He 	struct virtio_device		vdev;
4740ce993fSPekka Enberg 	struct virtio_blk_config	blk_config;
48867b15ccSJean-Philippe Brucker 	u64				capacity;
4938605e1cSSasha Levin 	struct disk_image		*disk;
5010eca11dSPekka Enberg 
5145e47970SAsias He 	struct virt_queue		vqs[NUM_VIRT_QUEUES];
528b52f877SSasha Levin 	struct blk_dev_req		reqs[VIRTIO_BLK_QUEUE_SIZE];
535ac1178bSAsias He 
545ac1178bSAsias He 	pthread_t			io_thread;
555ac1178bSAsias He 	int				io_efd;
565ac1178bSAsias He 
575ac1178bSAsias He 	struct kvm			*kvm;
58fbc2fbf9SPekka Enberg };
59fbc2fbf9SPekka Enberg 
60ebe9ac19SSasha Levin static LIST_HEAD(bdevs);
61bdbbcb63SAsias He static int compat_id = -1;
6240ce993fSPekka Enberg 
virtio_blk_complete(void * param,long len)638b52f877SSasha Levin void virtio_blk_complete(void *param, long len)
648b52f877SSasha Levin {
658b52f877SSasha Levin 	struct blk_dev_req *req = param;
668b52f877SSasha Levin 	struct blk_dev *bdev = req->bdev;
678b52f877SSasha Levin 	int queueid = req->vq - bdev->vqs;
683fdf659dSSasha Levin 	u8 *status;
698b52f877SSasha Levin 
708b52f877SSasha Levin 	/* status */
7148427891SJean-Philippe Brucker 	status = req->status;
728b52f877SSasha Levin 	*status	= (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
738b52f877SSasha Levin 
748b52f877SSasha Levin 	mutex_lock(&bdev->mutex);
758b52f877SSasha Levin 	virt_queue__set_used_elem(req->vq, req->head, len);
768b52f877SSasha Levin 	mutex_unlock(&bdev->mutex);
778b52f877SSasha Levin 
787ab3d207SSasha Levin 	if (virtio_queue__should_signal(&bdev->vqs[queueid]))
7902eca50cSAsias He 		bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid);
808b52f877SSasha Levin }
818b52f877SSasha Levin 
virtio_blk_do_io_request(struct kvm * kvm,struct virt_queue * vq,struct blk_dev_req * req)8201dafc9eSMarc Zyngier static void virtio_blk_do_io_request(struct kvm *kvm, struct virt_queue *vq, struct blk_dev_req *req)
838b52f877SSasha Levin {
8448427891SJean-Philippe Brucker 	struct virtio_blk_outhdr req_hdr;
8548427891SJean-Philippe Brucker 	size_t iovcount, last_iov;
8669971b13SSasha Levin 	struct blk_dev *bdev;
8769971b13SSasha Levin 	struct iovec *iov;
8848427891SJean-Philippe Brucker 	ssize_t len;
8901dafc9eSMarc Zyngier 	u32 type;
9001dafc9eSMarc Zyngier 	u64 sector;
914155ba8cSPekka Enberg 
928b52f877SSasha Levin 	bdev		= req->bdev;
938b52f877SSasha Levin 	iov		= req->iov;
9403110ff3SAsias He 
9548427891SJean-Philippe Brucker 	iovcount = req->out;
9648427891SJean-Philippe Brucker 	len = memcpy_fromiovec_safe(&req_hdr, &iov, sizeof(req_hdr), &iovcount);
9748427891SJean-Philippe Brucker 	if (len) {
9848427891SJean-Philippe Brucker 		pr_warning("Failed to get header");
9948427891SJean-Philippe Brucker 		return;
10048427891SJean-Philippe Brucker 	}
10148427891SJean-Philippe Brucker 
102b17552eeSAndre Przywara 	type = virtio_guest_to_host_u32(vq->endian, req_hdr.type);
103b17552eeSAndre Przywara 	sector = virtio_guest_to_host_u64(vq->endian, req_hdr.sector);
10448427891SJean-Philippe Brucker 
10548427891SJean-Philippe Brucker 	iovcount += req->in;
10648427891SJean-Philippe Brucker 	if (!iov_size(iov, iovcount)) {
10748427891SJean-Philippe Brucker 		pr_warning("Invalid IOV");
10848427891SJean-Philippe Brucker 		return;
10948427891SJean-Philippe Brucker 	}
11048427891SJean-Philippe Brucker 
11148427891SJean-Philippe Brucker 	/* Extract status byte from iovec */
11248427891SJean-Philippe Brucker 	last_iov = iovcount - 1;
11348427891SJean-Philippe Brucker 	while (!iov[last_iov].iov_len)
11448427891SJean-Philippe Brucker 		last_iov--;
11548427891SJean-Philippe Brucker 	iov[last_iov].iov_len--;
11648427891SJean-Philippe Brucker 	req->status = iov[last_iov].iov_base + iov[last_iov].iov_len;
11748427891SJean-Philippe Brucker 	if (!iov[last_iov].iov_len)
11848427891SJean-Philippe Brucker 		iovcount--;
11901dafc9eSMarc Zyngier 
12001dafc9eSMarc Zyngier 	switch (type) {
12103110ff3SAsias He 	case VIRTIO_BLK_T_IN:
12248427891SJean-Philippe Brucker 		disk_image__read(bdev->disk, sector, iov, iovcount, req);
123258dd093SPekka Enberg 		break;
12403110ff3SAsias He 	case VIRTIO_BLK_T_OUT:
12548427891SJean-Philippe Brucker 		disk_image__write(bdev->disk, sector, iov, iovcount, req);
126258dd093SPekka Enberg 		break;
12729084a74SPrasad Joshi 	case VIRTIO_BLK_T_FLUSH:
12848427891SJean-Philippe Brucker 		len = disk_image__flush(bdev->disk);
12948427891SJean-Philippe Brucker 		virtio_blk_complete(req, len);
13029084a74SPrasad Joshi 		break;
131ff6462e8SSasha Levin 	case VIRTIO_BLK_T_GET_ID:
13248427891SJean-Philippe Brucker 		len = disk_image__get_serial(bdev->disk, iov, iovcount,
13348427891SJean-Philippe Brucker 					     VIRTIO_BLK_ID_BYTES);
13448427891SJean-Philippe Brucker 		virtio_blk_complete(req, len);
135ff6462e8SSasha Levin 		break;
136258dd093SPekka Enberg 	default:
13701dafc9eSMarc Zyngier 		pr_warning("request type %d", type);
138407475bfSPekka Enberg 		break;
13903110ff3SAsias He 	}
1404155ba8cSPekka Enberg }
1414155ba8cSPekka Enberg 
virtio_blk_do_io(struct kvm * kvm,struct virt_queue * vq,struct blk_dev * bdev)14269971b13SSasha Levin static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
14345e47970SAsias He {
1442fddfdb5SAsias He 	struct blk_dev_req *req;
1452fddfdb5SAsias He 	u16 head;
146407475bfSPekka Enberg 
1472fddfdb5SAsias He 	while (virt_queue__available(vq)) {
1482fddfdb5SAsias He 		head		= virt_queue__pop(vq);
1492fddfdb5SAsias He 		req		= &bdev->reqs[head];
15034239c78SAsias He 		req->head	= virt_queue__get_head_iov(vq, req->iov, &req->out,
15134239c78SAsias He 					&req->in, head, kvm);
1522fddfdb5SAsias He 		req->vq		= vq;
15345e47970SAsias He 
15401dafc9eSMarc Zyngier 		virtio_blk_do_io_request(kvm, vq, req);
15569971b13SSasha Levin 	}
1564baf6f73SSasha Levin }
1570528c2a7SPekka Enberg 
get_config(struct kvm * kvm,void * dev)158c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev)
159427948d5SSasha Levin {
160427948d5SSasha Levin 	struct blk_dev *bdev = dev;
161427948d5SSasha Levin 
162c5ae742bSSasha Levin 	return ((u8 *)(&bdev->blk_config));
163427948d5SSasha Levin }
164427948d5SSasha Levin 
get_config_size(struct kvm * kvm,void * dev)165e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev)
166e4730284SMartin Radev {
167e4730284SMartin Radev 	struct blk_dev *bdev = dev;
168e4730284SMartin Radev 
169e4730284SMartin Radev 	return sizeof(bdev->blk_config);
170e4730284SMartin Radev }
171e4730284SMartin Radev 
get_host_features(struct kvm * kvm,void * dev)1723c8f82b8SJean-Philippe Brucker static u64 get_host_features(struct kvm *kvm, void *dev)
173427948d5SSasha Levin {
1745c5cae75SJean-Philippe Brucker 	struct blk_dev *bdev = dev;
1755c5cae75SJean-Philippe Brucker 
1767ab3d207SSasha Levin 	return	1UL << VIRTIO_BLK_F_SEG_MAX
1777ab3d207SSasha Levin 		| 1UL << VIRTIO_BLK_F_FLUSH
178754c8ce3SSasha Levin 		| 1UL << VIRTIO_RING_F_EVENT_IDX
1795c5cae75SJean-Philippe Brucker 		| 1UL << VIRTIO_RING_F_INDIRECT_DESC
18048427891SJean-Philippe Brucker 		| 1UL << VIRTIO_F_ANY_LAYOUT
1815c5cae75SJean-Philippe Brucker 		| (bdev->disk->readonly ? 1UL << VIRTIO_BLK_F_RO : 0);
182427948d5SSasha Levin }
183427948d5SSasha Levin 
notify_status(struct kvm * kvm,void * dev,u32 status)18495242e44SJean-Philippe Brucker static void notify_status(struct kvm *kvm, void *dev, u32 status)
18595242e44SJean-Philippe Brucker {
186867b15ccSJean-Philippe Brucker 	struct blk_dev *bdev = dev;
187867b15ccSJean-Philippe Brucker 	struct virtio_blk_config *conf = &bdev->blk_config;
188867b15ccSJean-Philippe Brucker 
189867b15ccSJean-Philippe Brucker 	if (!(status & VIRTIO__STATUS_CONFIG))
190867b15ccSJean-Philippe Brucker 		return;
191867b15ccSJean-Philippe Brucker 
192b17552eeSAndre Przywara 	conf->capacity = virtio_host_to_guest_u64(bdev->vdev.endian, bdev->capacity);
193b17552eeSAndre Przywara 	conf->seg_max = virtio_host_to_guest_u32(bdev->vdev.endian, DISK_SEG_MAX);
19495242e44SJean-Philippe Brucker }
19595242e44SJean-Philippe Brucker 
virtio_blk_thread(void * dev)1965ac1178bSAsias He static void *virtio_blk_thread(void *dev)
1975ac1178bSAsias He {
1985ac1178bSAsias He 	struct blk_dev *bdev = dev;
1995ac1178bSAsias He 	u64 data;
200a7aa454eSSasha Levin 	int r;
2015ac1178bSAsias He 
202a4d8c55eSSasha Levin 	kvm__set_thread_name("virtio-blk-io");
203a4d8c55eSSasha Levin 
2045ac1178bSAsias He 	while (1) {
205a7aa454eSSasha Levin 		r = read(bdev->io_efd, &data, sizeof(u64));
206a7aa454eSSasha Levin 		if (r < 0)
207a7aa454eSSasha Levin 			continue;
2085ac1178bSAsias He 		virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev);
2095ac1178bSAsias He 	}
2105ac1178bSAsias He 
2115ac1178bSAsias He 	pthread_exit(NULL);
2125ac1178bSAsias He 	return NULL;
2135ac1178bSAsias He }
2145ac1178bSAsias He 
init_vq(struct kvm * kvm,void * dev,u32 vq)215609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq)
2166730b51fSJean-Philippe Brucker {
2176730b51fSJean-Philippe Brucker 	unsigned int i;
2186730b51fSJean-Philippe Brucker 	struct blk_dev *bdev = dev;
2196730b51fSJean-Philippe Brucker 
2206730b51fSJean-Philippe Brucker 	compat__remove_message(compat_id);
2216730b51fSJean-Philippe Brucker 
222fd41cde0SJean-Philippe Brucker 	virtio_init_device_vq(kvm, &bdev->vdev, &bdev->vqs[vq],
223609ee906SJean-Philippe Brucker 			      VIRTIO_BLK_QUEUE_SIZE);
2246730b51fSJean-Philippe Brucker 
2256730b51fSJean-Philippe Brucker 	if (vq != 0)
2266730b51fSJean-Philippe Brucker 		return 0;
2276730b51fSJean-Philippe Brucker 
2286730b51fSJean-Philippe Brucker 	for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
2296730b51fSJean-Philippe Brucker 		bdev->reqs[i] = (struct blk_dev_req) {
2306730b51fSJean-Philippe Brucker 			.bdev = bdev,
2316730b51fSJean-Philippe Brucker 			.kvm = kvm,
2326730b51fSJean-Philippe Brucker 		};
2336730b51fSJean-Philippe Brucker 	}
2346730b51fSJean-Philippe Brucker 
2356730b51fSJean-Philippe Brucker 	mutex_init(&bdev->mutex);
2366730b51fSJean-Philippe Brucker 	bdev->io_efd = eventfd(0, 0);
2376730b51fSJean-Philippe Brucker 	if (bdev->io_efd < 0)
2386730b51fSJean-Philippe Brucker 		return -errno;
2396730b51fSJean-Philippe Brucker 
2406730b51fSJean-Philippe Brucker 	if (pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev))
2416730b51fSJean-Philippe Brucker 		return -errno;
2426730b51fSJean-Philippe Brucker 
2436730b51fSJean-Philippe Brucker 	return 0;
2446730b51fSJean-Philippe Brucker }
2456730b51fSJean-Philippe Brucker 
exit_vq(struct kvm * kvm,void * dev,u32 vq)2466730b51fSJean-Philippe Brucker static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
2476730b51fSJean-Philippe Brucker {
2486730b51fSJean-Philippe Brucker 	struct blk_dev *bdev = dev;
2496730b51fSJean-Philippe Brucker 
2506730b51fSJean-Philippe Brucker 	if (vq != 0)
2516730b51fSJean-Philippe Brucker 		return;
2526730b51fSJean-Philippe Brucker 
2536730b51fSJean-Philippe Brucker 	close(bdev->io_efd);
2546730b51fSJean-Philippe Brucker 	pthread_cancel(bdev->io_thread);
2556730b51fSJean-Philippe Brucker 	pthread_join(bdev->io_thread, NULL);
2563f218e89SJean-Philippe Brucker 
2573f218e89SJean-Philippe Brucker 	disk_image__wait(bdev->disk);
2586730b51fSJean-Philippe Brucker }
2596730b51fSJean-Philippe Brucker 
notify_vq(struct kvm * kvm,void * dev,u32 vq)260427948d5SSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
261427948d5SSasha Levin {
262427948d5SSasha Levin 	struct blk_dev *bdev = dev;
2635ac1178bSAsias He 	u64 data = 1;
264a7aa454eSSasha Levin 	int r;
265427948d5SSasha Levin 
266a7aa454eSSasha Levin 	r = write(bdev->io_efd, &data, sizeof(data));
267a7aa454eSSasha Levin 	if (r < 0)
268a7aa454eSSasha Levin 		return r;
269427948d5SSasha Levin 
270427948d5SSasha Levin 	return 0;
271427948d5SSasha Levin }
272427948d5SSasha Levin 
get_vq(struct kvm * kvm,void * dev,u32 vq)27353fbb17bSJean-Philippe Brucker static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
274427948d5SSasha Levin {
275427948d5SSasha Levin 	struct blk_dev *bdev = dev;
276427948d5SSasha Levin 
27753fbb17bSJean-Philippe Brucker 	return &bdev->vqs[vq];
278427948d5SSasha Levin }
279427948d5SSasha Levin 
get_size_vq(struct kvm * kvm,void * dev,u32 vq)280427948d5SSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
281427948d5SSasha Levin {
282ffcc904aSAsias He 	/* FIXME: dynamic */
283427948d5SSasha Levin 	return VIRTIO_BLK_QUEUE_SIZE;
284427948d5SSasha Levin }
285427948d5SSasha Levin 
set_size_vq(struct kvm * kvm,void * dev,u32 vq,int size)286ffcc904aSAsias He static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
287ffcc904aSAsias He {
288ffcc904aSAsias He 	/* FIXME: dynamic */
289ffcc904aSAsias He 	return size;
290ffcc904aSAsias He }
291ffcc904aSAsias He 
get_vq_count(struct kvm * kvm,void * dev)29231e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev)
293b98ac591SJean-Philippe Brucker {
294b98ac591SJean-Philippe Brucker 	return NUM_VIRT_QUEUES;
295b98ac591SJean-Philippe Brucker }
296b98ac591SJean-Philippe Brucker 
29715542babSAndre Przywara static struct virtio_ops blk_dev_virtio_ops = {
2981c47ce69SSasha Levin 	.get_config		= get_config,
299e4730284SMartin Radev 	.get_config_size	= get_config_size,
3001c47ce69SSasha Levin 	.get_host_features	= get_host_features,
301b98ac591SJean-Philippe Brucker 	.get_vq_count		= get_vq_count,
3021c47ce69SSasha Levin 	.init_vq		= init_vq,
3036730b51fSJean-Philippe Brucker 	.exit_vq		= exit_vq,
30495242e44SJean-Philippe Brucker 	.notify_status		= notify_status,
3051c47ce69SSasha Levin 	.notify_vq		= notify_vq,
30653fbb17bSJean-Philippe Brucker 	.get_vq			= get_vq,
3071c47ce69SSasha Levin 	.get_size_vq		= get_size_vq,
308ffcc904aSAsias He 	.set_size_vq		= set_size_vq,
3091c47ce69SSasha Levin };
3101c47ce69SSasha Levin 
virtio_blk__init_one(struct kvm * kvm,struct disk_image * disk)3119f9207c5SSasha Levin static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
3124749e795SSasha Levin {
313fe2a70d1SSasha Levin 	struct blk_dev *bdev;
314db927775SAlexandru Elisei 	int r;
3154749e795SSasha Levin 
3164749e795SSasha Levin 	if (!disk)
3179f9207c5SSasha Levin 		return -EINVAL;
3184749e795SSasha Levin 
319ebe9ac19SSasha Levin 	bdev = calloc(1, sizeof(struct blk_dev));
320ebe9ac19SSasha Levin 	if (bdev == NULL)
3219f9207c5SSasha Levin 		return -ENOMEM;
3224749e795SSasha Levin 
323fe2a70d1SSasha Levin 	*bdev = (struct blk_dev) {
3244749e795SSasha Levin 		.disk			= disk,
3254749e795SSasha Levin 		.capacity		= disk->size / SECTOR_SIZE,
3265ac1178bSAsias He 		.kvm			= kvm,
327427948d5SSasha Levin 	};
328427948d5SSasha Levin 
329db927775SAlexandru Elisei 	list_add_tail(&bdev->list, &bdevs);
330db927775SAlexandru Elisei 
331db927775SAlexandru Elisei 	r = virtio_init(kvm, bdev, &bdev->vdev, &blk_dev_virtio_ops,
3329b46ebc5SRajnesh Kanwal 			kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_BLK,
333ae06ce71SWill Deacon 			VIRTIO_ID_BLOCK, PCI_CLASS_BLK);
334db927775SAlexandru Elisei 	if (r < 0)
335db927775SAlexandru Elisei 		return r;
336ebe9ac19SSasha Levin 
337fb434ac3SSasha Levin 	disk_image__set_callback(bdev->disk, virtio_blk_complete);
338fb434ac3SSasha Levin 
339d278197dSAsias He 	if (compat_id == -1)
34052f34d2cSAsias He 		compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");
3415ac1178bSAsias He 
3429f9207c5SSasha Levin 	return 0;
343b30d05adSPekka Enberg }
344bcb6aacaSPrasad Joshi 
virtio_blk__exit_one(struct kvm * kvm,struct blk_dev * bdev)3459f9207c5SSasha Levin static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev)
346bcb6aacaSPrasad Joshi {
3479f9207c5SSasha Levin 	list_del(&bdev->list);
348*74af1456SEduardo Bart 	virtio_exit(kvm, &bdev->vdev);
3499f9207c5SSasha Levin 	free(bdev);
350bcb6aacaSPrasad Joshi 
3519f9207c5SSasha Levin 	return 0;
352bcb6aacaSPrasad Joshi }
353a0a1e3c2SPrasad Joshi 
virtio_blk__init(struct kvm * kvm)3549f9207c5SSasha Levin int virtio_blk__init(struct kvm *kvm)
3559f9207c5SSasha Levin {
3569f9207c5SSasha Levin 	int i, r = 0;
3579f9207c5SSasha Levin 
3589f9207c5SSasha Levin 	for (i = 0; i < kvm->nr_disks; i++) {
359a67da3beSAsias He 		if (kvm->disks[i]->wwpn)
360a67da3beSAsias He 			continue;
3619f9207c5SSasha Levin 		r = virtio_blk__init_one(kvm, kvm->disks[i]);
3629f9207c5SSasha Levin 		if (r < 0)
3639f9207c5SSasha Levin 			goto cleanup;
3649f9207c5SSasha Levin 	}
3659f9207c5SSasha Levin 
3669f9207c5SSasha Levin 	return 0;
3679f9207c5SSasha Levin cleanup:
368db927775SAlexandru Elisei 	virtio_blk__exit(kvm);
369db927775SAlexandru Elisei 	return r;
3709f9207c5SSasha Levin }
37149a8afd1SSasha Levin virtio_dev_init(virtio_blk__init);
3729f9207c5SSasha Levin 
virtio_blk__exit(struct kvm * kvm)3739f9207c5SSasha Levin int virtio_blk__exit(struct kvm *kvm)
374a0a1e3c2SPrasad Joshi {
375ebe9ac19SSasha Levin 	while (!list_empty(&bdevs)) {
376ebe9ac19SSasha Levin 		struct blk_dev *bdev;
377a0a1e3c2SPrasad Joshi 
378ebe9ac19SSasha Levin 		bdev = list_first_entry(&bdevs, struct blk_dev, list);
3799f9207c5SSasha Levin 		virtio_blk__exit_one(kvm, bdev);
380ebe9ac19SSasha Levin 	}
3819f9207c5SSasha Levin 
3829f9207c5SSasha Levin 	return 0;
383a0a1e3c2SPrasad Joshi }
38449a8afd1SSasha Levin virtio_dev_exit(virtio_blk__exit);
385