Revision f214978a
b/block/qcow2-cluster.c | ||
---|---|---|
684 | 684 |
int l2_index, ret; |
685 | 685 |
uint64_t l2_offset, *l2_table, cluster_offset; |
686 | 686 |
int nb_clusters, i = 0; |
687 |
QCowL2Meta *old_alloc; |
|
687 | 688 |
|
688 | 689 |
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); |
689 | 690 |
if (ret == 0) |
... | ... | |
732 | 733 |
} |
733 | 734 |
nb_clusters = i; |
734 | 735 |
|
736 |
/* |
|
737 |
* Check if there already is an AIO write request in flight which allocates |
|
738 |
* the same cluster. In this case we need to wait until the previous |
|
739 |
* request has completed and updated the L2 table accordingly. |
|
740 |
*/ |
|
741 |
LIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) { |
|
742 |
|
|
743 |
uint64_t end_offset = offset + nb_clusters * s->cluster_size; |
|
744 |
uint64_t old_offset = old_alloc->offset; |
|
745 |
uint64_t old_end_offset = old_alloc->offset + |
|
746 |
old_alloc->nb_clusters * s->cluster_size; |
|
747 |
|
|
748 |
if (end_offset < old_offset || offset > old_end_offset) { |
|
749 |
/* No intersection */ |
|
750 |
} else { |
|
751 |
if (offset < old_offset) { |
|
752 |
/* Stop at the start of a running allocation */ |
|
753 |
nb_clusters = (old_offset - offset) >> s->cluster_bits; |
|
754 |
} else { |
|
755 |
nb_clusters = 0; |
|
756 |
} |
|
757 |
|
|
758 |
if (nb_clusters == 0) { |
|
759 |
/* Set dependency and wait for a callback */ |
|
760 |
m->depends_on = old_alloc; |
|
761 |
m->nb_clusters = 0; |
|
762 |
*num = 0; |
|
763 |
return 0; |
|
764 |
} |
|
765 |
} |
|
766 |
} |
|
767 |
|
|
768 |
if (!nb_clusters) { |
|
769 |
abort(); |
|
770 |
} |
|
771 |
|
|
772 |
LIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight); |
|
773 |
|
|
735 | 774 |
/* allocate a new cluster */ |
736 | 775 |
|
737 | 776 |
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size); |
b/block/qcow2.c | ||
---|---|---|
219 | 219 |
if (qcow2_refcount_init(bs) < 0) |
220 | 220 |
goto fail; |
221 | 221 |
|
222 |
LIST_INIT(&s->cluster_allocs); |
|
223 |
|
|
222 | 224 |
/* read qcow2 extensions */ |
223 | 225 |
if (header.backing_file_offset) |
224 | 226 |
ext_end = header.backing_file_offset; |
... | ... | |
338 | 340 |
QEMUIOVector hd_qiov; |
339 | 341 |
QEMUBH *bh; |
340 | 342 |
QCowL2Meta l2meta; |
343 |
LIST_ENTRY(QCowAIOCB) next_depend; |
|
341 | 344 |
} QCowAIOCB; |
342 | 345 |
|
343 | 346 |
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) |
... | ... | |
500 | 503 |
acb->n = 0; |
501 | 504 |
acb->cluster_offset = 0; |
502 | 505 |
acb->l2meta.nb_clusters = 0; |
506 |
LIST_INIT(&acb->l2meta.dependent_requests); |
|
503 | 507 |
return acb; |
504 | 508 |
} |
505 | 509 |
|
... | ... | |
517 | 521 |
return &acb->common; |
518 | 522 |
} |
519 | 523 |
|
524 |
static void qcow_aio_write_cb(void *opaque, int ret); |
|
525 |
|
|
526 |
static void run_dependent_requests(QCowL2Meta *m) |
|
527 |
{ |
|
528 |
QCowAIOCB *req; |
|
529 |
QCowAIOCB *next; |
|
530 |
|
|
531 |
/* Take the request off the list of running requests */ |
|
532 |
if (m->nb_clusters != 0) { |
|
533 |
LIST_REMOVE(m, next_in_flight); |
|
534 |
} |
|
535 |
|
|
536 |
/* |
|
537 |
* Restart all dependent requests. |
|
538 |
* Can't use LIST_FOREACH here - the next link might not be the same |
|
539 |
* any more after the callback (request could depend on a different |
|
540 |
* request now) |
|
541 |
*/ |
|
542 |
for (req = m->dependent_requests.lh_first; req != NULL; req = next) { |
|
543 |
next = req->next_depend.le_next; |
|
544 |
qcow_aio_write_cb(req, 0); |
|
545 |
} |
|
546 |
|
|
547 |
/* Empty the list for the next part of the request */ |
|
548 |
LIST_INIT(&m->dependent_requests); |
|
549 |
} |
|
550 |
|
|
520 | 551 |
static void qcow_aio_write_cb(void *opaque, int ret) |
521 | 552 |
{ |
522 | 553 |
QCowAIOCB *acb = opaque; |
... | ... | |
528 | 559 |
|
529 | 560 |
acb->hd_aiocb = NULL; |
530 | 561 |
|
562 |
if (ret >= 0) { |
|
563 |
ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta); |
|
564 |
} |
|
565 |
|
|
566 |
run_dependent_requests(&acb->l2meta); |
|
567 |
|
|
531 | 568 |
if (ret < 0) |
532 | 569 |
goto done; |
533 | 570 |
|
534 |
if (qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta) < 0) { |
|
535 |
qcow2_free_any_clusters(bs, acb->cluster_offset, acb->l2meta.nb_clusters); |
|
536 |
goto done; |
|
537 |
} |
|
538 |
|
|
539 | 571 |
acb->nb_sectors -= acb->n; |
540 | 572 |
acb->sector_num += acb->n; |
541 | 573 |
acb->buf += acb->n * 512; |
... | ... | |
555 | 587 |
acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9, |
556 | 588 |
index_in_cluster, |
557 | 589 |
n_end, &acb->n, &acb->l2meta); |
590 |
|
|
591 |
/* Need to wait for another request? If so, we are done for now. */ |
|
592 |
if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) { |
|
593 |
LIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests, |
|
594 |
acb, next_depend); |
|
595 |
return; |
|
596 |
} |
|
597 |
|
|
558 | 598 |
if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) { |
559 | 599 |
ret = -EIO; |
560 | 600 |
goto done; |
... | ... | |
650 | 690 |
|
651 | 691 |
nb_sectors = bdrv_getlength(bs) >> 9; |
652 | 692 |
offset = 0; |
693 |
LIST_INIT(&meta.dependent_requests); |
|
653 | 694 |
|
654 | 695 |
while (nb_sectors) { |
655 | 696 |
num = MIN(nb_sectors, INT_MAX >> 9); |
... | ... | |
665 | 706 |
return -1; |
666 | 707 |
} |
667 | 708 |
|
709 |
/* There are no dependent requests, but we need to remove our request |
|
710 |
* from the list of in-flight requests */ |
|
711 |
run_dependent_requests(&meta); |
|
712 |
|
|
668 | 713 |
/* TODO Preallocate data if requested */ |
669 | 714 |
|
670 | 715 |
nb_sectors -= num; |
b/block/qcow2.h | ||
---|---|---|
98 | 98 |
uint8_t *cluster_cache; |
99 | 99 |
uint8_t *cluster_data; |
100 | 100 |
uint64_t cluster_cache_offset; |
101 |
LIST_HEAD(QCowClusterAlloc, QCowL2Meta) cluster_allocs; |
|
101 | 102 |
|
102 | 103 |
uint64_t *refcount_table; |
103 | 104 |
uint64_t refcount_table_offset; |
... | ... | |
128 | 129 |
int64_t refcount_block_offset; |
129 | 130 |
} QCowCreateState; |
130 | 131 |
|
132 |
struct QCowAIOCB; |
|
133 |
|
|
131 | 134 |
/* XXX This could be private for qcow2-cluster.c */ |
132 | 135 |
typedef struct QCowL2Meta |
133 | 136 |
{ |
... | ... | |
135 | 138 |
int n_start; |
136 | 139 |
int nb_available; |
137 | 140 |
int nb_clusters; |
141 |
struct QCowL2Meta *depends_on; |
|
142 |
LIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests; |
|
143 |
|
|
144 |
LIST_ENTRY(QCowL2Meta) next_in_flight; |
|
138 | 145 |
} QCowL2Meta; |
139 | 146 |
|
140 | 147 |
static inline int size_to_clusters(BDRVQcowState *s, int64_t size) |
Also available in: Unified diff