xref: /openbmc/qemu/block.c (revision cf98951b82adefb46318b3ed45c8456aac2b9575)
1fc01f7e7Sbellard /*
2fc01f7e7Sbellard  * QEMU System Emulator block driver
3fc01f7e7Sbellard  *
4fc01f7e7Sbellard  * Copyright (c) 2003 Fabrice Bellard
5fc01f7e7Sbellard  *
6fc01f7e7Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7fc01f7e7Sbellard  * of this software and associated documentation files (the "Software"), to deal
8fc01f7e7Sbellard  * in the Software without restriction, including without limitation the rights
9fc01f7e7Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10fc01f7e7Sbellard  * copies of the Software, and to permit persons to whom the Software is
11fc01f7e7Sbellard  * furnished to do so, subject to the following conditions:
12fc01f7e7Sbellard  *
13fc01f7e7Sbellard  * The above copyright notice and this permission notice shall be included in
14fc01f7e7Sbellard  * all copies or substantial portions of the Software.
15fc01f7e7Sbellard  *
16fc01f7e7Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fc01f7e7Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fc01f7e7Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19fc01f7e7Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fc01f7e7Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21fc01f7e7Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22fc01f7e7Sbellard  * THE SOFTWARE.
23fc01f7e7Sbellard  */
24fc01f7e7Sbellard #include <stdlib.h>
25fc01f7e7Sbellard #include <stdio.h>
26fc01f7e7Sbellard #include <stdarg.h>
27fc01f7e7Sbellard #include <string.h>
28fc01f7e7Sbellard #include <getopt.h>
29fc01f7e7Sbellard #include <inttypes.h>
30fc01f7e7Sbellard #include <unistd.h>
31fc01f7e7Sbellard #include <sys/mman.h>
32fc01f7e7Sbellard #include <fcntl.h>
33fc01f7e7Sbellard #include <signal.h>
34fc01f7e7Sbellard #include <time.h>
35fc01f7e7Sbellard #include <sys/time.h>
36fc01f7e7Sbellard #include <malloc.h>
37fc01f7e7Sbellard #include <termios.h>
38fc01f7e7Sbellard #include <sys/poll.h>
39fc01f7e7Sbellard #include <errno.h>
40fc01f7e7Sbellard #include <sys/wait.h>
4133e3963eSbellard #include <netinet/in.h>
42fc01f7e7Sbellard 
43fc01f7e7Sbellard #include "vl.h"
44fc01f7e7Sbellard 
4533e3963eSbellard #define NO_THUNK_TYPE_SIZE
4633e3963eSbellard #include "thunk.h"
4733e3963eSbellard 
48fc01f7e7Sbellard struct BlockDriverState {
4933e3963eSbellard     int fd; /* if -1, only COW mappings */
50fc01f7e7Sbellard     int64_t total_sectors;
510849bf08Sbellard     int read_only;
5233e3963eSbellard 
5333e3963eSbellard     uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
5433e3963eSbellard     uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
5533e3963eSbellard     int cow_bitmap_size;
5633e3963eSbellard     int cow_fd;
5733e3963eSbellard     int64_t cow_sectors_offset;
58*cf98951bSbellard     int boot_sector_enabled;
59*cf98951bSbellard     uint8_t boot_sector_data[512];
60*cf98951bSbellard 
6133e3963eSbellard     char filename[1024];
62fc01f7e7Sbellard };
63fc01f7e7Sbellard 
6433e3963eSbellard BlockDriverState *bdrv_open(const char *filename, int snapshot)
65fc01f7e7Sbellard {
66fc01f7e7Sbellard     BlockDriverState *bs;
6733e3963eSbellard     int fd, cow_fd;
68fc01f7e7Sbellard     int64_t size;
6933e3963eSbellard     char template[] = "/tmp/vl.XXXXXX";
7033e3963eSbellard     struct cow_header_v2 cow_header;
7133e3963eSbellard     struct stat st;
72fc01f7e7Sbellard 
73fc01f7e7Sbellard     bs = malloc(sizeof(BlockDriverState));
74fc01f7e7Sbellard     if(!bs)
75fc01f7e7Sbellard         return NULL;
760849bf08Sbellard     bs->read_only = 0;
7733e3963eSbellard     bs->fd = -1;
7833e3963eSbellard     bs->cow_fd = -1;
7933e3963eSbellard     bs->cow_bitmap = NULL;
8033e3963eSbellard     strcpy(bs->filename, filename);
8133e3963eSbellard 
8233e3963eSbellard     /* open standard HD image */
8333e3963eSbellard     fd = open(filename, O_RDWR | O_LARGEFILE);
84fc01f7e7Sbellard     if (fd < 0) {
8533e3963eSbellard         /* read only image on disk */
8633e3963eSbellard         fd = open(filename, O_RDONLY | O_LARGEFILE);
870849bf08Sbellard         if (fd < 0) {
8833e3963eSbellard             perror(filename);
8933e3963eSbellard             goto fail;
90fc01f7e7Sbellard         }
9133e3963eSbellard         if (!snapshot)
920849bf08Sbellard             bs->read_only = 1;
930849bf08Sbellard     }
9433e3963eSbellard     bs->fd = fd;
9533e3963eSbellard 
9633e3963eSbellard     /* see if it is a cow image */
9733e3963eSbellard     if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
9833e3963eSbellard         fprintf(stderr, "%s: could not read header\n", filename);
9933e3963eSbellard         goto fail;
10033e3963eSbellard     }
10133e3963eSbellard     if (cow_header.magic == htonl(COW_MAGIC) &&
10233e3963eSbellard         cow_header.version == htonl(COW_VERSION)) {
10333e3963eSbellard         /* cow image found */
10433e3963eSbellard         size = cow_header.size;
10533e3963eSbellard #ifndef WORDS_BIGENDIAN
10633e3963eSbellard         size = bswap64(size);
10733e3963eSbellard #endif
10833e3963eSbellard         bs->total_sectors = size / 512;
10933e3963eSbellard 
11033e3963eSbellard         bs->cow_fd = fd;
11133e3963eSbellard         bs->fd = -1;
11233e3963eSbellard         if (cow_header.backing_file[0] != '\0') {
11333e3963eSbellard             if (stat(cow_header.backing_file, &st) != 0) {
11433e3963eSbellard                 fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
11533e3963eSbellard                 goto fail;
11633e3963eSbellard             }
11733e3963eSbellard             if (st.st_mtime != htonl(cow_header.mtime)) {
11833e3963eSbellard                 fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
11933e3963eSbellard                 goto fail;
12033e3963eSbellard             }
12133e3963eSbellard             fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
12233e3963eSbellard             if (fd < 0)
12333e3963eSbellard                 goto fail;
12433e3963eSbellard             bs->fd = fd;
12533e3963eSbellard         }
12633e3963eSbellard         /* mmap the bitmap */
12733e3963eSbellard         bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
12833e3963eSbellard         bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
12933e3963eSbellard                                    bs->cow_bitmap_size,
13033e3963eSbellard                                    PROT_READ | PROT_WRITE,
13133e3963eSbellard                                    MAP_SHARED, bs->cow_fd, 0);
13233e3963eSbellard         if (bs->cow_bitmap_addr == MAP_FAILED)
13333e3963eSbellard             goto fail;
13433e3963eSbellard         bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
13533e3963eSbellard         bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
13633e3963eSbellard         snapshot = 0;
13733e3963eSbellard     } else {
13833e3963eSbellard         /* standard raw image */
139fc01f7e7Sbellard         size = lseek64(fd, 0, SEEK_END);
140fc01f7e7Sbellard         bs->total_sectors = size / 512;
141fc01f7e7Sbellard         bs->fd = fd;
14233e3963eSbellard     }
14333e3963eSbellard 
14433e3963eSbellard     if (snapshot) {
14533e3963eSbellard         /* create a temporary COW file */
14633e3963eSbellard         cow_fd = mkstemp(template);
14733e3963eSbellard         if (cow_fd < 0)
14833e3963eSbellard             goto fail;
14933e3963eSbellard         bs->cow_fd = cow_fd;
15033e3963eSbellard 	unlink(template);
15133e3963eSbellard 
15233e3963eSbellard         /* just need to allocate bitmap */
15333e3963eSbellard         bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
15433e3963eSbellard         bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
15533e3963eSbellard                                    bs->cow_bitmap_size,
15633e3963eSbellard                                    PROT_READ | PROT_WRITE,
15733e3963eSbellard                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
15833e3963eSbellard         if (bs->cow_bitmap_addr == MAP_FAILED)
15933e3963eSbellard             goto fail;
16033e3963eSbellard         bs->cow_bitmap = bs->cow_bitmap_addr;
16133e3963eSbellard         bs->cow_sectors_offset = 0;
16233e3963eSbellard     }
16333e3963eSbellard 
164fc01f7e7Sbellard     return bs;
16533e3963eSbellard  fail:
16633e3963eSbellard     bdrv_close(bs);
16733e3963eSbellard     return NULL;
168fc01f7e7Sbellard }
169fc01f7e7Sbellard 
170fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs)
171fc01f7e7Sbellard {
17233e3963eSbellard     /* we unmap the mapping so that it is written to the COW file */
17333e3963eSbellard     if (bs->cow_bitmap_addr)
17433e3963eSbellard         munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
17533e3963eSbellard     if (bs->cow_fd >= 0)
17633e3963eSbellard         close(bs->cow_fd);
17733e3963eSbellard     if (bs->fd >= 0)
178fc01f7e7Sbellard         close(bs->fd);
179fc01f7e7Sbellard     free(bs);
180fc01f7e7Sbellard }
181fc01f7e7Sbellard 
18233e3963eSbellard static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
18333e3963eSbellard {
18433e3963eSbellard     bitmap[bitnum / 8] |= (1 << (bitnum%8));
18533e3963eSbellard }
18633e3963eSbellard 
18733e3963eSbellard static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
18833e3963eSbellard {
18933e3963eSbellard     return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
19033e3963eSbellard }
19133e3963eSbellard 
19233e3963eSbellard 
19333e3963eSbellard /* Return true if first block has been changed (ie. current version is
19433e3963eSbellard  * in COW file).  Set the number of continuous blocks for which that
19533e3963eSbellard  * is true. */
19633e3963eSbellard static int is_changed(uint8_t *bitmap,
19733e3963eSbellard                       int64_t sector_num, int nb_sectors,
19833e3963eSbellard                       int *num_same)
19933e3963eSbellard {
20033e3963eSbellard     int changed;
20133e3963eSbellard 
20233e3963eSbellard     if (!bitmap || nb_sectors == 0) {
20333e3963eSbellard 	*num_same = nb_sectors;
20433e3963eSbellard 	return 0;
20533e3963eSbellard     }
20633e3963eSbellard 
20733e3963eSbellard     changed = is_bit_set(bitmap, sector_num);
20833e3963eSbellard     for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
20933e3963eSbellard 	if (is_bit_set(bitmap, sector_num + *num_same) != changed)
21033e3963eSbellard 	    break;
21133e3963eSbellard     }
21233e3963eSbellard 
21333e3963eSbellard     return changed;
21433e3963eSbellard }
21533e3963eSbellard 
21633e3963eSbellard /* commit COW file into the raw image */
21733e3963eSbellard int bdrv_commit(BlockDriverState *bs)
21833e3963eSbellard {
21933e3963eSbellard     int64_t i;
22033e3963eSbellard     uint8_t *cow_bitmap;
22133e3963eSbellard 
22233e3963eSbellard     if (!bs->cow_bitmap) {
22333e3963eSbellard 	fprintf(stderr, "Already committed to %s\n", bs->filename);
22433e3963eSbellard 	return 0;
22533e3963eSbellard     }
22633e3963eSbellard 
22733e3963eSbellard     if (bs->read_only) {
22833e3963eSbellard 	fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
22933e3963eSbellard 	return -1;
23033e3963eSbellard     }
23133e3963eSbellard 
23233e3963eSbellard     cow_bitmap = bs->cow_bitmap;
23333e3963eSbellard     for (i = 0; i < bs->total_sectors; i++) {
23433e3963eSbellard 	if (is_bit_set(cow_bitmap, i)) {
23533e3963eSbellard 	    unsigned char sector[512];
23633e3963eSbellard 	    if (bdrv_read(bs, i, sector, 1) != 0) {
23733e3963eSbellard 		fprintf(stderr, "Error reading sector %lli: aborting commit\n",
23833e3963eSbellard 			(long long)i);
23933e3963eSbellard 		return -1;
24033e3963eSbellard 	    }
24133e3963eSbellard 
24233e3963eSbellard 	    /* Make bdrv_write write to real file for a moment. */
24333e3963eSbellard 	    bs->cow_bitmap = NULL;
24433e3963eSbellard 	    if (bdrv_write(bs, i, sector, 1) != 0) {
24533e3963eSbellard 		fprintf(stderr, "Error writing sector %lli: aborting commit\n",
24633e3963eSbellard 			(long long)i);
24733e3963eSbellard 		bs->cow_bitmap = cow_bitmap;
24833e3963eSbellard 		return -1;
24933e3963eSbellard 	    }
25033e3963eSbellard 	    bs->cow_bitmap = cow_bitmap;
25133e3963eSbellard 	}
25233e3963eSbellard     }
25333e3963eSbellard     fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
25433e3963eSbellard     return 0;
25533e3963eSbellard }
25633e3963eSbellard 
257fc01f7e7Sbellard /* return -1 if error */
258fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num,
259fc01f7e7Sbellard               uint8_t *buf, int nb_sectors)
260fc01f7e7Sbellard {
26133e3963eSbellard     int ret, n, fd;
26233e3963eSbellard     int64_t offset;
263fc01f7e7Sbellard 
26433e3963eSbellard     while (nb_sectors > 0) {
26533e3963eSbellard         if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
26633e3963eSbellard             fd = bs->cow_fd;
26733e3963eSbellard             offset = bs->cow_sectors_offset;
268*cf98951bSbellard         } else if (sector_num == 0 && bs->boot_sector_enabled) {
269*cf98951bSbellard             memcpy(buf, bs->boot_sector_data, 512);
270*cf98951bSbellard             n = 1;
271*cf98951bSbellard             goto next;
27233e3963eSbellard         } else {
27333e3963eSbellard             fd = bs->fd;
27433e3963eSbellard             offset = 0;
27533e3963eSbellard         }
27633e3963eSbellard 
27733e3963eSbellard         if (fd < 0) {
27833e3963eSbellard             /* no file, just return empty sectors */
27933e3963eSbellard             memset(buf, 0, n * 512);
28033e3963eSbellard         } else {
28133e3963eSbellard             offset += sector_num * 512;
28233e3963eSbellard             lseek64(fd, offset, SEEK_SET);
28333e3963eSbellard             ret = read(fd, buf, n * 512);
28433e3963eSbellard             if (ret != n * 512) {
285fc01f7e7Sbellard                 return -1;
28633e3963eSbellard             }
28733e3963eSbellard         }
288*cf98951bSbellard     next:
28933e3963eSbellard         nb_sectors -= n;
29033e3963eSbellard         sector_num += n;
29133e3963eSbellard         buf += n * 512;
29233e3963eSbellard     }
293fc01f7e7Sbellard     return 0;
294fc01f7e7Sbellard }
295fc01f7e7Sbellard 
296fc01f7e7Sbellard /* return -1 if error */
297fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num,
298fc01f7e7Sbellard                const uint8_t *buf, int nb_sectors)
299fc01f7e7Sbellard {
30033e3963eSbellard     int ret, fd, i;
30133e3963eSbellard     int64_t offset, retl;
302fc01f7e7Sbellard 
3030849bf08Sbellard     if (bs->read_only)
3040849bf08Sbellard         return -1;
3050849bf08Sbellard 
30633e3963eSbellard     if (bs->cow_bitmap) {
30733e3963eSbellard         fd = bs->cow_fd;
30833e3963eSbellard         offset = bs->cow_sectors_offset;
30933e3963eSbellard     } else {
31033e3963eSbellard         fd = bs->fd;
31133e3963eSbellard         offset = 0;
31233e3963eSbellard     }
31333e3963eSbellard 
31433e3963eSbellard     offset += sector_num * 512;
31533e3963eSbellard     retl = lseek64(fd, offset, SEEK_SET);
31633e3963eSbellard     if (retl == -1) {
317fc01f7e7Sbellard         return -1;
31833e3963eSbellard     }
31933e3963eSbellard     ret = write(fd, buf, nb_sectors * 512);
32033e3963eSbellard     if (ret != nb_sectors * 512) {
32133e3963eSbellard         return -1;
32233e3963eSbellard     }
32333e3963eSbellard 
32433e3963eSbellard     if (bs->cow_bitmap) {
32533e3963eSbellard 	for (i = 0; i < nb_sectors; i++)
32633e3963eSbellard 	    set_bit(bs->cow_bitmap, sector_num + i);
32733e3963eSbellard     }
328fc01f7e7Sbellard     return 0;
329fc01f7e7Sbellard }
330fc01f7e7Sbellard 
331fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
332fc01f7e7Sbellard {
333fc01f7e7Sbellard     *nb_sectors_ptr = bs->total_sectors;
334fc01f7e7Sbellard }
335*cf98951bSbellard 
336*cf98951bSbellard /* force a given boot sector. */
337*cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
338*cf98951bSbellard {
339*cf98951bSbellard     bs->boot_sector_enabled = 1;
340*cf98951bSbellard     if (size > 512)
341*cf98951bSbellard         size = 512;
342*cf98951bSbellard     memcpy(bs->boot_sector_data, data, size);
343*cf98951bSbellard     memset(bs->boot_sector_data + size, 0, 512 - size);
344*cf98951bSbellard }
345