Revision e97fc193

b/block-qcow2.c
177 177
static int64_t alloc_bytes(BlockDriverState *bs, int size);
178 178
static void free_clusters(BlockDriverState *bs,
179 179
                          int64_t offset, int64_t size);
180
#ifdef DEBUG_ALLOC
181
static void check_refcounts(BlockDriverState *bs);
182
#endif
180
static int check_refcounts(BlockDriverState *bs);
183 181

  
184 182
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
185 183
{
......
2564 2562
    }
2565 2563
}
2566 2564

  
2567
#ifdef DEBUG_ALLOC
2568
static void inc_refcounts(BlockDriverState *bs,
2565
/*
2566
 * Increases the refcount for a range of clusters in a given refcount table.
2567
 * This is used to construct a temporary refcount table out of L1 and L2 tables
2568
 * which can be compared the the refcount table saved in the image.
2569
 *
2570
 * Returns the number of errors in the image that were found
2571
 */
2572
static int inc_refcounts(BlockDriverState *bs,
2569 2573
                          uint16_t *refcount_table,
2570 2574
                          int refcount_table_size,
2571 2575
                          int64_t offset, int64_t size)
......
2573 2577
    BDRVQcowState *s = bs->opaque;
2574 2578
    int64_t start, last, cluster_offset;
2575 2579
    int k;
2580
    int errors = 0;
2576 2581

  
2577 2582
    if (size <= 0)
2578
        return;
2583
        return 0;
2579 2584

  
2580 2585
    start = offset & ~(s->cluster_size - 1);
2581 2586
    last = (offset + size - 1) & ~(s->cluster_size - 1);
......
2585 2590
        if (k < 0 || k >= refcount_table_size) {
2586 2591
            fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
2587 2592
                cluster_offset);
2593
            errors++;
2588 2594
        } else {
2589 2595
            if (++refcount_table[k] == 0) {
2590 2596
                fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
2591 2597
                    "\n", cluster_offset);
2598
                errors++;
2592 2599
            }
2593 2600
        }
2594 2601
    }
2602

  
2603
    return errors;
2595 2604
}
2596 2605

  
2597 2606
static int check_refcounts_l1(BlockDriverState *bs,
......
2603 2612
    BDRVQcowState *s = bs->opaque;
2604 2613
    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
2605 2614
    int l2_size, i, j, nb_csectors, refcount;
2615
    int errors = 0;
2606 2616

  
2607 2617
    l2_table = NULL;
2608 2618
    l1_size2 = l1_size * sizeof(uint64_t);
2609 2619

  
2610
    inc_refcounts(bs, refcount_table, refcount_table_size,
2620
    errors += inc_refcounts(bs, refcount_table, refcount_table_size,
2611 2621
                  l1_table_offset, l1_size2);
2612 2622

  
2613 2623
    l1_table = qemu_malloc(l1_size2);
......
2627 2637
                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
2628 2638
                    fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
2629 2639
                        " refcount=%d\n", l2_offset, refcount);
2640
                    errors++;
2630 2641
                }
2631 2642
            }
2632 2643
            l2_offset &= ~QCOW_OFLAG_COPIED;
......
2641 2652
                                "copied flag must never be set for compressed "
2642 2653
                                "clusters\n", offset >> s->cluster_bits);
2643 2654
                            offset &= ~QCOW_OFLAG_COPIED;
2655
                            errors++;
2644 2656
                        }
2645 2657
                        nb_csectors = ((offset >> s->csize_shift) &
2646 2658
                                       s->csize_mask) + 1;
2647 2659
                        offset &= s->cluster_offset_mask;
2648
                        inc_refcounts(bs, refcount_table,
2660
                        errors += inc_refcounts(bs, refcount_table,
2649 2661
                                      refcount_table_size,
2650 2662
                                      offset & ~511, nb_csectors * 512);
2651 2663
                    } else {
......
2654 2666
                            if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
2655 2667
                                fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
2656 2668
                                    PRIx64 " refcount=%d\n", offset, refcount);
2669
                                errors++;
2657 2670
                            }
2658 2671
                        }
2659 2672
                        offset &= ~QCOW_OFLAG_COPIED;
2660
                        inc_refcounts(bs, refcount_table,
2673
                        errors += inc_refcounts(bs, refcount_table,
2661 2674
                                      refcount_table_size,
2662 2675
                                      offset, s->cluster_size);
2663 2676
                    }
2664 2677
                }
2665 2678
            }
2666
            inc_refcounts(bs, refcount_table,
2679
            errors += inc_refcounts(bs, refcount_table,
2667 2680
                          refcount_table_size,
2668 2681
                          l2_offset,
2669 2682
                          s->cluster_size);
......
2671 2684
    }
2672 2685
    qemu_free(l1_table);
2673 2686
    qemu_free(l2_table);
2674
    return 0;
2687
    return errors;
2675 2688
 fail:
2676 2689
    fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
2677 2690
    qemu_free(l1_table);
......
2679 2692
    return -EIO;
