root / block.c @ 6c9bf893
History | View | Annotate | Download (9.1 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 | 33e3963e | bellard | char filename[1024]; |
59 | fc01f7e7 | bellard | }; |
60 | fc01f7e7 | bellard | |
61 | 33e3963e | bellard | BlockDriverState *bdrv_open(const char *filename, int snapshot) |
62 | fc01f7e7 | bellard | { |
63 | fc01f7e7 | bellard | BlockDriverState *bs; |
64 | 33e3963e | bellard | int fd, cow_fd;
|
65 | fc01f7e7 | bellard | int64_t size; |
66 | 33e3963e | bellard | char template[] = "/tmp/vl.XXXXXX"; |
67 | 33e3963e | bellard | struct cow_header_v2 cow_header;
|
68 | 33e3963e | bellard | struct stat st;
|
69 | fc01f7e7 | bellard | |
70 | fc01f7e7 | bellard | bs = malloc(sizeof(BlockDriverState));
|
71 | fc01f7e7 | bellard | if(!bs)
|
72 | fc01f7e7 | bellard | return NULL; |
73 | 0849bf08 | bellard | bs->read_only = 0;
|
74 | 33e3963e | bellard | bs->fd = -1;
|
75 | 33e3963e | bellard | bs->cow_fd = -1;
|
76 | 33e3963e | bellard | bs->cow_bitmap = NULL;
|
77 | 33e3963e | bellard | strcpy(bs->filename, filename); |
78 | 33e3963e | bellard | |
79 | 33e3963e | bellard | /* open standard HD image */
|
80 | 33e3963e | bellard | fd = open(filename, O_RDWR | O_LARGEFILE); |
81 | fc01f7e7 | bellard | if (fd < 0) { |
82 | 33e3963e | bellard | /* read only image on disk */
|
83 | 33e3963e | bellard | fd = open(filename, O_RDONLY | O_LARGEFILE); |
84 | 0849bf08 | bellard | if (fd < 0) { |
85 | 33e3963e | bellard | perror(filename); |
86 | 33e3963e | bellard | goto fail;
|
87 | 0849bf08 | bellard | } |
88 | 33e3963e | bellard | if (!snapshot)
|
89 | 33e3963e | bellard | bs->read_only = 1;
|
90 | fc01f7e7 | bellard | } |
91 | fc01f7e7 | bellard | bs->fd = fd; |
92 | 33e3963e | bellard | |
93 | 33e3963e | bellard | /* see if it is a cow image */
|
94 | 33e3963e | bellard | if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { |
95 | 33e3963e | bellard | fprintf(stderr, "%s: could not read header\n", filename);
|
96 | 33e3963e | bellard | goto fail;
|
97 | 33e3963e | bellard | } |
98 | 33e3963e | bellard | if (cow_header.magic == htonl(COW_MAGIC) &&
|
99 | 33e3963e | bellard | cow_header.version == htonl(COW_VERSION)) { |
100 | 33e3963e | bellard | /* cow image found */
|
101 | 33e3963e | bellard | size = cow_header.size; |
102 | 33e3963e | bellard | #ifndef WORDS_BIGENDIAN
|
103 | 33e3963e | bellard | size = bswap64(size); |
104 | 33e3963e | bellard | #endif
|
105 | 33e3963e | bellard | bs->total_sectors = size / 512;
|
106 | 33e3963e | bellard | |
107 | 33e3963e | bellard | bs->cow_fd = fd; |
108 | 33e3963e | bellard | bs->fd = -1;
|
109 | 33e3963e | bellard | if (cow_header.backing_file[0] != '\0') { |
110 | 33e3963e | bellard | if (stat(cow_header.backing_file, &st) != 0) { |
111 | 33e3963e | bellard | fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
112 | 33e3963e | bellard | goto fail;
|
113 | 33e3963e | bellard | } |
114 | 33e3963e | bellard | if (st.st_mtime != htonl(cow_header.mtime)) {
|
115 | 33e3963e | bellard | fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
116 | 33e3963e | bellard | goto fail;
|
117 | 33e3963e | bellard | } |
118 | 33e3963e | bellard | fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); |
119 | 33e3963e | bellard | if (fd < 0) |
120 | 33e3963e | bellard | goto fail;
|
121 | 33e3963e | bellard | bs->fd = fd; |
122 | 33e3963e | bellard | } |
123 | 33e3963e | bellard | /* mmap the bitmap */
|
124 | 33e3963e | bellard | bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
125 | 33e3963e | bellard | bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
126 | 33e3963e | bellard | bs->cow_bitmap_size, |
127 | 33e3963e | bellard | PROT_READ | PROT_WRITE, |
128 | 33e3963e | bellard | MAP_SHARED, bs->cow_fd, 0);
|
129 | 33e3963e | bellard | if (bs->cow_bitmap_addr == MAP_FAILED)
|
130 | 33e3963e | bellard | goto fail;
|
131 | 33e3963e | bellard | bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
132 | 33e3963e | bellard | bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; |
133 | 33e3963e | bellard | snapshot = 0;
|
134 | 33e3963e | bellard | } else {
|
135 | 33e3963e | bellard | /* standard raw image */
|
136 | 33e3963e | bellard | size = lseek64(fd, 0, SEEK_END);
|
137 | 33e3963e | bellard | bs->total_sectors = size / 512;
|
138 | 33e3963e | bellard | bs->fd = fd; |
139 | 33e3963e | bellard | } |
140 | 33e3963e | bellard | |
141 | 33e3963e | bellard | if (snapshot) {
|
142 | 33e3963e | bellard | /* create a temporary COW file */
|
143 | 33e3963e | bellard | cow_fd = mkstemp(template); |
144 | 33e3963e | bellard | if (cow_fd < 0) |
145 | 33e3963e | bellard | goto fail;
|
146 | 33e3963e | bellard | bs->cow_fd = cow_fd; |
147 | 33e3963e | bellard | unlink(template); |
148 | 33e3963e | bellard | |
149 | 33e3963e | bellard | /* just need to allocate bitmap */
|
150 | 33e3963e | bellard | bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; |
151 | 33e3963e | bellard | bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
152 | 33e3963e | bellard | bs->cow_bitmap_size, |
153 | 33e3963e | bellard | PROT_READ | PROT_WRITE, |
154 | 33e3963e | bellard | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
155 | 33e3963e | bellard | if (bs->cow_bitmap_addr == MAP_FAILED)
|
156 | 33e3963e | bellard | goto fail;
|
157 | 33e3963e | bellard | bs->cow_bitmap = bs->cow_bitmap_addr; |
158 | 33e3963e | bellard | bs->cow_sectors_offset = 0;
|
159 | 33e3963e | bellard | } |
160 | 33e3963e | bellard | |
161 | fc01f7e7 | bellard | return bs;
|
162 | 33e3963e | bellard | fail:
|
163 | 33e3963e | bellard | bdrv_close(bs); |
164 | 33e3963e | bellard | return NULL; |
165 | fc01f7e7 | bellard | } |
166 | fc01f7e7 | bellard | |
167 | fc01f7e7 | bellard | void bdrv_close(BlockDriverState *bs)
|
168 | fc01f7e7 | bellard | { |
169 | 33e3963e | bellard | /* we unmap the mapping so that it is written to the COW file */
|
170 | 33e3963e | bellard | if (bs->cow_bitmap_addr)
|
171 | 33e3963e | bellard | munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); |
172 | 33e3963e | bellard | if (bs->cow_fd >= 0) |
173 | 33e3963e | bellard | close(bs->cow_fd); |
174 | 33e3963e | bellard | if (bs->fd >= 0) |
175 | 33e3963e | bellard | close(bs->fd); |
176 | fc01f7e7 | bellard | free(bs); |
177 | fc01f7e7 | bellard | } |
178 | fc01f7e7 | bellard | |
179 | 33e3963e | bellard | static inline void set_bit(uint8_t *bitmap, int64_t bitnum) |
180 | 33e3963e | bellard | { |
181 | 33e3963e | bellard | bitmap[bitnum / 8] |= (1 << (bitnum%8)); |
182 | 33e3963e | bellard | } |
183 | 33e3963e | bellard | |
184 | 33e3963e | bellard | static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) |
185 | 33e3963e | bellard | { |
186 | 33e3963e | bellard | return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); |
187 | 33e3963e | bellard | } |
188 | 33e3963e | bellard | |
189 | 33e3963e | bellard | |
190 | 33e3963e | bellard | /* Return true if first block has been changed (ie. current version is
|
191 | 33e3963e | bellard | * in COW file). Set the number of continuous blocks for which that
|
192 | 33e3963e | bellard | * is true. */
|
193 | 33e3963e | bellard | static int is_changed(uint8_t *bitmap, |
194 | 33e3963e | bellard | int64_t sector_num, int nb_sectors,
|
195 | 33e3963e | bellard | int *num_same)
|
196 | 33e3963e | bellard | { |
197 | 33e3963e | bellard | int changed;
|
198 | 33e3963e | bellard | |
199 | 33e3963e | bellard | if (!bitmap || nb_sectors == 0) { |
200 | 33e3963e | bellard | *num_same = nb_sectors; |
201 | 33e3963e | bellard | return 0; |
202 | 33e3963e | bellard | } |
203 | 33e3963e | bellard | |
204 | 33e3963e | bellard | changed = is_bit_set(bitmap, sector_num); |
205 | 33e3963e | bellard | for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { |
206 | 33e3963e | bellard | if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
207 | 33e3963e | bellard | break;
|
208 | 33e3963e | bellard | } |
209 | 33e3963e | bellard | |
210 | 33e3963e | bellard | return changed;
|
211 | 33e3963e | bellard | } |
212 | 33e3963e | bellard | |
213 | 33e3963e | bellard | /* commit COW file into the raw image */
|
214 | 33e3963e | bellard | int bdrv_commit(BlockDriverState *bs)
|
215 | 33e3963e | bellard | { |
216 | 33e3963e | bellard | int64_t i; |
217 | 33e3963e | bellard | uint8_t *cow_bitmap; |
218 | 33e3963e | bellard | |
219 | 33e3963e | bellard | if (!bs->cow_bitmap) {
|
220 | 33e3963e | bellard | fprintf(stderr, "Already committed to %s\n", bs->filename);
|
221 | 33e3963e | bellard | return 0; |
222 | 33e3963e | bellard | } |
223 | 33e3963e | bellard | |
224 | 33e3963e | bellard | if (bs->read_only) {
|
225 | 33e3963e | bellard | fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
|
226 | 33e3963e | bellard | return -1; |
227 | 33e3963e | bellard | } |
228 | 33e3963e | bellard | |
229 | 33e3963e | bellard | cow_bitmap = bs->cow_bitmap; |
230 | 33e3963e | bellard | for (i = 0; i < bs->total_sectors; i++) { |
231 | 33e3963e | bellard | if (is_bit_set(cow_bitmap, i)) {
|
232 | 33e3963e | bellard | unsigned char sector[512]; |
233 | 33e3963e | bellard | if (bdrv_read(bs, i, sector, 1) != 0) { |
234 | 33e3963e | bellard | fprintf(stderr, "Error reading sector %lli: aborting commit\n",
|
235 | 33e3963e | bellard | (long long)i); |
236 | 33e3963e | bellard | return -1; |
237 | 33e3963e | bellard | } |
238 | 33e3963e | bellard | |
239 | 33e3963e | bellard | /* Make bdrv_write write to real file for a moment. */
|
240 | 33e3963e | bellard | bs->cow_bitmap = NULL;
|
241 | 33e3963e | bellard | if (bdrv_write(bs, i, sector, 1) != 0) { |
242 | 33e3963e | bellard | fprintf(stderr, "Error writing sector %lli: aborting commit\n",
|
243 | 33e3963e | bellard | (long long)i); |
244 | 33e3963e | bellard | bs->cow_bitmap = cow_bitmap; |
245 | 33e3963e | bellard | return -1; |
246 | 33e3963e | bellard | } |
247 | 33e3963e | bellard | bs->cow_bitmap = cow_bitmap; |
248 | 33e3963e | bellard | } |
249 | 33e3963e | bellard | } |
250 | 33e3963e | bellard | fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
|
251 | 33e3963e | bellard | return 0; |
252 | 33e3963e | bellard | } |
253 | 33e3963e | bellard | |
254 | fc01f7e7 | bellard | /* return -1 if error */
|
255 | fc01f7e7 | bellard | int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
256 | fc01f7e7 | bellard | uint8_t *buf, int nb_sectors)
|
257 | fc01f7e7 | bellard | { |
258 | 33e3963e | bellard | int ret, n, fd;
|
259 | 33e3963e | bellard | int64_t offset; |
260 | 33e3963e | bellard | |
261 | 33e3963e | bellard | while (nb_sectors > 0) { |
262 | 33e3963e | bellard | if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
263 | 33e3963e | bellard | fd = bs->cow_fd; |
264 | 33e3963e | bellard | offset = bs->cow_sectors_offset; |
265 | 33e3963e | bellard | } else {
|
266 | 33e3963e | bellard | fd = bs->fd; |
267 | 33e3963e | bellard | offset = 0;
|
268 | 33e3963e | bellard | } |
269 | fc01f7e7 | bellard | |
270 | 33e3963e | bellard | if (fd < 0) { |
271 | 33e3963e | bellard | /* no file, just return empty sectors */
|
272 | 33e3963e | bellard | memset(buf, 0, n * 512); |
273 | 33e3963e | bellard | } else {
|
274 | 33e3963e | bellard | offset += sector_num * 512;
|
275 | 33e3963e | bellard | lseek64(fd, offset, SEEK_SET); |
276 | 33e3963e | bellard | ret = read(fd, buf, n * 512);
|
277 | 33e3963e | bellard | if (ret != n * 512) { |
278 | 33e3963e | bellard | return -1; |
279 | 33e3963e | bellard | } |
280 | 33e3963e | bellard | } |
281 | 33e3963e | bellard | nb_sectors -= n; |
282 | 33e3963e | bellard | sector_num += n; |
283 | 33e3963e | bellard | buf += n * 512;
|
284 | 33e3963e | bellard | } |
285 | 33e3963e | bellard | return 0; |
286 | fc01f7e7 | bellard | } |
287 | fc01f7e7 | bellard | |
288 | fc01f7e7 | bellard | /* return -1 if error */
|
289 | fc01f7e7 | bellard | int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
290 | fc01f7e7 | bellard | const uint8_t *buf, int nb_sectors) |
291 | fc01f7e7 | bellard | { |
292 | 33e3963e | bellard | int ret, fd, i;
|
293 | 33e3963e | bellard | int64_t offset, retl; |
294 | fc01f7e7 | bellard | |
295 | 0849bf08 | bellard | if (bs->read_only)
|
296 | 0849bf08 | bellard | return -1; |
297 | 0849bf08 | bellard | |
298 | 33e3963e | bellard | if (bs->cow_bitmap) {
|
299 | 33e3963e | bellard | fd = bs->cow_fd; |
300 | 33e3963e | bellard | offset = bs->cow_sectors_offset; |
301 | 33e3963e | bellard | } else {
|
302 | 33e3963e | bellard | fd = bs->fd; |
303 | 33e3963e | bellard | offset = 0;
|
304 | 33e3963e | bellard | } |
305 | 33e3963e | bellard | |
306 | 33e3963e | bellard | offset += sector_num * 512;
|
307 | 33e3963e | bellard | retl = lseek64(fd, offset, SEEK_SET); |
308 | 33e3963e | bellard | if (retl == -1) { |
309 | fc01f7e7 | bellard | return -1; |
310 | 33e3963e | bellard | } |
311 | 33e3963e | bellard | ret = write(fd, buf, nb_sectors * 512);
|
312 | 33e3963e | bellard | if (ret != nb_sectors * 512) { |
313 | 33e3963e | bellard | return -1; |
314 | 33e3963e | bellard | } |
315 | 33e3963e | bellard | |
316 | 33e3963e | bellard | if (bs->cow_bitmap) {
|
317 | 33e3963e | bellard | for (i = 0; i < nb_sectors; i++) |
318 | 33e3963e | bellard | set_bit(bs->cow_bitmap, sector_num + i); |
319 | 33e3963e | bellard | } |
320 | 33e3963e | bellard | return 0; |
321 | fc01f7e7 | bellard | } |
322 | fc01f7e7 | bellard | |
323 | fc01f7e7 | bellard | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
324 | fc01f7e7 | bellard | { |
325 | fc01f7e7 | bellard | *nb_sectors_ptr = bs->total_sectors; |
326 | fc01f7e7 | bellard | } |