Commit 72375c22 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote branch 'kwolf/for-anthony' into HEAD

parents a6dac6a9 d748768c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o

block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
block-nested-y += parallels.o nbd.o blkdebug.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
+275 −109
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                        uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
                         const uint8_t *buf, int nb_sectors);
static BlockDriver *find_protocol(const char *filename);

static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
    QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -203,6 +204,18 @@ int bdrv_create(BlockDriver *drv, const char* filename,
    return drv->bdrv_create(filename, options);
}

int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
{
    BlockDriver *drv;

    drv = find_protocol(filename);
    if (drv == NULL) {
        drv = bdrv_find_format("file");
    }

    return bdrv_create(drv, filename, options);
}

#ifdef _WIN32
void get_tmp_filename(char *filename, int size)
{
@@ -246,6 +259,28 @@ int is_windows_drive(const char *filename)
}
#endif

/*
 * Detect host devices. By convention, /dev/cdrom[N] is always
 * recognized as a host CDROM.
 */
static BlockDriver *find_hdev_driver(const char *filename)
{
    int score_max = 0, score;
    BlockDriver *drv = NULL, *d;

    QLIST_FOREACH(d, &bdrv_drivers, list) {
        if (d->bdrv_probe_device) {
            score = d->bdrv_probe_device(filename);
            if (score > score_max) {
                score_max = score;
                drv = d;
            }
        }
    }

    return drv;
}

static BlockDriver *find_protocol(const char *filename)
{
    BlockDriver *drv1;
@@ -253,14 +288,21 @@ static BlockDriver *find_protocol(const char *filename)
    int len;
    const char *p;

    /* TODO Drivers without bdrv_file_open must be specified explicitly */

#ifdef _WIN32
    if (is_windows_drive(filename) ||
        is_windows_drive_prefix(filename))
        return bdrv_find_format("raw");
        return bdrv_find_format("file");
#endif
    p = strchr(filename, ':');
    if (!p)
        return bdrv_find_format("raw");
    if (!p) {
        drv1 = find_hdev_driver(filename);
        if (!drv1) {
            drv1 = bdrv_find_format("file");
        }
        return drv1;
    }
    len = p - filename;
    if (len > sizeof(protocol) - 1)
        len = sizeof(protocol) - 1;
@@ -275,28 +317,6 @@ static BlockDriver *find_protocol(const char *filename)
    return NULL;
}

/*
 * Detect host devices. By convention, /dev/cdrom[N] is always
 * recognized as a host CDROM.
 */
static BlockDriver *find_hdev_driver(const char *filename)
{
    int score_max = 0, score;
    BlockDriver *drv = NULL, *d;

    QLIST_FOREACH(d, &bdrv_drivers, list) {
        if (d->bdrv_probe_device) {
            score = d->bdrv_probe_device(filename);
            if (score > score_max) {
                score_max = score;
                drv = d;
            }
        }
    }

    return drv;
}

static BlockDriver *find_image_format(const char *filename)
{
    int ret, score, score_max;
@@ -319,6 +339,7 @@ static BlockDriver *find_image_format(const char *filename)
    }

    score_max = 0;
    drv = NULL;
    QLIST_FOREACH(drv1, &bdrv_drivers, list) {
        if (drv1->bdrv_probe) {
            score = drv1->bdrv_probe(buf, ret, filename);
@@ -331,6 +352,118 @@ static BlockDriver *find_image_format(const char *filename)
    return drv;
}

/**
 * Set the current 'total_sectors' value
 */
static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{
    BlockDriver *drv = bs->drv;

    /* query actual device if possible, otherwise just trust the hint */
    if (drv->bdrv_getlength) {
        int64_t length = drv->bdrv_getlength(bs);
        if (length < 0) {
            return length;
        }
        hint = length >> BDRV_SECTOR_BITS;
    }

    bs->total_sectors = hint;
    return 0;
}

/*
 * Common part for opening disk images and files
 */
static int bdrv_open_common(BlockDriverState *bs, const char *filename,
    int flags, BlockDriver *drv)
{
    int ret, open_flags;

    assert(drv != NULL);

    bs->file = NULL;
    bs->total_sectors = 0;
    bs->is_temporary = 0;
    bs->encrypted = 0;
    bs->valid_key = 0;
    bs->open_flags = flags;
    /* buffer_alignment defaulted to 512, drivers can change this value */
    bs->buffer_alignment = 512;

    pstrcpy(bs->filename, sizeof(bs->filename), filename);

    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
        return -ENOTSUP;
    }

    bs->drv = drv;
    bs->opaque = qemu_mallocz(drv->instance_size);

    /*
     * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
     * write cache to the guest.  We do need the fdatasync to flush
     * out transactions for block allocations, and we maybe have a
     * volatile write cache in our backing device to deal with.
     */
    if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
        bs->enable_write_cache = 1;

    /*
     * Clear flags that are internal to the block layer before opening the
     * image.
     */
    open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);

    /*
     * Snapshots should be writeable.
     */
    if (bs->is_temporary) {
        open_flags |= BDRV_O_RDWR;
    }

    /* Open the image, either directly or using a protocol */
    if (drv->bdrv_file_open) {
        ret = drv->bdrv_file_open(bs, filename, open_flags);
    } else {
        ret = bdrv_file_open(&bs->file, filename, open_flags);
        if (ret >= 0) {
            ret = drv->bdrv_open(bs, open_flags);
        }
    }

    if (ret < 0) {
        goto free_and_fail;
    }

    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);

    ret = refresh_total_sectors(bs, bs->total_sectors);
    if (ret < 0) {
        goto free_and_fail;
    }