2680 2693
}
2681 2694

  
2682
static void check_refcounts(BlockDriverState *bs)
2695
/*
2696
 * Checks an image for refcount consistency.
2697
 *
2698
 * Returns 0 if no errors are found, the number of errors in case the image is
2699
 * detected as corrupted, and -errno when an internal error occured.
2700
 */
2701
static int check_refcounts(BlockDriverState *bs)
2683 2702
{
2684 2703
    BDRVQcowState *s = bs->opaque;
2685 2704
    int64_t size;
2686 2705
    int nb_clusters, refcount1, refcount2, i;
2687 2706
    QCowSnapshot *sn;
2688 2707
    uint16_t *refcount_table;
2708
    int ret, errors = 0;
2689 2709

  
2690 2710
    size = bdrv_getlength(s->hd);
2691 2711
    nb_clusters = size_to_clusters(s, size);
2692 2712
    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
2693 2713

  
2694 2714
    /* header */
2695
    inc_refcounts(bs, refcount_table, nb_clusters,
2715
    errors += inc_refcounts(bs, refcount_table, nb_clusters,
2696 2716
                  0, s->cluster_size);
2697 2717

  
2698
    check_refcounts_l1(bs, refcount_table, nb_clusters,
2718
    ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
2699 2719
                       s->l1_table_offset, s->l1_size, 1);
2720
    if (ret < 0) {
2721
        return ret;
2722
    }
2723
    errors += ret;
2700 2724

  
2701 2725
    /* snapshots */
2702 2726
    for(i = 0; i < s->nb_snapshots; i++) {
......
2704 2728
        check_refcounts_l1(bs, refcount_table, nb_clusters,
2705 2729
                           sn->l1_table_offset, sn->l1_size, 0);
2706 2730
    }
2707
    inc_refcounts(bs, refcount_table, nb_clusters,
2731
    errors += inc_refcounts(bs, refcount_table, nb_clusters,
2708 2732
                  s->snapshots_offset, s->snapshots_size);
2709 2733

  
2710 2734
    /* refcount data */
2711
    inc_refcounts(bs, refcount_table, nb_clusters,
2735
    errors += inc_refcounts(bs, refcount_table, nb_clusters,
2712 2736
                  s->refcount_table_offset,
2713 2737
                  s->refcount_table_size * sizeof(uint64_t));
2714 2738
    for(i = 0; i < s->refcount_table_size; i++) {
2715 2739
        int64_t offset;
2716 2740
        offset = s->refcount_table[i];
2717 2741
        if (offset != 0) {
2718
            inc_refcounts(bs, refcount_table, nb_clusters,
2742
            errors += inc_refcounts(bs, refcount_table, nb_clusters,
2719 2743
                          offset, s->cluster_size);
2720 2744
        }
2721 2745
    }
......
2724 2748
    for(i = 0; i < nb_clusters; i++) {
2725 2749
        refcount1 = get_refcount(bs, i);
2726 2750
        refcount2 = refcount_table[i];
2727
        if (refcount1 != refcount2)
2751
        if (refcount1 != refcount2) {
2728 2752
            fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
2729 2753
                   i, refcount1, refcount2);
2754
            errors++;
2755
        }
2730 2756
    }
2731 2757

  
2732 2758
    qemu_free(refcount_table);
2759

  
2760
    return errors;
2761
}
2762

  
2763
static int qcow_check(BlockDriverState *bs)
2764
{
2765
    return check_refcounts(bs);
2733 2766
}
2734 2767

  
2735 2768
#if 0
......
2751 2784
    }
2752 2785
}
2753 2786
#endif
2754
#endif
2755 2787

  
2756 2788
static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
2757 2789
                           int64_t pos, int size)
......
2806 2838
    .bdrv_get_buffer    = qcow_get_buffer,
2807 2839

  
2808 2840
    .bdrv_create2 = qcow_create2,
2841
    .bdrv_check = qcow_check,
2809 2842
};
b/block.c
506 506
    qemu_free(bs);
507 507
}
508 508

  
509
/*
510
 * Run consistency checks on an image
511
 *
512
 * Returns the number of errors or -errno when an internal error occurs
513
 */
514
int bdrv_check(BlockDriverState *bs)
515
{
516
    if (bs->drv->bdrv_check == NULL) {
517
        return -ENOTSUP;
518
    }
519

  
520
    return bs->drv->bdrv_check(bs);
521
}
522

  
509 523
/* commit COW file into the raw image */
510 524
int bdrv_commit(BlockDriverState *bs)
511 525
{
b/block.h
73 73
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
74 74
               BlockDriver *drv);
75 75
void bdrv_close(BlockDriverState *bs);
76
int bdrv_check(BlockDriverState *bs);
76 77
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
77 78
              uint8_t *buf, int nb_sectors);
78 79
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
b/block_int.h
102 102
                        const char *backing_file, const char *backing_format,
103 103
                        int flags);
104 104

  
105
    /* Returns number of errors in image, -errno for internal errors */
106
    int (*bdrv_check)(BlockDriverState* bs);
107

  
105 108
    struct BlockDriver *next;
106 109
};
107 110

  

Also available in: Unified diff