Statistics
| Branch: | Revision:

root / block / qed-table.c @ 3178e275

History | View | Annotate | Download (8.4 kB)

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->qiov.size / 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

    
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);
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);
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

    
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);
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;
217
    uint64_t l2_offset = read_l2_table_cb->l2_offset;
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 {
224
        l2_table->offset = l2_offset;
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
         */
231
        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
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
}