|
|
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; ! 32: int noffsets = read_table_cb->iov.iov_len / sizeof(uint64_t); ! 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: BlockDriverAIOCB *aiocb; ! 58: ! 59: trace_qed_read_table(s, offset, table); ! 60: ! 61: read_table_cb->s = s; ! 62: read_table_cb->table = table; ! 63: read_table_cb->iov.iov_base = table->offsets, ! 64: read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size, ! 65: ! 66: qemu_iovec_init_external(qiov, &read_table_cb->iov, 1); ! 67: aiocb = bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov, ! 68: read_table_cb->iov.iov_len / BDRV_SECTOR_SIZE, ! 69: qed_read_table_cb, read_table_cb); ! 70: if (!aiocb) { ! 71: qed_read_table_cb(read_table_cb, -EIO); ! 72: } ! 73: } ! 74: ! 75: typedef struct { ! 76: GenericCB gencb; ! 77: BDRVQEDState *s; ! 78: QEDTable *orig_table; ! 79: QEDTable *table; ! 80: bool flush; /* flush after write? */ ! 81: ! 82: struct iovec iov; ! 83: QEMUIOVector qiov; ! 84: } QEDWriteTableCB; ! 85: ! 86: static void qed_write_table_cb(void *opaque, int ret) ! 87: { ! 88: QEDWriteTableCB *write_table_cb = opaque; ! 89: ! 90: trace_qed_write_table_cb(write_table_cb->s, ! 91: write_table_cb->orig_table, ! 92: write_table_cb->flush, ! 93: ret); ! 94: ! 95: if (ret) { ! 96: goto out; ! 97: } ! 98: ! 99: if (write_table_cb->flush) { ! 100: /* We still need to flush first */ ! 101: write_table_cb->flush = false; ! 102: bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb, ! 103: write_table_cb); ! 104: return; ! 105: } ! 106: ! 107: out: ! 108: qemu_vfree(write_table_cb->table); ! 109: gencb_complete(&write_table_cb->gencb, ret); ! 110: return; ! 111: } ! 112: ! 113: /** ! 114: * Write out an updated part or all of a table ! 115: * ! 116: * @s: QED state ! 117: * @offset: Offset of table in image file, in bytes ! 118: * @table: Table ! 119: * @index: Index of first element ! 120: * @n: Number of elements ! 121: * @flush: Whether or not to sync to disk ! 122: * @cb: Completion function ! 123: * @opaque: Argument for completion function ! 124: */ ! 125: static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, ! 126: unsigned int index, unsigned int n, bool flush, ! 127: BlockDriverCompletionFunc *cb, void *opaque) ! 128: { ! 129: QEDWriteTableCB *write_table_cb; ! 130: BlockDriverAIOCB *aiocb; ! 131: unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1; ! 132: unsigned int start, end, i; ! 133: size_t len_bytes; ! 134: ! 135: trace_qed_write_table(s, offset, table, index, n); ! 136: ! 137: /* Calculate indices of the first and one after last elements */ ! 138: start = index & ~sector_mask; ! 139: end = (index + n + sector_mask) & ~sector_mask; ! 140: ! 141: len_bytes = (end - start) * sizeof(uint64_t); ! 142: ! 143: write_table_cb = gencb_alloc(sizeof(*write_table_cb), cb, opaque); ! 144: write_table_cb->s = s; ! 145: write_table_cb->orig_table = table; ! 146: write_table_cb->flush = flush; ! 147: write_table_cb->table = qemu_blockalign(s->bs, len_bytes); ! 148: write_table_cb->iov.iov_base = write_table_cb->table->offsets; ! 149: write_table_cb->iov.iov_len = len_bytes; ! 150: qemu_iovec_init_external(&write_table_cb->qiov, &write_table_cb->iov, 1); ! 151: ! 152: /* Byteswap table */ ! 153: for (i = start; i < end; i++) { ! 154: uint64_t le_offset = cpu_to_le64(table->offsets[i]); ! 155: write_table_cb->table->offsets[i - start] = le_offset; ! 156: } ! 157: ! 158: /* Adjust for offset into table */ ! 159: offset += start * sizeof(uint64_t); ! 160: ! 161: aiocb = bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE, ! 162: &write_table_cb->qiov, ! 163: write_table_cb->iov.iov_len / BDRV_SECTOR_SIZE, ! 164: qed_write_table_cb, write_table_cb); ! 165: if (!aiocb) { ! 166: qed_write_table_cb(write_table_cb, -EIO); ! 167: } ! 168: } ! 169: ! 170: /** ! 171: * Propagate return value from async callback ! 172: */ ! 173: static void qed_sync_cb(void *opaque, int ret) ! 174: { ! 175: *(int *)opaque = ret; ! 176: } ! 177: ! 178: int qed_read_l1_table_sync(BDRVQEDState *s) ! 179: { ! 180: int ret = -EINPROGRESS; ! 181: ! 182: async_context_push(); ! 183: ! 184: qed_read_table(s, s->header.l1_table_offset, ! 185: s->l1_table, qed_sync_cb, &ret); ! 186: while (ret == -EINPROGRESS) { ! 187: qemu_aio_wait(); ! 188: } ! 189: ! 190: async_context_pop(); ! 191: ! 192: return ret; ! 193: } ! 194: ! 195: void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n, ! 196: BlockDriverCompletionFunc *cb, void *opaque) ! 197: { ! 198: BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE); ! 199: qed_write_table(s, s->header.l1_table_offset, ! 200: s->l1_table, index, n, false, cb, opaque); ! 201: } ! 202: ! 203: int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, ! 204: unsigned int n) ! 205: { ! 206: int ret = -EINPROGRESS; ! 207: ! 208: async_context_push(); ! 209: ! 210: qed_write_l1_table(s, index, n, qed_sync_cb, &ret); ! 211: while (ret == -EINPROGRESS) { ! 212: qemu_aio_wait(); ! 213: } ! 214: ! 215: async_context_pop(); ! 216: ! 217: return ret; ! 218: } ! 219: ! 220: typedef struct { ! 221: GenericCB gencb; ! 222: BDRVQEDState *s; ! 223: uint64_t l2_offset; ! 224: QEDRequest *request; ! 225: } QEDReadL2TableCB; ! 226: ! 227: static void qed_read_l2_table_cb(void *opaque, int ret) ! 228: { ! 229: QEDReadL2TableCB *read_l2_table_cb = opaque; ! 230: QEDRequest *request = read_l2_table_cb->request; ! 231: BDRVQEDState *s = read_l2_table_cb->s; ! 232: CachedL2Table *l2_table = request->l2_table; ! 233: ! 234: if (ret) { ! 235: /* can't trust loaded L2 table anymore */ ! 236: qed_unref_l2_cache_entry(l2_table); ! 237: request->l2_table = NULL; ! 238: } else { ! 239: l2_table->offset = read_l2_table_cb->l2_offset; ! 240: ! 241: qed_commit_l2_cache_entry(&s->l2_cache, l2_table); ! 242: ! 243: /* This is guaranteed to succeed because we just committed the entry ! 244: * to the cache. ! 245: */ ! 246: request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, ! 247: l2_table->offset); ! 248: assert(request->l2_table != NULL); ! 249: } ! 250: ! 251: gencb_complete(&read_l2_table_cb->gencb, ret); ! 252: } ! 253: ! 254: void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset, ! 255: BlockDriverCompletionFunc *cb, void *opaque) ! 256: { ! 257: QEDReadL2TableCB *read_l2_table_cb; ! 258: ! 259: qed_unref_l2_cache_entry(request->l2_table); ! 260: ! 261: /* Check for cached L2 entry */ ! 262: request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset); ! 263: if (request->l2_table) { ! 264: cb(opaque, 0); ! 265: return; ! 266: } ! 267: ! 268: request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache); ! 269: request->l2_table->table = qed_alloc_table(s); ! 270: ! 271: read_l2_table_cb = gencb_alloc(sizeof(*read_l2_table_cb), cb, opaque); ! 272: read_l2_table_cb->s = s; ! 273: read_l2_table_cb->l2_offset = offset; ! 274: read_l2_table_cb->request = request; ! 275: ! 276: BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD); ! 277: qed_read_table(s, offset, request->l2_table->table, ! 278: qed_read_l2_table_cb, read_l2_table_cb); ! 279: } ! 280: ! 281: int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset) ! 282: { ! 283: int ret = -EINPROGRESS; ! 284: ! 285: async_context_push(); ! 286: ! 287: qed_read_l2_table(s, request, offset, qed_sync_cb, &ret); ! 288: while (ret == -EINPROGRESS) { ! 289: qemu_aio_wait(); ! 290: } ! 291: ! 292: async_context_pop(); ! 293: return ret; ! 294: } ! 295: ! 296: void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, ! 297: unsigned int index, unsigned int n, bool flush, ! 298: BlockDriverCompletionFunc *cb, void *opaque) ! 299: { ! 300: BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE); ! 301: qed_write_table(s, request->l2_table->offset, ! 302: request->l2_table->table, index, n, flush, cb, opaque); ! 303: } ! 304: ! 305: int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, ! 306: unsigned int index, unsigned int n, bool flush) ! 307: { ! 308: int ret = -EINPROGRESS; ! 309: ! 310: async_context_push(); ! 311: ! 312: qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret); ! 313: while (ret == -EINPROGRESS) { ! 314: qemu_aio_wait(); ! 315: } ! 316: ! 317: async_context_pop(); ! 318: return ret; ! 319: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.