qemu

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

bitmap-qmp-cmds.c (9188B)


      1 /*
      2  * QEMU block dirty bitmap QMP commands
      3  *
      4  * Copyright (c) 2003-2008 Fabrice Bellard
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or
      7  * later.  See the COPYING file in the top-level directory.
      8  *
      9  * This file incorporates work covered by the following copyright and
     10  * permission notice:
     11  *
     12  * Copyright (c) 2003-2008 Fabrice Bellard
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining a copy
     15  * of this software and associated documentation files (the "Software"), to deal
     16  * in the Software without restriction, including without limitation the rights
     17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     18  * copies of the Software, and to permit persons to whom the Software is
     19  * furnished to do so, subject to the following conditions:
     20  *
     21  * The above copyright notice and this permission notice shall be included in
     22  * all copies or substantial portions of the Software.
     23  *
     24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     30  * THE SOFTWARE.
     31  */
     32 
     33 #include "qemu/osdep.h"
     34 
     35 #include "block/block_int.h"
     36 #include "qapi/qapi-commands-block.h"
     37 #include "qapi/error.h"
     38 
     39 /**
     40  * block_dirty_bitmap_lookup:
     41  * Return a dirty bitmap (if present), after validating
     42  * the node reference and bitmap names.
     43  *
     44  * @node: The name of the BDS node to search for bitmaps
     45  * @name: The name of the bitmap to search for
     46  * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
     47  * @errp: Output pointer for error information. Can be NULL.
     48  *
     49  * @return: A bitmap object on success, or NULL on failure.
     50  */
     51 BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
     52                                            const char *name,
     53                                            BlockDriverState **pbs,
     54                                            Error **errp)
     55 {
     56     BlockDriverState *bs;
     57     BdrvDirtyBitmap *bitmap;
     58 
     59     GLOBAL_STATE_CODE();
     60 
     61     if (!node) {
     62         error_setg(errp, "Node cannot be NULL");
     63         return NULL;
     64     }
     65     if (!name) {
     66         error_setg(errp, "Bitmap name cannot be NULL");
     67         return NULL;
     68     }
     69     bs = bdrv_lookup_bs(node, node, NULL);
     70     if (!bs) {
     71         error_setg(errp, "Node '%s' not found", node);
     72         return NULL;
     73     }
     74 
     75     bitmap = bdrv_find_dirty_bitmap(bs, name);
     76     if (!bitmap) {
     77         error_setg(errp, "Dirty bitmap '%s' not found", name);
     78         return NULL;
     79     }
     80 
     81     if (pbs) {
     82         *pbs = bs;
     83     }
     84 
     85     return bitmap;
     86 }
     87 
     88 void qmp_block_dirty_bitmap_add(const char *node, const char *name,
     89                                 bool has_granularity, uint32_t granularity,
     90                                 bool has_persistent, bool persistent,
     91                                 bool has_disabled, bool disabled,
     92                                 Error **errp)
     93 {
     94     BlockDriverState *bs;
     95     BdrvDirtyBitmap *bitmap;
     96     AioContext *aio_context;
     97 
     98     if (!name || name[0] == '\0') {
     99         error_setg(errp, "Bitmap name cannot be empty");
    100         return;
    101     }
    102 
    103     bs = bdrv_lookup_bs(node, node, errp);
    104     if (!bs) {
    105         return;
    106     }
    107 
    108     aio_context = bdrv_get_aio_context(bs);
    109     aio_context_acquire(aio_context);
    110 
    111     if (has_granularity) {
    112         if (granularity < 512 || !is_power_of_2(granularity)) {
    113             error_setg(errp, "Granularity must be power of 2 "
    114                              "and at least 512");
    115             goto out;
    116         }
    117     } else {
    118         /* Default to cluster size, if available: */
    119         granularity = bdrv_get_default_bitmap_granularity(bs);
    120     }
    121 
    122     if (!has_persistent) {
    123         persistent = false;
    124     }
    125 
    126     if (!has_disabled) {
    127         disabled = false;
    128     }
    129 
    130     if (persistent &&
    131         !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
    132     {
    133         goto out;
    134     }
    135 
    136     bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
    137     if (bitmap == NULL) {
    138         goto out;
    139     }
    140 
    141     if (disabled) {
    142         bdrv_disable_dirty_bitmap(bitmap);
    143     }
    144 
    145     bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
    146 
    147 out:
    148     aio_context_release(aio_context);
    149 }
    150 
    151 BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
    152                                            bool release,
    153                                            BlockDriverState **bitmap_bs,
    154                                            Error **errp)
    155 {
    156     BlockDriverState *bs;
    157     BdrvDirtyBitmap *bitmap;
    158     AioContext *aio_context;
    159 
    160     GLOBAL_STATE_CODE();
    161 
    162     bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
    163     if (!bitmap || !bs) {
    164         return NULL;
    165     }
    166 
    167     aio_context = bdrv_get_aio_context(bs);
    168     aio_context_acquire(aio_context);
    169 
    170     if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
    171                                 errp)) {
    172         aio_context_release(aio_context);
    173         return NULL;
    174     }
    175 
    176     if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
    177         bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
    178     {
    179         aio_context_release(aio_context);
    180         return NULL;
    181     }
    182 
    183     if (release) {
    184         bdrv_release_dirty_bitmap(bitmap);
    185     }
    186 
    187     if (bitmap_bs) {
    188         *bitmap_bs = bs;
    189     }
    190 
    191     aio_context_release(aio_context);
    192     return release ? NULL : bitmap;
    193 }
    194 
    195 void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
    196                                    Error **errp)
    197 {
    198     block_dirty_bitmap_remove(node, name, true, NULL, errp);
    199 }
    200 
    201 /**
    202  * Completely clear a bitmap, for the purposes of synchronizing a bitmap
    203  * immediately after a full backup operation.
    204  */
    205 void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
    206                                   Error **errp)
    207 {
    208     BdrvDirtyBitmap *bitmap;
    209     BlockDriverState *bs;
    210 
    211     bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
    212     if (!bitmap || !bs) {
    213         return;
    214     }
    215 
    216     if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
    217         return;
    218     }
    219 
    220     bdrv_clear_dirty_bitmap(bitmap, NULL);
    221 }
    222 
    223 void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
    224                                    Error **errp)
    225 {
    226     BlockDriverState *bs;
    227     BdrvDirtyBitmap *bitmap;
    228 
    229     bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
    230     if (!bitmap) {
    231         return;
    232     }
    233 
    234     if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
    235         return;
    236     }
    237 
    238     bdrv_enable_dirty_bitmap(bitmap);
    239 }
    240 
    241 void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
    242                                     Error **errp)
    243 {
    244     BlockDriverState *bs;
    245     BdrvDirtyBitmap *bitmap;
    246 
    247     bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
    248     if (!bitmap) {
    249         return;
    250     }
    251 
    252     if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
    253         return;
    254     }
    255 
    256     bdrv_disable_dirty_bitmap(bitmap);
    257 }
    258 
    259 BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
    260                                           BlockDirtyBitmapOrStrList *bms,
    261                                           HBitmap **backup, Error **errp)
    262 {
    263     BlockDriverState *bs;
    264     BdrvDirtyBitmap *dst, *src;
    265     BlockDirtyBitmapOrStrList *lst;
    266     HBitmap *local_backup = NULL;
    267 
    268     GLOBAL_STATE_CODE();
    269 
    270     dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
    271     if (!dst) {
    272         return NULL;
    273     }
    274 
    275     for (lst = bms; lst; lst = lst->next) {
    276         switch (lst->value->type) {
    277             const char *name, *node;
    278         case QTYPE_QSTRING:
    279             name = lst->value->u.local;
    280             src = bdrv_find_dirty_bitmap(bs, name);
    281             if (!src) {
    282                 error_setg(errp, "Dirty bitmap '%s' not found", name);
    283                 goto fail;
    284             }
    285             break;
    286         case QTYPE_QDICT:
    287             node = lst->value->u.external.node;
    288             name = lst->value->u.external.name;
    289             src = block_dirty_bitmap_lookup(node, name, NULL, errp);
    290             if (!src) {
    291                 goto fail;
    292             }
    293             break;
    294         default:
    295             abort();
    296         }
    297 
    298         /* We do backup only for first merge operation */
    299         if (!bdrv_merge_dirty_bitmap(dst, src,
    300                                      local_backup ? NULL : &local_backup,
    301                                      errp))
    302         {
    303             goto fail;
    304         }
    305     }
    306 
    307     if (backup) {
    308         *backup = local_backup;
    309     } else {
    310         hbitmap_free(local_backup);
    311     }
    312 
    313     return dst;
    314 
    315 fail:
    316     if (local_backup) {
    317         bdrv_restore_dirty_bitmap(dst, local_backup);
    318     }
    319 
    320     return NULL;
    321 }
    322 
    323 void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
    324                                   BlockDirtyBitmapOrStrList *bitmaps,
    325                                   Error **errp)
    326 {
    327     block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
    328 }