Commit 52d893ecf98a43d17f9b65c5a22a130ecacd9bf1
1 parent
05203524
Extract compressing part from alloc_cluster_offset() (Laurent Vivier)
Divide alloc_cluster_offset() into alloc_cluster_offset() and alloc_compressed_cluster_offset(). Common parts are moved to free_any_clusters() and get_cluster_table(); Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5005 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
124 additions
and
45 deletions
block-qcow2.c
@@ -652,26 +652,53 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset) | @@ -652,26 +652,53 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset) | ||
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 | BDRVQcowState *s = bs->opaque; | 699 | BDRVQcowState *s = bs->opaque; |
673 | int l1_index, l2_index, ret; | 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 | /* seek the the l2 offset in the l1 table */ | 703 | /* seek the the l2 offset in the l1 table */ |
677 | 704 | ||
@@ -703,47 +730,97 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs, | @@ -703,47 +730,97 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs, | ||
703 | /* find the cluster offset for the given disk offset */ | 730 | /* find the cluster offset for the given disk offset */ |
704 | 731 | ||
705 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); | 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 | if (cluster_offset & QCOW_OFLAG_COPIED) | 768 | if (cluster_offset & QCOW_OFLAG_COPIED) |
709 | return cluster_offset & ~QCOW_OFLAG_COPIED; | 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 | /* allocate a new cluster */ | 825 | /* allocate a new cluster */ |
749 | 826 | ||
@@ -916,7 +993,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, | @@ -916,7 +993,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, | ||
916 | n = s->cluster_sectors - index_in_cluster; | 993 | n = s->cluster_sectors - index_in_cluster; |
917 | if (n > nb_sectors) | 994 | if (n > nb_sectors) |
918 | n = nb_sectors; | 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 | index_in_cluster, | 997 | index_in_cluster, |
921 | index_in_cluster + n); | 998 | index_in_cluster + n); |
922 | if (!cluster_offset) | 999 | if (!cluster_offset) |
@@ -1100,7 +1177,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) | @@ -1100,7 +1177,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) | ||
1100 | acb->n = s->cluster_sectors - index_in_cluster; | 1177 | acb->n = s->cluster_sectors - index_in_cluster; |
1101 | if (acb->n > acb->nb_sectors) | 1178 | if (acb->n > acb->nb_sectors) |
1102 | acb->n = acb->nb_sectors; | 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 | index_in_cluster, | 1181 | index_in_cluster, |
1105 | index_in_cluster + acb->n); | 1182 | index_in_cluster + acb->n); |
1106 | if (!cluster_offset || (cluster_offset & 511) != 0) { | 1183 | if (!cluster_offset || (cluster_offset & 511) != 0) { |
@@ -1362,8 +1439,10 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, | @@ -1362,8 +1439,10 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, | ||
1362 | /* could not compress: write normal cluster */ | 1439 | /* could not compress: write normal cluster */ |
1363 | qcow_write(bs, sector_num, buf, s->cluster_sectors); | 1440 | qcow_write(bs, sector_num, buf, s->cluster_sectors); |
1364 | } else { | 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 | cluster_offset &= s->cluster_offset_mask; | 1446 | cluster_offset &= s->cluster_offset_mask; |
1368 | if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { | 1447 | if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { |
1369 | qemu_free(out_buf); | 1448 | qemu_free(out_buf); |