|  | /* | 
|  | * Block driver for the COW format | 
|  | * | 
|  | * Copyright (c) 2004 Fabrice Bellard | 
|  | * | 
|  | * Permission is hereby granted, free of charge, to any person obtaining a copy | 
|  | * of this software and associated documentation files (the "Software"), to deal | 
|  | * in the Software without restriction, including without limitation the rights | 
|  | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|  | * copies of the Software, and to permit persons to whom the Software is | 
|  | * furnished to do so, subject to the following conditions: | 
|  | * | 
|  | * The above copyright notice and this permission notice shall be included in | 
|  | * all copies or substantial portions of the Software. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
|  | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|  | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|  | * THE SOFTWARE. | 
|  | */ | 
|  | #include "qemu-common.h" | 
|  | #include "block/block_int.h" | 
|  | #include "qemu/module.h" | 
|  |  | 
|  | /**************************************************************/ | 
|  | /* COW block driver using file system holes */ | 
|  |  | 
|  | /* user mode linux compatible COW file */ | 
|  | #define COW_MAGIC 0x4f4f4f4d  /* MOOO */ | 
|  | #define COW_VERSION 2 | 
|  |  | 
|  | struct cow_header_v2 { | 
|  | uint32_t magic; | 
|  | uint32_t version; | 
|  | char backing_file[1024]; | 
|  | int32_t mtime; | 
|  | uint64_t size; | 
|  | uint32_t sectorsize; | 
|  | }; | 
|  |  | 
|  | typedef struct BDRVCowState { | 
|  | CoMutex lock; | 
|  | int64_t cow_sectors_offset; | 
|  | } BDRVCowState; | 
|  |  | 
|  | static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) | 
|  | { | 
|  | const struct cow_header_v2 *cow_header = (const void *)buf; | 
|  |  | 
|  | if (buf_size >= sizeof(struct cow_header_v2) && | 
|  | be32_to_cpu(cow_header->magic) == COW_MAGIC && | 
|  | be32_to_cpu(cow_header->version) == COW_VERSION) | 
|  | return 100; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int cow_open(BlockDriverState *bs, QDict *options, int flags, | 
|  | Error **errp) | 
|  | { | 
|  | BDRVCowState *s = bs->opaque; | 
|  | struct cow_header_v2 cow_header; | 
|  | int bitmap_size; | 
|  | int64_t size; | 
|  | int ret; | 
|  |  | 
|  | /* see if it is a cow image */ | 
|  | ret = bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header)); | 
|  | if (ret < 0) { | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | if (be32_to_cpu(cow_header.magic) != COW_MAGIC) { | 
|  | ret = -EMEDIUMTYPE; | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | if (be32_to_cpu(cow_header.version) != COW_VERSION) { | 
|  | char version[64]; | 
|  | snprintf(version, sizeof(version), | 
|  | "COW version %d", cow_header.version); | 
|  | qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, | 
|  | bs->device_name, "cow", version); | 
|  | ret = -ENOTSUP; | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | /* cow image found */ | 
|  | size = be64_to_cpu(cow_header.size); | 
|  | bs->total_sectors = size / 512; | 
|  |  | 
|  | pstrcpy(bs->backing_file, sizeof(bs->backing_file), | 
|  | cow_header.backing_file); | 
|  |  | 
|  | bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); | 
|  | s->cow_sectors_offset = (bitmap_size + 511) & ~511; | 
|  | qemu_co_mutex_init(&s->lock); | 
|  | return 0; | 
|  | fail: | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * XXX(hch): right now these functions are extremely inefficient. | 
|  | * We should just read the whole bitmap we'll need in one go instead. | 
|  | */ | 
|  | static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum, bool *first) | 
|  | { | 
|  | uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8; | 
|  | uint8_t bitmap; | 
|  | int ret; | 
|  |  | 
|  | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (bitmap & (1 << (bitnum % 8))) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (*first) { | 
|  | ret = bdrv_flush(bs->file); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | *first = false; | 
|  | } | 
|  |  | 
|  | bitmap |= (1 << (bitnum % 8)); | 
|  |  | 
|  | ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap)); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define BITS_PER_BITMAP_SECTOR (512 * 8) | 
|  |  | 
|  | /* Cannot use bitmap.c on big-endian machines.  */ | 
|  | static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap) | 
|  | { | 
|  | return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0; | 
|  | } | 
|  |  | 
|  | static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors) | 
|  | { | 
|  | int streak_value = value ? 0xFF : 0; | 
|  | int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR); | 
|  | int bitnum = start; | 
|  | while (bitnum < last) { | 
|  | if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) { | 
|  | bitnum += 8; | 
|  | continue; | 
|  | } | 
|  | if (cow_test_bit(bitnum, bitmap) == value) { | 
|  | bitnum++; | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return MIN(bitnum, last) - start; | 
|  | } | 
|  |  | 
|  | /* Return true if first block has been changed (ie. current version is | 
|  | * in COW file).  Set the number of continuous blocks for which that | 
|  | * is true. */ | 
|  | static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs, | 
|  | int64_t sector_num, int nb_sectors, int *num_same) | 
|  | { | 
|  | int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; | 
|  | uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE; | 
|  | uint8_t bitmap[BDRV_SECTOR_SIZE]; | 
|  | int ret; | 
|  | int changed; | 
|  |  | 
|  | ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | bitnum &= BITS_PER_BITMAP_SECTOR - 1; | 
|  | changed = cow_test_bit(bitnum, bitmap); | 
|  | *num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors); | 
|  | return changed; | 
|  | } | 
|  |  | 
|  | static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs, | 
|  | int64_t sector_num, int nb_sectors, int *num_same) | 
|  | { | 
|  | BDRVCowState *s = bs->opaque; | 
|  | int ret = cow_co_is_allocated(bs, sector_num, nb_sectors, num_same); | 
|  | int64_t offset = s->cow_sectors_offset + (sector_num << BDRV_SECTOR_BITS); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | return (ret ? BDRV_BLOCK_DATA : 0) | offset | BDRV_BLOCK_OFFSET_VALID; | 
|  | } | 
|  |  | 
|  | static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, | 
|  | int nb_sectors) | 
|  | { | 
|  | int error = 0; | 
|  | int i; | 
|  | bool first = true; | 
|  |  | 
|  | for (i = 0; i < nb_sectors; i++) { | 
|  | error = cow_set_bit(bs, sector_num + i, &first); | 
|  | if (error) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return error; | 
|  | } | 
|  |  | 
|  | static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num, | 
|  | uint8_t *buf, int nb_sectors) | 
|  | { | 
|  | BDRVCowState *s = bs->opaque; | 
|  | int ret, n; | 
|  |  | 
|  | while (nb_sectors > 0) { | 
|  | ret = cow_co_is_allocated(bs, sector_num, nb_sectors, &n); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | if (ret) { | 
|  | ret = bdrv_pread(bs->file, | 
|  | s->cow_sectors_offset + sector_num * 512, | 
|  | buf, n * 512); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } else { | 
|  | if (bs->backing_hd) { | 
|  | /* read from the base image */ | 
|  | ret = bdrv_read(bs->backing_hd, sector_num, buf, n); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } else { | 
|  | memset(buf, 0, n * 512); | 
|  | } | 
|  | } | 
|  | nb_sectors -= n; | 
|  | sector_num += n; | 
|  | buf += n * 512; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num, | 
|  | uint8_t *buf, int nb_sectors) | 
|  | { | 
|  | int ret; | 
|  | BDRVCowState *s = bs->opaque; | 
|  | qemu_co_mutex_lock(&s->lock); | 
|  | ret = cow_read(bs, sector_num, buf, nb_sectors); | 
|  | qemu_co_mutex_unlock(&s->lock); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int cow_write(BlockDriverState *bs, int64_t sector_num, | 
|  | const uint8_t *buf, int nb_sectors) | 
|  | { | 
|  | BDRVCowState *s = bs->opaque; | 
|  | int ret; | 
|  |  | 
|  | ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512, | 
|  | buf, nb_sectors * 512); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return cow_update_bitmap(bs, sector_num, nb_sectors); | 
|  | } | 
|  |  | 
|  | static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num, | 
|  | const uint8_t *buf, int nb_sectors) | 
|  | { | 
|  | int ret; | 
|  | BDRVCowState *s = bs->opaque; | 
|  | qemu_co_mutex_lock(&s->lock); | 
|  | ret = cow_write(bs, sector_num, buf, nb_sectors); | 
|  | qemu_co_mutex_unlock(&s->lock); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void cow_close(BlockDriverState *bs) | 
|  | { | 
|  | } | 
|  |  | 
|  | static int cow_create(const char *filename, QEMUOptionParameter *options, | 
|  | Error **errp) | 
|  | { | 
|  | struct cow_header_v2 cow_header; | 
|  | struct stat st; | 
|  | int64_t image_sectors = 0; | 
|  | const char *image_filename = NULL; | 
|  | Error *local_err = NULL; | 
|  | int ret; | 
|  | BlockDriverState *cow_bs; | 
|  |  | 
|  | /* Read out options */ | 
|  | while (options && options->name) { | 
|  | if (!strcmp(options->name, BLOCK_OPT_SIZE)) { | 
|  | image_sectors = options->value.n / 512; | 
|  | } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { | 
|  | image_filename = options->value.s; | 
|  | } | 
|  | options++; | 
|  | } | 
|  |  | 
|  | ret = bdrv_create_file(filename, options, &local_err); | 
|  | if (ret < 0) { | 
|  | qerror_report_err(local_err); | 
|  | error_free(local_err); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR, &local_err); | 
|  | if (ret < 0) { | 
|  | qerror_report_err(local_err); | 
|  | error_free(local_err); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | memset(&cow_header, 0, sizeof(cow_header)); | 
|  | cow_header.magic = cpu_to_be32(COW_MAGIC); | 
|  | cow_header.version = cpu_to_be32(COW_VERSION); | 
|  | if (image_filename) { | 
|  | /* Note: if no file, we put a dummy mtime */ | 
|  | cow_header.mtime = cpu_to_be32(0); | 
|  |  | 
|  | if (stat(image_filename, &st) != 0) { | 
|  | goto mtime_fail; | 
|  | } | 
|  | cow_header.mtime = cpu_to_be32(st.st_mtime); | 
|  | mtime_fail: | 
|  | pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file), | 
|  | image_filename); | 
|  | } | 
|  | cow_header.sectorsize = cpu_to_be32(512); | 
|  | cow_header.size = cpu_to_be64(image_sectors * 512); | 
|  | ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header)); | 
|  | if (ret < 0) { | 
|  | goto exit; | 
|  | } | 
|  |  | 
|  | /* resize to include at least all the bitmap */ | 
|  | ret = bdrv_truncate(cow_bs, | 
|  | sizeof(cow_header) + ((image_sectors + 7) >> 3)); | 
|  | if (ret < 0) { | 
|  | goto exit; | 
|  | } | 
|  |  | 
|  | exit: | 
|  | bdrv_unref(cow_bs); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static QEMUOptionParameter cow_create_options[] = { | 
|  | { | 
|  | .name = BLOCK_OPT_SIZE, | 
|  | .type = OPT_SIZE, | 
|  | .help = "Virtual disk size" | 
|  | }, | 
|  | { | 
|  | .name = BLOCK_OPT_BACKING_FILE, | 
|  | .type = OPT_STRING, | 
|  | .help = "File name of a base image" | 
|  | }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | static BlockDriver bdrv_cow = { | 
|  | .format_name    = "cow", | 
|  | .instance_size  = sizeof(BDRVCowState), | 
|  |  | 
|  | .bdrv_probe     = cow_probe, | 
|  | .bdrv_open      = cow_open, | 
|  | .bdrv_close     = cow_close, | 
|  | .bdrv_create    = cow_create, | 
|  | .bdrv_has_zero_init     = bdrv_has_zero_init_1, | 
|  |  | 
|  | .bdrv_read              = cow_co_read, | 
|  | .bdrv_write             = cow_co_write, | 
|  | .bdrv_co_get_block_status   = cow_co_get_block_status, | 
|  |  | 
|  | .create_options = cow_create_options, | 
|  | }; | 
|  |  | 
|  | static void bdrv_cow_init(void) | 
|  | { | 
|  | bdrv_register(&bdrv_cow); | 
|  | } | 
|  |  | 
|  | block_init(bdrv_cow_init); |