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