#ifndef _WIN32
    if (bs->is_temporary) {
        unlink(filename);
    }
#endif
    return 0;

free_and_fail:
    if (bs->file) {
        bdrv_delete(bs->file);
        bs->file = NULL;
    }
    qemu_free(bs->opaque);
    bs->opaque = NULL;
    bs->drv = NULL;
    return ret;
}

/*
 * Opens a file using a protocol (file, host_device, nbd, ...)
 */
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
{
    BlockDriverState *bs;
@@ -343,7 +476,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
    }

    bs = bdrv_new("");
    ret = bdrv_open(bs, filename, flags, drv);
    ret = bdrv_open_common(bs, filename, flags, drv);
    if (ret < 0) {
        bdrv_delete(bs);
        return ret;
@@ -353,19 +486,13 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
    return 0;
}

/*
 * Opens a disk image (raw, qcow2, vmdk, ...)
 */
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
              BlockDriver *drv)
{
    int ret, open_flags;
    char tmp_filename[PATH_MAX];
    char backing_filename[PATH_MAX];

    bs->is_temporary = 0;
    bs->encrypted = 0;
    bs->valid_key = 0;
    bs->open_flags = flags;
    /* buffer_alignment defaulted to 512, drivers can change this value */
    bs->buffer_alignment = 512;
    int ret;

    if (flags & BDRV_O_SNAPSHOT) {
        BlockDriverState *bs1;
@@ -373,6 +500,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
        int is_protocol = 0;
        BlockDriver *bdrv_qcow2;
        QEMUOptionParameter *options;
        char tmp_filename[PATH_MAX];
        char backing_filename[PATH_MAX];

        /* if snapshot, we create a temporary backing file and open it
           instead of opening 'filename' directly */
@@ -411,6 +540,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
        }

        ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
        free_option_parameters(options);
        if (ret < 0) {
            return ret;
        }
@@ -420,66 +550,28 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
        bs->is_temporary = 1;
    }

    pstrcpy(bs->filename, sizeof(bs->filename), filename);

    if (!drv) {
        drv = find_hdev_driver(filename);
    /* Find the right image format driver */
    if (!drv) {
        drv = find_image_format(filename);
    }
    }

    if (!drv) {
        ret = -ENOENT;
        goto unlink_and_fail;
    }
    if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
        ret = -ENOTSUP;
        goto unlink_and_fail;
    }

    bs->drv = drv;
    bs->opaque = qemu_mallocz(drv->instance_size);

    /*
     * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
     * write cache to the guest.  We do need the fdatasync to flush
     * out transactions for block allocations, and we maybe have a
     * volatile write cache in our backing device to deal with.
     */
    if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
        bs->enable_write_cache = 1;

    /*
     * Clear flags that are internal to the block layer before opening the
     * image.
     */
    open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);

    /*
     * Snapshots should be writeable.
     */
    if (bs->is_temporary) {
        open_flags |= BDRV_O_RDWR;
    }

    ret = drv->bdrv_open(bs, filename, open_flags);
    /* Open the image */
    ret = bdrv_open_common(bs, filename, flags, drv);
    if (ret < 0) {
        goto free_and_fail;
        goto unlink_and_fail;
    }

    bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
    if (drv->bdrv_getlength) {
        bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
    }
#ifndef _WIN32
    if (bs->is_temporary) {
        unlink(filename);
    }
#endif
    /* If there is a backing file, use it */
    if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') {
        /* if there is a backing file, use it */
        char backing_filename[PATH_MAX];
        int back_flags;
        BlockDriver *back_drv = NULL;

        bs->backing_hd = bdrv_new("");
        path_combine(backing_filename, sizeof(backing_filename),
                     filename, bs->backing_file);
