Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


QCOW2 block storage backend for Palacios
[palacios.git] / palacios / src / devices / qcowdisk.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
11  * All rights reserved.
12  *
13  * Author: Yang Yang    <geraint0923@gmail.com>
14  *         Weixiao Fu   <weixiaofu2014@u.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22
23 #include <interfaces/vmm_file.h>
24 #include <palacios/vm_guest.h>
25
26 #ifndef V3_CONFIG_DEBUG_QCOWDISK
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31 #define V3_PACKED __attribute__((packed))
32 #define QCOW2_MAGIC             (('Q'<<24) | ('F'<<16) | ('I'<<8) | (0xfb))
33
34 #define QCOW2_COPIED            (1ULL<<63)
35 #define QCOW2_COMPRESSED        (1ULL<<62)
36 #define INIT_BUFF_SIZE  (512)
37
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__)
41
42
43 // the header structure for QCOW2
44 typedef struct v3_qcow2_header {
45   uint32_t magic;
46   uint32_t version;
47   
48   uint64_t backing_file_offset;
49   uint32_t backing_file_size;
50         
51   uint32_t cluster_bits;
52   uint64_t size;
53   
54   uint32_t crypt_method;
55   
56   uint32_t l1_size;
57   uint64_t l1_table_offset;
58   
59   uint64_t refcount_table_offset;
60   uint32_t refcount_table_clusters;
61   
62   uint32_t nb_snapshots;
63   uint64_t snapshots_offset;
64   
65 } V3_PACKED v3_qcow2_header_t;
66
67 // the header structure for each QCOW2 snapshot
68 typedef struct v3_qcow2_snapshot_header {
69   uint64_t l1_table_offset;
70   uint32_t l1_size;
71
72   uint16_t id_str_size;
73   uint16_t name_size;
74   
75   uint32_t date_sec;
76   uint32_t date_nsec;
77   
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;
82
83 // the private structure used by QCOW2 implementation
84 typedef struct v3_qcow2 {
85   v3_file_t fd;
86   struct v3_qcow2 *backing_qcow2;
87   char *backing_file_name;
88   uint64_t cluster_size;
89   uint32_t l1_bits;
90   uint64_t l1_mask;
91   uint32_t l2_bits;
92   uint64_t l2_mask;
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;
99 } v3_qcow2_t;
100
101 typedef struct v3_qcow2_table_entry {
102   uint64_t offset: 62;
103   uint8_t compressed: 1;
104   uint8_t copied: 1;
105 } v3_qcow2_table_entry_t;
106
107
108 // our implementations for Big/Little Endian conversion
109 static inline uint16_t be16toh(uint16_t v) 
110 {
111   return ((v&0xff)<<8) | ((v&0xff00)>>8);
112 }
113
114 static inline uint32_t be32toh(uint32_t v) 
115 {
116   return (((uint32_t)be16toh(v&0x0000ffffU))<<16) | (uint32_t)be16toh((v&0xffff0000U)>>16); 
117 }
118
119 static inline uint64_t be64toh(uint64_t v) 
120 {
121   return (((uint64_t)be32toh(v&0x00000000ffffffffU))<<32) | (uint64_t)be32toh((v&0xffffffff00000000U)>>32);
122 }
123
124 static inline uint16_t htobe16(uint16_t v) 
125 {
126   return be16toh(v);
127 }
128
129 static inline uint64_t htobe64(uint64_t v) 
130 {
131   return be64toh(v);
132 }
133
134 uint64_t v3_qcow2_get_capacity(v3_qcow2_t *pf) 
135 {
136   return pf ? pf->header.size : 0;
137 }
138
139 static inline uint64_t v3_qcow2_get_cluster_index(v3_qcow2_t *pf, uint64_t file_pos) 
140 {
141   if (!pf) {
142     return 0;
143   }
144   return file_pos >> pf->header.cluster_bits;
145 }
146
147 static int v3_qcow2_get_refcount(v3_qcow2_t *pf, uint64_t idx) 
148 {
149   int res = -1, ret = 0;
150   uint16_t val = 0;
151   uint64_t table_idx = 0, block_idx = 0, block_offset = 0;
152
153   if (!pf) {
154     return res;
155   }
156
157   block_idx = idx & pf->refcount_block_mask;
158   idx >>= pf->refcount_block_bits;
159   table_idx = idx & pf->refcount_table_mask;
160   
161   ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
162   
163   // FIXME: how to deal with the wrong position
164   if (ret != sizeof(uint64_t)) {
165     ERROR("read failed\n");
166     return 0;
167   }
168
169   block_offset = be64toh(block_offset);
170
171   // if cluster is not yet allocated, return 0
172   if (!block_offset) {
173     return 0;
174   }
175   
176   ret = v3_file_read(pf->fd, (uint8_t*)&val, sizeof(uint16_t), block_offset + block_idx * sizeof(uint16_t));
177   
178   if (ret != sizeof(uint16_t)) {
179     ERROR("read failed\n");
180     return 0;
181   }
182   
183   val = be16toh(val);
184   
185   return val;
186 }
187
188 /*
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
192  *
193  */
194 __attribute__((unused))
195 static int v3_qcow2_get_refcount_by_file_position(v3_qcow2_t *pf, uint64_t file_pos) 
196 {
197   int res = -1;
198   uint64_t idx = 0;
199
200   if (!pf) {
201     return res;
202   }
203   idx = v3_qcow2_get_cluster_index(pf, file_pos);
204
205   return v3_qcow2_get_refcount(pf, idx);
206 }
207
208
209 /*
210  * to allocate the contiguous clusters
211  * return the cluster index in the QCOW2 file
212  * return positive if successfully, otherwise zero(0)
213  */
214 static uint64_t v3_qcow2_alloc_clusters(v3_qcow2_t *pf, uint32_t nb_clusters) 
215 {
216   uint32_t i;
217   int refcount = 0;
218   uint64_t idx = 0, ret_idx = 0;
219   
220   if(!nb_clusters) {
221     return 0;
222   }
223         
224   if(!pf) {
225     return 0;
226   }
227
228   /*
229    * referenced the algorithm from Qemu
230    */
231  retry:
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);
236     if(refcount < 0) {
237       return 0;
238     } else if(refcount) {
239       goto retry;
240     }
241   }
242   return ret_idx;
243 }
244
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) 
246 {
247   if (!qc2 || !l1_idx || !l2_idx || !offset) {
248     return -1;
249   }
250         
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;
256
257   return 0;
258 }
259
260 static v3_qcow2_t *v3_qcow2_open(struct v3_vm_info* vm, char *path, int flags) 
261 {
262   int ret = 0;
263   if(!path) {
264     return NULL;
265   }
266         
267   v3_qcow2_t *res = (v3_qcow2_t*)V3_Malloc(sizeof(v3_qcow2_t));
268
269   if (!res) {
270     ERROR("failed to allocate\n");
271     goto failed;
272   }
273    
274   memset(res, 0, sizeof(v3_qcow2_t));
275   
276   res->fd = v3_file_open(vm, path, flags);
277         
278   if (res->fd < 0) {
279     ERROR("failed to open underlying file\n");
280     goto clean_mem;
281   }
282
283   ret = v3_file_read(res->fd, (uint8_t*)&res->header, sizeof(res->header), 0);
284
285   if (ret != sizeof(res->header)) {
286     ERROR("failed to read header\n");
287     goto clean_mem;
288   }
289   
290   res->header.magic = be32toh(res->header.magic);
291   
292   if (res->header.magic != QCOW2_MAGIC) {
293     ERROR("wrong magic in header\n");
294     goto clean_file;
295   } 
296 #ifdef __DEBUG__
297   else {
298     DEBUG("right magic\n");
299   }
300 #endif
301
302   res->header.version = be32toh(res->header.version);
303
304   if (res->header.version < 2) {
305     ERROR("unsupported version: %d\n", res->header.version);
306     goto clean_file;
307   }
308 #ifdef __DEBUG__
309   else {
310     DEBUG("supported version: %d\n", res->header.version);
311   }
312 #endif
313
314   res->header.backing_file_offset = be64toh(res->header.backing_file_offset);
315   res->header.backing_file_size = be32toh(res->header.backing_file_size);
316
317   if (res->header.backing_file_size) {
318 #ifdef __DEBUG__
319     DEBUG("backing file size is larger than zero: %d\n", res->header.backing_file_size);
320 #endif
321
322     res->backing_file_name = (char*)V3_Malloc(res->header.backing_file_size + 1);
323
324     if (!res->backing_file_name) {
325       ERROR("failed to allocate memory for backing file name\n");
326       goto clean_file;
327     }
328
329     res->backing_file_name[res->header.backing_file_size] = 0;
330
331     ret = v3_file_read(res->fd, (void*)res->backing_file_name, res->header.backing_file_size, res->header.backing_file_offset);
332
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);
336       goto clean_file;
337     }
338
339     res->backing_qcow2 = v3_qcow2_open(vm, res->backing_file_name, flags);
340
341     if(res->backing_qcow2) {
342       DEBUG("load backing file successfully\n");
343     } else {
344       ERROR("failed to load backing file, exit\n");
345       return NULL;
346     }
347     
348     DEBUG("successfully read the backing file name: %s\n", res->backing_file_name);
349
350   } else {
351     // no backing file
352
353     res->backing_qcow2 = NULL;
354
355     DEBUG("read no backing file name since size == %d\n", res->header.backing_file_size);
356
357   }
358   
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;
365   
366   DEBUG("cluster_bits: %d\n", res->header.cluster_bits);
367   
368   res->header.size = be64toh(res->header.size);
369   
370   DEBUG("size: %llu\n", res->header.size);
371   
372   res->header.crypt_method = be32toh(res->header.crypt_method);
373   
374   if (res->header.crypt_method) {
375     DEBUG("AES encryption\n");
376   } else {
377     DEBUG("no encryption\n");
378   }
379   
380   res->header.l1_size = be32toh(res->header.l1_size);
381   res->header.l1_table_offset = be64toh(res->header.l1_table_offset);
382   
383   res->header.refcount_table_offset = be64toh(res->header.refcount_table_offset);
384   res->header.refcount_table_clusters = be32toh(res->header.refcount_table_clusters);
385   
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;
390   
391   res->header.nb_snapshots = be32toh(res->header.nb_snapshots);
392   res->header.snapshots_offset = be64toh(res->header.snapshots_offset);
393   
394   
395   DEBUG("l1 size: %d\n", res->header.l1_size);
396   DEBUG("l1 table offset: %llu\n", res->header.l1_table_offset);
397   
398   DEBUG("refcount_table_offset: %llu\n", res->header.refcount_table_offset);
399   DEBUG("refcount_table_clusters: %d\n", res->header.refcount_table_clusters);
400   
401   DEBUG("nb_snapshots: %d\n", res->header.nb_snapshots);
402   DEBUG("snapshots_offset: %llu\n", res->header.snapshots_offset);
403   
404   res->free_cluster_index = 1;
405   
406   // TODO: initialize the free cluster index to a reasonable value
407   while (1) {
408     if (v3_qcow2_get_refcount(res, res->free_cluster_index)) {
409       res->free_cluster_index++;
410     } else {
411       break;
412     }
413   }
414   
415   
416   return res;
417   
418 clean_file:
419   v3_file_close(res->fd);
420 clean_mem:
421   V3_Free(res);
422 failed:
423   return NULL;
424 }
425
426 static void v3_qcow2_close(v3_qcow2_t *pf) 
427 {
428   if(!pf) {
429     return;
430   }
431
432   v3_file_close(pf->fd);
433
434   if (pf->backing_file_name) {
435     V3_Free(pf->backing_file_name);
436   }
437
438   if (pf->backing_qcow2) {
439     v3_qcow2_close(pf->backing_qcow2);
440   }
441
442   V3_Free(pf);
443 }
444
445 static uint64_t v3_qcow2_get_cluster_offset(v3_qcow2_t *qc, uint64_t l1_idx, uint64_t l2_idx, uint64_t offset) 
446 {
447   uint64_t res = 0;
448   uint64_t l1_val = 0, l2_val = 0;
449   v3_qcow2_table_entry_t *ent = NULL;
450   int ret = 0;
451
452   if (!qc) {
453     goto done;
454   }
455
456   if (l1_idx >= qc->header.l1_size) {
457     return 0ULL;
458   }
459
460   ret = v3_file_read(qc->fd, (void*)&l1_val, sizeof(uint64_t), l1_idx * sizeof(uint64_t) + qc->header.l1_table_offset);
461
462   if (ret != sizeof(uint64_t)) {
463     ERROR("Failed to read L1\n");
464     goto done;
465   }
466
467   l1_val = be64toh(l1_val);
468   ent = (v3_qcow2_table_entry_t*)&l1_val;
469
470   if (!ent->offset) {
471     goto done;
472   }
473         
474   ret = v3_file_read(qc->fd, (void*)&l2_val, sizeof(uint64_t), l2_idx * sizeof(uint64_t) + ent->offset);
475         
476   if (ret != sizeof(uint64_t)) {
477     ERROR("Failed to read L2\n");
478     goto done;
479   }
480
481   l2_val = be64toh(l2_val);
482   ent = (v3_qcow2_table_entry_t*)&l2_val;
483   res = ent->offset;
484
485 done:
486   return res;
487 }
488
489
490 static int v3_qcow2_read_cluster(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len) 
491 {
492   int ret = 0;
493   uint64_t l1_idx = 0, l2_idx = 0, offset = 0;
494   uint64_t file_offset = 0;
495
496   if(!pf || !buff || !len) {
497     return -1;
498   }
499
500   ret = v3_qcow2_addr_split(pf, pos, &l1_idx, &l2_idx, &offset);
501         
502   if (ret) {
503     ERROR("failed to split address\n");
504     return -1;
505   }
506   
507   file_offset = v3_qcow2_get_cluster_offset(pf, l1_idx, l2_idx, offset);
508
509   if (file_offset) {
510
511     ret = v3_file_read(pf->fd, buff, len, file_offset + (pos & (pf->cluster_size - 1)));
512
513     // it is possible to get a negative value because of the hole
514     if (ret < 0) {
515       return -1;
516     }
517
518   } else if(pf->backing_qcow2) {
519     return v3_qcow2_read_cluster(pf->backing_qcow2, buff, pos, len);
520   } else {
521     memset(buff, 0, len);
522   }
523
524   return 0;
525 }
526
527 static int v3_qcow2_read(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len) 
528 {
529   if(!pf || !buff || !len) {
530     return -1;
531   }
532         
533   uint64_t next_addr, cur_len;
534   int ret = 0;
535
536   while (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);
542     if (ret) {
543       return -1;
544     }
545     buff += cur_len;
546     pos += cur_len;
547     len -= cur_len;
548   }
549
550   return 0;
551 }
552
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) 
556 {
557   uint64_t table_idx = 0, block_idx = 0, block_offset = 0, idx = cluster_idx;
558   int ret = 0;
559   uint16_t val = count;
560   
561   if (!pf) {
562     return -1;
563   }
564         
565   block_idx = idx & pf->refcount_block_mask;
566   idx >>= pf->refcount_block_bits;
567   table_idx = idx & pf->refcount_table_mask;
568   
569   ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
570
571   if (ret != sizeof(uint64_t) || !block_offset) {
572     ERROR("something wrong with update refcount, exit\n");
573     return -1;
574   }
575
576   block_offset = be64toh(block_offset);
577   val = htobe16(val);
578   
579   ret = v3_file_write(pf->fd, (uint8_t*)&val, sizeof(uint16_t), block_offset + block_idx * sizeof(uint16_t));
580   
581   if (ret != sizeof(uint16_t)) {
582     ERROR("write failed when update refcount, exit\n");
583     return -1;
584   }
585   
586   return 0;
587 }
588
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) 
594 {
595   int res = -1, ret;
596   uint8_t zero_buff[INIT_BUFF_SIZE];
597   uint16_t val = 0;
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;
601         
602   if (!pf) {
603     return -1;
604   }
605         
606   block_idx = idx & pf->refcount_block_mask;
607   idx >>= pf->refcount_block_bits;
608   table_idx = idx & pf->refcount_table_mask;
609
610   // TODO: re-allocate larger refcount table if needed
611
612 retry:
613   ret = v3_file_read(pf->fd, (uint8_t*)&block_offset, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
614
615   if (ret != sizeof(uint64_t) || table_idx > pf->header.refcount_table_clusters) {
616     ERROR("read failed, exit!\n");
617     return -1;  
618   }
619         
620   block_offset = be64toh(block_offset);
621   
622   if (!block_offset) {
623     // allocate a cluster as a new refcount block
624     // and also initialize this cluster with zeros
625
626     new_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
627
628     if (new_cluster_idx <= 0) {
629       ERROR("failed to allocate new cluster, exit!\n");
630       return -1;
631     }
632
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;
637     
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);
642
643     while (left_size > 0) {
644       
645       buf_length = INIT_BUFF_SIZE < left_size ? INIT_BUFF_SIZE : left_size;
646       
647       ret = v3_file_write(pf->fd, zero_buff, buf_length, start_offset);
648       
649       if (ret != buf_length) {
650         ERROR("something wrong with write, exit\n");
651         return -1;
652       }
653
654       start_offset += buf_length;
655       
656       left_size -= buf_length;
657
658     }
659
660     // update the refcount table with the new refcount block
661
662     write_value = htobe64(new_table_idx << pf->header.cluster_bits);
663
664     ret = v3_file_write(pf->fd, (uint8_t*)&write_value, sizeof(uint64_t), pf->header.refcount_table_offset + table_idx * sizeof(uint64_t));
665     
666     if (ret != sizeof(uint64_t) ) {
667       ERROR("write of data failed\n");
668       return -1;
669     }
670
671     if (new_table_idx == table_idx) {
672       // in the same refcount block, increase its refcount here
673       val = htobe16(1);
674
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);
676
677       if (ret != sizeof(uint16_t)) {
678         ERROR("write failed\n");
679         return -1;
680       }
681
682     } else {
683       v3_qcow2_alloc_refcount(pf, new_cluster_idx);
684       v3_qcow2_update_refcount(pf, new_cluster_idx, 1);
685     }
686
687     goto retry;
688   }
689
690   res = 0;
691   return res;
692 }
693
694
695
696 static int v3_qcow2_increase_refcount(v3_qcow2_t *pf, uint64_t cluster_idx) 
697 {
698   int refcount = 0;
699
700   if (!pf) {
701     return -1;
702   }
703
704   refcount = v3_qcow2_get_refcount(pf, cluster_idx);
705         
706   if (refcount <= 0) {
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);
710
711     if (refcount) {
712       ERROR("something wrong when allocate refcount entry, exit!\n");
713       return -1;
714     }
715
716     refcount = 1;       
717
718   } else {
719
720     refcount++;
721
722   }
723
724   // write the refcount back to the file
725   return v3_qcow2_update_refcount(pf, cluster_idx, refcount);
726 }
727
728 /*
729  * this function is to decrease the reference count of a cluster
730  * since the snapshot is not implemented, 
731  */
732 __attribute__ ((unused))
733 static int v3_qcow2_decrease_refcount(v3_qcow2_t *pf, uint64_t cluster_idx) 
734 {
735   int refcount = 0;
736   
737   if (!pf) {
738     return -1;
739   }
740
741   refcount = v3_qcow2_get_refcount(pf, cluster_idx);
742
743   if(refcount <= 0) {
744     ERROR("attempt to decrease the refcount for a cluster, exit\n");
745     return -1;
746   }
747
748   refcount--;
749
750   return v3_qcow2_update_refcount(pf, cluster_idx, refcount);
751 }
752
753
754 /*
755  * do nothing but return if no need to allocate new cluster
756  * only allocate one cluster if necessary
757  */
758 static uint64_t v3_qcow2_alloc_cluster_offset(v3_qcow2_t *pf, uint64_t pos) 
759 {
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;
763   int ret = 0;
764   uint8_t init_buff[INIT_BUFF_SIZE], *data_buff;
765   
766   if (!pf) {
767     return res;
768   }
769         
770   ret = v3_qcow2_addr_split(pf, pos, &l1_idx, &l2_idx, &offset);
771
772   if (ret) {
773     ERROR("cannot split address\n");
774     return res;
775   }
776                 
777   // FIXME: in fact, we should check the refcount to be 1,
778   // otherwise we should copy
779   // do it later
780
781   res = v3_qcow2_get_cluster_offset(pf, l1_idx, l2_idx, offset);
782
783   if (res) {
784     cluster_offset = res;
785     goto done;
786   }
787
788   /*
789    * need to allocate a new cluster for write
790    * also need to update the l1 and l2 table
791    */
792         
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);
794   
795   if (ret != sizeof(uint64_t)) { 
796     ERROR("read failed\n");
797     return res;
798   }
799
800   l2_cluster_offset = be64toh(l2_cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
801
802   if (!l2_cluster_offset/*l1_idx >= pf->header.l1_size*/) { // huh?
803     /*
804      * need to allocate a new l1 entry
805      * for simplicity, only allow 2^(cluster_bits-3) entry in l1 table
806      */
807         
808     l2_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
809     l2_cluster_offset = (l2_cluster_idx << pf->header.cluster_bits);
810     
811     // increase the reference count for this cluster
812     v3_qcow2_increase_refcount(pf, l2_cluster_idx);
813
814     memset(init_buff, 0, INIT_BUFF_SIZE);
815         
816     for (done_bytes = 0; done_bytes < pf->cluster_size; done_bytes += INIT_BUFF_SIZE) {
817
818       ret = v3_file_write(pf->fd, init_buff, INIT_BUFF_SIZE, l2_cluster_offset + done_bytes);
819
820       if (ret != INIT_BUFF_SIZE) {
821         ERROR("write failed\n");
822         return res;
823       }
824     }
825         
826     /*
827      * set the copied bit
828      */
829     l2_cluster_offset |= QCOW2_COPIED;
830     l2_cluster_offset = htobe64(l2_cluster_offset);
831     
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);
833     
834     if (ret != sizeof(uint64_t)) { 
835       ERROR("write failed\n");
836       return res;
837     }
838     
839   }
840         
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);
842     
843   if (ret != sizeof(uint64_t)) {
844     ERROR("read failed\n");
845     return res;
846   }
847     
848   l2_cluster_offset = be64toh(l2_cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
849   
850   /*
851    * begin to retrieve cluster_offset
852    */
853   
854   // adjust the l2_cluster_offset to the right entry address
855   l2_cluster_offset += sizeof(uint64_t) * l2_idx;
856
857   ret = v3_file_read(pf->fd, (uint8_t*)&cluster_offset, sizeof(uint64_t), l2_cluster_offset);
858   
859   if (ret!=sizeof(uint64_t)) { 
860     ERROR("read failed\n");
861     return res;
862   }
863   
864   cluster_offset = be64toh(cluster_offset) & ~(QCOW2_COPIED | QCOW2_COMPRESSED);
865   
866   if (!cluster_offset) {
867     /*
868      * if the cluster_offset is not allocated
869      */
870     l2_cluster_idx = v3_qcow2_alloc_clusters(pf, 1);
871     cluster_offset = (l2_cluster_idx << pf->header.cluster_bits);
872     
873     // TODO: initialization
874     // initialize the cluster with the original data
875     data_buff = (uint8_t*)V3_Malloc(pf->cluster_size);
876     
877     if (data_buff) {
878       
879       pos = (pos >> pf->header.cluster_bits) << pf->header.cluster_bits;        
880       
881       v3_qcow2_read_cluster(pf, data_buff, pos, pf->cluster_size);
882       
883       ret = v3_file_write(pf->fd, data_buff, pf->cluster_size, cluster_offset);
884       
885       if (ret!=pf->cluster_size) { 
886         ERROR("write failed\n");
887         return res;
888       }
889       
890       V3_Free(data_buff);
891       
892     } else {
893       
894       ERROR("failed to initialize the original data\n");
895       
896     }
897     
898     offset = htobe64(cluster_offset | QCOW2_COPIED);
899     
900     ret = v3_file_write(pf->fd, (uint8_t*)&offset, sizeof(uint64_t), l2_cluster_offset);
901     
902     if (ret!=sizeof(uint64_t)) {
903       ERROR("write failed\n");
904       return res;
905     }
906     
907     v3_qcow2_increase_refcount(pf, l2_cluster_idx);
908     
909   }
910   
911  done:
912   return cluster_offset;
913 }
914
915 static int v3_qcow2_write_cluster(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len) 
916 {
917   if(!pf || !buff) {
918     return -1;
919   }
920
921   uint64_t cluster_addr, cluster_offset;
922   int ret = 0;
923
924   cluster_addr = v3_qcow2_alloc_cluster_offset(pf, pos);
925
926   if (!cluster_addr) {
927     ERROR("zero cluster address\n");
928     return -1;
929   }
930   
931   cluster_offset = pos & (pf->cluster_size - 1);
932         
933   ret = v3_file_write(pf->fd, buff, len, cluster_addr + cluster_offset);
934         
935   if (ret != len) {
936     ERROR("write failed\n");
937     return -1;
938   }
939   
940   return 0;
941 }
942
943 static int v3_qcow2_write(v3_qcow2_t *pf, uint8_t *buff, uint64_t pos, int len) 
944 {
945   if (!pf || !buff || !len) {
946     return -1;
947   }
948         
949   uint64_t next_addr, cur_len;
950   int ret = 0;
951
952   while (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;
956
957     DEBUG("pos=%llu, len=%llu\n", pos, cur_len);
958                 
959     ret = v3_qcow2_write_cluster(pf, buff, pos, cur_len);
960     
961     if (ret) {
962       return -1;
963     }
964     
965     buff += cur_len;
966     pos += cur_len;
967     len -= cur_len;
968   }
969         
970   return ret;
971 }
972
973 static int read(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) 
974 {
975   v3_qcow2_t * disk = (v3_qcow2_t *) private_data;
976
977   DEBUG("QCOW Reading %llu bytes from %llu to 0x%p\n", num_bytes, lba, buf);
978
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);
982     return -1;
983   }
984
985   return v3_qcow2_read(disk, buf, lba, num_bytes);
986 }
987
988
989 static int write(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data) 
990 {
991   v3_qcow2_t * disk = (v3_qcow2_t *) private_data;
992   
993   DEBUG("QCOW Writing %llu bytes from 0x%p to %llu\n", num_bytes,  buf, lba);
994   
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);
998     return -1;
999   }
1000
1001   return v3_qcow2_write(disk, buf, lba, num_bytes);
1002   
1003 }
1004
1005
1006 static uint64_t get_capacity(void * private_data) 
1007 {
1008     v3_qcow2_t * disk = (v3_qcow2_t *)private_data;
1009
1010     DEBUG("Querying QCOWDISK capacity %llu\n", v3_qcow2_get_capacity(disk));
1011     
1012     return v3_qcow2_get_capacity(disk);
1013 }
1014
1015 static struct v3_dev_blk_ops blk_ops = {
1016     .read = read, 
1017     .write = write,
1018     .get_capacity = get_capacity,
1019 };
1020
1021
1022
1023
1024 static int disk_free(v3_qcow2_t * disk) 
1025 {
1026     v3_qcow2_close(disk);
1027     return 0;
1028 }
1029
1030 static struct v3_device_ops dev_ops = {
1031     .free = (int (*)(void *))disk_free,
1032 };
1033
1034
1035
1036
1037 static int disk_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
1038 {
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");
1044
1045     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
1046     int flags = FILE_OPEN_MODE_READ;
1047
1048     PrintDebug(vm,VCORE_NONE,"Welcome to the QCOWDISK Implementation!\n");
1049
1050     if ( ((writable) && (writable[0] == '1')) ||
1051          ((writeable) && (writeable[0] == '1')) ) {
1052         flags |= FILE_OPEN_MODE_WRITE;
1053     }
1054
1055     if (path == NULL) {
1056         PrintError(vm, VCORE_NONE, "Missing path (%s) for %s\n", path, dev_id);
1057         return -1;
1058     }
1059
1060     disk = v3_qcow2_open(vm, path, flags);
1061
1062     if (disk == NULL) {
1063         PrintError(vm, VCORE_NONE, "Could not open file disk:%s\n", path);
1064         return -1;
1065     }
1066
1067     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, disk);
1068
1069     if (dev == NULL) {
1070         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
1071         V3_Free(disk);
1072         return -1;
1073     }
1074
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);
1080         return -1;
1081     }
1082     
1083
1084     return 0;
1085 }
1086
1087
1088 device_register("QCOWDISK", disk_init)