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