qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

copy-on-read.c (8821B)


      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 
     31 typedef struct BDRVStateCOR {
     32     BlockDriverState *bottom_bs;
     33     bool chain_frozen;
     34 } BDRVStateCOR;
     35 
     36 
     37 static 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     int ret;
     45 
     46     ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
     47     if (ret < 0) {
     48         return ret;
     49     }
     50 
     51     bs->supported_read_flags = BDRV_REQ_PREFETCH;
     52 
     53     bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
     54         (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
     55 
     56     bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
     57         ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
     58             bs->file->bs->supported_zero_flags);
     59 
     60     if (bottom_node) {
     61         bottom_bs = bdrv_find_node(bottom_node);
     62         if (!bottom_bs) {
     63             error_setg(errp, "Bottom node '%s' not found", bottom_node);
     64             qdict_del(options, "bottom");
     65             return -EINVAL;
     66         }
     67         qdict_del(options, "bottom");
     68 
     69         if (!bottom_bs->drv) {
     70             error_setg(errp, "Bottom node '%s' not opened", bottom_node);
     71             return -EINVAL;
     72         }
     73 
     74         if (bottom_bs->drv->is_filter) {
     75             error_setg(errp, "Bottom node '%s' is a filter", bottom_node);
     76             return -EINVAL;
     77         }
     78 
     79         if (bdrv_freeze_backing_chain(bs, bottom_bs, errp) < 0) {
     80             return -EINVAL;
     81         }
     82         state->chain_frozen = true;
     83 
     84         /*
     85          * We do freeze the chain, so it shouldn't be removed. Still, storing a
     86          * pointer worth bdrv_ref().
     87          */
     88         bdrv_ref(bottom_bs);
     89     }
     90     state->bottom_bs = bottom_bs;
     91 
     92     /*
     93      * We don't need to call bdrv_child_refresh_perms() now as the permissions
     94      * will be updated later when the filter node gets its parent.
     95      */
     96 
     97     return 0;
     98 }
     99 
    100 
    101 #define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
    102                           | BLK_PERM_WRITE \
    103                           | BLK_PERM_RESIZE)
    104 #define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
    105 
    106 static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
    107                            BdrvChildRole role,
    108                            BlockReopenQueue *reopen_queue,
    109                            uint64_t perm, uint64_t shared,
    110                            uint64_t *nperm, uint64_t *nshared)
    111 {
    112     *nperm = perm & PERM_PASSTHROUGH;
    113     *nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
    114 
    115     /* We must not request write permissions for an inactive node, the child
    116      * cannot provide it. */
    117     if (!(bs->open_flags & BDRV_O_INACTIVE)) {
    118         *nperm |= BLK_PERM_WRITE_UNCHANGED;
    119     }
    120 }
    121 
    122 
    123 static int64_t cor_getlength(BlockDriverState *bs)
    124 {
    125     return bdrv_getlength(bs->file->bs);
    126 }
    127 
    128 
    129 static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
    130                                            int64_t offset, int64_t bytes,
    131                                            QEMUIOVector *qiov,
    132                                            size_t qiov_offset,
    133                                            BdrvRequestFlags flags)
    134 {
    135     int64_t n;
    136     int local_flags;
    137     int ret;
    138     BDRVStateCOR *state = bs->opaque;
    139 
    140     if (!state->bottom_bs) {
    141         return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
    142                                    flags | BDRV_REQ_COPY_ON_READ);
    143     }
    144 
    145     while (bytes) {
    146         local_flags = flags;
    147 
    148         /* In case of failure, try to copy-on-read anyway */
    149         ret = bdrv_is_allocated(bs->file->bs, offset, bytes, &n);
    150         if (ret <= 0) {
    151             ret = bdrv_is_allocated_above(bdrv_backing_chain_next(bs->file->bs),
    152                                           state->bottom_bs, true, offset,
    153                                           n, &n);
    154             if (ret > 0 || ret < 0) {
    155                 local_flags |= BDRV_REQ_COPY_ON_READ;
    156             }
    157             /* Finish earlier if the end of a backing file has been reached */
    158             if (n == 0) {
    159                 break;
    160             }
    161         }
    162 
    163         /* Skip if neither read nor write are needed */
    164         if ((local_flags & (BDRV_REQ_PREFETCH | BDRV_REQ_COPY_ON_READ)) !=
    165             BDRV_REQ_PREFETCH) {
    166             ret = bdrv_co_preadv_part(bs->file, offset, n, qiov, qiov_offset,
    167                                       local_flags);
    168             if (ret < 0) {
    169                 return ret;
    170             }
    171         }
    172 
    173         offset += n;
    174         qiov_offset += n;
    175         bytes -= n;
    176     }
    177 
    178     return 0;
    179 }
    180 
    181 
    182 static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
    183                                             int64_t offset,
    184                                             int64_t bytes,
    185                                             QEMUIOVector *qiov,
    186                                             size_t qiov_offset,
    187                                             BdrvRequestFlags flags)
    188 {
    189     return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
    190                                 flags);
    191 }
    192 
    193 
    194 static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
    195                                              int64_t offset, int64_t bytes,
    196                                              BdrvRequestFlags flags)
    197 {
    198     return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
    199 }
    200 
    201 
    202 static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
    203                                         int64_t offset, int64_t bytes)
    204 {
    205     return bdrv_co_pdiscard(bs->file, offset, bytes);
    206 }
    207 
    208 
    209 static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs,
    210                                                   int64_t offset,
    211                                                   int64_t bytes,
    212                                                   QEMUIOVector *qiov)
    213 {
    214     return bdrv_co_pwritev(bs->file, offset, bytes, qiov,
    215                            BDRV_REQ_WRITE_COMPRESSED);
    216 }
    217 
    218 
    219 static void cor_eject(BlockDriverState *bs, bool eject_flag)
    220 {
    221     bdrv_eject(bs->file->bs, eject_flag);
    222 }
    223 
    224 
    225 static void cor_lock_medium(BlockDriverState *bs, bool locked)
    226 {
    227     bdrv_lock_medium(bs->file->bs, locked);
    228 }
    229 
    230 
    231 static void cor_close(BlockDriverState *bs)
    232 {
    233     BDRVStateCOR *s = bs->opaque;
    234 
    235     if (s->chain_frozen) {
    236         s->chain_frozen = false;
    237         bdrv_unfreeze_backing_chain(bs, s->bottom_bs);
    238     }
    239 
    240     bdrv_unref(s->bottom_bs);
    241 }
    242 
    243 
    244 static BlockDriver bdrv_copy_on_read = {
    245     .format_name                        = "copy-on-read",
    246     .instance_size                      = sizeof(BDRVStateCOR),
    247 
    248     .bdrv_open                          = cor_open,
    249     .bdrv_close                         = cor_close,
    250     .bdrv_child_perm                    = cor_child_perm,
    251 
    252     .bdrv_getlength                     = cor_getlength,
    253 
    254     .bdrv_co_preadv_part                = cor_co_preadv_part,
    255     .bdrv_co_pwritev_part               = cor_co_pwritev_part,
    256     .bdrv_co_pwrite_zeroes              = cor_co_pwrite_zeroes,
    257     .bdrv_co_pdiscard                   = cor_co_pdiscard,
    258     .bdrv_co_pwritev_compressed         = cor_co_pwritev_compressed,
    259 
    260     .bdrv_eject                         = cor_eject,
    261     .bdrv_lock_medium                   = cor_lock_medium,
    262 
    263     .has_variable_length                = true,
    264     .is_filter                          = true,
    265 };
    266 
    267 
    268 void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
    269 {
    270     BDRVStateCOR *s = cor_filter_bs->opaque;
    271 
    272     /* unfreeze, as otherwise bdrv_replace_node() will fail */
    273     if (s->chain_frozen) {
    274         s->chain_frozen = false;
    275         bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
    276     }
    277     bdrv_drop_filter(cor_filter_bs, &error_abort);
    278     bdrv_unref(cor_filter_bs);
    279 }
    280 
    281 
    282 static void bdrv_copy_on_read_init(void)
    283 {
    284     bdrv_register(&bdrv_copy_on_read);
    285 }
    286 
    287 block_init(bdrv_copy_on_read_init);