mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-31 12:07:31 +00:00 
			
		
		
		
	 54277a2aab
			
		
	
	
		54277a2aab
		
	
	
	
	
		
			
			qed_read_table and qed_write_table use coroutine-only interfaces but are not marked coroutine_fn. Happily, they are called only from coroutine context, so we only need to add missed markers. Reported-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
		
			
				
	
	
		
			195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * QEMU Enhanced Disk Format Table I/O
 | |
|  *
 | |
|  * Copyright IBM, Corp. 2010
 | |
|  *
 | |
|  * Authors:
 | |
|  *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | |
|  *  Anthony Liguori   <aliguori@us.ibm.com>
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | |
|  * See the COPYING.LIB file in the top-level directory.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "trace.h"
 | |
| #include "qemu/sockets.h" /* for EINPROGRESS on Windows */
 | |
| #include "qed.h"
 | |
| #include "qemu/bswap.h"
 | |
| 
 | |
| /* Called with table_lock held.  */
 | |
| static int coroutine_fn qed_read_table(BDRVQEDState *s, uint64_t offset,
 | |
|                                        QEDTable *table)
 | |
| {
 | |
|     unsigned int bytes = s->header.cluster_size * s->header.table_size;
 | |
| 
 | |
|     int noffsets;
 | |
|     int i, ret;
 | |
| 
 | |
|     trace_qed_read_table(s, offset, table);
 | |
| 
 | |
|     qemu_co_mutex_unlock(&s->table_lock);
 | |
|     ret = bdrv_co_pread(s->bs->file, offset, bytes, table->offsets, 0);
 | |
|     qemu_co_mutex_lock(&s->table_lock);
 | |
|     if (ret < 0) {
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     /* Byteswap offsets */
 | |
|     noffsets = bytes / sizeof(uint64_t);
 | |
|     for (i = 0; i < noffsets; i++) {
 | |
|         table->offsets[i] = le64_to_cpu(table->offsets[i]);
 | |
|     }
 | |
| 
 | |
|     ret = 0;
 | |
| out:
 | |
|     /* Completion */
 | |
|     trace_qed_read_table_cb(s, table, ret);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Write out an updated part or all of a table
 | |
|  *
 | |
|  * @s:          QED state
 | |
|  * @offset:     Offset of table in image file, in bytes
 | |
|  * @table:      Table
 | |
|  * @index:      Index of first element
 | |
|  * @n:          Number of elements
 | |
|  * @flush:      Whether or not to sync to disk
 | |
|  *
 | |
|  * Called with table_lock held.
 | |
|  */
 | |
| static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset,
 | |
|                                         QEDTable *table, unsigned int index,
 | |
|                                         unsigned int n, bool flush)
 | |
| {
 | |
|     unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
 | |
|     unsigned int start, end, i;
 | |
|     QEDTable *new_table;
 | |
|     size_t len_bytes;
 | |
|     int ret;
 | |
| 
 | |
|     trace_qed_write_table(s, offset, table, index, n);
 | |
| 
 | |
|     /* Calculate indices of the first and one after last elements */
 | |
|     start = index & ~sector_mask;
 | |
|     end = (index + n + sector_mask) & ~sector_mask;
 | |
| 
 | |
|     len_bytes = (end - start) * sizeof(uint64_t);
 | |
| 
 | |
|     new_table = qemu_blockalign(s->bs, len_bytes);
 | |
| 
 | |
|     /* Byteswap table */
 | |
|     for (i = start; i < end; i++) {
 | |
|         uint64_t le_offset = cpu_to_le64(table->offsets[i]);
 | |
|         new_table->offsets[i - start] = le_offset;
 | |
|     }
 | |
| 
 | |
|     /* Adjust for offset into table */
 | |
|     offset += start * sizeof(uint64_t);
 | |
| 
 | |
|     qemu_co_mutex_unlock(&s->table_lock);
 | |
|     ret = bdrv_co_pwrite(s->bs->file, offset, len_bytes, new_table->offsets, 0);
 | |
|     qemu_co_mutex_lock(&s->table_lock);
 | |
|     trace_qed_write_table_cb(s, table, flush, ret);
 | |
|     if (ret < 0) {
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     if (flush) {
 | |
|         ret = bdrv_flush(s->bs);
 | |
|         if (ret < 0) {
 | |
|             goto out;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ret = 0;
 | |
| out:
 | |
|     qemu_vfree(new_table);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s)
 | |
| {
 | |
|     return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
 | |
| }
 | |
| 
 | |
| /* Called with table_lock held.  */
 | |
| int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
 | |
|                                     unsigned int n)
 | |
| {
 | |
|     BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
 | |
|     return qed_write_table(s, s->header.l1_table_offset,
 | |
|                            s->l1_table, index, n, false);
 | |
| }
 | |
| 
 | |
| int coroutine_fn qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 | |
|                                          unsigned int n)
 | |
| {
 | |
|     return qed_write_l1_table(s, index, n);
 | |
| }
 | |
| 
 | |
| /* Called with table_lock held.  */
 | |
| int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
 | |
|                                    uint64_t offset)
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     qed_unref_l2_cache_entry(request->l2_table);
 | |
| 
 | |
|     /* Check for cached L2 entry */
 | |
|     request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
 | |
|     if (request->l2_table) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
 | |
|     request->l2_table->table = qed_alloc_table(s);
 | |
| 
 | |
|     BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
 | |
|     ret = qed_read_table(s, offset, request->l2_table->table);
 | |
| 
 | |
|     if (ret) {
 | |
|         /* can't trust loaded L2 table anymore */
 | |
|         qed_unref_l2_cache_entry(request->l2_table);
 | |
|         request->l2_table = NULL;
 | |
|     } else {
 | |
|         request->l2_table->offset = offset;
 | |
| 
 | |
|         qed_commit_l2_cache_entry(&s->l2_cache, request->l2_table);
 | |
| 
 | |
|         /* This is guaranteed to succeed because we just committed the entry
 | |
|          * to the cache.
 | |
|          */
 | |
|         request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
 | |
|         assert(request->l2_table != NULL);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 | |
|                                         uint64_t offset)
 | |
| {
 | |
|     return qed_read_l2_table(s, request, offset);
 | |
| }
 | |
| 
 | |
| /* Called with table_lock held.  */
 | |
| int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
 | |
|                                     unsigned int index, unsigned int n,
 | |
|                                     bool flush)
 | |
| {
 | |
|     BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
 | |
|     return qed_write_table(s, request->l2_table->offset,
 | |
|                            request->l2_table->table, index, n, flush);
 | |
| }
 | |
| 
 | |
| int coroutine_fn qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 | |
|                                          unsigned int index, unsigned int n,
 | |
|                                          bool flush)
 | |
| {
 | |
|     return qed_write_l2_table(s, request, index, n, flush);
 | |
| }
 |