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 | +} | ... | ... |