Commit 108534b9681579002f46942139a77732a2510436
1 parent
16b98a97
qcow2: Extract code from get_cluster_offset() (Laurent Vivier)
Extract code from get_cluster_offset() into new functions: - seek_l2_table() Search an l2 offset in the l2_cache table. - l2_load() Read the l2 entry from disk - l2_allocate() Allocate a new l2 entry. Some comment fixups from Kevin Wolf Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net> Signed-off-by: Kevin Wolf <kwolf@suse.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5003 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
153 additions
and
62 deletions
block-qcow2.c
... | ... | @@ -480,101 +480,191 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) |
480 | 480 | return -EIO; |
481 | 481 | } |
482 | 482 | |
483 | -/* 'allocate' is: | |
483 | +/* | |
484 | + * seek_l2_table | |
485 | + * | |
486 | + * seek l2_offset in the l2_cache table | |
487 | + * if not found, return NULL, | |
488 | + * if found, | |
489 | + * increments the l2 cache hit count of the entry, | |
490 | + * if counter overflow, divide by two all counters | |
491 | + * return the pointer to the l2 cache entry | |
492 | + * | |
493 | + */ | |
494 | + | |
495 | +static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset) | |
496 | +{ | |
497 | + int i, j; | |
498 | + | |
499 | + for(i = 0; i < L2_CACHE_SIZE; i++) { | |
500 | + if (l2_offset == s->l2_cache_offsets[i]) { | |
501 | + /* increment the hit count */ | |
502 | + if (++s->l2_cache_counts[i] == 0xffffffff) { | |
503 | + for(j = 0; j < L2_CACHE_SIZE; j++) { | |
504 | + s->l2_cache_counts[j] >>= 1; | |
505 | + } | |
506 | + } | |
507 | + return s->l2_cache + (i << s->l2_bits); | |
508 | + } | |
509 | + } | |
510 | + return NULL; | |
511 | +} | |
512 | + | |
513 | +/* | |
514 | + * l2_load | |
484 | 515 | * |
485 | - * 0 not to allocate. | |
516 | + * Loads a L2 table into memory. If the table is in the cache, the cache | |
517 | + * is used; otherwise the L2 table is loaded from the image file. | |
486 | 518 | * |
487 | - * 1 to allocate a normal cluster (for sector indexes 'n_start' to | |
488 | - * 'n_end') | |
519 | + * Returns a pointer to the L2 table on success, or NULL if the read from | |
520 | + * the image file failed. | |
521 | + */ | |
522 | + | |
523 | +static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) | |
524 | +{ | |
525 | + BDRVQcowState *s = bs->opaque; | |
526 | + int min_index; | |
527 | + uint64_t *l2_table; | |
528 | + | |
529 | + /* seek if the table for the given offset is in the cache */ | |
530 | + | |
531 | + l2_table = seek_l2_table(s, l2_offset); | |
532 | + if (l2_table != NULL) | |
533 | + return l2_table; | |
534 | + | |
535 | + /* not found: load a new entry in the least used one */ | |
536 | + | |
537 | + min_index = l2_cache_new_entry(bs); | |
538 | + l2_table = s->l2_cache + (min_index << s->l2_bits); | |
539 | + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != | |
540 | + s->l2_size * sizeof(uint64_t)) | |
541 | + return NULL; | |
542 | + s->l2_cache_offsets[min_index] = l2_offset; | |
543 | + s->l2_cache_counts[min_index] = 1; | |
544 | + | |
545 | + return l2_table; | |
546 | +} | |
547 | + | |
548 | +/* | |
549 | + * l2_allocate | |
489 | 550 | * |
490 | - * 2 to allocate a compressed cluster of size | |
491 | - * 'compressed_size'. 'compressed_size' must be > 0 and < | |
492 | - * cluster_size | |
551 | + * Allocate a new l2 entry in the file. If l1_index points to an already | |
552 | + * used entry in the L2 table (i.e. we are doing a copy on write for the L2 | |
553 | + * table) copy the contents of the old L2 table into the newly allocated one. | |
554 | + * Otherwise the new table is initialized with zeros. | |
493 | 555 | * |
494 | - * return 0 if not allocated. | |
495 | 556 | */ |
557 | + | |
558 | +static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) | |
559 | +{ | |
560 | + BDRVQcowState *s = bs->opaque; | |
561 | + int min_index; | |
562 | + uint64_t old_l2_offset, tmp; | |
563 | + uint64_t *l2_table, l2_offset; | |
564 | + | |
565 | + old_l2_offset = s->l1_table[l1_index]; | |
566 | + | |
567 | + /* allocate a new l2 entry */ | |
568 | + | |
569 | + l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); | |
570 | + | |
571 | + /* update the L1 entry */ | |
572 | + | |
573 | + s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; | |
574 | + | |
575 | + tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED); | |
576 | + if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), | |
577 | + &tmp, sizeof(tmp)) != sizeof(tmp)) | |
578 | + return NULL; | |
579 | + | |
580 | + /* allocate a new entry in the l2 cache */ | |
581 | + | |
582 | + min_index = l2_cache_new_entry(bs); | |
583 | + l2_table = s->l2_cache + (min_index << s->l2_bits); | |
584 | + | |
585 | + if (old_l2_offset == 0) { | |
586 | + /* if there was no old l2 table, clear the new table */ | |
587 | + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); | |
588 | + } else { | |
589 | + /* if there was an old l2 table, read it from the disk */ | |
590 | + if (bdrv_pread(s->hd, old_l2_offset, | |
591 | + l2_table, s->l2_size * sizeof(uint64_t)) != | |
592 | + s->l2_size * sizeof(uint64_t)) | |
593 | + return NULL; | |
594 | + } | |
595 | + /* write the l2 table to the file */ | |
596 | + if (bdrv_pwrite(s->hd, l2_offset, | |
597 | + l2_table, s->l2_size * sizeof(uint64_t)) != | |
598 | + s->l2_size * sizeof(uint64_t)) | |
599 | + return NULL; | |
600 | + | |
601 | + /* update the l2 cache entry */ | |
602 | + | |
603 | + s->l2_cache_offsets[min_index] = l2_offset; | |
604 | + s->l2_cache_counts[min_index] = 1; | |
605 | + | |
606 | + return l2_table; | |
607 | +} | |
608 | + | |
496 | 609 | static uint64_t get_cluster_offset(BlockDriverState *bs, |
497 | 610 | uint64_t offset, int allocate, |
498 | 611 | int compressed_size, |
499 | 612 | int n_start, int n_end) |
500 | 613 | { |
501 | 614 | BDRVQcowState *s = bs->opaque; |
502 | - int min_index, i, j, l1_index, l2_index, ret; | |
503 | - uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset; | |
615 | + int l1_index, l2_index, ret; | |
616 | + uint64_t l2_offset, *l2_table, cluster_offset, tmp; | |
617 | + | |
618 | + /* seek the the l2 offset in the l1 table */ | |
504 | 619 | |
505 | 620 | l1_index = offset >> (s->l2_bits + s->cluster_bits); |
506 | 621 | if (l1_index >= s->l1_size) { |
507 | 622 | /* outside l1 table is allowed: we grow the table if needed */ |
508 | 623 | if (!allocate) |
509 | 624 | return 0; |
510 | - if (grow_l1_table(bs, l1_index + 1) < 0) | |
625 | + ret = grow_l1_table(bs, l1_index + 1); | |
626 | + if (ret < 0) | |
511 | 627 | return 0; |
512 | 628 | } |
513 | 629 | l2_offset = s->l1_table[l1_index]; |
630 | + | |
631 | + /* seek the l2 table of the given l2 offset */ | |
632 | + | |
514 | 633 | if (!l2_offset) { |
634 | + /* the l2 table doesn't exist */ | |
515 | 635 | if (!allocate) |
516 | 636 | return 0; |
517 | - l2_allocate: | |
518 | - old_l2_offset = l2_offset; | |
519 | - /* allocate a new l2 entry */ | |
520 | - l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); | |
521 | - /* update the L1 entry */ | |
522 | - s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; | |
523 | - tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED); | |
524 | - if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), | |
525 | - &tmp, sizeof(tmp)) != sizeof(tmp)) | |
526 | - return 0; | |
527 | - min_index = l2_cache_new_entry(bs); | |
528 | - l2_table = s->l2_cache + (min_index << s->l2_bits); | |
529 | - | |
530 | - if (old_l2_offset == 0) { | |
531 | - memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); | |
532 | - } else { | |
533 | - if (bdrv_pread(s->hd, old_l2_offset, | |
534 | - l2_table, s->l2_size * sizeof(uint64_t)) != | |
535 | - s->l2_size * sizeof(uint64_t)) | |
536 | - return 0; | |
537 | - } | |
538 | - if (bdrv_pwrite(s->hd, l2_offset, | |
539 | - l2_table, s->l2_size * sizeof(uint64_t)) != | |
540 | - s->l2_size * sizeof(uint64_t)) | |
637 | + /* allocate a new l2 table for this offset */ | |
638 | + l2_table = l2_allocate(bs, l1_index); | |
639 | + if (l2_table == NULL) | |
541 | 640 | return 0; |
641 | + l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; | |
542 | 642 | } else { |
543 | - if (!(l2_offset & QCOW_OFLAG_COPIED)) { | |
544 | - if (allocate) { | |
545 | - free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); | |
546 | - goto l2_allocate; | |
547 | - } | |
643 | + /* the l2 table exists */ | |
644 | + if (!(l2_offset & QCOW_OFLAG_COPIED) && allocate) { | |
645 | + /* duplicate the l2 table, and free the old table */ | |
646 | + free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); | |
647 | + l2_table = l2_allocate(bs, l1_index); | |
648 | + if (l2_table == NULL) | |
649 | + return 0; | |
650 | + l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; | |
548 | 651 | } else { |
652 | + /* load the l2 table in memory */ | |
549 | 653 | l2_offset &= ~QCOW_OFLAG_COPIED; |
654 | + l2_table = l2_load(bs, l2_offset); | |
655 | + if (l2_table == NULL) | |
656 | + return 0; | |
550 | 657 | } |
551 | - for(i = 0; i < L2_CACHE_SIZE; i++) { | |
552 | - if (l2_offset == s->l2_cache_offsets[i]) { | |
553 | - /* increment the hit count */ | |
554 | - if (++s->l2_cache_counts[i] == 0xffffffff) { | |
555 | - for(j = 0; j < L2_CACHE_SIZE; j++) { | |
556 | - s->l2_cache_counts[j] >>= 1; | |
557 | - } | |
558 | - } | |
559 | - l2_table = s->l2_cache + (i << s->l2_bits); | |
560 | - goto found; | |
561 | - } | |
562 | - } | |
563 | - /* not found: load a new entry in the least used one */ | |
564 | - min_index = l2_cache_new_entry(bs); | |
565 | - l2_table = s->l2_cache + (min_index << s->l2_bits); | |
566 | - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != | |
567 | - s->l2_size * sizeof(uint64_t)) | |
568 | - return 0; | |
569 | 658 | } |
570 | - s->l2_cache_offsets[min_index] = l2_offset; | |
571 | - s->l2_cache_counts[min_index] = 1; | |
572 | - found: | |
659 | + | |
660 | + /* find the cluster offset for the given disk offset */ | |
661 | + | |
573 | 662 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); |
574 | 663 | cluster_offset = be64_to_cpu(l2_table[l2_index]); |
575 | 664 | if (!cluster_offset) { |
665 | + /* cluster doesn't exist */ | |
576 | 666 | if (!allocate) |
577 | - return cluster_offset; | |
667 | + return 0; | |
578 | 668 | } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) { |
579 | 669 | if (!allocate) |
580 | 670 | return cluster_offset; |
... | ... | @@ -592,6 +682,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, |
592 | 682 | cluster_offset &= ~QCOW_OFLAG_COPIED; |
593 | 683 | return cluster_offset; |
594 | 684 | } |
685 | + | |
595 | 686 | if (allocate == 1) { |
596 | 687 | /* allocate a new cluster */ |
597 | 688 | cluster_offset = alloc_clusters(bs, s->cluster_size); | ... | ... |