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