Revision 44ff42de block/qcow2.c

b/block/qcow2.c
173 173
static int update_cluster_refcount(BlockDriverState *bs,
174 174
                                   int64_t cluster_index,
175 175
                                   int addend);
176
static void update_refcount(BlockDriverState *bs,
176
static int update_refcount(BlockDriverState *bs,
177 177
                            int64_t offset, int64_t length,
178 178
                            int addend);
179 179
static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
......
2508 2508
    return -EIO;
2509 2509
}
2510 2510

  
2511
/* addend must be 1 or -1 */
2512
/* XXX: cache several refcount block clusters ? */
2513
static int update_cluster_refcount(BlockDriverState *bs,
2514
                                   int64_t cluster_index,
2515
                                   int addend)
2511

  
2512
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
2516 2513
{
2517 2514
    BDRVQcowState *s = bs->opaque;
2518 2515
    int64_t offset, refcount_block_offset;
2519
    int ret, refcount_table_index, block_index, refcount;
2516
    int ret, refcount_table_index;
2520 2517
    uint64_t data64;
2521 2518

  
2519
    /* Find L1 index and grow refcount table if needed */
2522 2520
    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
2523 2521
    if (refcount_table_index >= s->refcount_table_size) {
2524
        if (addend < 0)
2525
            return -EINVAL;
2526 2522
        ret = grow_refcount_table(bs, refcount_table_index + 1);
2527 2523
        if (ret < 0)
2528 2524
            return ret;
2529 2525
    }
2526

  
2527
    /* Load or allocate the refcount block */
2530 2528
    refcount_block_offset = s->refcount_table[refcount_table_index];
2531 2529
    if (!refcount_block_offset) {
2532
        if (addend < 0)
2533
            return -EINVAL;
2534 2530
        /* create a new refcount block */
2535 2531
        /* Note: we cannot update the refcount now to avoid recursion */
2536 2532
        offset = alloc_clusters_noref(bs, s->cluster_size);
......
2555 2551
                return -EIO;
2556 2552
        }
2557 2553
    }
2558
    /* we can update the count and save it */
2559
    block_index = cluster_index &
2560
        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
2561
    refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
2562
    refcount += addend;
2563
    if (refcount < 0 || refcount > 0xffff)
2564
        return -EINVAL;
2565
    if (refcount == 0 && cluster_index < s->free_cluster_index) {
2566
        s->free_cluster_index = cluster_index;
2554

  
2555
    return refcount_block_offset;
2556
}
2557

  
2558
/* addend must be 1 or -1 */
2559
static int update_cluster_refcount(BlockDriverState *bs,
2560
                                   int64_t cluster_index,
2561
                                   int addend)
2562
{
2563
    BDRVQcowState *s = bs->opaque;
2564
    int ret;
2565

  
2566
    ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
2567
    if (ret < 0) {
2568
        return ret;
2567 2569
    }
2568
    s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
2569
    if (bdrv_pwrite(s->hd,
2570
                    refcount_block_offset + (block_index << REFCOUNT_SHIFT),
2571
                    &s->refcount_block_cache[block_index], 2) != 2)
2572
        return -EIO;
2573
    return refcount;
2570

  
2571
    return get_refcount(bs, cluster_index);
2574 2572
}
2575 2573

  
2576
static void update_refcount(BlockDriverState *bs,
2574
/* XXX: cache several refcount block clusters ? */
2575
static int update_refcount(BlockDriverState *bs,
2577 2576
                            int64_t offset, int64_t length,
2578 2577
                            int addend)
2579 2578
{
......
2585 2584
           offset, length, addend);
2586 2585
#endif
2587 2586
    if (length <= 0)
2588
        return;
2587
        return -EINVAL;
2589 2588
    start = offset & ~(s->cluster_size - 1);
2590 2589
    last = (offset + length - 1) & ~(s->cluster_size - 1);
2591 2590
    for(cluster_offset = start; cluster_offset <= last;
2592
        cluster_offset += s->cluster_size) {
2593
        update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
2591
        cluster_offset += s->cluster_size)
2592
    {
2593
        int64_t refcount_block_offset;
2594
        int block_index, refcount;
2595
        int64_t cluster_index = cluster_offset >> s->cluster_bits;
2596

  
2597
        /* Load the refcount block and allocate it if needed */
2598
        refcount_block_offset = alloc_refcount_block(bs, cluster_index);
2599
        if (refcount_block_offset < 0) {
2600
            return refcount_block_offset;
2601
        }
2602

  
2603
        /* we can update the count and save it */
2604
        block_index = cluster_index &
2605
            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
2606
        refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
2607
        refcount += addend;
2608
        if (refcount < 0 || refcount > 0xffff)
2609
            return -EINVAL;
2610
        if (refcount == 0 && cluster_index < s->free_cluster_index) {
2611
            s->free_cluster_index = cluster_index;
2612
        }
2613
        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
2614
        if (bdrv_pwrite(s->hd,
2615
                        refcount_block_offset + (block_index << REFCOUNT_SHIFT),
2616
                        &s->refcount_block_cache[block_index], 2) != 2)
2617
            return -EIO;
2618

  
2594 2619
    }
2620
    return 0;
2595 2621
}
2596 2622

  
2597 2623
/*

Also available in: Unified diff