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 | 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,47 +730,97 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs, |
| 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,7 +993,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, |
| 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,7 +1177,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) |
| 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,8 +1439,10 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, |
| 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); | ... | ... |