xref: /kvmtool/disk/raw.c (revision dcd3cd8e4e8267fb5e13930ffb8d47cd1268e07d)
1 #include "kvm/disk-image.h"
2 
3 #include <linux/err.h>
4 
5 #ifdef CONFIG_HAS_AIO
6 #include <libaio.h>
7 #endif
8 
9 ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
10 				int iovcount, void *param)
11 {
12 	u64 offset = sector << SECTOR_SHIFT;
13 
14 #ifdef CONFIG_HAS_AIO
15 	struct iocb iocb;
16 
17 	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
18 				disk->evt, param);
19 #else
20 	return preadv_in_full(disk->fd, iov, iovcount, offset);
21 #endif
22 }
23 
24 ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
25 				int iovcount, void *param)
26 {
27 	u64 offset = sector << SECTOR_SHIFT;
28 
29 #ifdef CONFIG_HAS_AIO
30 	struct iocb iocb;
31 
32 	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
33 				disk->evt, param);
34 #else
35 	return pwritev_in_full(disk->fd, iov, iovcount, offset);
36 #endif
37 }
38 
39 ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
40 				int iovcount, void *param)
41 {
42 	u64 offset = sector << SECTOR_SHIFT;
43 	ssize_t total = 0;
44 
45 	while (iovcount--) {
46 		memcpy(iov->iov_base, disk->priv + offset, iov->iov_len);
47 
48 		sector	+= iov->iov_len >> SECTOR_SHIFT;
49 		offset	+= iov->iov_len;
50 		total	+= iov->iov_len;
51 		iov++;
52 	}
53 
54 	return total;
55 }
56 
57 ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
58 				int iovcount, void *param)
59 {
60 	u64 offset = sector << SECTOR_SHIFT;
61 	ssize_t total = 0;
62 
63 	while (iovcount--) {
64 		memcpy(disk->priv + offset, iov->iov_base, iov->iov_len);
65 
66 		sector	+= iov->iov_len >> SECTOR_SHIFT;
67 		offset	+= iov->iov_len;
68 		total	+= iov->iov_len;
69 		iov++;
70 	}
71 
72 	return total;
73 }
74 
75 int raw_image__close(struct disk_image *disk)
76 {
77 	int ret = 0;
78 
79 	if (disk->priv != MAP_FAILED)
80 		ret = munmap(disk->priv, disk->size);
81 
82 	close(disk->evt);
83 
84 #ifdef CONFIG_HAS_VIRTIO
85 	io_destroy(disk->ctx);
86 #endif
87 
88 	return ret;
89 }
90 
91 /*
92  * multiple buffer based disk image operations
93  */
94 static struct disk_image_operations raw_image_regular_ops = {
95 	.read	= raw_image__read,
96 	.write	= raw_image__write,
97 };
98 
99 struct disk_image_operations ro_ops = {
100 	.read	= raw_image__read_mmap,
101 	.write	= raw_image__write_mmap,
102 	.close		= raw_image__close,
103 };
104 
105 struct disk_image_operations ro_ops_nowrite = {
106 	.read	= raw_image__read,
107 };
108 
109 struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly)
110 {
111 	struct disk_image *disk;
112 
113 	if (readonly) {
114 		/*
115 		 * Use mmap's MAP_PRIVATE to implement non-persistent write
116 		 * FIXME: This does not work on 32-bit host.
117 		 */
118 		struct disk_image *disk;
119 
120 		disk = disk_image__new(fd, st->st_size, &ro_ops, DISK_IMAGE_MMAP);
121 		if (IS_ERR_OR_NULL(disk)) {
122 			disk = disk_image__new(fd, st->st_size, &ro_ops_nowrite, DISK_IMAGE_REGULAR);
123 #ifdef CONFIG_HAS_AIO
124 			if (!IS_ERR_OR_NULL(disk))
125 				disk->async = 1;
126 #endif
127 		}
128 
129 		return disk;
130 	} else {
131 		/*
132 		 * Use read/write instead of mmap
133 		 */
134 		disk = disk_image__new(fd, st->st_size, &raw_image_regular_ops, DISK_IMAGE_REGULAR);
135 #ifdef CONFIG_HAS_AIO
136 		if (!IS_ERR_OR_NULL(disk))
137 			disk->async = 1;
138 #endif
139 		return disk;
140 	}
141 }
142