Commit 33e3963e1b9298e01cadd738124f0e618b5b79f5

Authored by bellard
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
Makefile
@@ -28,7 +28,7 @@ else @@ -28,7 +28,7 @@ else
28 LDFLAGS+=-Wl,-shared 28 LDFLAGS+=-Wl,-shared
29 endif 29 endif
30 ifeq ($(TARGET_ARCH), i386) 30 ifeq ($(TARGET_ARCH), i386)
31 -PROGS+=vl 31 +PROGS+=vl vlmkcow
32 endif 32 endif
33 endif 33 endif
34 34
@@ -141,7 +141,10 @@ endif @@ -141,7 +141,10 @@ endif
141 141
142 # must use static linking to avoid leaving stuff in virtual address space 142 # must use static linking to avoid leaving stuff in virtual address space
143 vl: vl.o block.o libqemu.a 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 depend: $(SRCS) 149 depend: $(SRCS)
147 $(CC) -MM $(CFLAGS) $^ 1>.depend 150 $(CC) -MM $(CFLAGS) $^ 1>.depend
@@ -38,76 +38,286 @@ @@ -38,76 +38,286 @@
38 #include <sys/poll.h> 38 #include <sys/poll.h>
39 #include <errno.h> 39 #include <errno.h>
40 #include <sys/wait.h> 40 #include <sys/wait.h>
  41 +#include <netinet/in.h>
41 42
42 #include "vl.h" 43 #include "vl.h"
43 44
  45 +#define NO_THUNK_TYPE_SIZE
  46 +#include "thunk.h"
  47 +
