xref: /kvmtool/disk/core.c (revision b48735e5d562eaffb96cf98a91da212176f1534c)
1 #include "kvm/disk-image.h"
2 #include "kvm/qcow.h"
3 #include "kvm/virtio-blk.h"
4 #include "kvm/kvm.h"
5 #include "kvm/iovec.h"
6 
7 #include <linux/err.h>
8 #include <poll.h>
9 
10 int debug_iodelay;
11 
12 static int disk_image__close(struct disk_image *disk);
13 
disk_img_name_parser(const struct option * opt,const char * arg,int unset)14 int disk_img_name_parser(const struct option *opt, const char *arg, int unset)
15 {
16 	const char *cur;
17 	char *sep;
18 	struct kvm *kvm = opt->ptr;
19 
20 	if (kvm->nr_disks >= MAX_DISK_IMAGES)
21 		die("Currently only 4 images are supported");
22 
23 	kvm->cfg.disk_image[kvm->nr_disks].filename = arg;
24 	cur = arg;
25 
26 	if (strncmp(arg, "scsi:", 5) == 0) {
27 		sep = strstr(arg, ":");
28 		kvm->cfg.disk_image[kvm->nr_disks].wwpn = sep + 1;
29 
30 		/* Old invocation had two parameters. Ignore the second one. */
31 		sep = strstr(sep + 1, ":");
32 		if (sep) {
33 			*sep = 0;
34 			cur = sep + 1;
35 		}
36 	}
37 
38 	do {
39 		sep = strstr(cur, ",");
40 		if (sep) {
41 			if (strncmp(sep + 1, "ro", 2) == 0)
42 				kvm->cfg.disk_image[kvm->nr_disks].readonly = true;
43 			else if (strncmp(sep + 1, "direct", 6) == 0)
44 				kvm->cfg.disk_image[kvm->nr_disks].direct = true;
45 			*sep = 0;
46 			cur = sep + 1;
47 		}
48 	} while (sep);
49 
50 	kvm->nr_disks++;
51 
52 	return 0;
53 }
54 
disk_image__new(int fd,u64 size,struct disk_image_operations * ops,int use_mmap)55 struct disk_image *disk_image__new(int fd, u64 size,
56 				   struct disk_image_operations *ops,
57 				   int use_mmap)
58 {
59 	struct disk_image *disk;
60 	int r;
61 
62 	disk = malloc(sizeof *disk);
63 	if (!disk)
64 		return ERR_PTR(-ENOMEM);
65 
66 	*disk = (struct disk_image) {
67 		.fd	= fd,
68 		.size	= size,
69 		.ops	= ops,
70 	};
71 
72 	if (use_mmap == DISK_IMAGE_MMAP) {
73 		/*
74 		 * The write to disk image will be discarded
75 		 */
76 		disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
77 		if (disk->priv == MAP_FAILED) {
78 			r = -errno;
79 			goto err_free_disk;
80 		}
81 	}
82 
83 	r = disk_aio_setup(disk);
84 	if (r)
85 		goto err_unmap_disk;
86 
87 	return disk;
88 
89 err_unmap_disk:
90 	if (disk->priv)
91 		munmap(disk->priv, size);
92 err_free_disk:
93 	free(disk);
94 	return ERR_PTR(r);
95 }
96 
disk_image__open(const char * filename,bool readonly,bool direct)97 static struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct)
98 {
99 	struct disk_image *disk;
100 	struct stat st;
101 	int fd, flags;
102 
103 	if (readonly)
104 		flags = O_RDONLY;
105 	else
106 		flags = O_RDWR;
107 	if (direct)
108 		flags |= O_DIRECT;
109 
110 	if (stat(filename, &st) < 0)
111 		return ERR_PTR(-errno);
112 
113 	/* blk device ?*/
114 	disk = blkdev__probe(filename, flags, &st);
115 	if (!IS_ERR_OR_NULL(disk)) {
116 		disk->readonly = readonly;
117 		return disk;
118 	}
119 
120 	fd = open(filename, flags);
121 	if (fd < 0)
122 		return ERR_PTR(fd);
123 
124 	/* qcow image ?*/
125 	disk = qcow_probe(fd, true);
126 	if (!IS_ERR_OR_NULL(disk)) {
127 		pr_warning("Forcing read-only support for QCOW");
128 		disk->readonly = true;
129 		return disk;
130 	}
131 
132 	/* raw image ?*/
133 	disk = raw_image__probe(fd, &st, readonly);
134 	if (!IS_ERR_OR_NULL(disk)) {
135 		disk->readonly = readonly;
136 		return disk;
137 	}
138 
139 	if (close(fd) < 0)
140 		pr_warning("close() failed");
141 
142 	return ERR_PTR(-ENOSYS);
143 }
144 
disk_image__open_all(struct kvm * kvm)145 static struct disk_image **disk_image__open_all(struct kvm *kvm)
146 {
147 	struct disk_image **disks;
148 	const char *filename;
149 	const char *wwpn;
150 	bool readonly;
151 	bool direct;
152 	void *err;
153 	int i;
154 	struct disk_image_params *params = (struct disk_image_params *)&kvm->cfg.disk_image;
155 	int count = kvm->nr_disks;
156 
157 	if (!count)
158 		return ERR_PTR(-EINVAL);
159 	if (count > MAX_DISK_IMAGES)
160 		return ERR_PTR(-ENOSPC);
161 
162 	disks = calloc(count, sizeof(*disks));
163 	if (!disks)
164 		return ERR_PTR(-ENOMEM);
165 
166 	for (i = 0; i < count; i++) {
167 		filename = params[i].filename;
168 		readonly = params[i].readonly;
169 		direct = params[i].direct;
170 		wwpn = params[i].wwpn;
171 
172 		if (wwpn) {
173 			disks[i] = malloc(sizeof(struct disk_image));
174 			if (!disks[i]) {
175 				err = ERR_PTR(-ENOMEM);
176 				goto error;
177 			}
178 			disks[i]->wwpn = wwpn;
179 			continue;
180 		}
181 
182 		if (!filename)
183 			continue;
184 
185 		disks[i] = disk_image__open(filename, readonly, direct);
186 		if (IS_ERR_OR_NULL(disks[i])) {
187 			pr_err("Loading disk image '%s' failed", filename);
188 			err = disks[i];
189 			goto error;
190 		}
191 		disks[i]->debug_iodelay = kvm->cfg.debug_iodelay;
192 	}
193 
194 	return disks;
195 error:
196 	for (i = 0; i < count; i++) {
197 		if (IS_ERR_OR_NULL(disks[i]))
198 			continue;
199 
200 		if (disks[i]->wwpn)
201 			free(disks[i]);
202 		else
203 			disk_image__close(disks[i]);
204 	}
205 	free(disks);
206 	return err;
207 }
208 
disk_image__wait(struct disk_image * disk)209 int disk_image__wait(struct disk_image *disk)
210 {
211 	if (disk->ops->wait)
212 		return disk->ops->wait(disk);
213 
214 	return 0;
215 }
216 
disk_image__flush(struct disk_image * disk)217 int disk_image__flush(struct disk_image *disk)
218 {
219 	if (disk->ops->flush)
220 		return disk->ops->flush(disk);
221 
222 	return fsync(disk->fd);
223 }
224 
disk_image__close(struct disk_image * disk)225 static int disk_image__close(struct disk_image *disk)
226 {
227 	/* If there was no disk image then there's nothing to do: */
228 	if (!disk)
229 		return 0;
230 
231 	disk_aio_destroy(disk);
232 
233 	if (disk->ops && disk->ops->close)
234 		return disk->ops->close(disk);
235 
236 	if (disk->fd && close(disk->fd) < 0)
237 		pr_warning("close() failed");
238 
239 	free(disk);
240 
241 	return 0;
242 }
243 
disk_image__close_all(struct disk_image ** disks,int count)244 static int disk_image__close_all(struct disk_image **disks, int count)
245 {
246 	while (count)
247 		disk_image__close(disks[--count]);
248 
249 	free(disks);
250 
251 	return 0;
252 }
253 
254 /*
255  * Fill iov with disk data, starting from sector 'sector'.
256  * Return amount of bytes read.
257  */
disk_image__read(struct disk_image * disk,u64 sector,const struct iovec * iov,int iovcount,void * param)258 ssize_t disk_image__read(struct disk_image *disk, u64 sector,
259 			 const struct iovec *iov, int iovcount, void *param)
260 {
261 	ssize_t total = 0;
262 
263 	if (debug_iodelay)
264 		msleep(debug_iodelay);
265 
266 	if (disk->ops->read) {
267 		total = disk->ops->read(disk, sector, iov, iovcount, param);
268 		if (total < 0) {
269 			pr_info("disk_image__read error: total=%ld\n", (long)total);
270 			return total;
271 		}
272 	}
273 
274 	if (!disk->async && disk->disk_req_cb)
275 		disk->disk_req_cb(param, total);
276 
277 	return total;
278 }
279 
280 /*
281  * Write iov to disk, starting from sector 'sector'.
282  * Return amount of bytes written.
283  */
disk_image__write(struct disk_image * disk,u64 sector,const struct iovec * iov,int iovcount,void * param)284 ssize_t disk_image__write(struct disk_image *disk, u64 sector,
285 			  const struct iovec *iov, int iovcount, void *param)
286 {
287 	ssize_t total = 0;
288 
289 	if (debug_iodelay)
290 		msleep(debug_iodelay);
291 
292 	if (disk->ops->write) {
293 		/*
294 		 * Try writev based operation first
295 		 */
296 
297 		total = disk->ops->write(disk, sector, iov, iovcount, param);
298 		if (total < 0) {
299 			pr_info("disk_image__write error: total=%ld\n", (long)total);
300 			return total;
301 		}
302 	} else {
303 		/* Do nothing */
304 	}
305 
306 	if (!disk->async && disk->disk_req_cb)
307 		disk->disk_req_cb(param, total);
308 
309 	return total;
310 }
311 
disk_image__get_serial(struct disk_image * disk,struct iovec * iov,int iovcount,ssize_t len)312 ssize_t disk_image__get_serial(struct disk_image *disk, struct iovec *iov,
313 			       int iovcount, ssize_t len)
314 {
315 	struct stat st;
316 	void *buf;
317 	int r;
318 
319 	r = fstat(disk->fd, &st);
320 	if (r)
321 		return r;
322 
323 	buf = malloc(len);
324 	if (!buf)
325 		return -ENOMEM;
326 
327 	len = snprintf(buf, len, "%llu%llu%llu",
328 		       (unsigned long long)st.st_dev,
329 		       (unsigned long long)st.st_rdev,
330 		       (unsigned long long)st.st_ino);
331 	if (len < 0 || (size_t)len > iov_size(iov, iovcount)) {
332 		free(buf);
333 		return -ENOMEM;
334 	}
335 
336 	memcpy_toiovec(iov, buf, len);
337 	free(buf);
338 	return len;
339 }
340 
disk_image__set_callback(struct disk_image * disk,void (* disk_req_cb)(void * param,long len))341 void disk_image__set_callback(struct disk_image *disk,
342 			      void (*disk_req_cb)(void *param, long len))
343 {
344 	disk->disk_req_cb = disk_req_cb;
345 }
346 
disk_image__init(struct kvm * kvm)347 int disk_image__init(struct kvm *kvm)
348 {
349 	if (kvm->nr_disks) {
350 		kvm->disks = disk_image__open_all(kvm);
351 		if (IS_ERR(kvm->disks))
352 			return PTR_ERR(kvm->disks);
353 	}
354 
355 	return 0;
356 }
357 dev_base_init(disk_image__init);
358 
disk_image__exit(struct kvm * kvm)359 int disk_image__exit(struct kvm *kvm)
360 {
361 	return disk_image__close_all(kvm->disks, kvm->nr_disks);
362 }
363 dev_base_exit(disk_image__exit);
364