@@ -448,7 +448,8 @@ static int bdrv_qed_flush(BlockDriverState *bs)
static int qed_create(const char *filename, uint32_t cluster_size,
uint64_t image_size, uint32_t table_size,
- const char *backing_file, const char *backing_fmt)
+ const char *backing_file, const char *backing_fmt,
+ bool copy_on_read)
{
QEDHeader header = {
.magic = QED_MAGIC,
@@ -490,6 +491,9 @@ static int qed_create(const char *filename, uint32_t cluster_size,
if (qed_fmt_is_raw(backing_fmt)) {
header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
}
+ if (copy_on_read) {
+ header.compat_features |= QED_CF_COPY_ON_READ;
+ }
}
qed_header_cpu_to_le(&header, &le_header);
@@ -523,6 +527,7 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
uint32_t table_size = QED_DEFAULT_TABLE_SIZE;
const char *backing_file = NULL;
const char *backing_fmt = NULL;
+ bool copy_on_read = false;
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -539,6 +544,10 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
if (options->value.n) {
table_size = options->value.n;
}
+ } else if (!strcmp(options->name, "copy_on_read")) {
+ if (options->value.n) {
+ copy_on_read = true;
+ }
}
options++;
}
@@ -559,9 +568,14 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
qed_max_image_size(cluster_size, table_size));
return -EINVAL;
}
+ if (copy_on_read && !backing_file) {
+ fprintf(stderr,
+ "QED only supports Copy-on-Read with a backing file\n");
+ return -EINVAL;
+ }
return qed_create(filename, cluster_size, image_size, table_size,
- backing_file, backing_fmt);
+ backing_file, backing_fmt, copy_on_read);
}
typedef struct {
@@ -1092,6 +1106,27 @@ static void qed_aio_write_data(void *opaque, int ret,
}
/**
+ * Copy on read callback
+ *
+ * Write data from backing file to QED that's been read if CoR is enabled.
+ */
+static void qed_copy_on_read_cb(void *opaque, int ret)
+{
+ QEDAIOCB *acb = opaque;
+ BDRVQEDState *s = acb_to_s(acb);
+ BlockDriverAIOCB *cor_acb;
+
+ cor_acb = bdrv_aio_writev(s->bs,
+ acb->cur_pos / BDRV_SECTOR_SIZE,
+ &acb->cur_qiov,
+ acb->cur_qiov.size / BDRV_SECTOR_SIZE,
+ qed_aio_next_io, acb);
+ if (!cor_acb) {
+ qed_aio_complete(acb, -EIO);
+ }
+}
+
+/**
* Read data cluster
*
* @opaque: Read request
@@ -1127,8 +1162,14 @@ static void qed_aio_read_data(void *opaque, int ret,
qed_aio_next_io(acb, 0);
return;
} else if (ret != QED_CLUSTER_FOUND) {
+ BlockDriverCompletionFunc *cb = qed_aio_next_io;
+
+ if (bs->backing_hd &&
+ (s->header.compat_features & QED_CF_COPY_ON_READ)) {
+ cb = qed_copy_on_read_cb;
+ }
qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
- qed_aio_next_io, acb);
+ cb, acb);
return;
}
@@ -1349,6 +1390,10 @@ static QEMUOptionParameter qed_create_options[] = {
.name = BLOCK_OPT_TABLE_SIZE,
.type = OPT_SIZE,
.help = "L1/L2 table size (in clusters)"
+ }, {
+ .name = "copy_on_read",
+ .type = OPT_FLAG,
+ .help = "Copy blocks from base image on read"
},
{ /* end of list */ }
};
@@ -56,12 +56,19 @@ enum {
/* The backing file format must not be probed, treat as raw image */
QED_F_BACKING_FORMAT_NO_PROBE = 0x04,
- /* Feature bits must be used when the on-disk format changes */
- QED_FEATURE_MASK = QED_F_BACKING_FILE | /* supported feature bits */
+ /* Reads to the backing file should populate the image file */
+ QED_CF_COPY_ON_READ = 0x01,
+
+ /* Supported feature bits */
+ QED_FEATURE_MASK = QED_F_BACKING_FILE |
QED_F_NEED_CHECK |
QED_F_BACKING_FORMAT_NO_PROBE,
- QED_COMPAT_FEATURE_MASK = 0, /* supported compat feature bits */
- QED_AUTOCLEAR_FEATURE_MASK = 0, /* supported autoclear feature bits */
+
+ /* Supported compat feature bits */
+ QED_COMPAT_FEATURE_MASK = QED_CF_COPY_ON_READ,
+
+ /* Supported autoclear feature bits */
+ QED_AUTOCLEAR_FEATURE_MASK = 0,
/* Data is stored in groups of sectors called clusters. Cluster size must
* be large to avoid keeping too much metadata. I/O requests that have