@@ -487,9 +579,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
            back_drv = bdrv_find_format(bs->backing_format);

        /* backing files always opened read-only */
        open_flags &= ~BDRV_O_RDWR;
        back_flags =
            flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);

        ret = bdrv_open(bs->backing_hd, backing_filename, open_flags, back_drv);
        ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
        if (ret < 0) {
            bdrv_close(bs);
            return ret;
@@ -508,23 +601,23 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
        if (bs->change_cb)
            bs->change_cb(bs->change_opaque);
    }

    return 0;

free_and_fail:
    qemu_free(bs->opaque);
    bs->opaque = NULL;
    bs->drv = NULL;
unlink_and_fail:
    if (bs->is_temporary)
    if (bs->is_temporary) {
        unlink(filename);
    }
    return ret;
}

void bdrv_close(BlockDriverState *bs)
{
    if (bs->drv) {
        if (bs->backing_hd)
        if (bs->backing_hd) {
            bdrv_delete(bs->backing_hd);
            bs->backing_hd = NULL;
        }
        bs->drv->bdrv_close(bs);
        qemu_free(bs->opaque);
#ifdef _WIN32
@@ -535,6 +628,10 @@ void bdrv_close(BlockDriverState *bs)
        bs->opaque = NULL;
        bs->drv = NULL;

        if (bs->file != NULL) {
            bdrv_close(bs->file);
        }

        /* call the change callback */
        bs->media_changed = 1;
        if (bs->change_cb)
@@ -550,6 +647,10 @@ void bdrv_delete(BlockDriverState *bs)
    }

    bdrv_close(bs);
    if (bs->file != NULL) {
        bdrv_delete(bs->file);
    }

    qemu_free(bs);
}

@@ -780,6 +881,10 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
    }

    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
        bs->wr_highest_sector = sector_num + nb_sectors - 1;
    }

    return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}

@@ -883,13 +988,18 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
int bdrv_truncate(BlockDriverState *bs, int64_t offset)
{
    BlockDriver *drv = bs->drv;
    int ret;
    if (!drv)
        return -ENOMEDIUM;
    if (!drv->bdrv_truncate)
        return -ENOTSUP;
    if (bs->read_only)
        return -EACCES;
    return drv->bdrv_truncate(bs, offset);
    ret = drv->bdrv_truncate(bs, offset);
    if (ret == 0) {
        ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
    }
    return ret;
}

/**
@@ -900,8 +1010,12 @@ int64_t bdrv_getlength(BlockDriverState *bs)
    BlockDriver *drv = bs->drv;
    if (!drv)
        return -ENOMEDIUM;
    if (!drv->bdrv_getlength) {
        /* legacy mode */

    /* Fixed size devices use the total_sectors value for speed instead of
       issuing a length query (like lseek) on each call.  Also, legacy block
       drivers don't provide a bdrv_getlength function and must use
       total_sectors. */
    if (!bs->growable || !drv->bdrv_getlength) {
        return bs->total_sectors * BDRV_SECTOR_SIZE;
    }
    return drv->bdrv_getlength(bs);
@@ -1208,6 +1322,19 @@ void bdrv_flush_all(void)
    }
}

int bdrv_has_zero_init(BlockDriverState *bs)
{
    assert(bs->drv);

    if (bs->drv->no_zero_init) {
        return 0;
    } else if (bs->file) {
        return bdrv_has_zero_init(bs->file);
    }

    return 1;
}

/*
 * Returns true iff the specified sector is present in the disk image. Drivers
 * not implementing the functionality are assumed to not support backing files,
@@ -1408,6 +1535,35 @@ void bdrv_stats_print(Monitor *mon, const QObject *data)
    qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
}

static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
{
    QObject *res;
    QDict *dict;

    res = qobject_from_jsonf("{ 'stats': {"
                             "'rd_bytes': %" PRId64 ","
                             "'wr_bytes': %" PRId64 ","
                             "'rd_operations': %" PRId64 ","
                             "'wr_operations': %" PRId64 ","
                             "'wr_highest_offset': %" PRId64
                             "} }",
                             bs->rd_bytes, bs->wr_bytes,
                             bs->rd_ops, bs->wr_ops,
                             bs->wr_highest_sector * 512);
    dict  = qobject_to_qdict(res);

    if (*bs->device_name) {
        qdict_put(dict, "device", qstring_from_str(bs->device_name));
    }

    if (bs->file) {
        QObject *parent = bdrv_info_stats_bs(bs->file);
        qdict_put_obj(dict, "parent", parent);
    }

    return res;
}

/**
 * bdrv_info_stats(): show block device statistics
 *
@@ -1422,6 +1578,11 @@ void bdrv_stats_print(Monitor *mon, const QObject *data)
 *     - "wr_bytes": bytes written
 *     - "rd_operations": read operations
 *     - "wr_operations": write operations
 *     - "wr_highest_offset": Highest offset of a sector written since the
 *       BlockDriverState has been opened
 *     - "parent": Contains recursively the statistics of the underlying
 *       protocol (e.g. the host file for a qcow2 image). If there is no
 *       underlying protocol, this field is omitted.
 *
 * Example:
 *
@@ -1429,12 +1590,22 @@ void bdrv_stats_print(Monitor *mon, const QObject *data)
 *               "stats": { "rd_bytes": 512,
 *                          "wr_bytes": 0,
 *                          "rd_operations": 1,
 *                          "wr_operations": 0 } },
 *                          "wr_operations": 0,
 *                          "wr_highest_offset": 0,
 *                          "parent": {
 *                              "stats": { "rd_bytes": 1024,
 *                                         "wr_bytes": 0,
 *                                         "rd_operations": 2,
 *                                         "wr_operations": 0,
 *                                         "wr_highest_offset": 0,
 *                              }
 *                          } } },
 *   { "device": "ide1-cd0",
 *               "stats": { "rd_bytes": 0,
 *                          "wr_bytes": 0,
 *                          "rd_operations": 0,
 *                          "wr_operations": 0 } } ]
 *                          "wr_operations": 0,
 *                          "wr_highest_offset": 0 } },
 */
