Revision 09508d13
b/block/qcow2-refcount.c | ||
---|---|---|
278 | 278 |
int64_t refcount_block_offset = 0; |
279 | 279 |
int64_t table_index = -1, old_table_index; |
280 | 280 |
int first_index = -1, last_index = -1; |
281 |
int ret; |
|
281 | 282 |
|
282 | 283 |
#ifdef DEBUG_ALLOC2 |
283 | 284 |
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n", |
... | ... | |
292 | 293 |
{ |
293 | 294 |
int block_index, refcount; |
294 | 295 |
int64_t cluster_index = cluster_offset >> s->cluster_bits; |
296 |
int64_t new_block; |
|
295 | 297 |
|
296 | 298 |
/* Only write refcount block to disk when we are done with it */ |
297 | 299 |
old_table_index = table_index; |
... | ... | |
309 | 311 |
} |
310 | 312 |
|
311 | 313 |
/* Load the refcount block and allocate it if needed */ |
312 |
refcount_block_offset = alloc_refcount_block(bs, cluster_index); |
|
313 |
if (refcount_block_offset < 0) { |
|
314 |
return refcount_block_offset; |
|
314 |
new_block = alloc_refcount_block(bs, cluster_index); |
|
315 |
if (new_block < 0) { |
|
316 |
ret = new_block; |
|
317 |
goto fail; |
|
315 | 318 |
} |
319 |
refcount_block_offset = new_block; |
|
316 | 320 |
|
317 | 321 |
/* we can update the count and save it */ |
318 | 322 |
block_index = cluster_index & |
... | ... | |
326 | 330 |
|
327 | 331 |
refcount = be16_to_cpu(s->refcount_block_cache[block_index]); |
328 | 332 |
refcount += addend; |
329 |
if (refcount < 0 || refcount > 0xffff) |
|
330 |
return -EINVAL; |
|
333 |
if (refcount < 0 || refcount > 0xffff) { |
|
334 |
ret = -EINVAL; |
|
335 |
goto fail; |
|
336 |
} |
|
331 | 337 |
if (refcount == 0 && cluster_index < s->free_cluster_index) { |
332 | 338 |
s->free_cluster_index = cluster_index; |
333 | 339 |
} |
334 | 340 |
s->refcount_block_cache[block_index] = cpu_to_be16(refcount); |
335 | 341 |
} |
336 | 342 |
|
343 |
ret = 0; |
|
344 |
fail: |
|
345 |
|
|
337 | 346 |
/* Write last changed block to disk */ |
338 | 347 |
if (refcount_block_offset != 0) { |
339 | 348 |
if (write_refcount_block_entries(s, refcount_block_offset, |
340 | 349 |
first_index, last_index) < 0) |
341 | 350 |
{ |
342 |
return -EIO; |
|
351 |
return ret < 0 ? ret : -EIO;
|
|
343 | 352 |
} |
344 | 353 |
} |
345 | 354 |
|
346 |
return 0; |
|
355 |
/* |
|
356 |
* Try do undo any updates if an error is returned (This may succeed in |
|
357 |
* some cases like ENOSPC for allocating a new refcount block) |
|
358 |
*/ |
|
359 |
if (ret < 0) { |
|
360 |
int dummy; |
|
361 |
dummy = update_refcount(bs, offset, cluster_offset - offset, -addend); |
|
362 |
} |
|
363 |
|
|
364 |
return ret; |
|
347 | 365 |
} |
348 | 366 |
|
349 | 367 |
/* addend must be 1 or -1 */ |
Also available in: Unified diff