xref: /kvmtool/disk/core.c (revision f41a132b0aebbc85cd5624b45beb2e746de57406)
1 #include "kvm/disk-image.h"
2 #include "kvm/qcow.h"
3 #include "kvm/virtio-blk.h"
4 
5 #include <sys/eventfd.h>
6 #include <sys/poll.h>
7 
8 #define AIO_MAX 32
9 
10 int debug_iodelay;
11 
12 #ifdef CONFIG_HAS_AIO
13 static void *disk_image__thread(void *param)
14 {
15 	struct disk_image *disk = param;
16 	u64 dummy;
17 
18 	while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
19 		struct io_event event;
20 		struct timespec notime = {0};
21 
22 		while (io_getevents(disk->ctx, 1, 1, &event, &notime) > 0)
23 			disk->disk_req_cb(event.data, event.res);
24 	}
25 
26 	return NULL;
27 }
28 #endif
29 
30 struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap)
31 {
32 	struct disk_image *disk;
33 
34 	disk		= malloc(sizeof *disk);
35 	if (!disk)
36 		return NULL;
37 
38 	disk->fd	= fd;
39 	disk->size	= size;
40 	disk->ops	= ops;
41 
42 	if (use_mmap == DISK_IMAGE_MMAP) {
43 		/*
44 		 * The write to disk image will be discarded
45 		 */
46 		disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
47 		if (disk->priv == MAP_FAILED) {
48 			free(disk);
49 			disk = NULL;
50 		}
51 	}
52 
53 #ifdef CONFIG_HAS_AIO
54 	if (disk) {
55 		pthread_t thread;
56 
57 		disk->evt = eventfd(0, 0);
58 		io_setup(AIO_MAX, &disk->ctx);
59 		if (pthread_create(&thread, NULL, disk_image__thread, disk) != 0)
60 			die("Failed starting IO thread");
61 	}
62 #endif
63 	return disk;
64 }
65 
66 struct disk_image *disk_image__open(const char *filename, bool readonly)
67 {
68 	struct disk_image *disk;
69 	struct stat st;
70 	int fd;
71 
72 	if (stat(filename, &st) < 0)
73 		return NULL;
74 
75 	/* blk device ?*/
76 	disk		= blkdev__probe(filename, &st);
77 	if (disk)
78 		return disk;
79 
80 	fd		= open(filename, readonly ? O_RDONLY : O_RDWR);
81 	if (fd < 0)
82 		return NULL;
83 
84 	/* qcow image ?*/
85 	disk		= qcow_probe(fd, true);
86 	if (disk) {
87 		pr_warning("Forcing read-only support for QCOW");
88 		return disk;
89 	}
90 
91 	/* raw image ?*/
92 	disk		= raw_image__probe(fd, &st, readonly);
93 	if (disk)
94 		return disk;
95 
96 	if (close(fd) < 0)
97 		pr_warning("close() failed");
98 
99 	return NULL;
100 }
101 
102 struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count)
103 {
104 	struct disk_image **disks;
105 	int i;
106 
107 	if (!count || count > MAX_DISK_IMAGES)
108 		return NULL;
109 
110 	disks = calloc(count, sizeof(*disks));
111 	if (!disks)
112 		return NULL;
113 
114 	for (i = 0; i < count; i++) {
115 		if (!filenames[i])
116 			continue;
117 
118 		disks[i] = disk_image__open(filenames[i], readonly[i]);
119 		if (!disks[i]) {
120 			pr_error("Loading disk image '%s' failed", filenames[i]);
121 			goto error;
122 		}
123 	}
124 
125 	return disks;
126 error:
127 	for (i = 0; i < count; i++)
128 		disk_image__close(disks[i]);
129 
130 	free(disks);
131 	return NULL;
132 }
133 
134 int disk_image__flush(struct disk_image *disk)
135 {
136 	if (disk->ops->flush)
137 		return disk->ops->flush(disk);
138 
139 	return fsync(disk->fd);
140 }
141 
142 int disk_image__close(struct disk_image *disk)
143 {
144 	/* If there was no disk image then there's nothing to do: */
145 	if (!disk)
146 		return 0;
147 
148 	if (disk->ops->close)
149 		return disk->ops->close(disk);
150 
151 	if (close(disk->fd) < 0)
152 		pr_warning("close() failed");
153 
154 	free(disk);
155 
156 	return 0;
157 }
158 
159 void disk_image__close_all(struct disk_image **disks, int count)
160 {
161 	while (count)
162 		disk_image__close(disks[--count]);
163 
164 	free(disks);
165 }
166 
167 /*
168  * Fill iov with disk data, starting from sector 'sector'.
169  * Return amount of bytes read.
170  */
171 ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
172 				int iovcount, void *param)
173 {
174 	ssize_t total = 0;
175 
176 	if (debug_iodelay)
177 		msleep(debug_iodelay);
178 
179 	if (disk->ops->read_sector) {
180 		total = disk->ops->read_sector(disk, sector, iov, iovcount, param);
181 		if (total < 0) {
182 			pr_info("disk_image__read error: total=%ld\n", (long)total);
183 			return -1;
184 		}
185 	} else {
186 		/* Do nothing */
187 	}
188 
189 	if (!disk->async && disk->disk_req_cb)
190 		disk->disk_req_cb(param, total);
191 
192 	return total;
193 }
194 
195 /*
196  * Write iov to disk, starting from sector 'sector'.
197  * Return amount of bytes written.
198  */
199 ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
200 				int iovcount, void *param)
201 {
202 	ssize_t total = 0;
203 
204 	if (debug_iodelay)
205 		msleep(debug_iodelay);
206 
207 	if (disk->ops->write_sector) {
208 		/*
209 		 * Try writev based operation first
210 		 */
211 
212 		total = disk->ops->write_sector(disk, sector, iov, iovcount, param);
213 		if (total < 0) {
214 			pr_info("disk_image__write error: total=%ld\n", (long)total);
215 			return -1;
216 		}
217 	} else {
218 		/* Do nothing */
219 	}
220 
221 	if (!disk->async && disk->disk_req_cb)
222 		disk->disk_req_cb(param, total);
223 
224 	return total;
225 }
226 
227 ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len)
228 {
229 	struct stat st;
230 
231 	if (fstat(disk->fd, &st) != 0)
232 		return 0;
233 
234 	*len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino);
235 	return *len;
236 }
237 
238 void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len))
239 {
240 	disk->disk_req_cb = disk_req_cb;
241 }
242