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