|
|
1.1 ! root 1: /* ! 2: * Block driver for the COW format ! 3: * ! 4: * Copyright (c) 2004 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: #ifndef _WIN32 ! 25: #include "qemu-common.h" ! 26: #include "block_int.h" ! 27: #include "module.h" ! 28: #include <sys/mman.h> ! 29: ! 30: /**************************************************************/ ! 31: /* COW block driver using file system holes */ ! 32: ! 33: /* user mode linux compatible COW file */ ! 34: #define COW_MAGIC 0x4f4f4f4d /* MOOO */ ! 35: #define COW_VERSION 2 ! 36: ! 37: struct cow_header_v2 { ! 38: uint32_t magic; ! 39: uint32_t version; ! 40: char backing_file[1024]; ! 41: int32_t mtime; ! 42: uint64_t size; ! 43: uint32_t sectorsize; ! 44: }; ! 45: ! 46: typedef struct BDRVCowState { ! 47: int fd; ! 48: uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ ! 49: uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ ! 50: int cow_bitmap_size; ! 51: int64_t cow_sectors_offset; ! 52: } BDRVCowState; ! 53: ! 54: static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) ! 55: { ! 56: const struct cow_header_v2 *cow_header = (const void *)buf; ! 57: ! 58: if (buf_size >= sizeof(struct cow_header_v2) && ! 59: be32_to_cpu(cow_header->magic) == COW_MAGIC && ! 60: be32_to_cpu(cow_header->version) == COW_VERSION) ! 61: return 100; ! 62: else ! 63: return 0; ! 64: } ! 65: ! 66: static int cow_open(BlockDriverState *bs, const char *filename, int flags) ! 67: { ! 68: BDRVCowState *s = bs->opaque; ! 69: int fd; ! 70: struct cow_header_v2 cow_header; ! 71: int64_t size; ! 72: ! 73: fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ! 74: if (fd < 0) { ! 75: fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); ! 76: if (fd < 0) ! 77: return -1; ! 78: } ! 79: s->fd = fd; ! 80: /* see if it is a cow image */ ! 81: if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { ! 82: goto fail; ! 83: } ! 84: ! 85: if (be32_to_cpu(cow_header.magic) != COW_MAGIC || ! 86: be32_to_cpu(cow_header.version) != COW_VERSION) { ! 87: goto fail; ! 88: } ! 89: ! 90: /* cow image found */ ! 91: size = be64_to_cpu(cow_header.size); ! 92: bs->total_sectors = size / 512; ! 93: ! 94: pstrcpy(bs->backing_file, sizeof(bs->backing_file), ! 95: cow_header.backing_file); ! 96: ! 97: /* mmap the bitmap */ ! 98: s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); ! 99: s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size), ! 100: s->cow_bitmap_size, ! 101: PROT_READ | PROT_WRITE, ! 102: MAP_SHARED, s->fd, 0); ! 103: if (s->cow_bitmap_addr == MAP_FAILED) ! 104: goto fail; ! 105: s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header); ! 106: s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511; ! 107: return 0; ! 108: fail: ! 109: close(fd); ! 110: return -1; ! 111: } ! 112: ! 113: static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum) ! 114: { ! 115: bitmap[bitnum / 8] |= (1 << (bitnum%8)); ! 116: } ! 117: ! 118: static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) ! 119: { ! 120: return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); ! 121: } ! 122: ! 123: ! 124: /* Return true if first block has been changed (ie. current version is ! 125: * in COW file). Set the number of continuous blocks for which that ! 126: * is true. */ ! 127: static inline int is_changed(uint8_t *bitmap, ! 128: int64_t sector_num, int nb_sectors, ! 129: int *num_same) ! 130: { ! 131: int changed; ! 132: ! 133: if (!bitmap || nb_sectors == 0) { ! 134: *num_same = nb_sectors; ! 135: return 0; ! 136: } ! 137: ! 138: changed = is_bit_set(bitmap, sector_num); ! 139: for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { ! 140: if (is_bit_set(bitmap, sector_num + *num_same) != changed) ! 141: break; ! 142: } ! 143: ! 144: return changed; ! 145: } ! 146: ! 147: static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, ! 148: int nb_sectors, int *pnum) ! 149: { ! 150: BDRVCowState *s = bs->opaque; ! 151: return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum); ! 152: } ! 153: ! 154: static int cow_read(BlockDriverState *bs, int64_t sector_num, ! 155: uint8_t *buf, int nb_sectors) ! 156: { ! 157: BDRVCowState *s = bs->opaque; ! 158: int ret, n; ! 159: ! 160: while (nb_sectors > 0) { ! 161: if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) { ! 162: lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); ! 163: ret = read(s->fd, buf, n * 512); ! 164: if (ret != n * 512) ! 165: return -1; ! 166: } else { ! 167: if (bs->backing_hd) { ! 168: /* read from the base image */ ! 169: ret = bdrv_read(bs->backing_hd, sector_num, buf, n); ! 170: if (ret < 0) ! 171: return -1; ! 172: } else { ! 173: memset(buf, 0, n * 512); ! 174: } ! 175: } ! 176: nb_sectors -= n; ! 177: sector_num += n; ! 178: buf += n * 512; ! 179: } ! 180: return 0; ! 181: } ! 182: ! 183: static int cow_write(BlockDriverState *bs, int64_t sector_num, ! 184: const uint8_t *buf, int nb_sectors) ! 185: { ! 186: BDRVCowState *s = bs->opaque; ! 187: int ret, i; ! 188: ! 189: lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); ! 190: ret = write(s->fd, buf, nb_sectors * 512); ! 191: if (ret != nb_sectors * 512) ! 192: return -1; ! 193: for (i = 0; i < nb_sectors; i++) ! 194: cow_set_bit(s->cow_bitmap, sector_num + i); ! 195: return 0; ! 196: } ! 197: ! 198: static void cow_close(BlockDriverState *bs) ! 199: { ! 200: BDRVCowState *s = bs->opaque; ! 201: munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size); ! 202: close(s->fd); ! 203: } ! 204: ! 205: static int cow_create(const char *filename, QEMUOptionParameter *options) ! 206: { ! 207: int fd, cow_fd; ! 208: struct cow_header_v2 cow_header; ! 209: struct stat st; ! 210: int64_t image_sectors = 0; ! 211: const char *image_filename = NULL; ! 212: ! 213: /* Read out options */ ! 214: while (options && options->name) { ! 215: if (!strcmp(options->name, BLOCK_OPT_SIZE)) { ! 216: image_sectors = options->value.n / 512; ! 217: } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { ! 218: image_filename = options->value.s; ! 219: } ! 220: options++; ! 221: } ! 222: ! 223: cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, ! 224: 0644); ! 225: if (cow_fd < 0) ! 226: return -1; ! 227: memset(&cow_header, 0, sizeof(cow_header)); ! 228: cow_header.magic = cpu_to_be32(COW_MAGIC); ! 229: cow_header.version = cpu_to_be32(COW_VERSION); ! 230: if (image_filename) { ! 231: /* Note: if no file, we put a dummy mtime */ ! 232: cow_header.mtime = cpu_to_be32(0); ! 233: ! 234: fd = open(image_filename, O_RDONLY | O_BINARY); ! 235: if (fd < 0) { ! 236: close(cow_fd); ! 237: goto mtime_fail; ! 238: } ! 239: if (fstat(fd, &st) != 0) { ! 240: close(fd); ! 241: goto mtime_fail; ! 242: } ! 243: close(fd); ! 244: cow_header.mtime = cpu_to_be32(st.st_mtime); ! 245: mtime_fail: ! 246: pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file), ! 247: image_filename); ! 248: } ! 249: cow_header.sectorsize = cpu_to_be32(512); ! 250: cow_header.size = cpu_to_be64(image_sectors * 512); ! 251: write(cow_fd, &cow_header, sizeof(cow_header)); ! 252: /* resize to include at least all the bitmap */ ! 253: ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); ! 254: close(cow_fd); ! 255: return 0; ! 256: } ! 257: ! 258: static void cow_flush(BlockDriverState *bs) ! 259: { ! 260: BDRVCowState *s = bs->opaque; ! 261: fsync(s->fd); ! 262: } ! 263: ! 264: static QEMUOptionParameter cow_create_options[] = { ! 265: { ! 266: .name = BLOCK_OPT_SIZE, ! 267: .type = OPT_SIZE, ! 268: .help = "Virtual disk size" ! 269: }, ! 270: { ! 271: .name = BLOCK_OPT_BACKING_FILE, ! 272: .type = OPT_STRING, ! 273: .help = "File name of a base image" ! 274: }, ! 275: { NULL } ! 276: }; ! 277: ! 278: static BlockDriver bdrv_cow = { ! 279: .format_name = "cow", ! 280: .instance_size = sizeof(BDRVCowState), ! 281: .bdrv_probe = cow_probe, ! 282: .bdrv_open = cow_open, ! 283: .bdrv_read = cow_read, ! 284: .bdrv_write = cow_write, ! 285: .bdrv_close = cow_close, ! 286: .bdrv_create = cow_create, ! 287: .bdrv_flush = cow_flush, ! 288: .bdrv_is_allocated = cow_is_allocated, ! 289: ! 290: .create_options = cow_create_options, ! 291: }; ! 292: ! 293: static void bdrv_cow_init(void) ! 294: { ! 295: bdrv_register(&bdrv_cow); ! 296: } ! 297: ! 298: block_init(bdrv_cow_init); ! 299: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.