xref: /qemu/block/qed-table.c (revision 17362398)
1298800caSStefan Hajnoczi /*
2298800caSStefan Hajnoczi  * QEMU Enhanced Disk Format Table I/O
3298800caSStefan Hajnoczi  *
4298800caSStefan Hajnoczi  * Copyright IBM, Corp. 2010
5298800caSStefan Hajnoczi  *
6298800caSStefan Hajnoczi  * Authors:
7298800caSStefan Hajnoczi  *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
8298800caSStefan Hajnoczi  *  Anthony Liguori   <aliguori@us.ibm.com>
9298800caSStefan Hajnoczi  *
10298800caSStefan Hajnoczi  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11298800caSStefan Hajnoczi  * See the COPYING.LIB file in the top-level directory.
12298800caSStefan Hajnoczi  *
13298800caSStefan Hajnoczi  */
14298800caSStefan Hajnoczi 
1580c71a24SPeter Maydell #include "qemu/osdep.h"
16e2c1c34fSMarkus Armbruster #include "block/block-io.h"
17298800caSStefan Hajnoczi #include "trace.h"
181de7afc9SPaolo Bonzini #include "qemu/sockets.h" /* for EINPROGRESS on Windows */
19298800caSStefan Hajnoczi #include "qed.h"
2058369e22SPaolo Bonzini #include "qemu/bswap.h"
215df022cfSPeter Maydell #include "qemu/memalign.h"
22298800caSStefan Hajnoczi 
232fd61638SPaolo Bonzini /* Called with table_lock held.  */
24b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK
qed_read_table(BDRVQEDState * s,uint64_t offset,QEDTable * table)25b9b10c35SKevin Wolf qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
26298800caSStefan Hajnoczi {
27696e8cb2SVladimir Sementsov-Ogievskiy     unsigned int bytes = s->header.cluster_size * s->header.table_size;
28696e8cb2SVladimir Sementsov-Ogievskiy 
2911273076SKevin Wolf     int noffsets;
3011273076SKevin Wolf     int i, ret;
31298800caSStefan Hajnoczi 
3211273076SKevin Wolf     trace_qed_read_table(s, offset, table);
3311273076SKevin Wolf 
341f01e50bSPaolo Bonzini     qemu_co_mutex_unlock(&s->table_lock);
35696e8cb2SVladimir Sementsov-Ogievskiy     ret = bdrv_co_pread(s->bs->file, offset, bytes, table->offsets, 0);
361f01e50bSPaolo Bonzini     qemu_co_mutex_lock(&s->table_lock);
3711273076SKevin Wolf     if (ret < 0) {
38298800caSStefan Hajnoczi         goto out;
39298800caSStefan Hajnoczi     }
40298800caSStefan Hajnoczi 
41298800caSStefan Hajnoczi     /* Byteswap offsets */
42696e8cb2SVladimir Sementsov-Ogievskiy     noffsets = bytes / sizeof(uint64_t);
43298800caSStefan Hajnoczi     for (i = 0; i < noffsets; i++) {
44298800caSStefan Hajnoczi         table->offsets[i] = le64_to_cpu(table->offsets[i]);
45298800caSStefan Hajnoczi     }
46298800caSStefan Hajnoczi 
4711273076SKevin Wolf     ret = 0;
48298800caSStefan Hajnoczi out:
49298800caSStefan Hajnoczi     /* Completion */
5011273076SKevin Wolf     trace_qed_read_table_cb(s, table, ret);
51f6513529SKevin Wolf     return ret;
52298800caSStefan Hajnoczi }
53298800caSStefan Hajnoczi 
54298800caSStefan Hajnoczi /**
55298800caSStefan Hajnoczi  * Write out an updated part or all of a table
56298800caSStefan Hajnoczi  *
57298800caSStefan Hajnoczi  * @s:          QED state
58298800caSStefan Hajnoczi  * @offset:     Offset of table in image file, in bytes
59298800caSStefan Hajnoczi  * @table:      Table
60298800caSStefan Hajnoczi  * @index:      Index of first element
61298800caSStefan Hajnoczi  * @n:          Number of elements
62298800caSStefan Hajnoczi  * @flush:      Whether or not to sync to disk
631f01e50bSPaolo Bonzini  *
642fd61638SPaolo Bonzini  * Called with table_lock held.
65298800caSStefan Hajnoczi  */
6688095349SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK
qed_write_table(BDRVQEDState * s,uint64_t offset,QEDTable * table,unsigned int index,unsigned int n,bool flush)6788095349SEmanuele Giuseppe Esposito qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
6888095349SEmanuele Giuseppe Esposito                 unsigned int index, unsigned int n, bool flush)
69298800caSStefan Hajnoczi {
70298800caSStefan Hajnoczi     unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
71298800caSStefan Hajnoczi     unsigned int start, end, i;
72602b57fbSKevin Wolf     QEDTable *new_table;
73298800caSStefan Hajnoczi     size_t len_bytes;
74602b57fbSKevin Wolf     int ret;
75298800caSStefan Hajnoczi 
76298800caSStefan Hajnoczi     trace_qed_write_table(s, offset, table, index, n);
77298800caSStefan Hajnoczi 
78298800caSStefan Hajnoczi     /* Calculate indices of the first and one after last elements */
79298800caSStefan Hajnoczi     start = index & ~sector_mask;
80298800caSStefan Hajnoczi     end = (index + n + sector_mask) & ~sector_mask;
81298800caSStefan Hajnoczi 
82298800caSStefan Hajnoczi     len_bytes = (end - start) * sizeof(uint64_t);
83298800caSStefan Hajnoczi 
84602b57fbSKevin Wolf     new_table = qemu_blockalign(s->bs, len_bytes);
85298800caSStefan Hajnoczi 
86298800caSStefan Hajnoczi     /* Byteswap table */
87298800caSStefan Hajnoczi     for (i = start; i < end; i++) {
88298800caSStefan Hajnoczi         uint64_t le_offset = cpu_to_le64(table->offsets[i]);
89602b57fbSKevin Wolf         new_table->offsets[i - start] = le_offset;
90298800caSStefan Hajnoczi     }
91298800caSStefan Hajnoczi 
92298800caSStefan Hajnoczi     /* Adjust for offset into table */
93298800caSStefan Hajnoczi     offset += start * sizeof(uint64_t);
94298800caSStefan Hajnoczi 
951f01e50bSPaolo Bonzini     qemu_co_mutex_unlock(&s->table_lock);
96696e8cb2SVladimir Sementsov-Ogievskiy     ret = bdrv_co_pwrite(s->bs->file, offset, len_bytes, new_table->offsets, 0);
971f01e50bSPaolo Bonzini     qemu_co_mutex_lock(&s->table_lock);
98602b57fbSKevin Wolf     trace_qed_write_table_cb(s, table, flush, ret);
99602b57fbSKevin Wolf     if (ret < 0) {
100602b57fbSKevin Wolf         goto out;
101602b57fbSKevin Wolf     }
102602b57fbSKevin Wolf 
103602b57fbSKevin Wolf     if (flush) {
1043aba34adSAlberto Faria         ret = bdrv_co_flush(s->bs);
105602b57fbSKevin Wolf         if (ret < 0) {
106602b57fbSKevin Wolf             goto out;
107602b57fbSKevin Wolf         }
108602b57fbSKevin Wolf     }
109602b57fbSKevin Wolf 
110602b57fbSKevin Wolf     ret = 0;
111602b57fbSKevin Wolf out:
112602b57fbSKevin Wolf     qemu_vfree(new_table);
113453e53e2SKevin Wolf     return ret;
114298800caSStefan Hajnoczi }
115298800caSStefan Hajnoczi 
qed_read_l1_table_sync(BDRVQEDState * s)11654277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s)
117298800caSStefan Hajnoczi {
118f6513529SKevin Wolf     return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
119298800caSStefan Hajnoczi }
120298800caSStefan Hajnoczi 
1212fd61638SPaolo Bonzini /* Called with table_lock held.  */
qed_write_l1_table(BDRVQEDState * s,unsigned int index,unsigned int n)12254277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
12354277a2aSVladimir Sementsov-Ogievskiy                                     unsigned int n)
124298800caSStefan Hajnoczi {
12517362398SPaolo Bonzini     BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
126453e53e2SKevin Wolf     return qed_write_table(s, s->header.l1_table_offset,
127453e53e2SKevin Wolf                            s->l1_table, index, n, false);
128298800caSStefan Hajnoczi }
129298800caSStefan Hajnoczi 
qed_write_l1_table_sync(BDRVQEDState * s,unsigned int index,unsigned int n)13054277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
131298800caSStefan Hajnoczi                                          unsigned int n)
132298800caSStefan Hajnoczi {
133453e53e2SKevin Wolf     return qed_write_l1_table(s, index, n);
134298800caSStefan Hajnoczi }
135298800caSStefan Hajnoczi 
1362fd61638SPaolo Bonzini /* Called with table_lock held.  */
qed_read_l2_table(BDRVQEDState * s,QEDRequest * request,uint64_t offset)13754277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
13854277a2aSVladimir Sementsov-Ogievskiy                                    uint64_t offset)
139298800caSStefan Hajnoczi {
140f6513529SKevin Wolf     int ret;
141298800caSStefan Hajnoczi 
142298800caSStefan Hajnoczi     qed_unref_l2_cache_entry(request->l2_table);
143298800caSStefan Hajnoczi 
144298800caSStefan Hajnoczi     /* Check for cached L2 entry */
145298800caSStefan Hajnoczi     request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
146298800caSStefan Hajnoczi     if (request->l2_table) {
147a8165d2dSKevin Wolf         return 0;
148298800caSStefan Hajnoczi     }
149298800caSStefan Hajnoczi 
150298800caSStefan Hajnoczi     request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
151298800caSStefan Hajnoczi     request->l2_table->table = qed_alloc_table(s);
152298800caSStefan Hajnoczi 
15317362398SPaolo Bonzini     BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_LOAD);
154f6513529SKevin Wolf     ret = qed_read_table(s, offset, request->l2_table->table);
155f6513529SKevin Wolf 
156f6513529SKevin Wolf     if (ret) {
157f6513529SKevin Wolf         /* can't trust loaded L2 table anymore */
158f6513529SKevin Wolf         qed_unref_l2_cache_entry(request->l2_table);
159f6513529SKevin Wolf         request->l2_table = NULL;
160f6513529SKevin Wolf     } else {
161f6513529SKevin Wolf         request->l2_table->offset = offset;
162f6513529SKevin Wolf 
163f6513529SKevin Wolf         qed_commit_l2_cache_entry(&s->l2_cache, request->l2_table);
164f6513529SKevin Wolf 
165f6513529SKevin Wolf         /* This is guaranteed to succeed because we just committed the entry
166f6513529SKevin Wolf          * to the cache.
167f6513529SKevin Wolf          */
168f6513529SKevin Wolf         request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
169f6513529SKevin Wolf         assert(request->l2_table != NULL);
170f6513529SKevin Wolf     }
171f6513529SKevin Wolf 
172a8165d2dSKevin Wolf     return ret;
173298800caSStefan Hajnoczi }
174298800caSStefan Hajnoczi 
qed_read_l2_table_sync(BDRVQEDState * s,QEDRequest * request,uint64_t offset)17554277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
17654277a2aSVladimir Sementsov-Ogievskiy                                         uint64_t offset)
177298800caSStefan Hajnoczi {
178a8165d2dSKevin Wolf     return qed_read_l2_table(s, request, offset);
179298800caSStefan Hajnoczi }
180298800caSStefan Hajnoczi 
1812fd61638SPaolo Bonzini /* Called with table_lock held.  */
qed_write_l2_table(BDRVQEDState * s,QEDRequest * request,unsigned int index,unsigned int n,bool flush)18254277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
18354277a2aSVladimir Sementsov-Ogievskiy                                     unsigned int index, unsigned int n,
18454277a2aSVladimir Sementsov-Ogievskiy                                     bool flush)
185298800caSStefan Hajnoczi {
18617362398SPaolo Bonzini     BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
187453e53e2SKevin Wolf     return qed_write_table(s, request->l2_table->offset,
188453e53e2SKevin Wolf                            request->l2_table->table, index, n, flush);
189298800caSStefan Hajnoczi }
190298800caSStefan Hajnoczi 
qed_write_l2_table_sync(BDRVQEDState * s,QEDRequest * request,unsigned int index,unsigned int n,bool flush)19154277a2aSVladimir Sementsov-Ogievskiy int coroutine_fn qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
19254277a2aSVladimir Sementsov-Ogievskiy                                          unsigned int index, unsigned int n,
19354277a2aSVladimir Sementsov-Ogievskiy                                          bool flush)
194298800caSStefan Hajnoczi {
195453e53e2SKevin Wolf     return qed_write_l2_table(s, request, index, n, flush);
196298800caSStefan Hajnoczi }
197