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