Commit e97fc193e1c65deb51643d5251e98affe07c59ca
1 parent
8ddbc04f
Introduce bdrv_check (Kevin Wolf)
From: Kevin Wolf <kwolf@redhat.com> Introduce a new bdrv_check function pointer for block drivers. Modify qcow2 to return an error status in check_refcounts(), so it can implement bdrv_check. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7214 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
70 additions
and
19 deletions
block-qcow2.c
... | ... | @@ -177,9 +177,7 @@ static int64_t alloc_clusters(BlockDriverState *bs, int64_t size); |
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,8 +2562,14 @@ static void update_refcount(BlockDriverState *bs, |
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,9 +2577,10 @@ static void inc_refcounts(BlockDriverState *bs, |
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,13 +2590,17 @@ static void inc_refcounts(BlockDriverState *bs, |
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,11 +2612,12 @@ 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,6 +2637,7 @@ static int check_refcounts_l1(BlockDriverState *bs, |
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,11 +2652,12 @@ static int check_refcounts_l1(BlockDriverState *bs, |
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,16 +2666,17 @@ static int check_refcounts_l1(BlockDriverState *bs, |
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,7 +2684,7 @@ static int check_refcounts_l1(BlockDriverState *bs, |
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,24 +2692,35 @@ static int check_refcounts_l1(BlockDriverState *bs, |
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,18 +2728,18 @@ static void check_refcounts(BlockDriverState *bs) |
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,12 +2748,21 @@ static void check_refcounts(BlockDriverState *bs) |
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,7 +2784,6 @@ static void dump_refcounts(BlockDriverState *bs) |
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,4 +2838,5 @@ BlockDriver bdrv_qcow2 = { |
2806 | 2838 | .bdrv_get_buffer = qcow_get_buffer, |
2807 | 2839 | |
2808 | 2840 | .bdrv_create2 = qcow_create2, |
2841 | + .bdrv_check = qcow_check, | |
2809 | 2842 | }; | ... | ... |
block.c
... | ... | @@ -506,6 +506,20 @@ void bdrv_delete(BlockDriverState *bs) |
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 | { | ... | ... |
block.h
... | ... | @@ -73,6 +73,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags); |
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, | ... | ... |
block_int.h
... | ... | @@ -102,6 +102,9 @@ struct BlockDriver { |
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 | ... | ... |