void bdrv_info_stats(Monitor *mon, QObject **ret_data)
{
@@ -1445,15 +1616,7 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data)
    devices = qlist_new();

    QTAILQ_FOREACH(bs, &bdrv_states, list) {
        obj = qobject_from_jsonf("{ 'device': %s, 'stats': {"
                                 "'rd_bytes': %" PRId64 ","
                                 "'wr_bytes': %" PRId64 ","
                                 "'rd_operations': %" PRId64 ","
                                 "'wr_operations': %" PRId64
                                 "} }",
                                 bs->device_name,
                                 bs->rd_bytes, bs->wr_bytes,
                                 bs->rd_ops, bs->wr_ops);
        obj = bdrv_info_stats_bs(bs);
        qlist_append_obj(devices, obj);
    }

@@ -1715,6 +1878,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
        /* Update stats even though technically transfer has not happened. */
        bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
        bs->wr_ops ++;
        if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
            bs->wr_highest_sector = sector_num + nb_sectors - 1;
        }
    }

    return ret;
+2 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ BlockDriver *bdrv_find_format(const char *format_name);
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
int bdrv_create(BlockDriver *drv, const char* filename,
    QEMUOptionParameter *options);
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
BlockDriverState *bdrv_new(const char *device_name);
void bdrv_delete(BlockDriverState *bs);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
@@ -121,6 +122,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
void bdrv_flush(BlockDriverState *bs);
void bdrv_flush_all(void);

int bdrv_has_zero_init(BlockDriverState *bs);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
	int *pnum);

+6 −11
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ typedef struct BlkdebugVars {
} BlkdebugVars;

typedef struct BDRVBlkdebugState {
    BlockDriverState *hd;
    BlkdebugVars vars;
    QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
} BDRVBlkdebugState;
@@ -303,7 +302,7 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
    filename = c + 1;

    /* Open the backing file */
    ret = bdrv_file_open(&s->hd, filename, flags);
    ret = bdrv_file_open(&bs->file, filename, flags);
    if (ret < 0) {
        return ret;
    }
@@ -362,7 +361,7 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
    }

    BlockDriverAIOCB *acb =
        bdrv_aio_readv(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
    return acb;
}

@@ -377,7 +376,7 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
    }

    BlockDriverAIOCB *acb =
        bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque);
        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
    return acb;
}

@@ -393,21 +392,17 @@ static void blkdebug_close(BlockDriverState *bs)
            qemu_free(rule);
        }
    }

    bdrv_delete(s->hd);
}

static void blkdebug_flush(BlockDriverState *bs)
{
    BDRVBlkdebugState *s = bs->opaque;
    bdrv_flush(s->hd);
    bdrv_flush(bs->file);
}

static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
    BlockDriverCompletionFunc *cb, void *opaque)
{
    BDRVBlkdebugState *s = bs->opaque;
    return bdrv_aio_flush(s->hd, cb, opaque);
    return bdrv_aio_flush(bs->file, cb, opaque);
}

static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
@@ -456,7 +451,7 @@ static BlockDriver bdrv_blkdebug = {

    .instance_size      = sizeof(BDRVBlkdebugState),

    .bdrv_open          = blkdebug_open,
    .bdrv_file_open     = blkdebug_open,
    .bdrv_close         = blkdebug_close,
    .bdrv_flush         = blkdebug_flush,

+1 −1
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ static BlockDriver bdrv_bochs = {
    .format_name	= "bochs",
    .instance_size	= sizeof(BDRVBochsState),
    .bdrv_probe		= bochs_probe,
    .bdrv_open		= bochs_open,
    .bdrv_file_open	= bochs_open,
    .bdrv_read		= bochs_read,
    .bdrv_close		= bochs_close,
};
Loading