qemu/block/snapshot.c
<<
>>
Prefs
   1/*
   2 * Block layer snapshot related functions
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "block/snapshot.h"
  26#include "block/block_int.h"
  27#include "qapi/qmp/qerror.h"
  28
  29QemuOptsList internal_snapshot_opts = {
  30    .name = "snapshot",
  31    .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
  32    .desc = {
  33        {
  34            .name = SNAPSHOT_OPT_ID,
  35            .type = QEMU_OPT_STRING,
  36            .help = "snapshot id"
  37        },{
  38            .name = SNAPSHOT_OPT_NAME,
  39            .type = QEMU_OPT_STRING,
  40            .help = "snapshot name"
  41        },{
  42            /* end of list */
  43        }
  44    },
  45};
  46
  47int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
  48                       const char *name)
  49{
  50    QEMUSnapshotInfo *sn_tab, *sn;
  51    int nb_sns, i, ret;
  52
  53    ret = -ENOENT;
  54    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
  55    if (nb_sns < 0) {
  56        return ret;
  57    }
  58    for (i = 0; i < nb_sns; i++) {
  59        sn = &sn_tab[i];
  60        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
  61            *sn_info = *sn;
  62            ret = 0;
  63            break;
  64        }
  65    }
  66    g_free(sn_tab);
  67    return ret;
  68}
  69
  70/**
  71 * Look up an internal snapshot by @id and @name.
  72 * @bs: block device to search
  73 * @id: unique snapshot ID, or NULL
  74 * @name: snapshot name, or NULL
  75 * @sn_info: location to store information on the snapshot found
  76 * @errp: location to store error, will be set only for exception
  77 *
  78 * This function will traverse snapshot list in @bs to search the matching
  79 * one, @id and @name are the matching condition:
  80 * If both @id and @name are specified, find the first one with id @id and
  81 * name @name.
  82 * If only @id is specified, find the first one with id @id.
  83 * If only @name is specified, find the first one with name @name.
  84 * if none is specified, abort().
  85 *
  86 * Returns: true when a snapshot is found and @sn_info will be filled, false
  87 * when error or not found. If all operation succeed but no matching one is
  88 * found, @errp will NOT be set.
  89 */
  90bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
  91                                       const char *id,
  92                                       const char *name,
  93                                       QEMUSnapshotInfo *sn_info,
  94                                       Error **errp)
  95{
  96    QEMUSnapshotInfo *sn_tab, *sn;
  97    int nb_sns, i;
  98    bool ret = false;
  99
 100    assert(id || name);
 101
 102    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
 103    if (nb_sns < 0) {
 104        error_setg_errno(errp, -nb_sns, "Failed to get a snapshot list");
 105        return false;
 106    } else if (nb_sns == 0) {
 107        return false;
 108    }
 109
 110    if (id && name) {
 111        for (i = 0; i < nb_sns; i++) {
 112            sn = &sn_tab[i];
 113            if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
 114                *sn_info = *sn;
 115                ret = true;
 116                break;
 117            }
 118        }
 119    } else if (id) {
 120        for (i = 0; i < nb_sns; i++) {
 121            sn = &sn_tab[i];
 122            if (!strcmp(sn->id_str, id)) {
 123                *sn_info = *sn;
 124                ret = true;
 125                break;
 126            }
 127        }
 128    } else if (name) {
 129        for (i = 0; i < nb_sns; i++) {
 130            sn = &sn_tab[i];
 131            if (!strcmp(sn->name, name)) {
 132                *sn_info = *sn;
 133                ret = true;
 134                break;
 135            }
 136        }
 137    }
 138
 139    g_free(sn_tab);
 140    return ret;
 141}
 142
 143int bdrv_can_snapshot(BlockDriverState *bs)
 144{
 145    BlockDriver *drv = bs->drv;
 146    if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
 147        return 0;
 148    }
 149
 150    if (!drv->bdrv_snapshot_create) {
 151        if (bs->file != NULL) {
 152            return bdrv_can_snapshot(bs->file);
 153        }
 154        return 0;
 155    }
 156
 157    return 1;
 158}
 159
 160int bdrv_snapshot_create(BlockDriverState *bs,
 161                         QEMUSnapshotInfo *sn_info)
 162{
 163    BlockDriver *drv = bs->drv;
 164    if (!drv) {
 165        return -ENOMEDIUM;
 166    }
 167    if (drv->bdrv_snapshot_create) {
 168        return drv->bdrv_snapshot_create(bs, sn_info);
 169    }
 170    if (bs->file) {
 171        return bdrv_snapshot_create(bs->file, sn_info);
 172    }
 173    return -ENOTSUP;
 174}
 175
 176int bdrv_snapshot_goto(BlockDriverState *bs,
 177                       const char *snapshot_id)
 178{
 179    BlockDriver *drv = bs->drv;
 180    int ret, open_ret;
 181
 182    if (!drv) {
 183        return -ENOMEDIUM;
 184    }
 185    if (drv->bdrv_snapshot_goto) {
 186        return drv->bdrv_snapshot_goto(bs, snapshot_id);
 187    }
 188
 189    if (bs->file) {
 190        drv->bdrv_close(bs);
 191        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
 192        open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL);
 193        if (open_ret < 0) {
 194            bdrv_unref(bs->file);
 195            bs->drv = NULL;
 196            return open_ret;
 197        }
 198        return ret;
 199    }
 200
 201    return -ENOTSUP;
 202}
 203
 204/**
 205 * Delete an internal snapshot by @snapshot_id and @name.
 206 * @bs: block device used in the operation
 207 * @snapshot_id: unique snapshot ID, or NULL
 208 * @name: snapshot name, or NULL
 209 * @errp: location to store error
 210 *
 211 * If both @snapshot_id and @name are specified, delete the first one with
 212 * id @snapshot_id and name @name.
 213 * If only @snapshot_id is specified, delete the first one with id
 214 * @snapshot_id.
 215 * If only @name is specified, delete the first one with name @name.
 216 * if none is specified, return -EINVAL.
 217 *
 218 * Returns: 0 on success, -errno on failure. If @bs is not inserted, return
 219 * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
 220 * does not support internal snapshot deletion, return -ENOTSUP. If @bs does
 221 * not support parameter @snapshot_id or @name, or one of them is not correctly
 222 * specified, return -EINVAL. If @bs can't find one matching @id and @name,
 223 * return -ENOENT. If @errp != NULL, it will always be filled with error
 224 * message on failure.
 225 */
 226int bdrv_snapshot_delete(BlockDriverState *bs,
 227                         const char *snapshot_id,
 228                         const char *name,
 229                         Error **errp)
 230{
 231    BlockDriver *drv = bs->drv;
 232    if (!drv) {
 233        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
 234        return -ENOMEDIUM;
 235    }
 236    if (!snapshot_id && !name) {
 237        error_setg(errp, "snapshot_id and name are both NULL");
 238        return -EINVAL;
 239    }
 240
 241    /* drain all pending i/o before deleting snapshot */
 242    bdrv_drain(bs);
 243
 244    if (drv->bdrv_snapshot_delete) {
 245        return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
 246    }
 247    if (bs->file) {
 248        return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp);
 249    }
 250    error_setg(errp, "Block format '%s' used by device '%s' "
 251               "does not support internal snapshot deletion",
 252               drv->format_name, bdrv_get_device_name(bs));
 253    return -ENOTSUP;
 254}
 255
 256void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
 257                                        const char *id_or_name,
 258                                        Error **errp)
 259{
 260    int ret;
 261    Error *local_err = NULL;
 262
 263    ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err);
 264    if (ret == -ENOENT || ret == -EINVAL) {
 265        error_free(local_err);
 266        local_err = NULL;
 267        ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err);
 268    }
 269
 270    if (ret < 0) {
 271        error_propagate(errp, local_err);
 272    }
 273}
 274
 275int bdrv_snapshot_list(BlockDriverState *bs,
 276                       QEMUSnapshotInfo **psn_info)
 277{
 278    BlockDriver *drv = bs->drv;
 279    if (!drv) {
 280        return -ENOMEDIUM;
 281    }
 282    if (drv->bdrv_snapshot_list) {
 283        return drv->bdrv_snapshot_list(bs, psn_info);
 284    }
 285    if (bs->file) {
 286        return bdrv_snapshot_list(bs->file, psn_info);
 287    }
 288    return -ENOTSUP;
 289}
 290
 291/**
 292 * Temporarily load an internal snapshot by @snapshot_id and @name.
 293 * @bs: block device used in the operation
 294 * @snapshot_id: unique snapshot ID, or NULL
 295 * @name: snapshot name, or NULL
 296 * @errp: location to store error
 297 *
 298 * If both @snapshot_id and @name are specified, load the first one with
 299 * id @snapshot_id and name @name.
 300 * If only @snapshot_id is specified, load the first one with id
 301 * @snapshot_id.
 302 * If only @name is specified, load the first one with name @name.
 303 * if none is specified, return -EINVAL.
 304 *
 305 * Returns: 0 on success, -errno on fail. If @bs is not inserted, return
 306 * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support
 307 * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and
 308 * @name, return -ENOENT. If @errp != NULL, it will always be filled on
 309 * failure.
 310 */
 311int bdrv_snapshot_load_tmp(BlockDriverState *bs,
 312                           const char *snapshot_id,
 313                           const char *name,
 314                           Error **errp)
 315{
 316    BlockDriver *drv = bs->drv;
 317
 318    if (!drv) {
 319        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
 320        return -ENOMEDIUM;
 321    }
 322    if (!snapshot_id && !name) {
 323        error_setg(errp, "snapshot_id and name are both NULL");
 324        return -EINVAL;
 325    }
 326    if (!bs->read_only) {
 327        error_setg(errp, "Device is not readonly");
 328        return -EINVAL;
 329    }
 330    if (drv->bdrv_snapshot_load_tmp) {
 331        return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
 332    }
 333    error_setg(errp, "Block format '%s' used by device '%s' "
 334               "does not support temporarily loading internal snapshots",
 335               drv->format_name, bdrv_get_device_name(bs));
 336    return -ENOTSUP;
 337}
 338
 339int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
 340                                         const char *id_or_name,
 341                                         Error **errp)
 342{
 343    int ret;
 344    Error *local_err = NULL;
 345
 346    ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
 347    if (ret == -ENOENT || ret == -EINVAL) {
 348        error_free(local_err);
 349        local_err = NULL;
 350        ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
 351    }
 352
 353    if (local_err) {
 354        error_propagate(errp, local_err);
 355    }
 356
 357    return ret;
 358}
 359