vvfat: Use BdrvChild for s->qcow

vvfat uses a temporary qcow file to cache written data in read-write
mode. In order to do things properly, this should show up in the BDS
graph and I/O should go through BdrvChild like for every other node.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Kevin Wolf 2016-05-30 17:13:09 +02:00
parent a9d52a7563
commit eecc77473b

View file

@ -341,9 +341,8 @@ typedef struct BDRVVVFATState {
unsigned int current_cluster; unsigned int current_cluster;
/* write support */ /* write support */
BlockDriverState* write_target;
char* qcow_filename; char* qcow_filename;
BlockDriverState* qcow; BdrvChild* qcow;
void* fat2; void* fat2;
char* used_clusters; char* used_clusters;
array_t commits; array_t commits;
@ -981,7 +980,7 @@ static int init_directories(BDRVVVFATState* s,
static BDRVVVFATState *vvv = NULL; static BDRVVVFATState *vvv = NULL;
#endif #endif
static int enable_write_target(BDRVVVFATState *s, Error **errp); static int enable_write_target(BlockDriverState *bs, Error **errp);
static int is_consistent(BDRVVVFATState *s); static int is_consistent(BDRVVVFATState *s);
static QemuOptsList runtime_opts = { static QemuOptsList runtime_opts = {
@ -1159,7 +1158,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
/* read only is the default for safety */ /* read only is the default for safety */
bs->read_only = true; bs->read_only = true;
s->qcow = s->write_target = NULL; s->qcow = NULL;
s->qcow_filename = NULL; s->qcow_filename = NULL;
s->fat2 = NULL; s->fat2 = NULL;
s->downcase_short_names = 1; s->downcase_short_names = 1;
@ -1170,7 +1169,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
if (qemu_opt_get_bool(opts, "rw", false)) { if (qemu_opt_get_bool(opts, "rw", false)) {
ret = enable_write_target(s, errp); ret = enable_write_target(bs, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -1391,9 +1390,10 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
return -1; return -1;
if (s->qcow) { if (s->qcow) {
int n; int n;
if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) { if (bdrv_is_allocated(s->qcow->bs, sector_num, nb_sectors-i, &n)) {
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n)); DLOG(fprintf(stderr, "sectors %d+%d allocated\n",
if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) { (int)sector_num, n));
if (bdrv_read(s->qcow->bs, sector_num, buf + i * 0x200, n)) {
return -1; return -1;
} }
i += n - 1; i += n - 1;
@ -1669,12 +1669,15 @@ static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
int was_modified = 0; int was_modified = 0;
int i, dummy; int i, dummy;
if (s->qcow == NULL) if (s->qcow == NULL) {
return 0; return 0;
}
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
was_modified = bdrv_is_allocated(s->qcow, was_modified = bdrv_is_allocated(s->qcow->bs,
cluster2sector(s, cluster_num) + i, 1, &dummy); cluster2sector(s, cluster_num) + i,
1, &dummy);
}
return was_modified; return was_modified;
} }
@ -1823,11 +1826,17 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
vvfat_close_current_file(s); vvfat_close_current_file(s);
for (i = 0; i < s->sectors_per_cluster; i++) { for (i = 0; i < s->sectors_per_cluster; i++) {
if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) { int res;
if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
res = bdrv_is_allocated(s->qcow->bs, offset + i, 1, &dummy);
if (!res) {
res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
if (res) {
return -1; return -1;
} }
if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) { res = bdrv_write(s->qcow->bs, offset,
s->cluster_buffer, 1);
if (res) {
return -2; return -2;
} }
} }
@ -2783,8 +2792,8 @@ static int do_commit(BDRVVVFATState* s)
return ret; return ret;
} }
if (s->qcow->drv->bdrv_make_empty) { if (s->qcow->bs->drv->bdrv_make_empty) {
s->qcow->drv->bdrv_make_empty(s->qcow); s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
} }
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
@ -2880,7 +2889,7 @@ DLOG(checkpoint());
* Use qcow backend. Commit later. * Use qcow backend. Commit later.
*/ */
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors); ret = bdrv_write(s->qcow->bs, sector_num, buf, nb_sectors);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error writing to qcow backend\n"); fprintf(stderr, "Error writing to qcow backend\n");
return ret; return ret;
@ -2950,7 +2959,7 @@ write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
static void write_target_close(BlockDriverState *bs) { static void write_target_close(BlockDriverState *bs) {
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bdrv_unref(s->qcow); bdrv_unref_child(s->bs, s->qcow);
g_free(s->qcow_filename); g_free(s->qcow_filename);
} }
@ -2960,8 +2969,19 @@ static BlockDriver vvfat_write_target = {
.bdrv_close = write_target_close, .bdrv_close = write_target_close,
}; };
static int enable_write_target(BDRVVVFATState *s, Error **errp) static void vvfat_qcow_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
{ {
*child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
}
static const BdrvChildRole child_vvfat_qcow = {
.inherit_options = vvfat_qcow_options,
};
static int enable_write_target(BlockDriverState *bs, Error **errp)
{
BDRVVVFATState *s = bs->opaque;
BlockDriver *bdrv_qcow = NULL; BlockDriver *bdrv_qcow = NULL;
BlockDriverState *backing; BlockDriverState *backing;
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
@ -3000,8 +3020,8 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
options = qdict_new(); options = qdict_new();
qdict_put(options, "driver", qstring_from_str("qcow")); qdict_put(options, "driver", qstring_from_str("qcow"));
s->qcow = bdrv_open(s->qcow_filename, NULL, options, s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp); &child_vvfat_qcow, false, errp);
if (!s->qcow) { if (!s->qcow) {
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;