Commit 33e3963e1b9298e01cadd738124f0e618b5b79f5
1 parent
cd4c3e88
added user mode Linux Copy On Write disk image support - added -snapshot support…
… (initial patch by Rusty Russell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@309 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
442 additions
and
44 deletions
Makefile
... | ... | @@ -28,7 +28,7 @@ else |
28 | 28 | LDFLAGS+=-Wl,-shared |
29 | 29 | endif |
30 | 30 | ifeq ($(TARGET_ARCH), i386) |
31 | -PROGS+=vl | |
31 | +PROGS+=vl vlmkcow | |
32 | 32 | endif |
33 | 33 | endif |
34 | 34 | |
... | ... | @@ -141,7 +141,10 @@ endif |
141 | 141 | |
142 | 142 | # must use static linking to avoid leaving stuff in virtual address space |
143 | 143 | vl: vl.o block.o libqemu.a |
144 | - $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) | |
144 | + $(CC) -pg -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) | |
145 | + | |
146 | +vlmkcow: vlmkcow.o | |
147 | + $(CC) -o $@ $^ $(LIBS) | |
145 | 148 | |
146 | 149 | depend: $(SRCS) |
147 | 150 | $(CC) -MM $(CFLAGS) $^ 1>.depend | ... | ... |
block.c
... | ... | @@ -38,76 +38,286 @@ |
38 | 38 | #include <sys/poll.h> |
39 | 39 | #include <errno.h> |
40 | 40 | #include <sys/wait.h> |
41 | +#include <netinet/in.h> | |
41 | 42 | |
42 | 43 | #include "vl.h" |
43 | 44 | |
45 | +#define NO_THUNK_TYPE_SIZE | |
46 | +#include "thunk.h" | |
47 | + | |
44 | 48 | struct BlockDriverState { |
45 | - int fd; | |
49 | + int fd; /* if -1, only COW mappings */ | |
46 | 50 | int64_t total_sectors; |
47 | 51 | int read_only; |
52 | + | |
53 | + uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ | |
54 | + uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ | |
55 | + int cow_bitmap_size; | |
56 | + int cow_fd; | |
57 | + int64_t cow_sectors_offset; | |
58 | + char filename[1024]; | |
48 | 59 | }; |
49 | 60 | |
50 | -BlockDriverState *bdrv_open(const char *filename) | |
61 | +BlockDriverState *bdrv_open(const char *filename, int snapshot) | |
51 | 62 | { |
52 | 63 | BlockDriverState *bs; |
53 | - int fd; | |
64 | + int fd, cow_fd; | |
54 | 65 | int64_t size; |
66 | + char template[] = "/tmp/vl.XXXXXX"; | |
67 | + struct cow_header_v2 cow_header; | |
68 | + struct stat st; | |
55 | 69 | |
56 | 70 | bs = malloc(sizeof(BlockDriverState)); |
57 | 71 | if(!bs) |
58 | 72 | return NULL; |
59 | 73 | bs->read_only = 0; |
60 | - fd = open(filename, O_RDWR); | |
74 | + bs->fd = -1; | |
75 | + bs->cow_fd = -1; | |
76 | + bs->cow_bitmap = NULL; | |
77 | + strcpy(bs->filename, filename); | |
78 | + | |
79 | + /* open standard HD image */ | |
80 | + fd = open(filename, O_RDWR | O_LARGEFILE); | |
61 | 81 | if (fd < 0) { |
62 | - fd = open(filename, O_RDONLY); | |
82 | + /* read only image on disk */ | |
83 | + fd = open(filename, O_RDONLY | O_LARGEFILE); | |
63 | 84 | if (fd < 0) { |
64 | - close(fd); | |
65 | - free(bs); | |
66 | - return NULL; | |
85 | + perror(filename); | |
86 | + goto fail; | |
67 | 87 | } |
68 | - bs->read_only = 1; | |
88 | + if (!snapshot) | |
89 | + bs->read_only = 1; | |
69 | 90 | } |
70 | - size = lseek64(fd, 0, SEEK_END); | |
71 | - bs->total_sectors = size / 512; | |
72 | 91 | bs->fd = fd; |
92 | + | |
93 | + /* see if it is a cow image */ | |
94 | + if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { | |
95 | + fprintf(stderr, "%s: could not read header\n", filename); | |
96 | + goto fail; | |
97 | + } | |
98 | + if (cow_header.magic == htonl(COW_MAGIC) && | |
99 | + cow_header.version == htonl(COW_VERSION)) { | |
100 | + /* cow image found */ | |
101 | + size = cow_header.size; | |
102 | +#ifndef WORDS_BIGENDIAN | |
103 | + size = bswap64(size); | |
104 | +#endif | |
105 | + bs->total_sectors = size / 512; | |
106 | + | |
107 | + bs->cow_fd = fd; | |
108 | + bs->fd = -1; | |
109 | + if (cow_header.backing_file[0] != '\0') { | |
110 | + if (stat(cow_header.backing_file, &st) != 0) { | |
111 | + fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); | |
112 | + goto fail; | |
113 | + } | |
114 | + if (st.st_mtime != htonl(cow_header.mtime)) { | |
115 | + fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); | |
116 | + goto fail; | |
117 | + } | |
118 | + fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); | |
119 | + if (fd < 0) | |
120 | + goto fail; | |
121 | + bs->fd = fd; | |
122 | + } | |
123 | + /* mmap the bitmap */ | |
124 | + bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); | |
125 | + bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), | |
126 | + bs->cow_bitmap_size, | |
127 | + PROT_READ | PROT_WRITE, | |
128 | + MAP_SHARED, bs->cow_fd, 0); | |
129 | + if (bs->cow_bitmap_addr == MAP_FAILED) | |
130 | + goto fail; | |
131 | + bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); | |
132 | + bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; | |
133 | + snapshot = 0; | |
134 | + } else { | |
135 | + /* standard raw image */ | |
136 | + size = lseek64(fd, 0, SEEK_END); | |
137 | + bs->total_sectors = size / 512; | |
138 | + bs->fd = fd; | |
139 | + } | |
140 | + | |
141 | + if (snapshot) { | |
142 | + /* create a temporary COW file */ | |
143 | + cow_fd = mkstemp(template); | |
144 | + if (cow_fd < 0) | |
145 | + goto fail; | |
146 | + bs->cow_fd = cow_fd; | |
147 | + unlink(template); | |
148 | + | |
149 | + /* just need to allocate bitmap */ | |
150 | + bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; | |
151 | + bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), | |
152 | + bs->cow_bitmap_size, | |
153 | + PROT_READ | PROT_WRITE, | |
154 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
155 | + if (bs->cow_bitmap_addr == MAP_FAILED) | |
156 | + goto fail; | |
157 | + bs->cow_bitmap = bs->cow_bitmap_addr; | |
158 | + bs->cow_sectors_offset = 0; | |
159 | + } | |
160 | + | |
73 | 161 | return bs; |
162 | + fail: | |
163 | + bdrv_close(bs); | |
164 | + return NULL; | |
74 | 165 | } |
75 | 166 | |
76 | 167 | void bdrv_close(BlockDriverState *bs) |
77 | 168 | { |
78 | - close(bs->fd); | |
169 | + /* we unmap the mapping so that it is written to the COW file */ | |
170 | + if (bs->cow_bitmap_addr) | |
171 | + munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); | |
172 | + if (bs->cow_fd >= 0) | |
173 | + close(bs->cow_fd); | |
174 | + if (bs->fd >= 0) | |
175 | + close(bs->fd); | |
79 | 176 | free(bs); |
80 | 177 | } |
81 | 178 | |
179 | +static inline void set_bit(uint8_t *bitmap, int64_t bitnum) | |
180 | +{ | |
181 | + bitmap[bitnum / 8] |= (1 << (bitnum%8)); | |
182 | +} | |
183 | + | |
184 | +static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) | |
185 | +{ | |
186 | + return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); | |
187 | +} | |
188 | + | |
189 | + | |
190 | +/* Return true if first block has been changed (ie. current version is | |
191 | + * in COW file). Set the number of continuous blocks for which that | |
192 | + * is true. */ | |
193 | +static int is_changed(uint8_t *bitmap, | |
194 | + int64_t sector_num, int nb_sectors, | |
195 | + int *num_same) | |
196 | +{ | |
197 | + int changed; | |
198 | + | |
199 | + if (!bitmap || nb_sectors == 0) { | |
200 | + *num_same = nb_sectors; | |
201 | + return 0; | |
202 | + } | |
203 | + | |
204 | + changed = is_bit_set(bitmap, sector_num); | |
205 | + for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { | |
206 | + if (is_bit_set(bitmap, sector_num + *num_same) != changed) | |
207 | + break; | |
208 | + } | |
209 | + | |
210 | + return changed; | |
211 | +} | |
212 | + | |
213 | +/* commit COW file into the raw image */ | |
214 | +int bdrv_commit(BlockDriverState *bs) | |
215 | +{ | |
216 | + int64_t i; | |
217 | + uint8_t *cow_bitmap; | |
218 | + | |
219 | + if (!bs->cow_bitmap) { | |
220 | + fprintf(stderr, "Already committed to %s\n", bs->filename); | |
221 | + return 0; | |
222 | + } | |
223 | + | |
224 | + if (bs->read_only) { | |
225 | + fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); | |
226 | + return -1; | |
227 | + } | |
228 | + | |
229 | + cow_bitmap = bs->cow_bitmap; | |
230 | + for (i = 0; i < bs->total_sectors; i++) { | |
231 | + if (is_bit_set(cow_bitmap, i)) { | |
232 | + unsigned char sector[512]; | |
233 | + if (bdrv_read(bs, i, sector, 1) != 0) { | |
234 | + fprintf(stderr, "Error reading sector %lli: aborting commit\n", | |
235 | + (long long)i); | |
236 | + return -1; | |
237 | + } | |
238 | + | |
239 | + /* Make bdrv_write write to real file for a moment. */ | |
240 | + bs->cow_bitmap = NULL; | |
241 | + if (bdrv_write(bs, i, sector, 1) != 0) { | |
242 | + fprintf(stderr, "Error writing sector %lli: aborting commit\n", | |
243 | + (long long)i); | |
244 | + bs->cow_bitmap = cow_bitmap; | |
245 | + return -1; | |
246 | + } | |
247 | + bs->cow_bitmap = cow_bitmap; | |
248 | + } | |
249 | + } | |
250 | + fprintf(stderr, "Committed snapshot to %s\n", bs->filename); | |
251 | + return 0; | |
252 | +} | |
253 | + | |
82 | 254 | /* return -1 if error */ |
83 | 255 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
84 | 256 | uint8_t *buf, int nb_sectors) |
85 | 257 | { |
86 | - int ret; | |
258 | + int ret, n, fd; | |
259 | + int64_t offset; | |
260 | + | |
261 | + while (nb_sectors > 0) { | |
262 | + if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { | |
263 | + fd = bs->cow_fd; | |
264 | + offset = bs->cow_sectors_offset; | |
265 | + } else { | |
266 | + fd = bs->fd; | |
267 | + offset = 0; | |
268 | + } | |
87 | 269 | |
88 | - lseek64(bs->fd, sector_num * 512, SEEK_SET); | |
89 | - ret = read(bs->fd, buf, nb_sectors * 512); | |
90 | - if (ret != nb_sectors * 512) | |
91 | - return -1; | |
92 | - else | |
93 | - return 0; | |
270 | + if (fd < 0) { | |
271 | + /* no file, just return empty sectors */ | |
272 | + memset(buf, 0, n * 512); | |
273 | + } else { | |
274 | + offset += sector_num * 512; | |
275 | + lseek64(fd, offset, SEEK_SET); | |
276 | + ret = read(fd, buf, n * 512); | |
277 | + if (ret != n * 512) { | |
278 | + return -1; | |
279 | + } | |
280 | + } | |
281 | + nb_sectors -= n; | |
282 | + sector_num += n; | |
283 | + buf += n * 512; | |
284 | + } | |
285 | + return 0; | |
94 | 286 | } |
95 | 287 | |
96 | 288 | /* return -1 if error */ |
97 | 289 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
98 | 290 | const uint8_t *buf, int nb_sectors) |
99 | 291 | { |
100 | - int ret; | |
292 | + int ret, fd, i; | |
293 | + int64_t offset, retl; | |
101 | 294 | |
102 | 295 | if (bs->read_only) |
103 | 296 | return -1; |
104 | 297 | |
105 | - lseek64(bs->fd, sector_num * 512, SEEK_SET); | |
106 | - ret = write(bs->fd, buf, nb_sectors * 512); | |
107 | - if (ret != nb_sectors * 512) | |
298 | + if (bs->cow_bitmap) { | |
299 | + fd = bs->cow_fd; | |
300 | + offset = bs->cow_sectors_offset; | |
301 | + } else { | |
302 | + fd = bs->fd; | |
303 | + offset = 0; | |
304 | + } | |
305 | + | |
306 | + offset += sector_num * 512; | |
307 | + retl = lseek64(fd, offset, SEEK_SET); | |
308 | + if (retl == -1) { | |
108 | 309 | return -1; |
109 | - else | |
110 | - return 0; | |
310 | + } | |
311 | + ret = write(fd, buf, nb_sectors * 512); | |
312 | + if (ret != nb_sectors * 512) { | |
313 | + return -1; | |
314 | + } | |
315 | + | |
316 | + if (bs->cow_bitmap) { | |
317 | + for (i = 0; i < nb_sectors; i++) | |
318 | + set_bit(bs->cow_bitmap, sector_num + i); | |
319 | + } | |
320 | + return 0; | |
111 | 321 | } |
112 | 322 | |
113 | 323 | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) | ... | ... |
vl.c
... | ... | @@ -63,6 +63,8 @@ |
63 | 63 | #define INITRD_LOAD_ADDR 0x00400000 |
64 | 64 | #define KERNEL_PARAMS_ADDR 0x00090000 |
65 | 65 | |
66 | +#define MAX_DISKS 2 | |
67 | + | |
66 | 68 | /* from plex86 (BSD license) */ |
67 | 69 | struct __attribute__ ((packed)) linux_params { |
68 | 70 | // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. |
... | ... | @@ -190,6 +192,7 @@ FILE *logfile = NULL; |
190 | 192 | int loglevel; |
191 | 193 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
192 | 194 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
195 | +BlockDriverState *bs_table[MAX_DISKS]; | |
193 | 196 | |
194 | 197 | /***********************************************************/ |
195 | 198 | /* x86 io ports */ |
... | ... | @@ -1265,6 +1268,7 @@ void term_print_help(void) |
1265 | 1268 | printf("\n" |
1266 | 1269 | "C-a h print this help\n" |
1267 | 1270 | "C-a x exit emulatior\n" |
1271 | + "C-a s save disk data back to file (if -snapshot)\n" | |
1268 | 1272 | "C-a b send break (magic sysrq)\n" |
1269 | 1273 | "C-a C-a send C-a\n" |
1270 | 1274 | ); |
... | ... | @@ -1282,6 +1286,15 @@ void serial_received_byte(SerialState *s, int ch) |
1282 | 1286 | case 'x': |
1283 | 1287 | exit(0); |
1284 | 1288 | break; |
1289 | + case 's': | |
1290 | + { | |
1291 | + int i; | |
1292 | + for (i = 0; i < MAX_DISKS; i++) { | |
1293 | + if (bs_table[i]) | |
1294 | + bdrv_commit(bs_table[i]); | |
1295 | + } | |
1296 | + } | |
1297 | + break; | |
1285 | 1298 | case 'b': |
1286 | 1299 | /* send break */ |
1287 | 1300 | s->rbr = 0; |
... | ... | @@ -1976,8 +1989,6 @@ void ne2000_init(void) |
1976 | 1989 | /* set to 1 set disable mult support */ |
1977 | 1990 | #define MAX_MULT_SECTORS 8 |
1978 | 1991 | |
1979 | -#define MAX_DISKS 2 | |
1980 | - | |
1981 | 1992 | struct IDEState; |
1982 | 1993 | |
1983 | 1994 | typedef void EndTransferFunc(struct IDEState *); |
... | ... | @@ -2009,7 +2020,6 @@ typedef struct IDEState { |
2009 | 2020 | uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; |
2010 | 2021 | } IDEState; |
2011 | 2022 | |
2012 | -BlockDriverState *bs_table[MAX_DISKS]; | |
2013 | 2023 | IDEState ide_state[MAX_DISKS]; |
2014 | 2024 | |
2015 | 2025 | static void padstr(char *str, const char *src, int len) |
... | ... | @@ -2513,6 +2523,16 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, |
2513 | 2523 | } |
2514 | 2524 | } |
2515 | 2525 | |
2526 | +unsigned long mmap_addr = PHYS_RAM_BASE; | |
2527 | + | |
2528 | +void *get_mmap_addr(unsigned long size) | |
2529 | +{ | |
2530 | + unsigned long addr; | |
2531 | + addr = mmap_addr; | |
2532 | + mmap_addr += ((size + 4095) & ~4095) + 4096; | |
2533 | + return (void *)addr; | |
2534 | +} | |
2535 | + | |
2516 | 2536 | /* main execution loop */ |
2517 | 2537 | |
2518 | 2538 | CPUState *cpu_gdbstub_get_env(void *opaque) |
... | ... | @@ -2612,6 +2632,7 @@ void help(void) |
2612 | 2632 | "-initrd file use 'file' as initial ram disk\n" |
2613 | 2633 | "-hda file use 'file' as hard disk 0 image\n" |
2614 | 2634 | "-hdb file use 'file' as hard disk 1 image\n" |
2635 | + "-snapshot write to temporary files instead of disk image files\n" | |
2615 | 2636 | "-m megs set virtual RAM size to megs MB\n" |
2616 | 2637 | "-n script set network init script [default=%s]\n" |
2617 | 2638 | "\n" |
... | ... | @@ -2630,12 +2651,14 @@ struct option long_options[] = { |
2630 | 2651 | { "initrd", 1, NULL, 0, }, |
2631 | 2652 | { "hda", 1, NULL, 0, }, |
2632 | 2653 | { "hdb", 1, NULL, 0, }, |
2654 | + { "snapshot", 0, NULL, 0, }, | |
2633 | 2655 | { NULL, 0, NULL, 0 }, |
2634 | 2656 | }; |
2635 | 2657 | |
2636 | 2658 | int main(int argc, char **argv) |
2637 | 2659 | { |
2638 | 2660 | int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; |
2661 | + int snapshot; | |
2639 | 2662 | struct linux_params *params; |
2640 | 2663 | struct sigaction act; |
2641 | 2664 | struct itimerval itv; |
... | ... | @@ -2652,6 +2675,7 @@ int main(int argc, char **argv) |
2652 | 2675 | pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); |
2653 | 2676 | use_gdbstub = 0; |
2654 | 2677 | gdbstub_port = DEFAULT_GDBSTUB_PORT; |
2678 | + snapshot = 0; | |
2655 | 2679 | for(;;) { |
2656 | 2680 | c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); |
2657 | 2681 | if (c == -1) |
... | ... | @@ -2668,6 +2692,9 @@ int main(int argc, char **argv) |
2668 | 2692 | case 2: |
2669 | 2693 | hd_filename[1] = optarg; |
2670 | 2694 | break; |
2695 | + case 3: | |
2696 | + snapshot = 1; | |
2697 | + break; | |
2671 | 2698 | } |
2672 | 2699 | break; |
2673 | 2700 | case 'h': |
... | ... | @@ -2711,18 +2738,6 @@ int main(int argc, char **argv) |
2711 | 2738 | setvbuf(logfile, NULL, _IOLBF, 0); |
2712 | 2739 | } |
2713 | 2740 | |
2714 | - /* open the virtual block devices */ | |
2715 | - for(i = 0; i < MAX_DISKS; i++) { | |
2716 | - if (hd_filename[i]) { | |
2717 | - bs_table[i] = bdrv_open(hd_filename[i]); | |
2718 | - if (!bs_table[i]) { | |
2719 | - fprintf(stderr, "vl: could not open hard disk image '%s\n", | |
2720 | - hd_filename[i]); | |
2721 | - exit(1); | |
2722 | - } | |
2723 | - } | |
2724 | - } | |
2725 | - | |
2726 | 2741 | /* init network tun interface */ |
2727 | 2742 | net_init(); |
2728 | 2743 | |
... | ... | @@ -2744,7 +2759,7 @@ int main(int argc, char **argv) |
2744 | 2759 | } |
2745 | 2760 | ftruncate(phys_ram_fd, phys_ram_size); |
2746 | 2761 | unlink(phys_ram_file); |
2747 | - phys_ram_base = mmap((void *)PHYS_RAM_BASE, phys_ram_size, | |
2762 | + phys_ram_base = mmap(get_mmap_addr(phys_ram_size), phys_ram_size, | |
2748 | 2763 | PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, |
2749 | 2764 | phys_ram_fd, 0); |
2750 | 2765 | if (phys_ram_base == MAP_FAILED) { |
... | ... | @@ -2752,6 +2767,18 @@ int main(int argc, char **argv) |
2752 | 2767 | exit(1); |
2753 | 2768 | } |
2754 | 2769 | |
2770 | + /* open the virtual block devices */ | |
2771 | + for(i = 0; i < MAX_DISKS; i++) { | |
2772 | + if (hd_filename[i]) { | |
2773 | + bs_table[i] = bdrv_open(hd_filename[i], snapshot); | |
2774 | + if (!bs_table[i]) { | |
2775 | + fprintf(stderr, "vl: could not open hard disk image '%s\n", | |
2776 | + hd_filename[i]); | |
2777 | + exit(1); | |
2778 | + } | |
2779 | + } | |
2780 | + } | |
2781 | + | |
2755 | 2782 | /* now we can load the kernel */ |
2756 | 2783 | ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); |
2757 | 2784 | if (ret < 0) { | ... | ... |
vl.h
... | ... | @@ -24,16 +24,32 @@ |
24 | 24 | #ifndef VL_H |
25 | 25 | #define VL_H |
26 | 26 | |
27 | +/* vl.c */ | |
28 | +void *get_mmap_addr(unsigned long size); | |
29 | + | |
27 | 30 | /* block.c */ |
28 | 31 | typedef struct BlockDriverState BlockDriverState; |
29 | 32 | |
30 | -BlockDriverState *bdrv_open(const char *filename); | |
33 | +BlockDriverState *bdrv_open(const char *filename, int snapshot); | |
31 | 34 | void bdrv_close(BlockDriverState *bs); |
32 | 35 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
33 | 36 | uint8_t *buf, int nb_sectors); |
34 | 37 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
35 | 38 | const uint8_t *buf, int nb_sectors); |
36 | 39 | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); |
40 | +int bdrv_commit(BlockDriverState *bs); | |
41 | + | |
42 | +/* user mode linux compatible COW file */ | |
43 | +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ | |
44 | +#define COW_VERSION 2 | |
37 | 45 | |
46 | +struct cow_header_v2 { | |
47 | + uint32_t magic; | |
48 | + uint32_t long version; | |
49 | + char backing_file[1024]; | |
50 | + int32_t mtime; | |
51 | + uint64_t size; | |
52 | + uint32_t sectorsize; | |
53 | +}; | |
38 | 54 | |
39 | 55 | #endif /* VL_H */ | ... | ... |
vlmkcow.c
0 → 100644
1 | +/* | |
2 | + * create a COW disk image | |
3 | + * | |
4 | + * Copyright (c) 2003 Fabrice Bellard | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | +#include <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "vl.h" | |
44 | + | |
45 | +#define NO_THUNK_TYPE_SIZE | |
46 | +#include "thunk.h" | |
47 | + | |
48 | +int cow_create(int cow_fd, const char *image_filename, | |
49 | + int64_t image_sectors) | |
50 | +{ | |
51 | + struct cow_header_v2 cow_header; | |
52 | + int fd; | |
53 | + struct stat st; | |
54 | + | |
55 | + memset(&cow_header, 0, sizeof(cow_header)); | |
56 | + cow_header.magic = htonl(COW_MAGIC); | |
57 | + cow_header.version = htonl(COW_VERSION); | |
58 | + if (image_filename) { | |
59 | + fd = open(image_filename, O_RDONLY); | |
60 | + if (fd < 0) { | |
61 | + perror(image_filename); | |
62 | + exit(1); | |
63 | + } | |
64 | + image_sectors = lseek64(fd, 0, SEEK_END); | |
65 | + if (fstat(fd, &st) != 0) { | |
66 | + close(fd); | |
67 | + return -1; | |
68 | + } | |
69 | + close(fd); | |
70 | + image_sectors /= 512; | |
71 | + cow_header.mtime = htonl(st.st_mtime); | |
72 | + realpath(image_filename, cow_header.backing_file); | |
73 | + } | |
74 | + cow_header.sectorsize = htonl(512); | |
75 | + cow_header.size = image_sectors * 512; | |
76 | +#ifndef WORDS_BIGENDIAN | |
77 | + cow_header.size = bswap64(cow_header.size); | |
78 | +#endif | |
79 | + write(cow_fd, &cow_header, sizeof(cow_header)); | |
80 | + /* resize to include at least all the bitmap */ | |
81 | + ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); | |
82 | + lseek(cow_fd, 0, SEEK_SET); | |
83 | + return 0; | |
84 | +} | |
85 | + | |
86 | +void help(void) | |
87 | +{ | |
88 | + printf("usage vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" | |
89 | + "Create a Copy On Write disk image from an optional raw disk image\n" | |
90 | + "\n" | |
91 | + "-f disk_image set the raw disk image name\n" | |
92 | + "cow_image the created cow_image\n" | |
93 | + "cow_size the create cow_image size in MB if no raw disk image is used\n" | |
94 | + "\n" | |
95 | + "Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" | |
96 | + ); | |
97 | + exit(1); | |
98 | +} | |
99 | + | |
100 | +int main(int argc, char **argv) | |
101 | +{ | |
102 | + const char *image_filename, *cow_filename; | |
103 | + int cow_fd, c, nb_args; | |
104 | + int64_t image_size; | |
105 | + | |
106 | + image_filename = NULL; | |
107 | + image_size = 0; | |
108 | + for(;;) { | |
109 | + c = getopt(argc, argv, "hf:"); | |
110 | + if (c == -1) | |
111 | + break; | |
112 | + switch(c) { | |
113 | + case 'h': | |
114 | + help(); | |
115 | + break; | |
116 | + case 'f': | |
117 | + image_filename = optarg; | |
118 | + break; | |
119 | + } | |
120 | + } | |
121 | + if (!image_filename) | |
122 | + nb_args = 2; | |
123 | + else | |
124 | + nb_args = 1; | |
125 | + if (optind + nb_args != argc) | |
126 | + help(); | |
127 | + | |
128 | + cow_filename = argv[optind]; | |
129 | + if (nb_args == 2) { | |
130 | + image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; | |
131 | + } | |
132 | + | |
133 | + cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); | |
134 | + if (!cow_fd < 0) | |
135 | + return -1; | |
136 | + if (cow_create(cow_fd, image_filename, image_size) < 0) { | |
137 | + fprintf(stderr, "%s: error while formating\n", cow_filename); | |
138 | + exit(1); | |
139 | + } | |
140 | + close(cow_fd); | |
141 | + return 0; | |
142 | +} | ... | ... |