qcow2: Employ metadata overlap checks
The pre-write overlap check function is now called before most of the qcow2 writes (aborting it on collision or other error). Signed-off-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
		
							parent
							
								
									a40f1c2add
								
							
						
					
					
						commit
						cf93980e77
					
				| @ -114,6 +114,23 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     if (c == s->refcount_block_cache) { | ||||
|         ret = qcow2_pre_write_overlap_check(bs, | ||||
|                 QCOW2_OL_DEFAULT & ~QCOW2_OL_REFCOUNT_BLOCK, | ||||
|                 c->entries[i].offset, s->cluster_size); | ||||
|     } else if (c == s->l2_table_cache) { | ||||
|         ret = qcow2_pre_write_overlap_check(bs, | ||||
|                 QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L2, | ||||
|                 c->entries[i].offset, s->cluster_size); | ||||
|     } else { | ||||
|         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|                 c->entries[i].offset, s->cluster_size); | ||||
|     } | ||||
| 
 | ||||
|     if (ret < 0) { | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     if (c == s->refcount_block_cache) { | ||||
|         BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART); | ||||
|     } else if (c == s->l2_table_cache) { | ||||
|  | ||||
| @ -80,6 +80,14 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     /* the L1 position has not yet been updated, so these clusters must
 | ||||
|      * indeed be completely free */ | ||||
|     ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|                                         new_l1_table_offset, new_l1_size2); | ||||
|     if (ret < 0) { | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE); | ||||
|     for(i = 0; i < s->l1_size; i++) | ||||
|         new_l1_table[i] = cpu_to_be64(new_l1_table[i]); | ||||
| @ -149,6 +157,13 @@ static int write_l1_entry(BlockDriverState *bs, int l1_index) | ||||
|         buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]); | ||||
|     } | ||||
| 
 | ||||
|     ret = qcow2_pre_write_overlap_check(bs, | ||||
|             QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L1, | ||||
|             s->l1_table_offset + 8 * l1_start_index, sizeof(buf)); | ||||
|     if (ret < 0) { | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); | ||||
|     ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index, | ||||
|         buf, sizeof(buf)); | ||||
| @ -368,6 +383,12 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs, | ||||
|                         &s->aes_encrypt_key); | ||||
|     } | ||||
| 
 | ||||
|     ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|             cluster_offset + n_start * BDRV_SECTOR_SIZE, n * BDRV_SECTOR_SIZE); | ||||
|     if (ret < 0) { | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|     BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); | ||||
|     ret = bdrv_co_writev(bs->file, (cluster_offset >> 9) + n_start, n, &qiov); | ||||
|     if (ret < 0) { | ||||
|  | ||||
| @ -189,6 +189,15 @@ static int qcow2_write_snapshots(BlockDriverState *bs) | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     /* The snapshot list position has not yet been updated, so these clusters
 | ||||
|      * must indeed be completely free */ | ||||
|     ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, offset, | ||||
|                                         s->snapshots_size); | ||||
|     if (ret < 0) { | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /* Write all snapshots to the new list */ | ||||
|     for(i = 0; i < s->nb_snapshots; i++) { | ||||
|         sn = s->snapshots + i; | ||||
| @ -363,6 +372,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||
|         l1_table[i] = cpu_to_be64(s->l1_table[i]); | ||||
|     } | ||||
| 
 | ||||
|     ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|             sn->l1_table_offset, s->l1_size * sizeof(uint64_t)); | ||||
|     if (ret < 0) { | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table, | ||||
|                       s->l1_size * sizeof(uint64_t)); | ||||
|     if (ret < 0) { | ||||
| @ -475,6 +490,13 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     ret = qcow2_pre_write_overlap_check(bs, | ||||
|             QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L1, | ||||
|             s->l1_table_offset, cur_l1_bytes); | ||||
|     if (ret < 0) { | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table, | ||||
|                            cur_l1_bytes); | ||||
|     if (ret < 0) { | ||||
|  | ||||
| @ -624,6 +624,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) | ||||
|     qcow2_free_snapshots(bs); | ||||
|     qcow2_refcount_close(bs); | ||||
|     g_free(s->l1_table); | ||||
|     /* else pre-write overlap checks in cache_destroy may crash */ | ||||
|     s->l1_table = NULL; | ||||
|     if (s->l2_table_cache) { | ||||
|         qcow2_cache_destroy(bs, s->l2_table_cache); | ||||
|     } | ||||
| @ -923,6 +925,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, | ||||
|                 cur_nr_sectors * 512); | ||||
|         } | ||||
| 
 | ||||
|         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|                 cluster_offset + index_in_cluster * BDRV_SECTOR_SIZE, | ||||
|                 cur_nr_sectors * BDRV_SECTOR_SIZE); | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
| 
 | ||||
|         qemu_co_mutex_unlock(&s->lock); | ||||
|         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); | ||||
|         trace_qcow2_writev_data(qemu_coroutine_self(), | ||||
| @ -989,6 +998,8 @@ static void qcow2_close(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVQcowState *s = bs->opaque; | ||||
|     g_free(s->l1_table); | ||||
|     /* else pre-write overlap checks in cache_destroy may crash */ | ||||
|     s->l1_table = NULL; | ||||
| 
 | ||||
|     qcow2_cache_flush(bs, s->l2_table_cache); | ||||
|     qcow2_cache_flush(bs, s->refcount_block_cache); | ||||
| @ -1668,6 +1679,14 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, | ||||
| 
 | ||||
|     if (ret != Z_STREAM_END || out_len >= s->cluster_size) { | ||||
|         /* could not compress: write normal cluster */ | ||||
| 
 | ||||
|         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|                 sector_num * BDRV_SECTOR_SIZE, | ||||
|                 s->cluster_sectors * BDRV_SECTOR_SIZE); | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
| 
 | ||||
|         ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors); | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
| @ -1680,6 +1699,13 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num, | ||||
|             goto fail; | ||||
|         } | ||||
|         cluster_offset &= s->cluster_offset_mask; | ||||
| 
 | ||||
|         ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, | ||||
|                 cluster_offset, out_len); | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
| 
 | ||||
|         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); | ||||
|         ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len); | ||||
|         if (ret < 0) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Max Reitz
						Max Reitz