root / block.c @ 97eb5b14
History | View | Annotate | Download (9.6 kB)
1 | fc01f7e7 | bellard | /*
|
---|---|---|---|
2 | fc01f7e7 | bellard | * QEMU System Emulator block driver
|
3 | fc01f7e7 | bellard | *
|
4 | fc01f7e7 | bellard | * Copyright (c) 2003 Fabrice Bellard
|
5 | fc01f7e7 | bellard | *
|
6 | fc01f7e7 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | fc01f7e7 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | fc01f7e7 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | fc01f7e7 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | fc01f7e7 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | fc01f7e7 | bellard | * furnished to do so, subject to the following conditions:
|
12 | fc01f7e7 | bellard | *
|
13 | fc01f7e7 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | fc01f7e7 | bellard | * all copies or substantial portions of the Software.
|
15 | fc01f7e7 | bellard | *
|
16 | fc01f7e7 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | fc01f7e7 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | fc01f7e7 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | fc01f7e7 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | fc01f7e7 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | fc01f7e7 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | fc01f7e7 | bellard | * THE SOFTWARE.
|
23 | fc01f7e7 | bellard | */
|
24 | fc01f7e7 | bellard | #include <stdlib.h> |
25 | fc01f7e7 | bellard | #include <stdio.h> |
26 | fc01f7e7 | bellard | #include <stdarg.h> |
27 | fc01f7e7 | bellard | #include <string.h> |
28 | fc01f7e7 | bellard | #include <getopt.h> |
29 | fc01f7e7 | bellard | #include <inttypes.h> |
30 | fc01f7e7 | bellard | #include <unistd.h> |
31 | fc01f7e7 | bellard | #include <sys/mman.h> |
32 | fc01f7e7 | bellard | #include <fcntl.h> |
33 | fc01f7e7 | bellard | #include <signal.h> |
34 | fc01f7e7 | bellard | #include <time.h> |
35 | fc01f7e7 | bellard | #include <sys/time.h> |
36 | fc01f7e7 | bellard | #include <malloc.h> |
37 | fc01f7e7 | bellard | #include <termios.h> |
38 | fc01f7e7 | bellard | #include <sys/poll.h> |
39 | fc01f7e7 | bellard | #include <errno.h> |
40 | fc01f7e7 | bellard | #include <sys/wait.h> |
41 | 33e3963e | bellard | #include <netinet/in.h> |
42 | fc01f7e7 | bellard | |
43 | fc01f7e7 | bellard | #include "vl.h" |
44 | fc01f7e7 | bellard | |
45 | 33e3963e | bellard | #define NO_THUNK_TYPE_SIZE
|
46 | 33e3963e | bellard | #include "thunk.h" |
47 | 33e3963e | bellard | |
48 | fc01f7e7 | bellard | struct BlockDriverState {
|
49 | 33e3963e | bellard | int fd; /* if -1, only COW mappings */ |
50 | fc01f7e7 | bellard | int64_t total_sectors; |
51 | 0849bf08 | bellard | int read_only;
|
52 | 33e3963e | bellard | |
53 | 33e3963e | bellard | uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
54 | 33e3963e | bellard | uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
55 | 33e3963e | bellard | int cow_bitmap_size;
|
56 | 33e3963e | bellard | int cow_fd;
|
57 | 33e3963e | bellard | int64_t cow_sectors_offset; |
58 | cf98951b | bellard | int boot_sector_enabled;
|
59 | cf98951b | bellard | uint8_t boot_sector_data[512];
|
60 | cf98951b | bellard | |
61 | 33e3963e | bellard | char filename[1024]; |
62 | fc01f7e7 | bellard | }; |
63 | fc01f7e7 | bellard | |
64 | 33e3963e | bellard | BlockDriverState *bdrv_open(const char *filename, int snapshot) |
65 | fc01f7e7 | bellard | { |
66 | fc01f7e7 | bellard | BlockDriverState *bs; |
67 | 33e3963e | bellard | int fd, cow_fd;
|
68 | fc01f7e7 | bellard | int64_t size; |
69 | 33e3963e | bellard | char template[] = "/tmp/vl.XXXXXX"; |
70 | 33e3963e | bellard | struct cow_header_v2 cow_header;
|
71 | 33e3963e | bellard | struct stat st;
|
72 | fc01f7e7 | bellard | |
73 | fc01f7e7 | bellard | bs = malloc(sizeof(BlockDriverState));
|
74 | fc01f7e7 | bellard | if(!bs)
|
75 | fc01f7e7 | bellard | return NULL; |
76 | 0849bf08 | bellard | bs->read_only = 0;
|
77 | 33e3963e | bellard | bs->fd = -1;
|
78 | 33e3963e | bellard | bs->cow_fd = -1;
|
79 | 33e3963e | bellard | bs->cow_bitmap = NULL;
|
80 | 33e3963e | bellard | strcpy(bs->filename, filename); |
81 | 33e3963e | bellard | |
82 | 33e3963e | bellard | /* open standard HD image */
|
83 | 33e3963e | bellard | fd = open(filename, O_RDWR | O_LARGEFILE); |
84 | fc01f7e7 | bellard | if (fd < 0) { |
85 | 33e3963e | bellard | /* read only image on disk */
|
86 | 33e3963e | bellard | fd = open(filename, O_RDONLY | O_LARGEFILE); |
87 | 0849bf08 | bellard | if (fd < 0) { |
88 | 33e3963e | bellard | perror(filename); |
89 | 33e3963e | bellard | goto fail;
|
90 | 0849bf08 | bellard | } |
91 | 33e3963e | bellard | if (!snapshot)
|
92 | 33e3963e | bellard | bs->read_only = 1;
|
93 | fc01f7e7 | bellard | } |
94 | fc01f7e7 | bellard | bs->fd = fd; |
95 | 33e3963e | bellard | |
96 | 33e3963e | bellard | /* see if it is a cow image */
|
97 | 33e3963e | bellard | if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { |
98 | 33e3963e | bellard | fprintf(stderr, "%s: could not read header\n", filename);
|
99 | 33e3963e | bellard | goto fail;
|
100 | 33e3963e | bellard | } |
101 | 33e3963e | bellard | if (cow_header.magic == htonl(COW_MAGIC) &&
|
102 | 33e3963e | bellard | cow_header.version == htonl(COW_VERSION)) { |
103 | 33e3963e | bellard | /* cow image found */
|
104 | 33e3963e | bellard | size = cow_header.size; |
105 | 33e3963e | bellard | #ifndef WORDS_BIGENDIAN
|
106 | 33e3963e | bellard | size = bswap64(size); |
107 | 33e3963e | bellard | #endif
|
108 | 33e3963e | bellard | bs->total_sectors = size / 512;
|
109 | 33e3963e | bellard | |
110 | 33e3963e | bellard | bs->cow_fd = fd; |
111 | 33e3963e | bellard | bs->fd = -1;
|
112 | 33e3963e | bellard | if (cow_header.backing_file[0] != '\0') { |
113 | 33e3963e | bellard | if (stat(cow_header.backing_file, &st) != 0) { |
114 | 33e3963e | bellard | fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
115 | 33e3963e | bellard | goto fail;
|
116 | 33e3963e | bellard | } |
117 | 33e3963e | bellard | if (st.st_mtime != htonl(cow_header.mtime)) {
|
118 | 33e3963e | bellard | fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
119 | 33e3963e | bellard | goto fail;
|
120 | 33e3963e | bellard | } |
121 | 33e3963e | bellard | fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); |
122 | 33e3963e | bellard | if (fd < 0) |
123 | 33e3963e | bellard | goto fail;
|
124 | 33e3963e | bellard | bs->fd = fd; |
125 | 33e3963e | bellard | } |
126 | 33e3963e | bellard | /* mmap the bitmap */
|
127 | 33e3963e | bellard | bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
128 | 33e3963e | bellard | bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
129 | 33e3963e | bellard | bs->cow_bitmap_size, |
130 | 33e3963e | bellard | PROT_READ | PROT_WRITE, |
131 | 33e3963e | bellard | MAP_SHARED, bs->cow_fd, 0);
|
132 | 33e3963e | bellard | if (bs->cow_bitmap_addr == MAP_FAILED)
|
133 | 33e3963e | bellard | goto fail;
|
134 | 33e3963e | bellard | bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
135 | 33e3963e | bellard | bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; |
136 | 33e3963e | bellard | snapshot = 0;
|
137 | 33e3963e | bellard | } else {
|
138 | 33e3963e | bellard | /* standard raw image */
|
139 | 33e3963e | bellard | size = lseek64(fd, 0, SEEK_END);
|
140 | 33e3963e | bellard | bs->total_sectors = size / 512;
|
141 | 33e3963e | bellard | bs->fd = fd; |
142 | 33e3963e | bellard | } |
143 | 33e3963e | bellard | |
144 | 33e3963e | bellard | if (snapshot) {
|
145 | 33e3963e | bellard | /* create a temporary COW file */
|
146 | 33e3963e | bellard | cow_fd = mkstemp(template); |
147 | 33e3963e | bellard | if (cow_fd < 0) |
148 | 33e3963e | bellard | goto fail;
|
149 | 33e3963e | bellard | bs->cow_fd = cow_fd; |
150 | 33e3963e | bellard | unlink(template); |
151 | 33e3963e | bellard | |
152 | 33e3963e | bellard | /* just need to allocate bitmap */
|
153 | 33e3963e | bellard | bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; |
154 | 33e3963e | bellard | bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
155 | 33e3963e | bellard | bs->cow_bitmap_size, |
156 | 33e3963e | bellard | PROT_READ | PROT_WRITE, |
157 | 33e3963e | bellard | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
158 | 33e3963e | bellard | if (bs->cow_bitmap_addr == MAP_FAILED)
|
159 | 33e3963e | bellard | goto fail;
|
160 | 33e3963e | bellard | bs->cow_bitmap = bs->cow_bitmap_addr; |
161 | 33e3963e | bellard | bs->cow_sectors_offset = 0;
|
162 | 33e3963e | bellard | } |
163 | 33e3963e | bellard | |
164 | fc01f7e7 | bellard | return bs;
|
165 | 33e3963e | bellard | fail:
|
166 | 33e3963e | bellard | bdrv_close(bs); |
167 | 33e3963e | bellard | return NULL; |
168 | fc01f7e7 | bellard | } |
169 | fc01f7e7 | bellard | |
170 | fc01f7e7 | bellard | void bdrv_close(BlockDriverState *bs)
|
171 | fc01f7e7 | bellard | { |
172 | 33e3963e | bellard | /* we unmap the mapping so that it is written to the COW file */
|
173 | 33e3963e | bellard | if (bs->cow_bitmap_addr)
|
174 | 33e3963e | bellard | munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); |
175 | 33e3963e | bellard | if (bs->cow_fd >= 0) |
176 | 33e3963e | bellard | close(bs->cow_fd); |
177 | 33e3963e | bellard | if (bs->fd >= 0) |
178 | 33e3963e | bellard | close(bs->fd); |
179 | fc01f7e7 | bellard | free(bs); |
180 | fc01f7e7 | bellard | } |
181 | fc01f7e7 | bellard | |
182 | 33e3963e | bellard | static inline void set_bit(uint8_t *bitmap, int64_t bitnum) |
183 | 33e3963e | bellard | { |
184 | 33e3963e | bellard | bitmap[bitnum / 8] |= (1 << (bitnum%8)); |
185 | 33e3963e | bellard | } |
186 | 33e3963e | bellard | |
187 | 33e3963e | bellard | static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) |
188 | 33e3963e | bellard | { |
189 | 33e3963e | bellard | return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); |
190 | 33e3963e | bellard | } |
191 | 33e3963e | bellard | |
192 | 33e3963e | bellard | |
193 | 33e3963e | bellard | /* Return true if first block has been changed (ie. current version is
|
194 | 33e3963e | bellard | * in COW file). Set the number of continuous blocks for which that
|
195 | 33e3963e | bellard | * is true. */
|
196 | 33e3963e | bellard | static int is_changed(uint8_t *bitmap, |
197 | 33e3963e | bellard | int64_t sector_num, int nb_sectors,
|
198 | 33e3963e | bellard | int *num_same)
|
199 | 33e3963e | bellard | { |
200 | 33e3963e | bellard | int changed;
|
201 | 33e3963e | bellard | |
202 | 33e3963e | bellard | if (!bitmap || nb_sectors == 0) { |
203 | 33e3963e | bellard | *num_same = nb_sectors; |
204 | 33e3963e | bellard | return 0; |
205 | 33e3963e | bellard | } |
206 | 33e3963e | bellard | |
207 | 33e3963e | bellard | changed = is_bit_set(bitmap, sector_num); |
208 | 33e3963e | bellard | for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { |
209 | 33e3963e | bellard | if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
210 | 33e3963e | bellard | break;
|
211 | 33e3963e | bellard | } |
212 | 33e3963e | bellard | |
213 | 33e3963e | bellard | return changed;
|
214 | 33e3963e | bellard | } |
215 | 33e3963e | bellard | |
216 | 33e3963e | bellard | /* commit COW file into the raw image */
|
217 | 33e3963e | bellard | int bdrv_commit(BlockDriverState *bs)
|
218 | 33e3963e | bellard | { |
219 | 33e3963e | bellard | int64_t i; |
220 | 33e3963e | bellard | uint8_t *cow_bitmap; |
221 | 33e3963e | bellard | |
222 | 33e3963e | bellard | if (!bs->cow_bitmap) {
|
223 | 33e3963e | bellard | fprintf(stderr, "Already committed to %s\n", bs->filename);
|
224 | 33e3963e | bellard | return 0; |
225 | 33e3963e | bellard | } |
226 | 33e3963e | bellard | |
227 | 33e3963e | bellard | if (bs->read_only) {
|
228 | 33e3963e | bellard | fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
|
229 | 33e3963e | bellard | return -1; |
230 | 33e3963e | bellard | } |
231 | 33e3963e | bellard | |
232 | 33e3963e | bellard | cow_bitmap = bs->cow_bitmap; |
233 | 33e3963e | bellard | for (i = 0; i < bs->total_sectors; i++) { |
234 | 33e3963e | bellard | if (is_bit_set(cow_bitmap, i)) {
|
235 | 33e3963e | bellard | unsigned char sector[512]; |
236 | 33e3963e | bellard | if (bdrv_read(bs, i, sector, 1) != 0) { |
237 | 33e3963e | bellard | fprintf(stderr, "Error reading sector %lli: aborting commit\n",
|
238 | 33e3963e | bellard | (long long)i); |
239 | 33e3963e | bellard | return -1; |
240 | 33e3963e | bellard | } |
241 | 33e3963e | bellard | |
242 | 33e3963e | bellard | /* Make bdrv_write write to real file for a moment. */
|
243 | 33e3963e | bellard | bs->cow_bitmap = NULL;
|
244 | 33e3963e | bellard | if (bdrv_write(bs, i, sector, 1) != 0) { |
245 | 33e3963e | bellard | fprintf(stderr, "Error writing sector %lli: aborting commit\n",
|
246 | 33e3963e | bellard | (long long)i); |
247 | 33e3963e | bellard | bs->cow_bitmap = cow_bitmap; |
248 | 33e3963e | bellard | return -1; |
249 | 33e3963e | bellard | } |
250 | 33e3963e | bellard | bs->cow_bitmap = cow_bitmap; |
251 | 33e3963e | bellard | } |
252 | 33e3963e | bellard | } |
253 | 33e3963e | bellard | fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
|
254 | 33e3963e | bellard | return 0; |
255 | 33e3963e | bellard | } |
256 | 33e3963e | bellard | |
257 | fc01f7e7 | bellard | /* return -1 if error */
|
258 | fc01f7e7 | bellard | int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
259 | fc01f7e7 | bellard | uint8_t *buf, int nb_sectors)
|
260 | fc01f7e7 | bellard | { |
261 | 33e3963e | bellard | int ret, n, fd;
|
262 | 33e3963e | bellard | int64_t offset; |
263 | 33e3963e | bellard | |
264 | 33e3963e | bellard | while (nb_sectors > 0) { |
265 | 33e3963e | bellard | if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
266 | 33e3963e | bellard | fd = bs->cow_fd; |
267 | 33e3963e | bellard | offset = bs->cow_sectors_offset; |
268 | cf98951b | bellard | } else if (sector_num == 0 && bs->boot_sector_enabled) { |
269 | cf98951b | bellard | memcpy(buf, bs->boot_sector_data, 512);
|
270 | cf98951b | bellard | n = 1;
|
271 | cf98951b | bellard | goto next;
|
272 | 33e3963e | bellard | } else {
|
273 | 33e3963e | bellard | fd = bs->fd; |
274 | 33e3963e | bellard | offset = 0;
|
275 | 33e3963e | bellard | } |
276 | fc01f7e7 | bellard | |
277 | 33e3963e | bellard | if (fd < 0) { |
278 | 33e3963e | bellard | /* no file, just return empty sectors */
|
279 | 33e3963e | bellard | memset(buf, 0, n * 512); |
280 | 33e3963e | bellard | } else {
|
281 | 33e3963e | bellard | offset += sector_num * 512;
|
282 | 33e3963e | bellard | lseek64(fd, offset, SEEK_SET); |
283 | 33e3963e | bellard | ret = read(fd, buf, n * 512);
|
284 | 33e3963e | bellard | if (ret != n * 512) { |
285 | 33e3963e | bellard | return -1; |
286 | 33e3963e | bellard | } |
287 | 33e3963e | bellard | } |
288 | cf98951b | bellard | next:
|
289 | 33e3963e | bellard | nb_sectors -= n; |
290 | 33e3963e | bellard | sector_num += n; |
291 | 33e3963e | bellard | buf += n * 512;
|
292 | 33e3963e | bellard | } |
293 | 33e3963e | bellard | return 0; |
294 | fc01f7e7 | bellard | } |
295 | fc01f7e7 | bellard | |
296 | fc01f7e7 | bellard | /* return -1 if error */
|
297 | fc01f7e7 | bellard | int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
298 | fc01f7e7 | bellard | const uint8_t *buf, int nb_sectors) |
299 | fc01f7e7 | bellard | { |
300 | 33e3963e | bellard | int ret, fd, i;
|
301 | 33e3963e | bellard | int64_t offset, retl; |
302 | cf98951b | bellard | |
303 | 0849bf08 | bellard | if (bs->read_only)
|
304 | 0849bf08 | bellard | return -1; |
305 | 0849bf08 | bellard | |
306 | 33e3963e | bellard | if (bs->cow_bitmap) {
|
307 | 33e3963e | bellard | fd = bs->cow_fd; |
308 | 33e3963e | bellard | offset = bs->cow_sectors_offset; |
309 | 33e3963e | bellard | } else {
|
310 | 33e3963e | bellard | fd = bs->fd; |
311 | 33e3963e | bellard | offset = 0;
|
312 | 33e3963e | bellard | } |
313 | 33e3963e | bellard | |
314 | 33e3963e | bellard | offset += sector_num * 512;
|
315 | 33e3963e | bellard | retl = lseek64(fd, offset, SEEK_SET); |
316 | 33e3963e | bellard | if (retl == -1) { |
317 | fc01f7e7 | bellard | return -1; |
318 | 33e3963e | bellard | } |
319 | 33e3963e | bellard | ret = write(fd, buf, nb_sectors * 512);
|
320 | 33e3963e | bellard | if (ret != nb_sectors * 512) { |
321 | 33e3963e | bellard | return -1; |
322 | 33e3963e | bellard | } |
323 | 33e3963e | bellard | |
324 | 33e3963e | bellard | if (bs->cow_bitmap) {
|
325 | 33e3963e | bellard | for (i = 0; i < nb_sectors; i++) |
326 | 33e3963e | bellard | set_bit(bs->cow_bitmap, sector_num + i); |
327 | 33e3963e | bellard | } |
328 | 33e3963e | bellard | return 0; |
329 | fc01f7e7 | bellard | } |
330 | fc01f7e7 | bellard | |
331 | fc01f7e7 | bellard | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
332 | fc01f7e7 | bellard | { |
333 | fc01f7e7 | bellard | *nb_sectors_ptr = bs->total_sectors; |
334 | fc01f7e7 | bellard | } |
335 | cf98951b | bellard | |
336 | cf98951b | bellard | /* force a given boot sector. */
|
337 | cf98951b | bellard | void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) |
338 | cf98951b | bellard | { |
339 | cf98951b | bellard | bs->boot_sector_enabled = 1;
|
340 | cf98951b | bellard | if (size > 512) |
341 | cf98951b | bellard | size = 512;
|
342 | cf98951b | bellard | memcpy(bs->boot_sector_data, data, size); |
343 | cf98951b | bellard | memset(bs->boot_sector_data + size, 0, 512 - size); |
344 | cf98951b | bellard | } |