44 struct BlockDriverState { 48 struct BlockDriverState {
45 - int fd; 49 + int fd; /* if -1, only COW mappings */
46 int64_t total_sectors; 50 int64_t total_sectors;
47 int read_only; 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 BlockDriverState *bs; 63 BlockDriverState *bs;
53 - int fd; 64 + int fd, cow_fd;
54 int64_t size; 65 int64_t size;
  66 + char template[] = "/tmp/vl.XXXXXX";
  67 + struct cow_header_v2 cow_header;
  68 + struct stat st;
55 69
56 bs = malloc(sizeof(BlockDriverState)); 70 bs = malloc(sizeof(BlockDriverState));
57 if(!bs) 71 if(!bs)
58 return NULL; 72 return NULL;
59 bs->read_only = 0; 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 if (fd < 0) { 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 if (fd < 0) { 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 bs->fd = fd; 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 return bs; 161 return bs;
  162 + fail:
  163 + bdrv_close(bs);
  164 + return NULL;
74 } 165 }
75 166
76 void bdrv_close(BlockDriverState *bs) 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 free(bs); 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 /* return -1 if error */ 254 /* return -1 if error */
83 int bdrv_read(BlockDriverState *bs, int64_t sector_num, 255 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
84 uint8_t *buf, int nb_sectors) 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 /* return -1 if error */ 288 /* return -1 if error */
97 int bdrv_write(BlockDriverState *bs, int64_t sector_num, 289 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
98 const uint8_t *buf, int nb_sectors) 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 if (bs->read_only) 295 if (bs->read_only)
103 return -1; 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 return -1; 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 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 323 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
@@ -63,6 +63,8 @@ @@ -63,6 +63,8 @@
63 #define INITRD_LOAD_ADDR 0x00400000 63 #define INITRD_LOAD_ADDR 0x00400000
64 #define KERNEL_PARAMS_ADDR 0x00090000 64 #define KERNEL_PARAMS_ADDR 0x00090000
65 65
  66 +#define MAX_DISKS 2
  67 +
66 /* from plex86 (BSD license) */ 68 /* from plex86 (BSD license) */
67 struct __attribute__ ((packed)) linux_params { 69 struct __attribute__ ((packed)) linux_params {
68 // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. 70 // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h.
@@ -190,6 +192,7 @@ FILE *logfile = NULL; @@ -190,6 +192,7 @@ FILE *logfile = NULL;
190 int loglevel; 192 int loglevel;
191 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; 193 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
192 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; 194 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
  195 +BlockDriverState *bs_table[MAX_DISKS];
193 196
194 /***********************************************************/ 197 /***********************************************************/
195 /* x86 io ports */ 198 /* x86 io ports */
@@ -1265,6 +1268,7 @@ void term_print_help(void) @@ -1265,6 +1268,7 @@ void term_print_help(void)
1265 printf("\n" 1268 printf("\n"
1266 "C-a h print this help\n" 1269 "C-a h print this help\n"
1267 "C-a x exit emulatior\n" 1270 "C-a x exit emulatior\n"
  1271 + "C-a s save disk data back to file (if -snapshot)\n"
1268 "C-a b send break (magic sysrq)\n" 1272 "C-a b send break (magic sysrq)\n"
1269 "C-a C-a send C-a\n" 1273 "C-a C-a send C-a\n"
1270 ); 1274 );
@@ -1282,6 +1286,15 @@ void serial_received_byte(SerialState *s, int ch) @@ -1282,6 +1286,15 @@ void serial_received_byte(SerialState *s, int ch)
1282 case 'x': 1286 case 'x':
1283 exit(0); 1287 exit(0);
1284 break; 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 case 'b': 1298 case 'b':
1286 /* send break */ 1299 /* send break */
1287 s->rbr = 0; 1300 s->rbr = 0;
@@ -1976,8 +1989,6 @@ void ne2000_init(void) @@ -1976,8 +1989,6 @@ void ne2000_init(void)
1976 /* set to 1 set disable mult support */ 1989 /* set to 1 set disable mult support */
1977 #define MAX_MULT_SECTORS 8 1990 #define MAX_MULT_SECTORS 8
1978 1991
1979 -#define MAX_DISKS 2  
1980 -  
1981 struct IDEState; 1992 struct IDEState;
1982 1993
1983 typedef void EndTransferFunc(struct IDEState *); 1994 typedef void EndTransferFunc(struct IDEState *);
@@ -2009,7 +2020,6 @@ typedef struct IDEState { @@ -2009,7 +2020,6 @@ typedef struct IDEState {
2009 uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; 2020 uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
2010 } IDEState; 2021 } IDEState;
2011 2022
2012 -BlockDriverState *bs_table[MAX_DISKS];  
2013 IDEState ide_state[MAX_DISKS]; 2023 IDEState ide_state[MAX_DISKS];
2014 2024
2015 static void padstr(char *str, const char *src, int len) 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,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 /* main execution loop */ 2536 /* main execution loop */
2517 2537
2518 CPUState *cpu_gdbstub_get_env(void *opaque) 2538 CPUState *cpu_gdbstub_get_env(void *opaque)
@@ -2612,6 +2632,7 @@ void help(void) @@ -2612,6 +2632,7 @@ void help(void)
2612 "-initrd file use 'file' as initial ram disk\n" 2632 "-initrd file use 'file' as initial ram disk\n"
2613 "-hda file use 'file' as hard disk 0 image\n" 2633 "-hda file use 'file' as hard disk 0 image\n"
2614 "-hdb file use 'file' as hard disk 1 image\n" 2634 "-hdb file use 'file' as hard disk 1 image\n"
  2635 + "-snapshot write to temporary files instead of disk image files\n"
2615 "-m megs set virtual RAM size to megs MB\n" 2636 "-m megs set virtual RAM size to megs MB\n"
2616 "-n script set network init script [default=%s]\n" 2637 "-n script set network init script [default=%s]\n"
2617 "\n" 2638 "\n"
@@ -2630,12 +2651,14 @@ struct option long_options[] = { @@ -2630,12 +2651,14 @@ struct option long_options[] = {
2630 { "initrd", 1, NULL, 0, }, 2651 { "initrd", 1, NULL, 0, },
2631 { "hda", 1, NULL, 0, }, 2652 { "hda", 1, NULL, 0, },
2632 { "hdb", 1, NULL, 0, }, 2653 { "hdb", 1, NULL, 0, },
  2654 + { "snapshot", 0, NULL, 0, },
2633 { NULL, 0, NULL, 0 }, 2655 { NULL, 0, NULL, 0 },
2634 }; 2656 };
2635 2657
2636 int main(int argc, char **argv) 2658 int main(int argc, char **argv)
2637 { 2659 {
2638 int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; 2660 int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index;
  2661 + int snapshot;
2639 struct linux_params *params; 2662 struct linux_params *params;
2640 struct sigaction act; 2663 struct sigaction act;
2641 struct itimerval itv; 2664 struct itimerval itv;
@@ -2652,6 +2675,7 @@ int main(int argc, char **argv) @@ -2652,6 +2675,7 @@ int main(int argc, char **argv)
2652 pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); 2675 pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
2653 use_gdbstub = 0; 2676 use_gdbstub = 0;
2654 gdbstub_port = DEFAULT_GDBSTUB_PORT; 2677 gdbstub_port = DEFAULT_GDBSTUB_PORT;
  2678 + snapshot = 0;
2655 for(;;) { 2679 for(;;) {
2656 c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); 2680 c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index);
2657 if (c == -1) 2681 if (c == -1)
@@ -2668,6 +2692,9 @@ int main(int argc, char **argv) @@ -2668,6 +2692,9 @@ int main(int argc, char **argv)
2668 case 2: 2692 case 2:
2669 hd_filename[1] = optarg; 2693 hd_filename[1] = optarg;
2670 break; 2694 break;
  2695 + case 3:
  2696 + snapshot = 1;
  2697 + break;
2671 } 2698 }
2672 break; 2699 break;
2673 case 'h': 2700 case 'h':
@@ -2711,18 +2738,6 @@ int main(int argc, char **argv) @@ -2711,18 +2738,6 @@ int main(int argc, char **argv)
2711 setvbuf(logfile, NULL, _IOLBF, 0); 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 /* init network tun interface */ 2741 /* init network tun interface */
2727 net_init(); 2742 net_init();
2728 2743
@@ -2744,7 +2759,7 @@ int main(int argc, char **argv) @@ -2744,7 +2759,7 @@ int main(int argc, char **argv)
2744 } 2759 }
2745 ftruncate(phys_ram_fd, phys_ram_size); 2760 ftruncate(phys_ram_fd, phys_ram_size);
2746 unlink(phys_ram_file); 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 PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, 2763 PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED,
2749 phys_ram_fd, 0); 2764 phys_ram_fd, 0);
2750 if (phys_ram_base == MAP_FAILED) { 2765 if (phys_ram_base == MAP_FAILED) {
@@ -2752,6 +2767,18 @@ int main(int argc, char **argv) @@ -2752,6 +2767,18 @@ int main(int argc, char **argv)
2752 exit(1); 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 /* now we can load the kernel */ 2782 /* now we can load the kernel */
2756 ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); 2783 ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR);
2757 if (ret < 0) { 2784 if (ret < 0) {
@@ -24,16 +24,32 @@ @@ -24,16 +24,32 @@
24 #ifndef VL_H 24 #ifndef VL_H
25 #define VL_H 25 #define VL_H
26 26
  27 +/* vl.c */
  28 +void *get_mmap_addr(unsigned long size);
  29 +
27 /* block.c */ 30 /* block.c */
28 typedef struct BlockDriverState BlockDriverState; 31 typedef struct BlockDriverState BlockDriverState;
29 32
30 -BlockDriverState *bdrv_open(const char *filename); 33 +BlockDriverState *bdrv_open(const char *filename, int snapshot);
31 void bdrv_close(BlockDriverState *bs); 34 void bdrv_close(BlockDriverState *bs);
32 int bdrv_read(BlockDriverState *bs, int64_t sector_num, 35 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
33 uint8_t *buf, int nb_sectors); 36 uint8_t *buf, int nb_sectors);
34 int bdrv_write(BlockDriverState *bs, int64_t sector_num, 37 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
35 const uint8_t *buf, int nb_sectors); 38 const uint8_t *buf, int nb_sectors);
36 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); 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 #endif /* VL_H */ 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 +}