#include "qapi/error.h"
#include "block/block_int.h"
#include "qemu/module.h"
+#include "qemu/bswap.h"
#include "migration/migration.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qbool.h"
static inline void* array_get_next(array_t* array) {
unsigned int next = array->next;
- void* result;
if (array_ensure_allocated(array, next) < 0)
return NULL;
array->next = next + 1;
- result = array_get(array, next);
-
- return result;
+ return array_get(array, next);
}
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
unsigned int current_cluster;
/* write support */
- BlockDriverState* write_target;
char* qcow_filename;
- BlockDriverState* qcow;
+ BdrvChild* qcow;
void* fat2;
char* used_clusters;
array_t commits;
static BDRVVVFATState *vvv = NULL;
#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 QemuOptsList runtime_opts = {
goto fail;
}
memcpy(s->volume_label, label, label_length);
+ } else {
+ memcpy(s->volume_label, "QEMU VVFAT", 10);
}
if (floppy) {
s->current_cluster=0xffffffff;
/* read only is the default for safety */
- bs->read_only = 1;
- s->qcow = s->write_target = NULL;
+ bs->read_only = true;
+ s->qcow = NULL;
s->qcow_filename = NULL;
s->fat2 = NULL;
s->downcase_short_names = 1;
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
if (qemu_opt_get_bool(opts, "rw", false)) {
- ret = enable_write_target(s, errp);
+ ret = enable_write_target(bs, errp);
if (ret < 0) {
goto fail;
}
- bs->read_only = 0;
+ bs->read_only = false;
}
bs->total_sectors = cyls * heads * secs;
return ret;
}
+static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
+{
+ bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
+}
+
static inline void vvfat_close_current_file(BDRVVVFATState *s)
{
if(s->current_mapping) {
return -1;
if (s->qcow) {
int n;
- if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
-DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
- if (bdrv_read(s->qcow, sector_num, buf + i*0x200, 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));
+ if (bdrv_read(s->qcow, sector_num, buf + i * 0x200, n)) {
return -1;
}
i += n - 1;
return 0;
}
-static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
+static int coroutine_fn
+vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
int ret;
BDRVVVFATState *s = bs->opaque;
+ uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
+ int nb_sectors = bytes >> BDRV_SECTOR_BITS;
+ void *buf;
+
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
+
+ buf = g_try_malloc(bytes);
+ if (bytes && buf == NULL) {
+ return -ENOMEM;
+ }
+
qemu_co_mutex_lock(&s->lock);
ret = vvfat_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock);
+
+ qemu_iovec_from_buf(qiov, 0, buf, bytes);
+ g_free(buf);
+
return ret;
}
int was_modified = 0;
int i, dummy;
- if (s->qcow == NULL)
- return 0;
+ if (s->qcow == NULL) {
+ return 0;
+ }
- for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
- was_modified = bdrv_is_allocated(s->qcow,
- cluster2sector(s, cluster_num) + i, 1, &dummy);
+ for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
+ was_modified = bdrv_is_allocated(s->qcow->bs,
+ cluster2sector(s, cluster_num) + i,
+ 1, &dummy);
+ }
return was_modified;
}
vvfat_close_current_file(s);
for (i = 0; i < s->sectors_per_cluster; i++) {
- if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
- if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
+ int res;
+
+ 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;
}
- if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
+ res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
+ if (res) {
return -2;
}
}
/* check file size with FAT */
cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
if (cluster_count !=
- (le32_to_cpu(direntries[i].size) + s->cluster_size
- - 1) / s->cluster_size) {
+ DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
DLOG(fprintf(stderr, "Cluster count mismatch\n"));
goto fail;
}
factor * (old_cluster_count - new_cluster_count));
for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
+ direntry_t *first_direntry;
void* direntry = array_get(&(s->directory), current_dir_index);
int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
s->sectors_per_cluster);
if (ret)
return ret;
- assert(!strncmp(s->directory.pointer, "QEMU", 4));
+
+ /* The first directory entry on the filesystem is the volume name */
+ first_direntry = (direntry_t*) s->directory.pointer;
+ assert(!memcmp(first_direntry->name, s->volume_label, 11));
+
current_dir_index += factor;
}
return ret;
}
- if (s->qcow->drv->bdrv_make_empty) {
- s->qcow->drv->bdrv_make_empty(s->qcow);
+ if (s->qcow->bs->drv->bdrv_make_empty) {
+ s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
}
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
return 0;
}
-static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
+static int coroutine_fn
+vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
int ret;
BDRVVVFATState *s = bs->opaque;
+ uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
+ int nb_sectors = bytes >> BDRV_SECTOR_BITS;
+ void *buf;
+
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
+
+ buf = g_try_malloc(bytes);
+ if (bytes && buf == NULL) {
+ return -ENOMEM;
+ }
+ qemu_iovec_to_buf(qiov, 0, buf, bytes);
+
qemu_co_mutex_lock(&s->lock);
ret = vvfat_write(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock);
+
+ g_free(buf);
+
return ret;
}
return BDRV_BLOCK_DATA;
}
-static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
- const uint8_t* buffer, int nb_sectors) {
+static int coroutine_fn
+write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
+{
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
return try_commit(s);
}
static void write_target_close(BlockDriverState *bs) {
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
- bdrv_unref(s->qcow);
+ bdrv_unref_child(s->bs, s->qcow);
g_free(s->qcow_filename);
}
static BlockDriver vvfat_write_target = {
.format_name = "vvfat_write_target",
- .bdrv_write = write_target_commit,
+ .bdrv_co_pwritev = write_target_commit,
.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)
{
+ qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
+ *child_flags = 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;
BlockDriverState *backing;
QemuOpts *opts = NULL;
goto err;
}
- s->qcow = NULL;
options = qdict_new();
- qdict_put(options, "driver", qstring_from_str("qcow"));
- ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, options,
- BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp);
- if (ret < 0) {
+ qdict_put(options, "write-target.driver", qstring_from_str("qcow"));
+ s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
+ &child_vvfat_qcow, false, errp);
+ QDECREF(options);
+ if (!s->qcow) {
+ ret = -EINVAL;
goto err;
}
.bdrv_parse_filename = vvfat_parse_filename,
.bdrv_file_open = vvfat_open,
+ .bdrv_refresh_limits = vvfat_refresh_limits,
.bdrv_close = vvfat_close,
- .bdrv_read = vvfat_co_read,
- .bdrv_write = vvfat_co_write,
+ .bdrv_co_preadv = vvfat_co_preadv,
+ .bdrv_co_pwritev = vvfat_co_pwritev,
.bdrv_co_get_block_status = vvfat_co_get_block_status,
};