|
|
1.1 root 1: /*
2: * QEMU Enhanced Disk Format Table I/O
3: *
4: * Copyright IBM, Corp. 2010
5: *
6: * Authors:
7: * Stefan Hajnoczi <[email protected]>
8: * Anthony Liguori <[email protected]>
9: *
10: * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11: * See the COPYING.LIB file in the top-level directory.
12: *
13: */
14:
15: #include "trace.h"
16: #include "qemu_socket.h" /* for EINPROGRESS on Windows */
17: #include "qed.h"
18:
19: typedef struct {
20: GenericCB gencb;
21: BDRVQEDState *s;
22: QEDTable *table;
23:
24: struct iovec iov;
25: QEMUIOVector qiov;
26: } QEDReadTableCB;
27:
28: static void qed_read_table_cb(void *opaque, int ret)
29: {
30: QEDReadTableCB *read_table_cb = opaque;
31: QEDTable *table = read_table_cb->table;
1.1.1.4 ! root 32: int noffsets = read_table_cb->qiov.size / sizeof(uint64_t);
1.1 root 33: int i;
34:
35: /* Handle I/O error */
36: if (ret) {
37: goto out;
38: }
39:
40: /* Byteswap offsets */
41: for (i = 0; i < noffsets; i++) {
42: table->offsets[i] = le64_to_cpu(table->offsets[i]);
43: }
44:
45: out:
46: /* Completion */
47: trace_qed_read_table_cb(read_table_cb->s, read_table_cb->table, ret);
48: gencb_complete(&read_table_cb->gencb, ret);
49: }
50:
51: static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
52: BlockDriverCompletionFunc *cb, void *opaque)
53: {
54: QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
55: cb, opaque);
56: QEMUIOVector *qiov = &read_table_cb->qiov;
57:
58: trace_qed_read_table(s, offset, table);
59:
60: read_table_cb->s = s;
61: read_table_cb->table = table;
62: read_table_cb->iov.iov_base = table->offsets,
63: read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
64:
65: qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
1.1.1.4 ! root 66: bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
! 67: qiov->size / BDRV_SECTOR_SIZE,
! 68: qed_read_table_cb, read_table_cb);
1.1 root 69: }
70:
71: typedef struct {
72: GenericCB gencb;
73: BDRVQEDState *s;
74: QEDTable *orig_table;
75: QEDTable *table;
76: bool flush; /* flush after write? */
77:
78: struct iovec iov;
79: QEMUIOVector qiov;
80: } QEDWriteTableCB;
81:
82: static void qed_write_table_cb(void *opaque, int ret)
83: {
84: QEDWriteTableCB *write_table_cb = opaque;
85:
86: trace_qed_write_table_cb(write_table_cb->s,
87: write_table_cb->orig_table,
88: write_table_cb->flush,
89: ret);
90:
91: if (ret) {
92: goto out;
93: }
94:
95: if (write_table_cb->flush) {
96: /* We still need to flush first */
97: write_table_cb->flush = false;
98: bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb,
99: write_table_cb);
100: return;
101: }
102:
103: out:
104: qemu_vfree(write_table_cb->table);
105: gencb_complete(&write_table_cb->gencb, ret);
106: return;
107: }
108:
109: /**
110: * Write out an updated part or all of a table
111: *
112: * @s: QED state
113: * @offset: Offset of table in image file, in bytes
114: * @table: Table
115: * @index: Index of first element
116: * @n: Number of elements
117: * @flush: Whether or not to sync to disk
118: * @cb: Completion function
119: * @opaque: Argument for completion function
120: */
121: static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
122: unsigned int index, unsigned int n, bool flush,
123: BlockDriverCompletionFunc *cb, void *opaque)
124: {
125: QEDWriteTableCB *write_table_cb;
126: unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
127: unsigned int start, end, i;
128: size_t len_bytes;
129:
130: trace_qed_write_table(s, offset, table, index, n);
131:
132: /* Calculate indices of the first and one after last elements */
133: start = index & ~sector_mask;
134: end = (index + n + sector_mask) & ~sector_mask;
135:
136: len_bytes = (end - start) * sizeof(uint64_t);
137:
138: write_table_cb = gencb_alloc(sizeof(*write_table_cb), cb, opaque);
139: write_table_cb->s = s;
140: write_table_cb->orig_table = table;
141: write_table_cb->flush = flush;
142: write_table_cb->table = qemu_blockalign(s->bs, len_bytes);
143: write_table_cb->iov.iov_base = write_table_cb->table->offsets;
144: write_table_cb->iov.iov_len = len_bytes;
145: qemu_iovec_init_external(&write_table_cb->qiov, &write_table_cb->iov, 1);
146:
147: /* Byteswap table */
148: for (i = start; i < end; i++) {
149: uint64_t le_offset = cpu_to_le64(table->offsets[i]);
150: write_table_cb->table->offsets[i - start] = le_offset;
151: }
152:
153: /* Adjust for offset into table */
154: offset += start * sizeof(uint64_t);
155:
1.1.1.4 ! root 156: bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
! 157: &write_table_cb->qiov,
! 158: write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
! 159: qed_write_table_cb, write_table_cb);
1.1 root 160: }
161:
162: /**
163: * Propagate return value from async callback
164: */
165: static void qed_sync_cb(void *opaque, int ret)
166: {
167: *(int *)opaque = ret;
168: }
169:
170: int qed_read_l1_table_sync(BDRVQEDState *s)
171: {
172: int ret = -EINPROGRESS;
173:
174: qed_read_table(s, s->header.l1_table_offset,
175: s->l1_table, qed_sync_cb, &ret);
176: while (ret == -EINPROGRESS) {
177: qemu_aio_wait();
178: }
179:
180: return ret;
181: }
182:
183: void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
184: BlockDriverCompletionFunc *cb, void *opaque)
185: {
186: BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
187: qed_write_table(s, s->header.l1_table_offset,
188: s->l1_table, index, n, false, cb, opaque);
189: }
190:
191: int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
192: unsigned int n)
193: {
194: int ret = -EINPROGRESS;
195:
196: qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
197: while (ret == -EINPROGRESS) {
198: qemu_aio_wait();
199: }
200:
201: return ret;
202: }
203:
204: typedef struct {
205: GenericCB gencb;
206: BDRVQEDState *s;
207: uint64_t l2_offset;
208: QEDRequest *request;
209: } QEDReadL2TableCB;
210:
211: static void qed_read_l2_table_cb(void *opaque, int ret)
212: {
213: QEDReadL2TableCB *read_l2_table_cb = opaque;
214: QEDRequest *request = read_l2_table_cb->request;
215: BDRVQEDState *s = read_l2_table_cb->s;
216: CachedL2Table *l2_table = request->l2_table;
1.1.1.2 root 217: uint64_t l2_offset = read_l2_table_cb->l2_offset;
1.1 root 218:
219: if (ret) {
220: /* can't trust loaded L2 table anymore */
221: qed_unref_l2_cache_entry(l2_table);
222: request->l2_table = NULL;
223: } else {
1.1.1.2 root 224: l2_table->offset = l2_offset;
1.1 root 225:
226: qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
227:
228: /* This is guaranteed to succeed because we just committed the entry
229: * to the cache.
230: */
1.1.1.2 root 231: request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
1.1 root 232: assert(request->l2_table != NULL);
233: }
234:
235: gencb_complete(&read_l2_table_cb->gencb, ret);
236: }
237:
238: void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
239: BlockDriverCompletionFunc *cb, void *opaque)
240: {
241: QEDReadL2TableCB *read_l2_table_cb;
242:
243: qed_unref_l2_cache_entry(request->l2_table);
244:
245: /* Check for cached L2 entry */
246: request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
247: if (request->l2_table) {
248: cb(opaque, 0);
249: return;
250: }
251:
252: request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
253: request->l2_table->table = qed_alloc_table(s);
254:
255: read_l2_table_cb = gencb_alloc(sizeof(*read_l2_table_cb), cb, opaque);
256: read_l2_table_cb->s = s;
257: read_l2_table_cb->l2_offset = offset;
258: read_l2_table_cb->request = request;
259:
260: BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
261: qed_read_table(s, offset, request->l2_table->table,
262: qed_read_l2_table_cb, read_l2_table_cb);
263: }
264:
265: int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
266: {
267: int ret = -EINPROGRESS;
268:
269: qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
270: while (ret == -EINPROGRESS) {
271: qemu_aio_wait();
272: }
273:
274: return ret;
275: }
276:
277: void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
278: unsigned int index, unsigned int n, bool flush,
279: BlockDriverCompletionFunc *cb, void *opaque)
280: {
281: BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
282: qed_write_table(s, request->l2_table->offset,
283: request->l2_table->table, index, n, flush, cb, opaque);
284: }
285:
286: int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
287: unsigned int index, unsigned int n, bool flush)
288: {
289: int ret = -EINPROGRESS;
290:
291: qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
292: while (ret == -EINPROGRESS) {
293: qemu_aio_wait();
294: }
295:
296: return ret;
297: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.