Commit 052035244f66acfa532b730b1444c4b7e8a4f302
1 parent
108534b9
Divide get_cluster_offset() (Laurent Vivier)
Divide get_cluster_offset() into get_cluster_offset() and alloc_cluster_offset(). 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@5004 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
132 additions
and
76 deletions
block-qcow2.c
@@ -606,22 +606,77 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) | @@ -606,22 +606,77 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) | ||
606 | return l2_table; | 606 | return l2_table; |
607 | } | 607 | } |
608 | 608 | ||
609 | -static uint64_t get_cluster_offset(BlockDriverState *bs, | ||
610 | - uint64_t offset, int allocate, | ||
611 | - int compressed_size, | ||
612 | - int n_start, int n_end) | 609 | +/* |
610 | + * get_cluster_offset | ||
611 | + * | ||
612 | + * For a given offset of the disk image, return cluster offset in | ||
613 | + * qcow2 file. | ||
614 | + * | ||
615 | + * Return 1, if the offset is found | ||
616 | + * Return 0, otherwise. | ||
617 | + * | ||
618 | + */ | ||
619 | + | ||
620 | +static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset) | ||
621 | +{ | ||
622 | + BDRVQcowState *s = bs->opaque; | ||
623 | + int l1_index, l2_index; | ||
624 | + uint64_t l2_offset, *l2_table, cluster_offset; | ||
625 | + | ||
626 | + /* seek the the l2 offset in the l1 table */ | ||
627 | + | ||
628 | + l1_index = offset >> (s->l2_bits + s->cluster_bits); | ||
629 | + if (l1_index >= s->l1_size) | ||
630 | + return 0; | ||
631 | + | ||
632 | + l2_offset = s->l1_table[l1_index]; | ||
633 | + | ||
634 | + /* seek the l2 table of the given l2 offset */ | ||
635 | + | ||
636 | + if (!l2_offset) | ||
637 | + return 0; | ||
638 | + | ||
639 | + /* load the l2 table in memory */ | ||
640 | + | ||
641 | + l2_offset &= ~QCOW_OFLAG_COPIED; | ||
642 | + l2_table = l2_load(bs, l2_offset); | ||
643 | + if (l2_table == NULL) | ||
644 | + return 0; | ||
645 | + | ||
646 | + /* find the cluster offset for the given disk offset */ | ||
647 | + | ||
648 | + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); | ||
649 | + cluster_offset = be64_to_cpu(l2_table[l2_index]); | ||
650 | + | ||
651 | + return cluster_offset & ~QCOW_OFLAG_COPIED; | ||
652 | +} | ||
653 | + | ||
654 | +/* | ||
655 | + * alloc_cluster_offset | ||
656 | + * | ||
657 | + * For a given offset of the disk image, return cluster offset in | ||
658 | + * qcow2 file. | ||
659 | + * | ||
660 | + * If the offset is not found, allocate a new cluster. | ||
661 | + * | ||
662 | + * Return the cluster offset if successful, | ||
663 | + * Return 0, otherwise. | ||
664 | + * | ||
665 | + */ | ||
666 | + | ||
667 | +static uint64_t alloc_cluster_offset(BlockDriverState *bs, | ||
668 | + uint64_t offset, | ||
669 | + int compressed_size, | ||
670 | + int n_start, int n_end) | ||
613 | { | 671 | { |
614 | BDRVQcowState *s = bs->opaque; | 672 | BDRVQcowState *s = bs->opaque; |
615 | int l1_index, l2_index, ret; | 673 | int l1_index, l2_index, ret; |
616 | - uint64_t l2_offset, *l2_table, cluster_offset, tmp; | 674 | + uint64_t l2_offset, *l2_table, cluster_offset; |
617 | 675 | ||
618 | /* seek the the l2 offset in the l1 table */ | 676 | /* seek the the l2 offset in the l1 table */ |
619 | 677 | ||
620 | l1_index = offset >> (s->l2_bits + s->cluster_bits); | 678 | l1_index = offset >> (s->l2_bits + s->cluster_bits); |
621 | if (l1_index >= s->l1_size) { | 679 | if (l1_index >= s->l1_size) { |
622 | - /* outside l1 table is allowed: we grow the table if needed */ | ||
623 | - if (!allocate) | ||
624 | - return 0; | ||
625 | ret = grow_l1_table(bs, l1_index + 1); | 680 | ret = grow_l1_table(bs, l1_index + 1); |
626 | if (ret < 0) | 681 | if (ret < 0) |
627 | return 0; | 682 | return 0; |
@@ -630,44 +685,30 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | @@ -630,44 +685,30 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | ||
630 | 685 | ||
631 | /* seek the l2 table of the given l2 offset */ | 686 | /* seek the l2 table of the given l2 offset */ |
632 | 687 | ||
633 | - if (!l2_offset) { | ||
634 | - /* the l2 table doesn't exist */ | ||
635 | - if (!allocate) | 688 | + if (l2_offset & QCOW_OFLAG_COPIED) { |
689 | + /* load the l2 table in memory */ | ||
690 | + l2_offset &= ~QCOW_OFLAG_COPIED; | ||
691 | + l2_table = l2_load(bs, l2_offset); | ||
692 | + if (l2_table == NULL) | ||
636 | return 0; | 693 | return 0; |
637 | - /* allocate a new l2 table for this offset */ | 694 | + } else { |
695 | + if (l2_offset) | ||
696 | + free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); | ||
638 | l2_table = l2_allocate(bs, l1_index); | 697 | l2_table = l2_allocate(bs, l1_index); |
639 | if (l2_table == NULL) | 698 | if (l2_table == NULL) |
640 | return 0; | 699 | return 0; |
641 | l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; | 700 | l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; |
642 | - } else { | ||
643 | - /* the l2 table exists */ | ||
644 | - if (!(l2_offset & QCOW_OFLAG_COPIED) && allocate) { | ||
645 | - /* duplicate the l2 table, and free the old table */ | ||
646 | - free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); | ||
647 | - l2_table = l2_allocate(bs, l1_index); | ||
648 | - if (l2_table == NULL) | ||
649 | - return 0; | ||
650 | - l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; | ||
651 | - } else { | ||
652 | - /* load the l2 table in memory */ | ||
653 | - l2_offset &= ~QCOW_OFLAG_COPIED; | ||
654 | - l2_table = l2_load(bs, l2_offset); | ||
655 | - if (l2_table == NULL) | ||
656 | - return 0; | ||
657 | - } | ||
658 | } | 701 | } |
659 | 702 | ||
660 | /* find the cluster offset for the given disk offset */ | 703 | /* find the cluster offset for the given disk offset */ |
661 | 704 | ||
662 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); | 705 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); |
663 | cluster_offset = be64_to_cpu(l2_table[l2_index]); | 706 | cluster_offset = be64_to_cpu(l2_table[l2_index]); |
664 | - if (!cluster_offset) { | ||
665 | - /* cluster doesn't exist */ | ||
666 | - if (!allocate) | ||
667 | - return 0; | ||
668 | - } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) { | ||
669 | - if (!allocate) | ||
670 | - return cluster_offset; | 707 | + |
708 | + if (cluster_offset & QCOW_OFLAG_COPIED) | ||
709 | + return cluster_offset & ~QCOW_OFLAG_COPIED; | ||
710 | + | ||
711 | + if (cluster_offset) { | ||
671 | /* free the cluster */ | 712 | /* free the cluster */ |
672 | if (cluster_offset & QCOW_OFLAG_COMPRESSED) { | 713 | if (cluster_offset & QCOW_OFLAG_COMPRESSED) { |
673 | int nb_csectors; | 714 | int nb_csectors; |
@@ -678,46 +719,62 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | @@ -678,46 +719,62 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | ||
678 | } else { | 719 | } else { |
679 | free_clusters(bs, cluster_offset, s->cluster_size); | 720 | free_clusters(bs, cluster_offset, s->cluster_size); |
680 | } | 721 | } |
681 | - } else { | ||
682 | - cluster_offset &= ~QCOW_OFLAG_COPIED; | ||
683 | - return cluster_offset; | ||
684 | } | 722 | } |
685 | 723 | ||
686 | - if (allocate == 1) { | ||
687 | - /* allocate a new cluster */ | ||
688 | - cluster_offset = alloc_clusters(bs, s->cluster_size); | ||
689 | - | ||
690 | - /* we must initialize the cluster content which won't be | ||
691 | - written */ | ||
692 | - if ((n_end - n_start) < s->cluster_sectors) { | ||
693 | - uint64_t start_sect; | ||
694 | - | ||
695 | - start_sect = (offset & ~(s->cluster_size - 1)) >> 9; | ||
696 | - ret = copy_sectors(bs, start_sect, | ||
697 | - cluster_offset, 0, n_start); | ||
698 | - if (ret < 0) | ||
699 | - return 0; | ||
700 | - ret = copy_sectors(bs, start_sect, | ||
701 | - cluster_offset, n_end, s->cluster_sectors); | ||
702 | - if (ret < 0) | ||
703 | - return 0; | ||
704 | - } | ||
705 | - tmp = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED); | ||
706 | - } else { | 724 | + if (compressed_size) { |
707 | int nb_csectors; | 725 | int nb_csectors; |
726 | + | ||
708 | cluster_offset = alloc_bytes(bs, compressed_size); | 727 | cluster_offset = alloc_bytes(bs, compressed_size); |
709 | nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - | 728 | nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - |
710 | - (cluster_offset >> 9); | 729 | + (cluster_offset >> 9); |
730 | + | ||
711 | cluster_offset |= QCOW_OFLAG_COMPRESSED | | 731 | cluster_offset |= QCOW_OFLAG_COMPRESSED | |
712 | - ((uint64_t)nb_csectors << s->csize_shift); | 732 | + ((uint64_t)nb_csectors << s->csize_shift); |
733 | + | ||
734 | + /* update L2 table */ | ||
735 | + | ||
713 | /* compressed clusters never have the copied flag */ | 736 | /* compressed clusters never have the copied flag */ |
714 | - tmp = cpu_to_be64(cluster_offset); | 737 | + |
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; | ||
744 | + | ||
745 | + return cluster_offset; | ||
746 | + } | ||
747 | + | ||
748 | + /* allocate a new cluster */ | ||
749 | + | ||
750 | + cluster_offset = alloc_clusters(bs, s->cluster_size); | ||
751 | + | ||
752 | + /* we must initialize the cluster content which won't be | ||
753 | + written */ | ||
754 | + | ||
755 | + if ((n_end - n_start) < s->cluster_sectors) { | ||
756 | + uint64_t start_sect; | ||
757 | + | ||
758 | + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; | ||
759 | + ret = copy_sectors(bs, start_sect, | ||
760 | + cluster_offset, 0, n_start); | ||
761 | + if (ret < 0) | ||
762 | + return 0; | ||
763 | + ret = copy_sectors(bs, start_sect, | ||
764 | + cluster_offset, n_end, s->cluster_sectors); | ||
765 | + if (ret < 0) | ||
766 | + return 0; | ||
715 | } | 767 | } |
768 | + | ||
716 | /* update L2 table */ | 769 | /* update L2 table */ |
717 | - l2_table[l2_index] = tmp; | 770 | + |
771 | + l2_table[l2_index] = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED); | ||
718 | if (bdrv_pwrite(s->hd, | 772 | if (bdrv_pwrite(s->hd, |
719 | - l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) | 773 | + l2_offset + l2_index * sizeof(uint64_t), |
774 | + l2_table + l2_index, | ||
775 | + sizeof(uint64_t)) != sizeof(uint64_t)) | ||
720 | return 0; | 776 | return 0; |
777 | + | ||
721 | return cluster_offset; | 778 | return cluster_offset; |
722 | } | 779 | } |
723 | 780 | ||
@@ -728,7 +785,7 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, | @@ -728,7 +785,7 @@ static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, | ||
728 | int index_in_cluster, n; | 785 | int index_in_cluster, n; |
729 | uint64_t cluster_offset; | 786 | uint64_t cluster_offset; |
730 | 787 | ||
731 | - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); | 788 | + cluster_offset = get_cluster_offset(bs, sector_num << 9); |
732 | index_in_cluster = sector_num & (s->cluster_sectors - 1); | 789 | index_in_cluster = sector_num & (s->cluster_sectors - 1); |
733 | n = s->cluster_sectors - index_in_cluster; | 790 | n = s->cluster_sectors - index_in_cluster; |
734 | if (n > nb_sectors) | 791 | if (n > nb_sectors) |
@@ -810,7 +867,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, | @@ -810,7 +867,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, | ||
810 | uint64_t cluster_offset; | 867 | uint64_t cluster_offset; |
811 | 868 | ||
812 | while (nb_sectors > 0) { | 869 | while (nb_sectors > 0) { |
813 | - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); | 870 | + cluster_offset = get_cluster_offset(bs, sector_num << 9); |
814 | index_in_cluster = sector_num & (s->cluster_sectors - 1); | 871 | index_in_cluster = sector_num & (s->cluster_sectors - 1); |
815 | n = s->cluster_sectors - index_in_cluster; | 872 | n = s->cluster_sectors - index_in_cluster; |
816 | if (n > nb_sectors) | 873 | if (n > nb_sectors) |
@@ -859,9 +916,9 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, | @@ -859,9 +916,9 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, | ||
859 | n = s->cluster_sectors - index_in_cluster; | 916 | n = s->cluster_sectors - index_in_cluster; |
860 | if (n > nb_sectors) | 917 | if (n > nb_sectors) |
861 | n = nb_sectors; | 918 | n = nb_sectors; |
862 | - cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, | ||
863 | - index_in_cluster, | ||
864 | - index_in_cluster + n); | 919 | + cluster_offset = alloc_cluster_offset(bs, sector_num << 9, 0, |
920 | + index_in_cluster, | ||
921 | + index_in_cluster + n); | ||
865 | if (!cluster_offset) | 922 | if (!cluster_offset) |
866 | return -1; | 923 | return -1; |
867 | if (s->crypt_method) { | 924 | if (s->crypt_method) { |
@@ -934,8 +991,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) | @@ -934,8 +991,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) | ||
934 | } | 991 | } |
935 | 992 | ||
936 | /* prepare next AIO request */ | 993 | /* prepare next AIO request */ |
937 | - acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, | ||
938 | - 0, 0, 0, 0); | 994 | + acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9); |
939 | index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); | 995 | index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); |
940 | acb->n = s->cluster_sectors - index_in_cluster; | 996 | acb->n = s->cluster_sectors - index_in_cluster; |
941 | if (acb->n > acb->nb_sectors) | 997 | if (acb->n > acb->nb_sectors) |
@@ -1044,9 +1100,9 @@ static void qcow_aio_write_cb(void *opaque, int ret) | @@ -1044,9 +1100,9 @@ static void qcow_aio_write_cb(void *opaque, int ret) | ||
1044 | acb->n = s->cluster_sectors - index_in_cluster; | 1100 | acb->n = s->cluster_sectors - index_in_cluster; |
1045 | if (acb->n > acb->nb_sectors) | 1101 | if (acb->n > acb->nb_sectors) |
1046 | acb->n = acb->nb_sectors; | 1102 | acb->n = acb->nb_sectors; |
1047 | - cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, | ||
1048 | - index_in_cluster, | ||
1049 | - index_in_cluster + acb->n); | 1103 | + cluster_offset = alloc_cluster_offset(bs, acb->sector_num << 9, 0, |
1104 | + index_in_cluster, | ||
1105 | + index_in_cluster + acb->n); | ||
1050 | if (!cluster_offset || (cluster_offset & 511) != 0) { | 1106 | if (!cluster_offset || (cluster_offset & 511) != 0) { |
1051 | ret = -EIO; | 1107 | ret = -EIO; |
1052 | goto fail; | 1108 | goto fail; |
@@ -1306,8 +1362,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, | @@ -1306,8 +1362,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, | ||
1306 | /* could not compress: write normal cluster */ | 1362 | /* could not compress: write normal cluster */ |
1307 | qcow_write(bs, sector_num, buf, s->cluster_sectors); | 1363 | qcow_write(bs, sector_num, buf, s->cluster_sectors); |
1308 | } else { | 1364 | } else { |
1309 | - cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, | ||
1310 | - out_len, 0, 0); | 1365 | + cluster_offset = alloc_cluster_offset(bs, sector_num << 9, |
1366 | + out_len, 0, 0); | ||
1311 | cluster_offset &= s->cluster_offset_mask; | 1367 | cluster_offset &= s->cluster_offset_mask; |
1312 | if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { | 1368 | if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { |
1313 | qemu_free(out_buf); | 1369 | qemu_free(out_buf); |