Commit ae2f14af54b089f793fcd1f5635dcb57a569adef
1 parent
1585969c
qcow2: Refcount checking code cleanup (Kevin Wolf)
This is purely cosmetical changes to make the code easier to read. Move L2 table processing from a deeply nested block to its own function, add some comments. Patch v2: Fix misplaced bracket causing false positives 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@7216 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
105 additions
and
44 deletions
block-qcow2.c
| @@ -2603,6 +2603,90 @@ static int inc_refcounts(BlockDriverState *bs, | @@ -2603,6 +2603,90 @@ static int inc_refcounts(BlockDriverState *bs, | ||
| 2603 | return errors; | 2603 | return errors; |
| 2604 | } | 2604 | } |
| 2605 | 2605 | ||
| 2606 | +/* | ||
| 2607 | + * Increases the refcount in the given refcount table for the all clusters | ||
| 2608 | + * referenced in the L2 table. While doing so, performs some checks on L2 | ||
| 2609 | + * entries. | ||
| 2610 | + * | ||
| 2611 | + * Returns the number of errors found by the checks or -errno if an internal | ||
| 2612 | + * error occurred. | ||
| 2613 | + */ | ||
| 2614 | +static int check_refcounts_l2(BlockDriverState *bs, | ||
| 2615 | + uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset, | ||
| 2616 | + int check_copied) | ||
| 2617 | +{ | ||
| 2618 | + BDRVQcowState *s = bs->opaque; | ||
| 2619 | + uint64_t *l2_table, offset; | ||
| 2620 | + int i, l2_size, nb_csectors, refcount; | ||
| 2621 | + int errors = 0; | ||
| 2622 | + | ||
| 2623 | + /* Read L2 table from disk */ | ||
| 2624 | + l2_size = s->l2_size * sizeof(uint64_t); | ||
| 2625 | + l2_table = qemu_malloc(l2_size); | ||
| 2626 | + | ||
| 2627 | + if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) | ||
| 2628 | + goto fail; | ||
| 2629 | + | ||
| 2630 | + /* Do the actual checks */ | ||
| 2631 | + for(i = 0; i < s->l2_size; i++) { | ||
| 2632 | + offset = be64_to_cpu(l2_table[i]); | ||
| 2633 | + if (offset != 0) { | ||
| 2634 | + if (offset & QCOW_OFLAG_COMPRESSED) { | ||
| 2635 | + /* Compressed clusters don't have QCOW_OFLAG_COPIED */ | ||
| 2636 | + if (offset & QCOW_OFLAG_COPIED) { | ||
| 2637 | + fprintf(stderr, "ERROR: cluster %" PRId64 ": " | ||
| 2638 | + "copied flag must never be set for compressed " | ||
| 2639 | + "clusters\n", offset >> s->cluster_bits); | ||
| 2640 | + offset &= ~QCOW_OFLAG_COPIED; | ||
| 2641 | + errors++; | ||
| 2642 | + } | ||
| 2643 | + | ||
| 2644 | + /* Mark cluster as used */ | ||
| 2645 | + nb_csectors = ((offset >> s->csize_shift) & | ||
| 2646 | + s->csize_mask) + 1; | ||
| 2647 | + offset &= s->cluster_offset_mask; | ||
| 2648 | + errors += inc_refcounts(bs, refcount_table, | ||
| 2649 | + refcount_table_size, | ||
| 2650 | + offset & ~511, nb_csectors * 512); | ||
| 2651 | + } else { | ||
| 2652 | + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ | ||
| 2653 | + if (check_copied) { | ||
| 2654 | + uint64_t entry = offset; | ||
| 2655 | + offset &= ~QCOW_OFLAG_COPIED; | ||
| 2656 | + refcount = get_refcount(bs, offset >> s->cluster_bits); | ||
| 2657 | + if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { | ||
| 2658 | + fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" | ||
| 2659 | + PRIx64 " refcount=%d\n", entry, refcount); | ||
| 2660 | + errors++; | ||
| 2661 | + } | ||
| 2662 | + } | ||
| 2663 | + | ||
| 2664 | + /* Mark cluster as used */ | ||
| 2665 | + offset &= ~QCOW_OFLAG_COPIED; | ||
| 2666 | + errors += inc_refcounts(bs, refcount_table, | ||
| 2667 | + refcount_table_size, | ||
| 2668 | + offset, s->cluster_size); | ||
| 2669 | + } | ||
| 2670 | + } | ||
| 2671 | + } | ||
| 2672 | + | ||
| 2673 | + qemu_free(l2_table); | ||
| 2674 | + return errors; | ||
| 2675 | + | ||
| 2676 | +fail: | ||
| 2677 | + fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); | ||
| 2678 | + qemu_free(l2_table); | ||
| 2679 | + return -EIO; | ||
| 2680 | +} | ||
| 2681 | + | ||
| 2682 | +/* | ||
| 2683 | + * Increases the refcount for the L1 table, its L2 tables and all referenced | ||
| 2684 | + * clusters in the given refcount table. While doing so, performs some checks | ||
| 2685 | + * on L1 and L2 entries. | ||
| 2686 | + * | ||
| 2687 | + * Returns the number of errors found by the checks or -errno if an internal | ||
| 2688 | + * error occurred. | ||
| 2689 | + */ | ||
| 2606 | static int check_refcounts_l1(BlockDriverState *bs, | 2690 | static int check_refcounts_l1(BlockDriverState *bs, |
| 2607 | uint16_t *refcount_table, | 2691 | uint16_t *refcount_table, |
| 2608 | int refcount_table_size, | 2692 | int refcount_table_size, |
| @@ -2610,16 +2694,17 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2610,16 +2694,17 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2610 | int check_copied) | 2694 | int check_copied) |
| 2611 | { | 2695 | { |
| 2612 | BDRVQcowState *s = bs->opaque; | 2696 | BDRVQcowState *s = bs->opaque; |
| 2613 | - uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2; | ||
| 2614 | - int l2_size, i, j, nb_csectors, refcount; | 2697 | + uint64_t *l1_table, l2_offset, l1_size2; |
| 2698 | + int i, refcount, ret; | ||
| 2615 | int errors = 0; | 2699 | int errors = 0; |
| 2616 | 2700 | ||
| 2617 | - l2_table = NULL; | ||
| 2618 | l1_size2 = l1_size * sizeof(uint64_t); | 2701 | l1_size2 = l1_size * sizeof(uint64_t); |
| 2619 | 2702 | ||
| 2703 | + /* Mark L1 table as used */ | ||
| 2620 | errors += inc_refcounts(bs, refcount_table, refcount_table_size, | 2704 | errors += inc_refcounts(bs, refcount_table, refcount_table_size, |
| 2621 | l1_table_offset, l1_size2); | 2705 | l1_table_offset, l1_size2); |
| 2622 | 2706 | ||
| 2707 | + /* Read L1 table entries from disk */ | ||
| 2623 | l1_table = qemu_malloc(l1_size2); | 2708 | l1_table = qemu_malloc(l1_size2); |
| 2624 | if (bdrv_pread(s->hd, l1_table_offset, | 2709 | if (bdrv_pread(s->hd, l1_table_offset, |
| 2625 | l1_table, l1_size2) != l1_size2) | 2710 | l1_table, l1_size2) != l1_size2) |
| @@ -2627,68 +2712,43 @@ static int check_refcounts_l1(BlockDriverState *bs, | @@ -2627,68 +2712,43 @@ static int check_refcounts_l1(BlockDriverState *bs, | ||
| 2627 | for(i = 0;i < l1_size; i++) | 2712 | for(i = 0;i < l1_size; i++) |
| 2628 | be64_to_cpus(&l1_table[i]); | 2713 | be64_to_cpus(&l1_table[i]); |
| 2629 | 2714 | ||
| 2630 | - l2_size = s->l2_size * sizeof(uint64_t); | ||
| 2631 | - l2_table = qemu_malloc(l2_size); | 2715 | + /* Do the actual checks */ |
| 2632 | for(i = 0; i < l1_size; i++) { | 2716 | for(i = 0; i < l1_size; i++) { |
| 2633 | l2_offset = l1_table[i]; | 2717 | l2_offset = l1_table[i]; |
| 2634 | if (l2_offset) { | 2718 | if (l2_offset) { |
| 2719 | + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ | ||
| 2635 | if (check_copied) { | 2720 | if (check_copied) { |
| 2636 | - refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits); | 2721 | + refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) |
| 2722 | + >> s->cluster_bits); | ||
| 2637 | if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { | 2723 | if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { |
| 2638 | fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 | 2724 | fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 |
| 2639 | " refcount=%d\n", l2_offset, refcount); | 2725 | " refcount=%d\n", l2_offset, refcount); |
| 2640 | errors++; | 2726 | errors++; |
| 2641 | } | 2727 | } |
| 2642 | } | 2728 | } |
| 2729 | + | ||
| 2730 | + /* Mark L2 table as used */ | ||
| 2643 | l2_offset &= ~QCOW_OFLAG_COPIED; | 2731 | l2_offset &= ~QCOW_OFLAG_COPIED; |
| 2644 | - if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) | ||
| 2645 | - goto fail; | ||
| 2646 | - for(j = 0; j < s->l2_size; j++) { | ||
| 2647 | - offset = be64_to_cpu(l2_table[j]); | ||
| 2648 | - if (offset != 0) { | ||
| 2649 | - if (offset & QCOW_OFLAG_COMPRESSED) { | ||
| 2650 | - if (offset & QCOW_OFLAG_COPIED) { | ||
| 2651 | - fprintf(stderr, "ERROR: cluster %" PRId64 ": " | ||
| 2652 | - "copied flag must never be set for compressed " | ||
| 2653 | - "clusters\n", offset >> s->cluster_bits); | ||
| 2654 | - offset &= ~QCOW_OFLAG_COPIED; | ||
| 2655 | - errors++; | ||
| 2656 | - } | ||
| 2657 | - nb_csectors = ((offset >> s->csize_shift) & | ||
| 2658 | - s->csize_mask) + 1; | ||
| 2659 | - offset &= s->cluster_offset_mask; | ||
| 2660 | - errors += inc_refcounts(bs, refcount_table, | ||
| 2661 | - refcount_table_size, | ||
| 2662 | - offset & ~511, nb_csectors * 512); | ||
| 2663 | - } else { | ||
| 2664 | - if (check_copied) { | ||
| 2665 | - refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits); | ||
| 2666 | - if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) { | ||
| 2667 | - fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" | ||
| 2668 | - PRIx64 " refcount=%d\n", offset, refcount); | ||
| 2669 | - errors++; | ||
| 2670 | - } | ||
| 2671 | - } | ||
| 2672 | - offset &= ~QCOW_OFLAG_COPIED; | ||
| 2673 | - errors += inc_refcounts(bs, refcount_table, | ||
| 2674 | - refcount_table_size, | ||
| 2675 | - offset, s->cluster_size); | ||
| 2676 | - } | ||
| 2677 | - } | ||
| 2678 | - } | ||
| 2679 | errors += inc_refcounts(bs, refcount_table, | 2732 | errors += inc_refcounts(bs, refcount_table, |
| 2680 | refcount_table_size, | 2733 | refcount_table_size, |
| 2681 | l2_offset, | 2734 | l2_offset, |
| 2682 | s->cluster_size); | 2735 | s->cluster_size); |
| 2736 | + | ||
| 2737 | + /* Process and check L2 entries */ | ||
| 2738 | + ret = check_refcounts_l2(bs, refcount_table, refcount_table_size, | ||
| 2739 | + l2_offset, check_copied); | ||
| 2740 | + if (ret < 0) { | ||
| 2741 | + goto fail; | ||
| 2742 | + } | ||
| 2743 | + errors += ret; | ||
| 2683 | } | 2744 | } |
| 2684 | } | 2745 | } |
| 2685 | qemu_free(l1_table); | 2746 | qemu_free(l1_table); |
| 2686 | - qemu_free(l2_table); | ||
| 2687 | return errors; | 2747 | return errors; |
| 2688 | - fail: | 2748 | + |
| 2749 | +fail: | ||
| 2689 | fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); | 2750 | fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); |
| 2690 | qemu_free(l1_table); | 2751 | qemu_free(l1_table); |
| 2691 | - qemu_free(l2_table); | ||
| 2692 | return -EIO; | 2752 | return -EIO; |
| 2693 | } | 2753 | } |
| 2694 | 2754 | ||
| @@ -2715,6 +2775,7 @@ static int check_refcounts(BlockDriverState *bs) | @@ -2715,6 +2775,7 @@ static int check_refcounts(BlockDriverState *bs) | ||
| 2715 | errors += inc_refcounts(bs, refcount_table, nb_clusters, | 2775 | errors += inc_refcounts(bs, refcount_table, nb_clusters, |
| 2716 | 0, s->cluster_size); | 2776 | 0, s->cluster_size); |
| 2717 | 2777 | ||
| 2778 | + /* current L1 table */ | ||
| 2718 | ret = check_refcounts_l1(bs, refcount_table, nb_clusters, | 2779 | ret = check_refcounts_l1(bs, refcount_table, nb_clusters, |
| 2719 | s->l1_table_offset, s->l1_size, 1); | 2780 | s->l1_table_offset, s->l1_size, 1); |
| 2720 | if (ret < 0) { | 2781 | if (ret < 0) { |