Revision 52d893ec block-qcow2.c
b/block-qcow2.c | ||
---|---|---|
652 | 652 |
} |
653 | 653 |
|
654 | 654 |
/* |
655 |
* alloc_cluster_offset
|
|
655 |
* free_any_clusters
|
|
656 | 656 |
* |
657 |
* For a given offset of the disk image, return cluster offset in |
|
658 |
* qcow2 file. |
|
657 |
* free clusters according to its type: compressed or not |
|
659 | 658 |
* |
660 |
* If the offset is not found, allocate a new cluster. |
|
659 |
*/ |
|
660 |
|
|
661 |
static void free_any_clusters(BlockDriverState *bs, |
|
662 |
uint64_t cluster_offset) |
|
663 |
{ |
|
664 |
BDRVQcowState *s = bs->opaque; |
|
665 |
|
|
666 |
if (cluster_offset == 0) |
|
667 |
return; |
|
668 |
|
|
669 |
/* free the cluster */ |
|
670 |
|
|
671 |
if (cluster_offset & QCOW_OFLAG_COMPRESSED) { |
|
672 |
int nb_csectors; |
|
673 |
nb_csectors = ((cluster_offset >> s->csize_shift) & |
|
674 |
s->csize_mask) + 1; |
|
675 |
free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, |
|
676 |
nb_csectors * 512); |
|
677 |
return; |
|
678 |
} |
|
679 |
|
|
680 |
free_clusters(bs, cluster_offset, s->cluster_size); |
|
681 |
} |
|
682 |
|
|
683 |
/* |
|
684 |
* get_cluster_table |
|
661 | 685 |
* |
662 |
* Return the cluster offset if successful, |
|
663 |
* Return 0, otherwise. |
|
686 |
* for a given disk offset, load (and allocate if needed) |
|
687 |
* the l2 table. |
|
688 |
* |
|
689 |
* the l2 table offset in the qcow2 file and the cluster index |
|
690 |
* in the l2 table are given to the caller. |
|
664 | 691 |
* |
665 | 692 |
*/ |
666 | 693 |
|
667 |
static uint64_t alloc_cluster_offset(BlockDriverState *bs,
|
|
668 |
uint64_t offset,
|
|
669 |
int compressed_size,
|
|
670 |
int n_start, int n_end)
|
|
694 |
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
|
695 |
uint64_t **new_l2_table,
|
|
696 |
uint64_t *new_l2_offset,
|
|
697 |
int *new_l2_index)
|
|
671 | 698 |
{ |
672 | 699 |
BDRVQcowState *s = bs->opaque; |
673 | 700 |
int l1_index, l2_index, ret; |
674 |
uint64_t l2_offset, *l2_table, cluster_offset;
|
|
701 |
uint64_t l2_offset, *l2_table; |
|
675 | 702 |
|
676 | 703 |
/* seek the the l2 offset in the l1 table */ |
677 | 704 |
|
... | ... | |
703 | 730 |
/* find the cluster offset for the given disk offset */ |
704 | 731 |
|
705 | 732 |
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); |
706 |
cluster_offset = be64_to_cpu(l2_table[l2_index]); |
|
707 | 733 |
|
734 |
*new_l2_table = l2_table; |
|
735 |
*new_l2_offset = l2_offset; |
|
736 |
*new_l2_index = l2_index; |
|
737 |
|
|
738 |
return 1; |
|
739 |
} |
|
740 |
|
|
741 |
/* |
|
742 |
* alloc_compressed_cluster_offset |
|
743 |
* |
|
744 |
* For a given offset of the disk image, return cluster offset in |
|
745 |
* qcow2 file. |
|
746 |
* |
|
747 |
* If the offset is not found, allocate a new compressed cluster. |
|
748 |
* |
|
749 |
* Return the cluster offset if successful, |
|
750 |
* Return 0, otherwise. |
|
751 |
* |
|
752 |
*/ |
|
753 |
|
|
754 |
static uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs, |
|
755 |
uint64_t offset, |
|
756 |
int compressed_size) |
|
757 |
{ |
|
758 |
BDRVQcowState *s = bs->opaque; |
|
759 |
int l2_index, ret; |
|
760 |
uint64_t l2_offset, *l2_table, cluster_offset; |
|
761 |
int nb_csectors; |
|
762 |
|
|
763 |
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); |
|
764 |
if (ret == 0) |
|
765 |
return 0; |
|
766 |
|
|
767 |
cluster_offset = be64_to_cpu(l2_table[l2_index]); |
|
708 | 768 |
if (cluster_offset & QCOW_OFLAG_COPIED) |
709 | 769 |
return cluster_offset & ~QCOW_OFLAG_COPIED; |
710 | 770 |
|
711 |
if (cluster_offset) { |
|
712 |
/* free the cluster */ |
|
713 |
if (cluster_offset & QCOW_OFLAG_COMPRESSED) { |
|
714 |
int nb_csectors; |
|
715 |
nb_csectors = ((cluster_offset >> s->csize_shift) & |
|
716 |
s->csize_mask) + 1; |
|
717 |
free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, |
|
718 |
nb_csectors * 512); |
|
719 |
} else { |
|
720 |
free_clusters(bs, cluster_offset, s->cluster_size); |
|
721 |
} |
|
722 |
} |
|
771 |
free_any_clusters(bs, cluster_offset); |
|
723 | 772 |
|
724 |
if (compressed_size) { |
|
725 |
int nb_csectors; |
|
773 |
cluster_offset = alloc_bytes(bs, compressed_size); |
|
774 |
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - |
|
775 |
(cluster_offset >> 9); |
|
726 | 776 |
|
727 |
cluster_offset = alloc_bytes(bs, compressed_size); |
|
728 |
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - |
|
729 |
(cluster_offset >> 9); |
|
777 |
cluster_offset |= QCOW_OFLAG_COMPRESSED | |
|
778 |
((uint64_t)nb_csectors << s->csize_shift); |
|
730 | 779 |
|
731 |
cluster_offset |= QCOW_OFLAG_COMPRESSED | |
|
732 |
((uint64_t)nb_csectors << s->csize_shift); |
|
780 |
/* update L2 table */ |
|
733 | 781 |
|
734 |
/* update L2 table */
|
|
782 |
/* compressed clusters never have the copied flag */
|
|
735 | 783 |
|
736 |
/* compressed clusters never have the copied flag */ |
|
784 |
l2_table[l2_index] = cpu_to_be64(cluster_offset); |
|
785 |
if (bdrv_pwrite(s->hd, |
|
786 |
l2_offset + l2_index * sizeof(uint64_t), |
|
787 |
l2_table + l2_index, |
|
788 |
sizeof(uint64_t)) != sizeof(uint64_t)) |
|
789 |
return 0; |
|
737 | 790 |
|
738 |
l2_table[l2_index] = cpu_to_be64(cluster_offset); |
|
739 |
if (bdrv_pwrite(s->hd, |
|
740 |
l2_offset + l2_index * sizeof(uint64_t), |
|
741 |
l2_table + l2_index, |
|
742 |
sizeof(uint64_t)) != sizeof(uint64_t)) |
|
743 |
return 0; |
|
791 |
return cluster_offset; |
|
792 |
} |
|
744 | 793 |
|
745 |
return cluster_offset; |
|
746 |
} |
|
794 |
/* |
|
795 |
* alloc_cluster_offset |
|
796 |
* |
|
797 |
* For a given offset of the disk image, return cluster offset in |
|
798 |
* qcow2 file. |
|
799 |
* |
|
800 |
* If the offset is not found, allocate a new cluster. |
|
801 |
* |
|
802 |
* Return the cluster offset if successful, |
|
803 |
* Return 0, otherwise. |
|
804 |
* |
|
805 |
*/ |
|
806 |
|
|
807 |
static uint64_t alloc_cluster_offset(BlockDriverState *bs, |
|
808 |
uint64_t offset, |
|
809 |
int n_start, int n_end) |
|
810 |
{ |
|
811 |
BDRVQcowState *s = bs->opaque; |
|
812 |
int l2_index, ret; |
|
813 |
uint64_t l2_offset, *l2_table, cluster_offset; |
|
814 |
|
|
815 |
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); |
|
816 |
if (ret == 0) |
|
817 |
return 0; |
|
818 |
|
|
819 |
cluster_offset = be64_to_cpu(l2_table[l2_index]); |
|
820 |
if (cluster_offset & QCOW_OFLAG_COPIED) |
|
821 |
return cluster_offset & ~QCOW_OFLAG_COPIED; |
|
822 |
|
|
823 |
free_any_clusters(bs, cluster_offset); |
|
747 | 824 |
|
748 | 825 |
/* allocate a new cluster */ |
749 | 826 |
|
... | ... | |
916 | 993 |
n = s->cluster_sectors - index_in_cluster; |
917 | 994 |
if (n > nb_sectors) |
918 | 995 |
n = nb_sectors; |
919 |
cluster_offset = alloc_cluster_offset(bs, sector_num << 9, 0,
|
|
996 |
cluster_offset = alloc_cluster_offset(bs, sector_num << 9, |
|
920 | 997 |
index_in_cluster, |
921 | 998 |
index_in_cluster + n); |
922 | 999 |
if (!cluster_offset) |
... | ... | |
1100 | 1177 |
acb->n = s->cluster_sectors - index_in_cluster; |
1101 | 1178 |
if (acb->n > acb->nb_sectors) |
1102 | 1179 |
acb->n = acb->nb_sectors; |
1103 |
cluster_offset = alloc_cluster_offset(bs, acb->sector_num << 9, 0,
|
|
1180 |
cluster_offset = alloc_cluster_offset(bs, acb->sector_num << 9, |
|
1104 | 1181 |
index_in_cluster, |
1105 | 1182 |
index_in_cluster + acb->n); |
1106 | 1183 |
if (!cluster_offset || (cluster_offset & 511) != 0) { |
... | ... | |
1362 | 1439 |
/* could not compress: write normal cluster */ |
1363 | 1440 |
qcow_write(bs, sector_num, buf, s->cluster_sectors); |
1364 | 1441 |
} else { |
1365 |
cluster_offset = alloc_cluster_offset(bs, sector_num << 9, |
|
1366 |
out_len, 0, 0); |
|
1442 |
cluster_offset = alloc_compressed_cluster_offset(bs, sector_num << 9, |
|
1443 |
out_len); |
|
1444 |
if (!cluster_offset) |
|
1445 |
return -1; |
|
1367 | 1446 |
cluster_offset &= s->cluster_offset_mask; |
1368 | 1447 |
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { |
1369 | 1448 |
qemu_free(out_buf); |
Also available in: Unified diff