~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to block/qed-table.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * QEMU Enhanced Disk Format Table I/O
 
3
 *
 
4
 * Copyright IBM, Corp. 2010
 
5
 *
 
6
 * Authors:
 
7
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 
8
 *  Anthony Liguori   <aliguori@us.ibm.com>
 
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
}