qemu/block/qed-table.c
<<
>>
Prefs
   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 "qemu/osdep.h"
  16#include "trace.h"
  17#include "qemu/sockets.h" /* for EINPROGRESS on Windows */
  18#include "qed.h"
  19#include "qemu/bswap.h"
  20
  21/* Called with table_lock held.  */
  22static int coroutine_fn qed_read_table(BDRVQEDState *s, uint64_t offset,
  23                                       QEDTable *table)
  24{
  25    unsigned int bytes = s->header.cluster_size * s->header.table_size;
  26
  27    int noffsets;
  28    int i, ret;
  29
  30    trace_qed_read_table(s, offset, table);
  31
  32    qemu_co_mutex_unlock(&s->table_lock);
  33    ret = bdrv_co_pread(s->bs->file, offset, bytes, table->offsets, 0);
  34    qemu_co_mutex_lock(&s->table_lock);
  35    if (ret < 0) {
  36        goto out;
  37    }
  38
  39    /* Byteswap offsets */
  40    noffsets = bytes / sizeof(uint64_t);
  41    for (i = 0; i < noffsets; i++) {
  42        table->offsets[i] = le64_to_cpu(table->offsets[i]);
  43    }
  44
  45    ret = 0;
  46out:
  47    /* Completion */
  48    trace_qed_read_table_cb(s, table, ret);
  49    return ret;
  50}
  51
  52/**
  53 * Write out an updated part or all of a table
  54 *
  55 * @s:          QED state
  56 * @offset:     Offset of table in image file, in bytes
  57 * @table:      Table
  58 * @index:      Index of first element
  59 * @n:          Number of elements
  60 * @flush:      Whether or not to sync to disk
  61 *
  62 * Called with table_lock held.
  63 */
  64static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset,
  65                                        QEDTable *table, unsigned int index,
  66                                        unsigned int n, bool flush)
  67{
  68    unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
  69    unsigned int start, end, i;
  70    QEDTable *new_table;
  71    size_t len_bytes;
  72    int ret;
  73
  74    trace_qed_write_table(s, offset, table, index, n);
  75
  76    /* Calculate indices of the first and one after last elements */
  77    start = index & ~sector_mask;
  78    end = (index + n + sector_mask) & ~sector_mask;
  79
  80    len_bytes = (end - start) * sizeof(uint64_t);
  81
  82    new_table = qemu_blockalign(s->bs, len_bytes);
  83
  84    /* Byteswap table */
  85    for (i = start; i < end; i++) {
  86        uint64_t le_offset = cpu_to_le64(table->offsets[i]);
  87        new_table->offsets[i - start] = le_offset;
  88    }
  89
  90    /* Adjust for offset into table */
  91    offset += start * sizeof(uint64_t);
  92
  93    qemu_co_mutex_unlock(&s->table_lock);
  94    ret = bdrv_co_pwrite(s->bs->file, offset, len_bytes, new_table->offsets, 0);
  95    qemu_co_mutex_lock(&s->table_lock);
  96    trace_qed_write_table_cb(s, table, flush, ret);
  97    if (ret < 0) {
  98        goto out;
  99    }
 100
 101    if (flush) {
 102        ret = bdrv_flush(s->bs);
 103        if (ret < 0) {
 104            goto out;
 105        }
 106    }
 107
 108    ret = 0;
 109out:
 110    qemu_vfree(new_table);
 111    return ret;
 112}
 113
 114int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s)
 115{
 116    return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
 117}
 118
 119/* Called with table_lock held.  */
 120int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
 121                                    unsigned int n)
 122{
 123    BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
 124    return qed_write_table(s, s->header.l1_table_offset,
 125                           s->l1_table, index, n, false);
 126}
 127
 128int coroutine_fn qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 129                                         unsigned int n)
 130{
 131    return qed_write_l1_table(s, index, n);
 132}
 133
 134/* Called with table_lock held.  */
 135int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
 136                                   uint64_t offset)
 137{
 138    int ret;
 139
 140    qed_unref_l2_cache_entry(request->l2_table);
 141
 142    /* Check for cached L2 entry */
 143    request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
 144    if (request->l2_table) {
 145        return 0;
 146    }
 147
 148    request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
 149    request->l2_table->table = qed_alloc_table(s);
 150
 151    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
 152    ret = qed_read_table(s, offset, request->l2_table->table);
 153
 154    if (ret) {
 155        /* can't trust loaded L2 table anymore */
 156        qed_unref_l2_cache_entry(request->l2_table);
 157        request->l2_table = NULL;
 158    } else {
 159        request->l2_table->offset = offset;
 160
 161        qed_commit_l2_cache_entry(&s->l2_cache, request->l2_table);
 162
 163        /* This is guaranteed to succeed because we just committed the entry
 164         * to the cache.
 165         */
 166        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
 167        assert(request->l2_table != NULL);
 168    }
 169
 170    return ret;
 171}
 172
 173int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 174                                        uint64_t offset)
 175{
 176    return qed_read_l2_table(s, request, offset);
 177}
 178
 179/* Called with table_lock held.  */
 180int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
 181                                    unsigned int index, unsigned int n,
 182                                    bool flush)
 183{
 184    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
 185    return qed_write_table(s, request->l2_table->offset,
 186                           request->l2_table->table, index, n, flush);
 187}
 188
 189int coroutine_fn qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 190                                         unsigned int index, unsigned int n,
 191                                         bool flush)
 192{
 193    return qed_write_l2_table(s, request, index, n, flush);
 194}
 195