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); |