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