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 28 QemuOptsList internal_snapshot_opts = { 29 .name = "snapshot", 30 .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head), 31 .desc = { 32 { 33 .name = SNAPSHOT_OPT_ID, 34 .type = QEMU_OPT_STRING, 35 .help = "snapshot id" 36 },{ 37 .name = SNAPSHOT_OPT_NAME, 38 .type = QEMU_OPT_STRING, 39 .help = "snapshot name" 40 },{ 41 /* end of list */ 42 } 43 }, 44 }; 45 46 int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, 47 const char *name) 48 { 49 QEMUSnapshotInfo *sn_tab, *sn; 50 int nb_sns, i, ret; 51 52 ret = -ENOENT; 53 nb_sns = bdrv_snapshot_list(bs, &sn_tab); 54 if (nb_sns < 0) { 55 return ret; 56 } 57 for (i = 0; i < nb_sns; i++) { 58 sn = &sn_tab[i]; 59 if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { 60 *sn_info = *sn; 61 ret = 0; 62 break; 63 } 64 } 65 g_free(sn_tab); 66 return ret; 67 } 68 69 /** 70 * Look up an internal snapshot by @id and @name. 71 * @bs: block device to search 72 * @id: unique snapshot ID, or NULL 73 * @name: snapshot name, or NULL 74 * @sn_info: location to store information on the snapshot found 75 * @errp: location to store error, will be set only for exception 76 * 77 * This function will traverse snapshot list in @bs to search the matching 78 * one, @id and @name are the matching condition: 79 * If both @id and @name are specified, find the first one with id @id and 80 * name @name. 81 * If only @id is specified, find the first one with id @id. 82 * If only @name is specified, find the first one with name @name. 83 * if none is specified, abort(). 84 * 85 * Returns: true when a snapshot is found and @sn_info will be filled, false 86 * when error or not found. If all operation succeed but no matching one is 87 * found, @errp will NOT be set. 88 */ 89 bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs, 90 const char *id, 91 const char *name, 92 QEMUSnapshotInfo *sn_info, 93 Error **errp) 94 { 95 QEMUSnapshotInfo *sn_tab, *sn; 96 int nb_sns, i; 97 bool ret = false; 98 99 assert(id || name); 100 101 nb_sns = bdrv_snapshot_list(bs, &sn_tab); 102 if (nb_sns < 0) { 103 error_setg_errno(errp, -nb_sns, "Failed to get a snapshot list"); 104 return false; 105 } else if (nb_sns == 0) { 106 return false; 107 } 108 109 if (id && name) { 110 for (i = 0; i < nb_sns; i++) { 111 sn = &sn_tab[i]; 112 if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) { 113 *sn_info = *sn; 114 ret = true; 115 break; 116 } 117 } 118 } else if (id) { 119 for (i = 0; i < nb_sns; i++) { 120 sn = &sn_tab[i]; 121 if (!strcmp(sn->id_str, id)) { 122 *sn_info = *sn; 123 ret = true; 124 break; 125 } 126 } 127 } else if (name) { 128 for (i = 0; i < nb_sns; i++) { 129 sn = &sn_tab[i]; 130 if (!strcmp(sn->name, name)) { 131 *sn_info = *sn; 132 ret = true; 133 break; 134 } 135 } 136 } 137 138 g_free(sn_tab); 139 return ret; 140 } 141 142 int bdrv_can_snapshot(BlockDriverState *bs) 143 { 144 BlockDriver *drv = bs->drv; 145 if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { 146 return 0; 147 } 148 149 if (!drv->bdrv_snapshot_create) { 150 if (bs->file != NULL) { 151 return bdrv_can_snapshot(bs->file); 152 } 153 return 0; 154 } 155 156 return 1; 157 } 158 159 int bdrv_snapshot_create(BlockDriverState *bs, 160 QEMUSnapshotInfo *sn_info) 161 { 162 BlockDriver *drv = bs->drv; 163 if (!drv) { 164 return -ENOMEDIUM; 165 } 166 if (drv->bdrv_snapshot_create) { 167 return drv->bdrv_snapshot_create(bs, sn_info); 168 } 169 if (bs->file) { 170 return bdrv_snapshot_create(bs->file, sn_info); 171 } 172 return -ENOTSUP; 173 } 174 175 int bdrv_snapshot_goto(BlockDriverState *bs, 176 const char *snapshot_id) 177 { 178 BlockDriver *drv = bs->drv; 179 int ret, open_ret; 180 181 if (!drv) { 182 return -ENOMEDIUM; 183 } 184 if (drv->bdrv_snapshot_goto) { 185 return drv->bdrv_snapshot_goto(bs, snapshot_id); 186 } 187 188 if (bs->file) { 189 drv->bdrv_close(bs); 190 ret = bdrv_snapshot_goto(bs->file, snapshot_id); 191 open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL); 192 if (open_ret < 0) { 193 bdrv_unref(bs->file); 194 bs->drv = NULL; 195 return open_ret; 196 } 197 return ret; 198 } 199 200 return -ENOTSUP; 201 } 202 203 /** 204 * Delete an internal snapshot by @snapshot_id and @name. 205 * @bs: block device used in the operation 206 * @snapshot_id: unique snapshot ID, or NULL 207 * @name: snapshot name, or NULL 208 * @errp: location to store error 209 * 210 * If both @snapshot_id and @name are specified, delete the first one with 211 * id @snapshot_id and name @name. 212 * If only @snapshot_id is specified, delete the first one with id 213 * @snapshot_id. 214 * If only @name is specified, delete the first one with name @name. 215 * if none is specified, return -EINVAL. 216 * 217 * Returns: 0 on success, -errno on failure. If @bs is not inserted, return 218 * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs 219 * does not support internal snapshot deletion, return -ENOTSUP. If @bs does 220 * not support parameter @snapshot_id or @name, or one of them is not correctly 221 * specified, return -EINVAL. If @bs can't find one matching @id and @name, 222 * return -ENOENT. If @errp != NULL, it will always be filled with error 223 * message on failure. 224 */ 225 int bdrv_snapshot_delete(BlockDriverState *bs, 226 const char *snapshot_id, 227 const char *name, 228 Error **errp) 229 { 230 BlockDriver *drv = bs->drv; 231 if (!drv) { 232 error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); 233 return -ENOMEDIUM; 234 } 235 if (!snapshot_id && !name) { 236 error_setg(errp, "snapshot_id and name are both NULL"); 237 return -EINVAL; 238 } 239 240 /* drain all pending i/o before deleting snapshot */ 241 bdrv_drain_all(); 242 243 if (drv->bdrv_snapshot_delete) { 244 return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); 245 } 246 if (bs->file) { 247 return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp); 248 } 249 error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, 250 drv->format_name, bdrv_get_device_name(bs), 251 "internal snapshot deletion"); 252 return -ENOTSUP; 253 } 254 255 void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, 256 const char *id_or_name, 257 Error **errp) 258 { 259 int ret; 260 Error *local_err = NULL; 261 262 ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err); 263 if (ret == -ENOENT || ret == -EINVAL) { 264 error_free(local_err); 265 local_err = NULL; 266 ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err); 267 } 268 269 if (ret < 0) { 270 error_propagate(errp, local_err); 271 } 272 } 273 274 int bdrv_snapshot_list(BlockDriverState *bs, 275 QEMUSnapshotInfo **psn_info) 276 { 277 BlockDriver *drv = bs->drv; 278 if (!drv) { 279 return -ENOMEDIUM; 280 } 281 if (drv->bdrv_snapshot_list) { 282 return drv->bdrv_snapshot_list(bs, psn_info); 283 } 284 if (bs->file) { 285 return bdrv_snapshot_list(bs->file, psn_info); 286 } 287 return -ENOTSUP; 288 } 289 290 /** 291 * Temporarily load an internal snapshot by @snapshot_id and @name. 292 * @bs: block device used in the operation 293 * @snapshot_id: unique snapshot ID, or NULL 294 * @name: snapshot name, or NULL 295 * @errp: location to store error 296 * 297 * If both @snapshot_id and @name are specified, load the first one with 298 * id @snapshot_id and name @name. 299 * If only @snapshot_id is specified, load the first one with id 300 * @snapshot_id. 301 * If only @name is specified, load the first one with name @name. 302 * if none is specified, return -EINVAL. 303 * 304 * Returns: 0 on success, -errno on fail. If @bs is not inserted, return 305 * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support 306 * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and 307 * @name, return -ENOENT. If @errp != NULL, it will always be filled on 308 * failure. 309 */ 310 int bdrv_snapshot_load_tmp(BlockDriverState *bs, 311 const char *snapshot_id, 312 const char *name, 313 Error **errp) 314 { 315 BlockDriver *drv = bs->drv; 316 317 if (!drv) { 318 error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); 319 return -ENOMEDIUM; 320 } 321 if (!snapshot_id && !name) { 322 error_setg(errp, "snapshot_id and name are both NULL"); 323 return -EINVAL; 324 } 325 if (!bs->read_only) { 326 error_setg(errp, "Device is not readonly"); 327 return -EINVAL; 328 } 329 if (drv->bdrv_snapshot_load_tmp) { 330 return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp); 331 } 332 error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, 333 drv->format_name, bdrv_get_device_name(bs), 334 "temporarily load internal snapshot"); 335 return -ENOTSUP; 336 } 337 338 int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, 339 const char *id_or_name, 340 Error **errp) 341 { 342 int ret; 343 Error *local_err = NULL; 344 345 ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err); 346 if (ret == -ENOENT || ret == -EINVAL) { 347 error_free(local_err); 348 local_err = NULL; 349 ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err); 350 } 351 352 if (local_err) { 353 error_propagate(errp, local_err); 354 } 355 356 return ret; 357 } 358