2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
11 * All rights reserved.
13 * Author: Yang Yang <geraint0923@gmail.com>
14 * Weixiao Fu <weixiaofu2014@u.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
23 #include <interfaces/vmm_file.h>
24 #include <palacios/vm_guest.h>
26 #ifndef V3_CONFIG_DEBUG_QCOWDISK
28 #define PrintDebug(fmt, args...)
31 #define V3_PACKED __attribute__((packed))
32 #define QCOW2_MAGIC (('Q'<<24) | ('F'<<16) | ('I'<<8) | (0xfb))
34 #define QCOW2_COPIED (1ULL<<63)
35 #define QCOW2_COMPRESSED (1ULL<<62)
36 #define INIT_BUFF_SIZE (512)
38 #define ERROR(...) PrintError(VM_NONE,VCORE_NONE,"qcow2: " __VA_ARGS__)
39 #define DEBUG(...) PrintDebug(VM_NONE,VCORE_NONE,"qcow2: " __VA_ARGS__)
40 #define INFO(...) V3_Print(VM_NONE,VCORE_NONE,"qcow2: " __VA_ARGS__)
43 // the header structure for QCOW2
44 typedef struct v3_qcow2_header {
48 uint64_t backing_file_offset;
49 uint32_t backing_file_size;
51 uint32_t cluster_bits;
54 uint32_t crypt_method;
57 uint64_t l1_table_offset;
59 uint64_t refcount_table_offset;
60 uint32_t refcount_table_clusters;
62 uint32_t nb_snapshots;
63 uint64_t snapshots_offset;
65 } V3_PACKED v3_qcow2_header_t;
67 // the header structure for each QCOW2 snapshot
68 typedef struct v3_qcow2_snapshot_header {
69 uint64_t l1_table_offset;
78 uint64_t vm_clock_nsec;
79 uint32_t vm_state_size;
80 uint32_t extra_data_size;
81 } V3_PACKED v3_qcow2_snapshot_header_t;
83 // the private structure used by QCOW2 implementation
84 typedef struct v3_qcow2 {
86 struct v3_qcow2 *backing_qcow2;
87 char *backing_file_name;
88 uint64_t cluster_size;
93 uint32_t refcount_block_bits;
94 uint64_t refcount_block_mask;
95 uint32_t refcount_table_bits;
96 uint64_t refcount_table_mask;
97 uint64_t free_cluster_index;
98 v3_qcow2_header_t header;
101 typedef struct v3_qcow2_table_entry {
103 uint8_t compressed: 1;
105 } v3_qcow2_table_entry_t;
108 // our implementations for Big/Little Endian conversion
109 static inline uint16_t be16toh(uint16_t v)
111 return ((v&0xff)<<8) | ((v&0xff00)>>8);
114 static inline uint32_t be32toh(uint32_t v)
116 return (((uint32_t)be16toh(v&0x0000ffffU))<<16) | (uint32_t)be16toh((v&0xffff0000U)>>16);
119 static inline uint64_t be64toh(uint64_t v)
121 return (((uint64_t)be32toh(v&0x00000000ffffffffU))<<32) | (uint64_t)be32toh((v&0xffffffff00000000U)>>32);
124 static inline uint16_t htobe16(uint16_t v)
129 static inline uint64_t htobe64(uint64_t v)
134 uint64_t v3_qcow2_get_capacity(v3_qcow2_t *pf)
136 return pf ? pf->header.size : 0;
139 static inline uint64_t v3_qcow2_get_cluster_index(v3_qcow2_t *pf, uint64_t file_pos)
144 return file_pos >> pf->header.cluster_bits;
147 static int v3_qcow2_get_refcount(v3_qcow2_t *pf, uint64_t idx)
149 int res = -1, ret = 0;
151 uint64_t table_idx = 0, block_idx = 0, block_offset = 0;
157 block_idx = idx & pf->refcount_block_mask;
158 idx >>= pf->refcount_block_bits;
159 table_idx = idx & pf->refcount_table_mask;
161 ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
163 // FIXME: how to deal with the wrong position
164 if (ret != sizeof(uint64_t)) {
165 ERROR("read failed\n");
169 block_offset = be64toh(block_offset);
171 // if cluster is not yet allocated, return 0
176 ret = v3_file_read(pf->fd, (uint8_t*)&val, sizeof(uint16_t), block_offset + block_idx * sizeof(uint16_t));
178 if (ret != sizeof(uint16_t)) {
179 ERROR("read failed\n");
189 * this function is a wrapper of v3_qcow2_get_refcount
190 * takes file offset and returns the reference count
191 * it is commented to avoid compile warning
194 __attribute__((unused))
195 static int v3_qcow2_get_refcount_by_file_position(v3_qcow2_t *pf, uint64_t file_pos)
203 idx = v3_qcow2_get_cluster_index(pf, file_pos);
205 return v3_qcow2_get_refcount(pf, idx);
210 * to allocate the contiguous clusters
211 * return the cluster index in the QCOW2 file
212 * return positive if successfully, otherwise zero(0)
214 static uint64_t v3_qcow2_alloc_clusters(v3_qcow2_t *pf, uint32_t nb_clusters)
218 uint64_t idx = 0, ret_idx = 0;
229 * referenced the algorithm from Qemu
232 ret_idx = pf->free_cluster_index;
233 for (i = 0; i < nb_clusters; i++) {
234 idx = pf->free_cluster_index++;
235 refcount = v3_qcow2_get_refcount(pf, idx);
238 } else if(refcount) {
245 static int v3_qcow2_addr_split(v3_qcow2_t *qc2, uint64_t addr, uint64_t *l1_idx, uint64_t *l2_idx, uint64_t *offset)
247 if (!qc2 || !l1_idx || !l2_idx || !offset) {
251 *offset = addr & (qc2->cluster_size - 1);
252 addr = addr >> qc2->header.cluster_bits;
253 *l2_idx = addr & qc2->l2_mask;
254 addr = addr >> qc2->l2_bits;
255 *l1_idx = addr * qc2->l1_mask;
260 static v3_qcow2_t *v3_qcow2_open(struct v3_vm_info* vm, char *path, int flags)
267 v3_qcow2_t *res = (v3_qcow2_t*)V3_Malloc(sizeof(v3_qcow2_t));
270 ERROR("failed to allocate\n");
274 memset(res, 0, sizeof(v3_qcow2_t));
276 res->fd = v3_file_open(vm, path, flags);
279 ERROR("failed to open underlying file\n");
283 ret = v3_file_read(res->fd, (uint8_t*)&res->header, sizeof(res->header), 0);
285 if (ret != sizeof(res->header)) {
286 ERROR("failed to read header\n");
290 res->header.magic = be32toh(res->header.magic);
292 if (res->header.magic != QCOW2_MAGIC) {
293 ERROR("wrong magic in header\n");
298 DEBUG("right magic\n");
302 res->header.version = be32toh(res->header.version);
304 if (res->header.version < 2) {
305 ERROR("unsupported version: %d\n", res->header.version);
310 DEBUG("supported version: %d\n", res->header.version);
314 res->header.backing_file_offset = be64toh(res->header.backing_file_offset);
315 res->header.backing_file_size = be32toh(res->header.backing_file_size);
317 if (res->header.backing_file_size) {
319 DEBUG("backing file size is larger than zero: %d\n", res->header.backing_file_size);
322 res->backing_file_name = (char*)V3_Malloc(res->header.backing_file_size + 1);
324 if (!res->backing_file_name) {
325 ERROR("failed to allocate memory for backing file name\n");
329 res->backing_file_name[res->header.backing_file_size] = 0;
331 ret = v3_file_read(res->fd, (void*)res->backing_file_name, res->header.backing_file_size, res->header.backing_file_offset);
333 if(ret != res->header.backing_file_size) {
334 ERROR("failed to read backing file name from %s\n", path);
335 V3_Free(res->backing_file_name);
339 res->backing_qcow2 = v3_qcow2_open(vm, res->backing_file_name, flags);
341 if(res->backing_qcow2) {
342 DEBUG("load backing file successfully\n");
344 ERROR("failed to load backing file, exit\n");
348 DEBUG("successfully read the backing file name: %s\n", res->backing_file_name);
353 res->backing_qcow2 = NULL;
355 DEBUG("read no backing file name since size == %d\n", res->header.backing_file_size);
359 res->header.cluster_bits = be32toh(res->header.cluster_bits);
360 res->cluster_size = 1 << res->header.cluster_bits;
361 res->l2_bits = res->header.cluster_bits - 3;
362 res->l2_mask = (((uint64_t)1)<<res->l2_bits) - 1;
363 res->l1_bits = sizeof(uint64_t) * 8 - res->l2_bits - res->header.cluster_bits;
364 res->l1_mask = (((uint64_t)1)<<res->l1_bits) - 1;
366 DEBUG("cluster_bits: %d\n", res->header.cluster_bits);
368 res->header.size = be64toh(res->header.size);
370 DEBUG("size: %llu\n", res->header.size);
372 res->header.crypt_method = be32toh(res->header.crypt_method);
374 if (res->header.crypt_method) {
375 DEBUG("AES encryption\n");
377 DEBUG("no encryption\n");
380 res->header.l1_size = be32toh(res->header.l1_size);
381 res->header.l1_table_offset = be64toh(res->header.l1_table_offset);
383 res->header.refcount_table_offset = be64toh(res->header.refcount_table_offset);
384 res->header.refcount_table_clusters = be32toh(res->header.refcount_table_clusters);
386 res->refcount_block_bits = res->header.cluster_bits - 1;
387 res->refcount_block_mask = (1LL<<res->refcount_block_bits) - 1;
388 res->refcount_table_bits = 8 * sizeof(uint64_t) - res->refcount_block_bits;
389 res->refcount_table_mask = (1LL<<res->refcount_table_bits) - 1;
391 res->header.nb_snapshots = be32toh(res->header.nb_snapshots);
392 res->header.snapshots_offset = be64toh(res->header.snapshots_offset);
395 DEBUG("l1 size: %d\n", res->header.l1_size);
396 DEBUG("l1 table offset: %llu\n", res->header.l1_table_offset);
398 DEBUG("refcount_table_offset: %llu\n", res->header.refcount_table_offset);
399 DEBUG("refcount_table_clusters: %d\n", res->header.refcount_table_clusters);
401 DEBUG("nb_snapshots: %d\n", res->header.nb_snapshots);
402 DEBUG("snapshots_offset: %llu\n", res->header.snapshots_offset);
404 res->free_cluster_index = 1;
406 // TODO: initialize the free cluster index to a reasonable value
408 if (v3_qcow2_get_refcount(res, res->free_cluster_index)) {
409 res->free_cluster_index++;
419 v3_file_close(res->fd);
426 static void v3_qcow2_close(v3_qcow2_t *pf)
432 v3_file_close(pf->fd);
434 if (pf->backing_file_name) {
435 V3_Free(pf->backing_file_name);
438 if (pf->backing_qcow2) {
439 v3_qcow2_close(pf->backing_qcow2);
445 static uint64_t v3_qcow2_get_cluster_offset(v3_qcow2_t *qc, uint64_t l1_idx, uint64_t l2_idx, uint64_t offset)
448 uint64_t l1_val = 0, l2_val = 0;
449 v3_qcow2_table_entry_t *ent = NULL;
456 if (l1_idx >= qc->header.l1_size) {
460 ret = v3_file_read(qc->fd, (void*)&l1_val, sizeof(uint64_t), l1_idx * sizeof(uint64_t) + qc->header.l1_table_offset);
462 if (ret != sizeof(uint64_t)) {
463 ERROR("Failed to read L1\n");
467 l1_val = be64toh(l1_val);
468 ent = (v3_qcow2_table_entry_t*)&l1_val;
474 ret = v3_file_read(qc->fd, (void*)&l2_val, sizeof(uint64_t), l2_idx * sizeof(uint64_t) + ent->offset);
476 if (ret != sizeof(uint64_t)) {
477 ERROR("Failed to read L2\n");
481 l2_val = be64toh(l2_val);
482 ent = (v3_qcow2_table_entry_t*)&l2_val;
490 static int v3_qcow2_read_cluster(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len)
493 uint64_t l1_idx = 0, l2_idx = 0, offset = 0;
494 uint64_t file_offset = 0;
496 if(!pf || !buff || !len) {
500 ret = v3_qcow2_addr_split(pf, pos, &l1_idx, &l2_idx, &offset);
503 ERROR("failed to split address\n");
507 file_offset = v3_qcow2_get_cluster_offset(pf, l1_idx, l2_idx, offset);
511 ret = v3_file_read(pf->fd, buff, len, file_offset + (pos & (pf->cluster_size - 1)));
513 // it is possible to get a negative value because of the hole
518 } else if(pf->backing_qcow2) {
519 return v3_qcow2_read_cluster(pf->backing_qcow2, buff, pos, len);
521 memset(buff, 0, len);
527 static int v3_qcow2_read(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len)
529 if(!pf || !buff || !len) {
533 uint64_t next_addr, cur_len;
537 next_addr = (pos + pf->cluster_size) & ~(pf->cluster_size - 1);
538 cur_len = next_addr - pos;
539 cur_len = cur_len < len ? cur_len : len;
540 //DEBUG("pos=%lu, len=%lu\n", pos, cur_len);
541 ret = v3_qcow2_read_cluster(pf, buff, pos, cur_len);
553 // in this function, we assmue we must have the corresponding refcount block
554 // so we will not allocate the refcount block here
555 static int v3_qcow2_update_refcount(v3_qcow2_t *pf, uint64_t cluster_idx, int count)
557 uint64_t table_idx = 0, block_idx = 0, block_offset = 0, idx = cluster_idx;
559 uint16_t val = count;
565 block_idx = idx & pf->refcount_block_mask;
566 idx >>= pf->refcount_block_bits;
567 table_idx = idx & pf->refcount_table_mask;
569 ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
571 if (ret != sizeof(uint64_t) || !block_offset) {
572 ERROR("something wrong with update refcount, exit\n");
576 block_offset = be64toh(block_offset);
579 ret = v3_file_write(pf->fd, (uint8_t*)&val, sizeof(uint16_t), block_offset + block_idx * sizeof(uint16_t));
581 if (ret != sizeof(uint16_t)) {
582 ERROR("write failed when update refcount, exit\n");
589 // in this function, we need to resolve the circular dependency when the refcount itself is not allocated
590 // since for cluster_bits==16, it needs 65536G to use more than one cluster to contain all the refcount
591 // table, we don't handle that case
592 // of course, we can handle this case if we have enough time
593 static int v3_qcow2_alloc_refcount(v3_qcow2_t *pf, uint64_t cluster_idx)
596 uint8_t zero_buff[INIT_BUFF_SIZE];
598 uint64_t idx = cluster_idx, table_idx = 0, block_idx = 0, block_offset = 0;
599 uint64_t new_cluster_idx, new_table_idx = 0, new_block_idx = 0, write_value;
600 uint64_t left_size, start_offset, buf_length;
606 block_idx = idx & pf->refcount_block_mask;
607 idx >>= pf->refcount_block_bits;
608 table_idx = idx & pf->refcount_table_mask;
610 // TODO: re-allocate larger refcount table if needed
613 ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
615 if (ret != sizeof(uint64_t) || table_idx > pf->header.refcount_table_clusters) {
616 ERROR("read failed, exit!\n");
620 block_offset = be64toh(block_offset);
623 // allocate a cluster as a new refcount block
624 // and also initialize this cluster with zeros
626 new_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
628 if (new_cluster_idx <= 0) {
629 ERROR("failed to allocate new cluster, exit!\n");
633 idx = new_cluster_idx;
634 new_block_idx = idx & pf->refcount_block_mask;
635 idx >>= pf->refcount_block_bits;
636 new_table_idx = idx & pf->refcount_table_mask;
638 // initialize with zeros
639 start_offset = new_cluster_idx << pf->header.cluster_bits;
640 left_size = pf->cluster_size;
641 memset(zero_buff, 0, INIT_BUFF_SIZE);
643 while (left_size > 0) {
645 buf_length = INIT_BUFF_SIZE < left_size ? INIT_BUFF_SIZE : left_size;
647 ret = v3_file_write(pf->fd, zero_buff, buf_length, start_offset);
649 if (ret != buf_length) {
650 ERROR("something wrong with write, exit\n");
654 start_offset += buf_length;
656 left_size -= buf_length;
660 // update the refcount table with the new refcount block
662 write_value = htobe64(new_table_idx << pf->header.cluster_bits);
664 ret = v3_file_write(pf->fd, (uint8_t*)&write_value, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
666 if (ret != sizeof(uint64_t) ) {
667 ERROR("write of data failed\n");
671 if (new_table_idx == table_idx) {
672 // in the same refcount block, increase its refcount here
675 ret = v3_file_write(pf->fd, (uint8_t*)&val, sizeof(uint16_t), (new_table_idx << pf->header.cluster_bits) + sizeof(uint16_t) * new_block_idx);
677 if (ret != sizeof(uint16_t)) {
678 ERROR("write failed\n");
683 v3_qcow2_alloc_refcount(pf, new_cluster_idx);
684 v3_qcow2_update_refcount(pf, new_cluster_idx, 1);
696 static int v3_qcow2_increase_refcount(v3_qcow2_t *pf, uint64_t cluster_idx)
704 refcount = v3_qcow2_get_refcount(pf, cluster_idx);
707 // execute to here means that no cluster block entry is allocated
708 // we need to allocate the entry here
709 refcount = v3_qcow2_alloc_refcount(pf, cluster_idx);
712 ERROR("something wrong when allocate refcount entry, exit!\n");
724 // write the refcount back to the file
725 return v3_qcow2_update_refcount(pf, cluster_idx, refcount);
729 * this function is to decrease the reference count of a cluster
730 * since the snapshot is not implemented,
732 __attribute__ ((unused))
733 static int v3_qcow2_decrease_refcount(v3_qcow2_t *pf, uint64_t cluster_idx)
741 refcount = v3_qcow2_get_refcount(pf, cluster_idx);
744 ERROR("attempt to decrease the refcount for a cluster, exit\n");
750 return v3_qcow2_update_refcount(pf, cluster_idx, refcount);
755 * do nothing but return if no need to allocate new cluster
756 * only allocate one cluster if necessary
758 static uint64_t v3_qcow2_alloc_cluster_offset(v3_qcow2_t *pf, uint64_t pos)
760 uint64_t res = 0, l1_idx = 0, l2_idx = 0, offset = 0, l2_cluster_offset, done_bytes;
761 uint64_t l2_cluster_idx;
762 uint64_t cluster_offset = 0;
764 uint8_t init_buff[INIT_BUFF_SIZE], *data_buff;
770 ret = v3_qcow2_addr_split(pf, pos, &l1_idx, &l2_idx, &offset);
773 ERROR("cannot split address\n");
777 // FIXME: in fact, we should check the refcount to be 1,
778 // otherwise we should copy
781 res = v3_qcow2_get_cluster_offset(pf, l1_idx, l2_idx, offset);
784 cluster_offset = res;
789 * need to allocate a new cluster for write
790 * also need to update the l1 and l2 table
793 ret = v3_file_read(pf->fd, (uint8_t*)&l2_cluster_offset, sizeof(uint64_t), pf->header.l1_table_offset + sizeof(uint64_t) * l1_idx);
795 if (ret != sizeof(uint64_t)) {
796 ERROR("read failed\n");
800 l2_cluster_offset = be64toh(l2_cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
802 if (!l2_cluster_offset/*l1_idx >= pf->header.l1_size*/) { // huh?
804 * need to allocate a new l1 entry
805 * for simplicity, only allow 2^(cluster_bits-3) entry in l1 table
808 l2_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
809 l2_cluster_offset = (l2_cluster_idx << pf->header.cluster_bits);
811 // increase the reference count for this cluster
812 v3_qcow2_increase_refcount(pf, l2_cluster_idx);
814 memset(init_buff, 0, INIT_BUFF_SIZE);
816 for (done_bytes = 0; done_bytes < pf->cluster_size; done_bytes += INIT_BUFF_SIZE) {
818 ret = v3_file_write(pf->fd, init_buff, INIT_BUFF_SIZE, l2_cluster_offset + done_bytes);
820 if (ret != INIT_BUFF_SIZE) {
821 ERROR("write failed\n");
829 l2_cluster_offset |= QCOW2_COPIED;
830 l2_cluster_offset = htobe64(l2_cluster_offset);
832 ret = v3_file_write(pf->fd, (uint8_t*)&l2_cluster_offset, sizeof(uint64_t), pf->header.l1_table_offset + sizeof(uint64_t) * l1_idx);
834 if (ret != sizeof(uint64_t)) {
835 ERROR("write failed\n");
841 ret = v3_file_read(pf->fd, (uint8_t*)&l2_cluster_offset, sizeof(uint64_t), pf->header.l1_table_offset + sizeof(uint64_t) * l1_idx);
843 if (ret != sizeof(uint64_t)) {
844 ERROR("read failed\n");
848 l2_cluster_offset = be64toh(l2_cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
851 * begin to retrieve cluster_offset
854 // adjust the l2_cluster_offset to the right entry address
855 l2_cluster_offset += sizeof(uint64_t) * l2_idx;
857 ret = v3_file_read(pf->fd, (uint8_t*)&cluster_offset, sizeof(uint64_t), l2_cluster_offset);
859 if (ret!=sizeof(uint64_t)) {
860 ERROR("read failed\n");
864 cluster_offset = be64toh(cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
866 if (!cluster_offset) {
868 * if the cluster_offset is not allocated
870 l2_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
871 cluster_offset = (l2_cluster_idx << pf->header.cluster_bits);
873 // TODO: initialization
874 // initialize the cluster with the original data
875 data_buff = (uint8_t*)V3_Malloc(pf->cluster_size);
879 pos = (pos >> pf->header.cluster_bits) << pf->header.cluster_bits;
881 v3_qcow2_read_cluster(pf, data_buff, pos, pf->cluster_size);
883 ret = v3_file_write(pf->fd, data_buff, pf->cluster_size, cluster_offset);
885 if (ret!=pf->cluster_size) {
886 ERROR("write failed\n");
894 ERROR("failed to initialize the original data\n");
898 offset = htobe64(cluster_offset | QCOW2_COPIED);
900 ret = v3_file_write(pf->fd, (uint8_t*)&offset, sizeof(uint64_t), l2_cluster_offset);
902 if (ret!=sizeof(uint64_t)) {
903 ERROR("write failed\n");
907 v3_qcow2_increase_refcount(pf, l2_cluster_idx);
912 return cluster_offset;
915 static int v3_qcow2_write_cluster(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len)
921 uint64_t cluster_addr, cluster_offset;
924 cluster_addr = v3_qcow2_alloc_cluster_offset(pf, pos);
927 ERROR("zero cluster address\n");
931 cluster_offset = pos & (pf->cluster_size - 1);
933 ret = v3_file_write(pf->fd, buff, len, cluster_addr + cluster_offset);
936 ERROR("write failed\n");
943 static int v3_qcow2_write(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len)
945 if (!pf || !buff || !len) {
949 uint64_t next_addr, cur_len;
953 next_addr = (pos + pf->cluster_size) & ~(pf->cluster_size - 1);
954 cur_len = next_addr - pos;
955 cur_len = cur_len < len ? cur_len : len;
957 DEBUG("pos=%llu, len=%llu\n", pos, cur_len);
959 ret = v3_qcow2_write_cluster(pf, buff, pos, cur_len);
973 static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data)
975 v3_qcow2_t * disk = (v3_qcow2_t *) private_data;
977 DEBUG("QCOW Reading %llu bytes from %llu to 0x%p\n", num_bytes, lba, buf);
979 if (lba + num_bytes > disk->header.size) {
980 ERROR("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n",
981 lba, num_bytes, disk->header.size);
985 return v3_qcow2_read(disk, buf, lba, num_bytes);
989 static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data)
991 v3_qcow2_t * disk = (v3_qcow2_t *) private_data;
993 DEBUG("QCOW Writing %llu bytes from 0x%p to %llu\n", num_bytes, buf, lba);
995 if (lba + num_bytes > disk->header.size) {
996 ERROR("Out of bounds read: lba=%llu, num_bytes=%llu, capacity=%llu\n",
997 lba, num_bytes, disk->header.size);
1001 return v3_qcow2_write(disk, buf, lba, num_bytes);
1006 static uint64_t get_capacity(void * private_data)
1008 v3_qcow2_t * disk = (v3_qcow2_t *)private_data;
1010 DEBUG("Querying QCOWDISK capacity %llu\n", v3_qcow2_get_capacity(disk));
1012 return v3_qcow2_get_capacity(disk);
1015 static struct v3_dev_blk_ops blk_ops = {
1018 .get_capacity = get_capacity,
1024 static int disk_free(v3_qcow2_t * disk)
1026 v3_qcow2_close(disk);
1030 static struct v3_device_ops dev_ops = {
1031 .free = (int (*)(void *))disk_free,
1037 static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg)
1039 v3_qcow2_t * disk = NULL;
1040 char * path = v3_cfg_val(cfg, "path");
1041 char * dev_id = v3_cfg_val(cfg, "ID");
1042 char * writable = v3_cfg_val(cfg, "writable");
1043 char * writeable = v3_cfg_val(cfg, "writeable");
1045 v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
1046 int flags = FILE_OPEN_MODE_READ;
1048 PrintDebug(vm,VCORE_NONE,"Welcome to the QCOWDISK Implementation!\n");
1050 if ( ((writable) && (writable[0] == '1')) ||
1051 ((writeable) && (writeable[0] == '1')) ) {
1052 flags |= FILE_OPEN_MODE_WRITE;
1056 PrintError(vm, VCORE_NONE, "Missing path (%s) for %s\n", path, dev_id);
1060 disk = v3_qcow2_open(vm, path, flags);
1063 PrintError(vm, VCORE_NONE, "Could not open file disk:%s\n", path);
1067 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, disk);
1070 PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
1075 if (v3_dev_connect_blk(vm, v3_cfg_val(frontend_cfg, "tag"),
1076 &blk_ops, frontend_cfg, disk) == -1) {
1077 PrintError(vm, VCORE_NONE, "Could not connect %s to frontend %s\n",
1078 dev_id, v3_cfg_val(frontend_cfg, "tag"));
1079 v3_remove_device(dev);
1088 device_register("QCOWDISK", disk_init)