Revision 108534b9 block-qcow2.c
b/block-qcow2.c | ||
---|---|---|
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 | 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); |
Also available in: Unified diff