Commit e97fc193e1c65deb51643d5251e98affe07c59ca

Authored by aliguori
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
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 };
@@ -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 {
@@ -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