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