cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

copy-on-read.c (8940B)


      1/*
      2 * Copy-on-read filter block driver
      3 *
      4 * Copyright (c) 2018 Red Hat, Inc.
      5 *
      6 * Author:
      7 *   Max Reitz <mreitz@redhat.com>
      8 *
      9 * This program is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU General Public License as
     11 * published by the Free Software Foundation; either version 2 or
     12 * (at your option) version 3 of the License.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 * GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     21 */
     22
     23#include "qemu/osdep.h"
     24#include "block/block_int.h"
     25#include "qemu/module.h"
     26#include "qapi/error.h"
     27#include "qapi/qmp/qdict.h"
     28#include "block/copy-on-read.h"
     29
     30
     31typedef struct BDRVStateCOR {
     32    BlockDriverState *bottom_bs;
     33    bool chain_frozen;
     34} BDRVStateCOR;
     35
     36
     37static int cor_open(BlockDriverState *bs, QDict *options, int flags,
     38                    Error **errp)
     39{
     40    BlockDriverState *bottom_bs = NULL;
     41    BDRVStateCOR *state = bs->opaque;
     42    /* Find a bottom node name, if any */
     43    const char *bottom_node = qdict_get_try_str(options, "bottom");
     44
     45    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
     46                               BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
     47                               false, errp);
     48    if (!bs->file) {
     49        return -EINVAL;
     50    }
     51
     52    bs->supported_read_flags = BDRV_REQ_PREFETCH;
     53
     54    bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
     55        (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
     56
     57    bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
     58        ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
     59            bs->file->bs->supported_zero_flags);
     60
     61    if (bottom_node) {
     62        bottom_bs = bdrv_find_node(bottom_node);
     63        if (!bottom_bs) {
     64            error_setg(errp, "Bottom node '%s' not found", bottom_node);
     65            qdict_del(options, "bottom");
     66            return -EINVAL;
     67        }
     68        qdict_del(options, "bottom");
     69
     70        if (!bottom_bs->drv) {
     71            error_setg(errp, "Bottom node '%s' not opened", bottom_node);
     72            return -EINVAL;
     73        }
     74
     75        if (bottom_bs->drv->is_filter) {
     76            error_setg(errp, "Bottom node '%s' is a filter", bottom_node);
     77            return -EINVAL;
     78        }
     79
     80        if (bdrv_freeze_backing_chain(bs, bottom_bs, errp) < 0) {
     81            return -EINVAL;
     82        }
     83        state->chain_frozen = true;
     84
     85        /*
     86         * We do freeze the chain, so it shouldn't be removed. Still, storing a
     87         * pointer worth bdrv_ref().
     88         */
     89        bdrv_ref(bottom_bs);
     90    }
     91    state->bottom_bs = bottom_bs;
     92
     93    /*
     94     * We don't need to call bdrv_child_refresh_perms() now as the permissions
     95     * will be updated later when the filter node gets its parent.
     96     */
     97
     98    return 0;
     99}
    100
    101
    102#define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
    103                          | BLK_PERM_WRITE \
    104                          | BLK_PERM_RESIZE)
    105#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
    106
    107static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
    108                           BdrvChildRole role,
    109                           BlockReopenQueue *reopen_queue,
    110                           uint64_t perm, uint64_t shared,
    111                           uint64_t *nperm, uint64_t *nshared)
    112{
    113    *nperm = perm & PERM_PASSTHROUGH;
    114    *nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
    115
    116    /* We must not request write permissions for an inactive node, the child
    117     * cannot provide it. */
    118    if (!(bs->open_flags & BDRV_O_INACTIVE)) {
    119        *nperm |= BLK_PERM_WRITE_UNCHANGED;
    120    }
    121}
    122
    123
    124static int64_t cor_getlength(BlockDriverState *bs)
    125{
    126    return bdrv_getlength(bs->file->bs);
    127}
    128
    129
    130static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
    131                                           int64_t offset, int64_t bytes,
    132                                           QEMUIOVector *qiov,
    133                                           size_t qiov_offset,
    134                                           BdrvRequestFlags flags)
    135{
    136    int64_t n;
    137    int local_flags;
    138    int ret;
    139    BDRVStateCOR *state = bs->opaque;
    140
    141    if (!state->bottom_bs) {
    142        return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
    143                                   flags | BDRV_REQ_COPY_ON_READ);
    144    }
    145
    146    while (bytes) {
    147        local_flags = flags;
    148
    149        /* In case of failure, try to copy-on-read anyway */
    150        ret = bdrv_is_allocated(bs->file->bs, offset, bytes, &n);
    151        if (ret <= 0) {
    152            ret = bdrv_is_allocated_above(bdrv_backing_chain_next(bs->file->bs),
    153                                          state->bottom_bs, true, offset,
    154                                          n, &n);
    155            if (ret > 0 || ret < 0) {
    156                local_flags |= BDRV_REQ_COPY_ON_READ;
    157            }
    158            /* Finish earlier if the end of a backing file has been reached */
    159            if (n == 0) {
    160                break;
    161            }
    162        }
    163
    164        /* Skip if neither read nor write are needed */
    165        if ((local_flags & (BDRV_REQ_PREFETCH | BDRV_REQ_COPY_ON_READ)) !=
    166            BDRV_REQ_PREFETCH) {
    167            ret = bdrv_co_preadv_part(bs->file, offset, n, qiov, qiov_offset,
    168                                      local_flags);
    169            if (ret < 0) {
    170                return ret;
    171            }
    172        }
    173
    174        offset += n;
    175        qiov_offset += n;
    176        bytes -= n;
    177    }
    178
    179    return 0;
    180}
    181
    182
    183static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
    184                                            int64_t offset,
    185                                            int64_t bytes,
    186                                            QEMUIOVector *qiov,
    187                                            size_t qiov_offset,
    188                                            BdrvRequestFlags flags)
    189{
    190    return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
    191                                flags);
    192}
    193
    194
    195static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
    196                                             int64_t offset, int64_t bytes,
    197                                             BdrvRequestFlags flags)
    198{
    199    return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
    200}
    201
    202
    203static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
    204                                        int64_t offset, int64_t bytes)
    205{
    206    return bdrv_co_pdiscard(bs->file, offset, bytes);
    207}
    208
    209
    210static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs,
    211                                                  int64_t offset,
    212                                                  int64_t bytes,
    213                                                  QEMUIOVector *qiov)
    214{
    215    return bdrv_co_pwritev(bs->file, offset, bytes, qiov,
    216                           BDRV_REQ_WRITE_COMPRESSED);
    217}
    218
    219
    220static void cor_eject(BlockDriverState *bs, bool eject_flag)
    221{
    222    bdrv_eject(bs->file->bs, eject_flag);
    223}
    224
    225
    226static void cor_lock_medium(BlockDriverState *bs, bool locked)
    227{
    228    bdrv_lock_medium(bs->file->bs, locked);
    229}
    230
    231
    232static void cor_close(BlockDriverState *bs)
    233{
    234    BDRVStateCOR *s = bs->opaque;
    235
    236    if (s->chain_frozen) {
    237        s->chain_frozen = false;
    238        bdrv_unfreeze_backing_chain(bs, s->bottom_bs);
    239    }
    240
    241    bdrv_unref(s->bottom_bs);
    242}
    243
    244
    245static BlockDriver bdrv_copy_on_read = {
    246    .format_name                        = "copy-on-read",
    247    .instance_size                      = sizeof(BDRVStateCOR),
    248
    249    .bdrv_open                          = cor_open,
    250    .bdrv_close                         = cor_close,
    251    .bdrv_child_perm                    = cor_child_perm,
    252
    253    .bdrv_getlength                     = cor_getlength,
    254
    255    .bdrv_co_preadv_part                = cor_co_preadv_part,
    256    .bdrv_co_pwritev_part               = cor_co_pwritev_part,
    257    .bdrv_co_pwrite_zeroes              = cor_co_pwrite_zeroes,
    258    .bdrv_co_pdiscard                   = cor_co_pdiscard,
    259    .bdrv_co_pwritev_compressed         = cor_co_pwritev_compressed,
    260
    261    .bdrv_eject                         = cor_eject,
    262    .bdrv_lock_medium                   = cor_lock_medium,
    263
    264    .has_variable_length                = true,
    265    .is_filter                          = true,
    266};
    267
    268
    269void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
    270{
    271    BDRVStateCOR *s = cor_filter_bs->opaque;
    272
    273    /* unfreeze, as otherwise bdrv_replace_node() will fail */
    274    if (s->chain_frozen) {
    275        s->chain_frozen = false;
    276        bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
    277    }
    278    bdrv_drop_filter(cor_filter_bs, &error_abort);
    279    bdrv_unref(cor_filter_bs);
    280}
    281
    282
    283static void bdrv_copy_on_read_init(void)
    284{
    285    bdrv_register(&bdrv_copy_on_read);
    286}
    287
    288block_init(bdrv_copy_on_read_init);