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,9 +177,7 @@ static int64_t alloc_clusters(BlockDriverState *bs, int64_t size); | ||
| 177 | static int64_t alloc_bytes(BlockDriverState *bs, int size); | 177 | static int64_t alloc_bytes(BlockDriverState *bs, int size); |
| 178 | static void free_clusters(BlockDriverState *bs, | 178 | static void free_clusters(BlockDriverState *bs, |
| 179 | int64_t offset, int64_t size); | 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 | static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) | 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,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 | uint16_t *refcount_table, | 2573 | uint16_t *refcount_table, |
| 2570 | int refcount_table_size, | 2574 | int refcount_table_size, |
| 2571 | int64_t offset, int64_t size) | 2575 | int64_t offset, int64_t size) |
| @@ -2573,9 +2577,10 @@ static void inc_refcounts(BlockDriverState *bs, | @@ -2573,9 +2577,10 @@ static void inc_refcounts(BlockDriverState *bs, | ||
| 2573 | BDRVQcowState *s = bs->opaque; | 2577 | BDRVQcowState *s = bs->opaque; |
| 2574 | int64_t start, last, cluster_offset; | 2578 | int64_t start, last, cluster_offset; |
| 2575 | int k; | 2579 | int k; |
| 2580 | + int errors = 0; | ||
| 2576 | 2581 | ||
| 2577 | if (size <= 0) | 2582 | if (size <= 0) |
| 2578 | - return; | 2583 | + return 0; |
| 2579 | 2584 | ||
| 2580 | start = offset & ~(s->cluster_size - 1); | 2585 | start = offset & ~(s->cluster_size - 1); |
| 2581 | last = (offset + size - 1) & ~(s->cluster_size - 1); | 2586 | last = (offset + size - 1) & ~(s->cluster_size - 1); |
| @@ -2585,13 +2590,17 @@ static void inc_refcounts(BlockDriverState *bs, | @@ -2585,13 +2590,17 @@ static void inc_refcounts(BlockDriverState *bs, | ||
| 2585 | if (k < 0 || k >= refcount_table_size) { | 2590 | if (k < 0 || k >= refcount_table_size) { |
| 2586 | fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n", | 2591 | fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n", |
| 2587 | cluster_offset); | 2592 | cluster_offset); |
| 2593 | + errors++; | ||
| 2588 | } else { | 2594 | } else { |
| 2589 | if (++refcount_table[k] == 0) { | 2595 | if (++refcount_table[k] == 0) { |
| 2590 | fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 | 2596 | fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 |
| 2591 | "\n", cluster_offset); | 2597 | "\n", cluster_offset); |
| 2598 | + errors++; | ||
| 2592 | } | 2599 | } |
| 2593 | } | 2600 | } |
| 2594 | } | 2601 | } |
| 2602 | + | ||
| 2603 | + return errors; | ||
| 2595 | } | 2604 | } |
| 2596 | 2605 | ||
| 2597 | static int check_refcounts_l1(BlockDriverState *bs, | 2606 | static int check_refcounts_l1(BlockDriverState *bs, |
| @@ -2603,11 +2612,12 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2603,11 +2612,12 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2603 | BDRVQcowState *s = bs->opaque; | 2612 | BDRVQcowState *s = bs->opaque; |
| 2604 | uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2; | 2613 | uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2; |
| 2605 | int l2_size, i, j, nb_csectors, refcount; | 2614 | int l2_size, i, j, nb_csectors, refcount; |
| 2615 | + int errors = 0; | ||
| 2606 | 2616 | ||
| 2607 | l2_table = NULL; | 2617 | l2_table = NULL; |
| 2608 | l1_size2 = l1_size * sizeof(uint64_t); | 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 | l1_table_offset, l1_size2); | 2621 | l1_table_offset, l1_size2); |
| 2612 | 2622 | ||
| 2613 | l1_table = qemu_malloc(l1_size2); | 2623 | l1_table = qemu_malloc(l1_size2); |
| @@ -2627,6 +2637,7 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2627,6 +2637,7 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2627 | if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { | 2637 | if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { |
| 2628 | fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 | 2638 | fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 |
| 2629 | " refcount=%d\n", l2_offset, refcount); | 2639 | " refcount=%d\n", l2_offset, refcount); |
| 2640 | + errors++; | ||
| 2630 | } | 2641 | } |
| 2631 | } | 2642 | } |
| 2632 | l2_offset &= ~QCOW_OFLAG_COPIED; | 2643 | l2_offset &= ~QCOW_OFLAG_COPIED; |
| @@ -2641,11 +2652,12 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2641,11 +2652,12 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2641 | "copied flag must never be set for compressed " | 2652 | "copied flag must never be set for compressed " |
| 2642 | "clusters\n", offset >> s->cluster_bits); | 2653 | "clusters\n", offset >> s->cluster_bits); |
| 2643 | offset &= ~QCOW_OFLAG_COPIED; | 2654 | offset &= ~QCOW_OFLAG_COPIED; |
| 2655 | + errors++; | ||
| 2644 | } | 2656 | } |
| 2645 | nb_csectors = ((offset >> s->csize_shift) & | 2657 | nb_csectors = ((offset >> s->csize_shift) & |
| 2646 | s->csize_mask) + 1; | 2658 | s->csize_mask) + 1; |
| 2647 | offset &= s->cluster_offset_mask; | 2659 | offset &= s->cluster_offset_mask; |
| 2648 | - inc_refcounts(bs, refcount_table, | 2660 | + errors += inc_refcounts(bs, refcount_table, |
| 2649 | refcount_table_size, | 2661 | refcount_table_size, |
| 2650 | offset & ~511, nb_csectors * 512); | 2662 | offset & ~511, nb_csectors * 512); |
| 2651 | } else { | 2663 | } else { |
| @@ -2654,16 +2666,17 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2654,16 +2666,17 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2654 | if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) { | 2666 | if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) { |
| 2655 | fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" | 2667 | fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" |
| 2656 | PRIx64 " refcount=%d\n", offset, refcount); | 2668 | PRIx64 " refcount=%d\n", offset, refcount); |
| 2669 | + errors++; | ||
| 2657 | } | 2670 | } |
| 2658 | } | 2671 | } |
| 2659 | offset &= ~QCOW_OFLAG_COPIED; | 2672 | offset &= ~QCOW_OFLAG_COPIED; |
| 2660 | - inc_refcounts(bs, refcount_table, | 2673 | + errors += inc_refcounts(bs, refcount_table, |
| 2661 | refcount_table_size, | 2674 | refcount_table_size, |
| 2662 | offset, s->cluster_size); | 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 | refcount_table_size, | 2680 | refcount_table_size, |
| 2668 | l2_offset, | 2681 | l2_offset, |
| 2669 | s->cluster_size); | 2682 | s->cluster_size); |
| @@ -2671,7 +2684,7 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2671,7 +2684,7 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2671 | } | 2684 | } |
| 2672 | qemu_free(l1_table); | 2685 | qemu_free(l1_table); |
| 2673 | qemu_free(l2_table); | 2686 | qemu_free(l2_table); |
| 2674 | - return 0; | 2687 | + return errors; |
| 2675 | fail: | 2688 | fail: |
| 2676 | fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); | 2689 | fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); |
| 2677 | qemu_free(l1_table); | 2690 | qemu_free(l1_table); |
| @@ -2679,24 +2692,35 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2679,24 +2692,35 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2679 | return -EIO; | 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 | BDRVQcowState *s = bs->opaque; | 2703 | BDRVQcowState *s = bs->opaque; |
| 2685 | int64_t size; | 2704 | int64_t size; |
| 2686 | int nb_clusters, refcount1, refcount2, i; | 2705 | int nb_clusters, refcount1, refcount2, i; |
| 2687 | QCowSnapshot *sn; | 2706 | QCowSnapshot *sn; |
| 2688 | uint16_t *refcount_table; | 2707 | uint16_t *refcount_table; |
| 2708 | + int ret, errors = 0; | ||
| 2689 | 2709 | ||
| 2690 | size = bdrv_getlength(s->hd); | 2710 | size = bdrv_getlength(s->hd); |
| 2691 | nb_clusters = size_to_clusters(s, size); | 2711 | nb_clusters = size_to_clusters(s, size); |
| 2692 | refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); | 2712 | refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); |
| 2693 | 2713 | ||
| 2694 | /* header */ | 2714 | /* header */ |
| 2695 | - inc_refcounts(bs, refcount_table, nb_clusters, | 2715 | + errors += inc_refcounts(bs, refcount_table, nb_clusters, |
| 2696 | 0, s->cluster_size); | 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 | s->l1_table_offset, s->l1_size, 1); | 2719 | s->l1_table_offset, s->l1_size, 1); |
| 2720 | + if (ret < 0) { | ||
| 2721 | + return ret; | ||
| 2722 | + } | ||
| 2723 | + errors += ret; | ||
| 2700 | 2724 | ||
| 2701 | /* snapshots */ | 2725 | /* snapshots */ |
| 2702 | for(i = 0; i < s->nb_snapshots; i++) { | 2726 | for(i = 0; i < s->nb_snapshots; i++) { |
| @@ -2704,18 +2728,18 @@ static void check_refcounts(BlockDriverState *bs) | @@ -2704,18 +2728,18 @@ static void check_refcounts(BlockDriverState *bs) | ||
| 2704 | check_refcounts_l1(bs, refcount_table, nb_clusters, | 2728 | check_refcounts_l1(bs, refcount_table, nb_clusters, |
| 2705 | sn->l1_table_offset, sn->l1_size, 0); | 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 | s->snapshots_offset, s->snapshots_size); | 2732 | s->snapshots_offset, s->snapshots_size); |
| 2709 | 2733 | ||
| 2710 | /* refcount data */ | 2734 | /* refcount data */ |
| 2711 | - inc_refcounts(bs, refcount_table, nb_clusters, | 2735 | + errors += inc_refcounts(bs, refcount_table, nb_clusters, |
| 2712 | s->refcount_table_offset, | 2736 | s->refcount_table_offset, |
| 2713 | s->refcount_table_size * sizeof(uint64_t)); | 2737 | s->refcount_table_size * sizeof(uint64_t)); |
| 2714 | for(i = 0; i < s->refcount_table_size; i++) { | 2738 | for(i = 0; i < s->refcount_table_size; i++) { |
| 2715 | int64_t offset; | 2739 | int64_t offset; |
| 2716 | offset = s->refcount_table[i]; | 2740 | offset = s->refcount_table[i]; |
| 2717 | if (offset != 0) { | 2741 | if (offset != 0) { |
| 2718 | - inc_refcounts(bs, refcount_table, nb_clusters, | 2742 | + errors += inc_refcounts(bs, refcount_table, nb_clusters, |
| 2719 | offset, s->cluster_size); | 2743 | offset, s->cluster_size); |
| 2720 | } | 2744 | } |
| 2721 | } | 2745 | } |
| @@ -2724,12 +2748,21 @@ static void check_refcounts(BlockDriverState *bs) | @@ -2724,12 +2748,21 @@ static void check_refcounts(BlockDriverState *bs) | ||
| 2724 | for(i = 0; i < nb_clusters; i++) { | 2748 | for(i = 0; i < nb_clusters; i++) { |
| 2725 | refcount1 = get_refcount(bs, i); | 2749 | refcount1 = get_refcount(bs, i); |
| 2726 | refcount2 = refcount_table[i]; | 2750 | refcount2 = refcount_table[i]; |
| 2727 | - if (refcount1 != refcount2) | 2751 | + if (refcount1 != refcount2) { |
| 2728 | fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n", | 2752 | fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n", |
| 2729 | i, refcount1, refcount2); | 2753 | i, refcount1, refcount2); |
| 2754 | + errors++; | ||
| 2755 | + } | ||
| 2730 | } | 2756 | } |
| 2731 | 2757 | ||
| 2732 | qemu_free(refcount_table); | 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 | #if 0 | 2768 | #if 0 |
| @@ -2751,7 +2784,6 @@ static void dump_refcounts(BlockDriverState *bs) | @@ -2751,7 +2784,6 @@ static void dump_refcounts(BlockDriverState *bs) | ||
| 2751 | } | 2784 | } |
| 2752 | } | 2785 | } |
| 2753 | #endif | 2786 | #endif |
| 2754 | -#endif | ||
| 2755 | 2787 | ||
| 2756 | static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf, | 2788 | static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf, |
| 2757 | int64_t pos, int size) | 2789 | int64_t pos, int size) |
| @@ -2806,4 +2838,5 @@ BlockDriver bdrv_qcow2 = { | @@ -2806,4 +2838,5 @@ BlockDriver bdrv_qcow2 = { | ||
| 2806 | .bdrv_get_buffer = qcow_get_buffer, | 2838 | .bdrv_get_buffer = qcow_get_buffer, |
| 2807 | 2839 | ||
| 2808 | .bdrv_create2 = qcow_create2, | 2840 | .bdrv_create2 = qcow_create2, |
| 2841 | + .bdrv_check = qcow_check, | ||
| 2809 | }; | 2842 | }; |
block.c
| @@ -506,6 +506,20 @@ void bdrv_delete(BlockDriverState *bs) | @@ -506,6 +506,20 @@ void bdrv_delete(BlockDriverState *bs) | ||
| 506 | qemu_free(bs); | 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 | /* commit COW file into the raw image */ | 523 | /* commit COW file into the raw image */ |
| 510 | int bdrv_commit(BlockDriverState *bs) | 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,6 +73,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags); | ||
| 73 | int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, | 73 | int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, |
| 74 | BlockDriver *drv); | 74 | BlockDriver *drv); |
| 75 | void bdrv_close(BlockDriverState *bs); | 75 | void bdrv_close(BlockDriverState *bs); |
| 76 | +int bdrv_check(BlockDriverState *bs); | ||
| 76 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, | 77 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
| 77 | uint8_t *buf, int nb_sectors); | 78 | uint8_t *buf, int nb_sectors); |
| 78 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, | 79 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
block_int.h
| @@ -102,6 +102,9 @@ struct BlockDriver { | @@ -102,6 +102,9 @@ struct BlockDriver { | ||
| 102 | const char *backing_file, const char *backing_format, | 102 | const char *backing_file, const char *backing_format, |
| 103 | int flags); | 103 | int flags); |
| 104 | 104 | ||
| 105 | + /* Returns number of errors in image, -errno for internal errors */ | ||
| 106 | + int (*bdrv_check)(BlockDriverState* bs); | ||
| 107 | + | ||
| 105 | struct BlockDriver *next; | 108 | struct BlockDriver *next; |
| 106 | }; | 109 | }; |
| 107 | 110 |