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 | 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 | 2690 | static int check_refcounts_l1(BlockDriverState *bs, |
2607 | 2691 | uint16_t *refcount_table, |
2608 | 2692 | int refcount_table_size, |
... | ... | @@ -2610,16 +2694,17 @@ static int check_refcounts_l1(BlockDriverState *bs, |
2610 | 2694 | int check_copied) |
2611 | 2695 | { |
2612 | 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 | 2699 | int errors = 0; |
2616 | 2700 | |
2617 | - l2_table = NULL; | |
2618 | 2701 | l1_size2 = l1_size * sizeof(uint64_t); |
2619 | 2702 | |
2703 | + /* Mark L1 table as used */ | |
2620 | 2704 | errors += inc_refcounts(bs, refcount_table, refcount_table_size, |
2621 | 2705 | l1_table_offset, l1_size2); |
2622 | 2706 | |
2707 | + /* Read L1 table entries from disk */ | |
2623 | 2708 | l1_table = qemu_malloc(l1_size2); |
2624 | 2709 | if (bdrv_pread(s->hd, l1_table_offset, |
2625 | 2710 | l1_table, l1_size2) != l1_size2) |
... | ... | @@ -2627,68 +2712,43 @@ static int check_refcounts_l1(BlockDriverState *bs, |
2627 | 2712 | for(i = 0;i < l1_size; i++) |
2628 | 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 | 2716 | for(i = 0; i < l1_size; i++) { |
2633 | 2717 | l2_offset = l1_table[i]; |
2634 | 2718 | if (l2_offset) { |
2719 | + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ | |
2635 | 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 | 2723 | if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { |
2638 | 2724 | fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 |
2639 | 2725 | " refcount=%d\n", l2_offset, refcount); |
2640 | 2726 | errors++; |
2641 | 2727 | } |
2642 | 2728 | } |
2729 | + | |
2730 | + /* Mark L2 table as used */ | |
2643 | 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 | 2732 | errors += inc_refcounts(bs, refcount_table, |
2680 | 2733 | refcount_table_size, |
2681 | 2734 | l2_offset, |
2682 | 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 | 2746 | qemu_free(l1_table); |
2686 | - qemu_free(l2_table); | |
2687 | 2747 | return errors; |
2688 | - fail: | |
2748 | + | |
2749 | +fail: | |
2689 | 2750 | fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); |
2690 | 2751 | qemu_free(l1_table); |
2691 | - qemu_free(l2_table); | |
2692 | 2752 | return -EIO; |
2693 | 2753 | } |
2694 | 2754 | |
... | ... | @@ -2715,6 +2775,7 @@ static int check_refcounts(BlockDriverState *bs) |
2715 | 2775 | errors += inc_refcounts(bs, refcount_table, nb_clusters, |
2716 | 2776 | 0, s->cluster_size); |
2717 | 2777 | |
2778 | + /* current L1 table */ | |
2718 | 2779 | ret = check_refcounts_l1(bs, refcount_table, nb_clusters, |
2719 | 2780 | s->l1_table_offset, s->l1_size, 1); |
2720 | 2781 | if (ret < 0) { | ... | ... |