- cluster_offset += s->cluster_size) {
- update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
+ cluster_offset += s->cluster_size)
+ {
+ int64_t refcount_block_offset;
+ int block_index, refcount;
+ int64_t cluster_index = cluster_offset >> s->cluster_bits;
+
+ /* Load the refcount block and allocate it if needed */
+ refcount_block_offset = alloc_refcount_block(bs, cluster_index);
+ if (refcount_block_offset < 0) {
+ return refcount_block_offset;
+ }
+
+ /* we can update the count and save it */
+ block_index = cluster_index &
+ ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+ refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+ refcount += addend;
+ if (refcount < 0 || refcount > 0xffff)
+ return -EINVAL;
+ if (refcount == 0 && cluster_index < s->free_cluster_index) {
+ s->free_cluster_index = cluster_index;
+ }
+ s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+ if (bdrv_pwrite(s->hd,
+ refcount_block_offset + (block_index << REFCOUNT_SHIFT),
+ &s->refcount_block_cache[block_index], 2) != 2)
+ return -EIO;
+