storage_backend_rbd.c 40.1 KB
Newer Older
1 2 3
/*
 * storage_backend_rbd.c: storage backend for RBD (RADOS Block Device) handling
 *
4
 * Copyright (C) 2013-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2012 Wido den Hollander
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25
 *
 * Author: Wido den Hollander <wido@widodh.nl>
 */

#include <config.h>

26
#include "datatypes.h"
27
#include "virerror.h"
28 29
#include "storage_backend_rbd.h"
#include "storage_conf.h"
30
#include "viralloc.h"
31
#include "virlog.h"
32
#include "base64.h"
33
#include "viruuid.h"
34
#include "virstring.h"
35
#include "virrandom.h"
36 37 38 39 40
#include "rados/librados.h"
#include "rbd/librbd.h"

#define VIR_FROM_THIS VIR_FROM_STORAGE

41 42
VIR_LOG_INIT("storage.storage_backend_rbd");

43 44 45 46 47 48 49
struct _virStorageBackendRBDState {
    rados_t cluster;
    rados_ioctx_t ioctx;
    time_t starttime;
};

typedef struct _virStorageBackendRBDState virStorageBackendRBDState;
E
Eric Blake 已提交
50
typedef virStorageBackendRBDState *virStorageBackendRBDStatePtr;
51

W
Wido den Hollander 已提交
52 53 54 55
static int
virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr,
                                  virConnectPtr conn,
                                  virStoragePoolSourcePtr source)
56 57
{
    int ret = -1;
58
    int r = 0;
59
    virStorageAuthDefPtr authdef = source->auth;
60 61 62 63 64 65
    unsigned char *secret_value = NULL;
    size_t secret_value_size;
    char *rados_key = NULL;
    virBuffer mon_host = VIR_BUFFER_INITIALIZER;
    virSecretPtr secret = NULL;
    char secretUuid[VIR_UUID_STRING_BUFLEN];
66
    size_t i;
67
    char *mon_buff = NULL;
68 69 70
    const char *client_mount_timeout = "30";
    const char *mon_op_timeout = "30";
    const char *osd_op_timeout = "30";
71
    const char *rbd_default_format = "2";
72

73 74
    if (authdef) {
        VIR_DEBUG("Using cephx authorization, username: %s", authdef->username);
W
Wido den Hollander 已提交
75 76

        if ((r = rados_create(&ptr->cluster, authdef->username)) < 0) {
77
            virReportSystemError(-r, "%s", _("failed to initialize RADOS"));
78 79 80
            goto cleanup;
        }

81 82 83 84 85 86 87
        if (!conn) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("'ceph' authentication not supported "
                             "for autostarted pools"));
            return -1;
        }

88 89
        if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
            virUUIDFormat(authdef->secret.uuid, secretUuid);
90 91
            VIR_DEBUG("Looking up secret by UUID: %s", secretUuid);
            secret = virSecretLookupByUUIDString(conn, secretUuid);
92
        } else if (authdef->secret.usage != NULL) {
93
            VIR_DEBUG("Looking up secret by usage: %s",
94
                      authdef->secret.usage);
95
            secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_CEPH,
96
                                            authdef->secret.usage);
97 98 99
        }

        if (secret == NULL) {
100
            if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
101 102
                virReportError(VIR_ERR_NO_SECRET,
                               _("no secret matches uuid '%s'"),
103
                                 secretUuid);
104 105 106
            } else {
                virReportError(VIR_ERR_NO_SECRET,
                               _("no secret matches usage value '%s'"),
107
                                 authdef->secret.usage);
108
            }
109 110 111
            goto cleanup;
        }

112 113
        secret_value = conn->secretDriver->secretGetValue(secret,
                                                          &secret_value_size, 0,
114 115 116
                                                          VIR_SECRET_GET_VALUE_INTERNAL_CALL);

        if (!secret_value) {
117
            if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
118 119 120
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not get the value of the secret "
                                 "for username '%s' using uuid '%s'"),
121
                               authdef->username, secretUuid);
122 123 124 125
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not get the value of the secret "
                                 "for username '%s' using usage value '%s'"),
126
                               authdef->username, authdef->secret.usage);
127
            }
128 129 130
            goto cleanup;
        }

131 132 133 134 135
        base64_encode_alloc((char *)secret_value,
                            secret_value_size, &rados_key);
        memset(secret_value, 0, secret_value_size);

        if (rados_key == NULL) {
136
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
137
                           _("failed to decode the RADOS key"));
138 139 140 141 142
            goto cleanup;
        }

        VIR_DEBUG("Found cephx key: %s", rados_key);
        if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) {
143 144 145
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to set RADOS option: %s"),
                           "rados_key");
146 147 148 149 150 151
            goto cleanup;
        }

        memset(rados_key, 0, strlen(rados_key));

        if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) {
152 153 154
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to set RADOS option: %s"),
                           "auth_supported");
155 156 157 158 159
            goto cleanup;
        }
    } else {
        VIR_DEBUG("Not using cephx authorization");
        if (rados_create(&ptr->cluster, NULL) < 0) {
160
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
161
                           _("failed to create the RADOS cluster"));
162 163 164
            goto cleanup;
        }
        if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) {
165 166 167
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to set RADOS option: %s"),
                           "auth_supported");
168 169 170 171 172
            goto cleanup;
        }
    }

    VIR_DEBUG("Found %zu RADOS cluster monitors in the pool configuration",
173
              source->nhost);
174

175 176 177
    for (i = 0; i < source->nhost; i++) {
        if (source->hosts[i].name != NULL &&
            !source->hosts[i].port) {
178
            virBufferAsprintf(&mon_host, "%s,",
179 180 181
                              source->hosts[i].name);
        } else if (source->hosts[i].name != NULL &&
            source->hosts[i].port) {
182
            virBufferAsprintf(&mon_host, "%s:%d,",
183 184
                              source->hosts[i].name,
                              source->hosts[i].port);
185
        } else {
186 187
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("received malformed monitor, check the XML definition"));
188 189 190
        }
    }

191 192
    if (virBufferCheckError(&mon_host) < 0)
        goto cleanup;
193 194 195 196

    mon_buff = virBufferContentAndReset(&mon_host);
    VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff);
    if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) {
J
Ján Tomko 已提交
197 198 199
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to set RADOS option: %s"),
                       "mon_host");
200 201 202
        goto cleanup;
    }

203 204 205 206 207 208 209 210 211 212 213 214 215 216
    /*
     * Set timeout options for librados.
     * In case the Ceph cluster is down libvirt won't block forever.
     * Operations in librados will return -ETIMEDOUT when the timeout is reached.
     */
    VIR_DEBUG("Setting RADOS option client_mount_timeout to %s", client_mount_timeout);
    rados_conf_set(ptr->cluster, "client_mount_timeout", client_mount_timeout);

    VIR_DEBUG("Setting RADOS option rados_mon_op_timeout to %s", mon_op_timeout);
    rados_conf_set(ptr->cluster, "rados_mon_op_timeout", mon_op_timeout);

    VIR_DEBUG("Setting RADOS option rados_osd_op_timeout to %s", osd_op_timeout);
    rados_conf_set(ptr->cluster, "rados_osd_op_timeout", osd_op_timeout);

217 218 219 220 221 222 223 224
    /*
     * Librbd supports creating RBD format 2 images. We no longer have to invoke
     * rbd_create3(), we can tell librbd to default to format 2.
     * This leaves us to simply use rbd_create() and use the default behavior of librbd
     */
    VIR_DEBUG("Setting RADOS option rbd_default_format to %s", rbd_default_format);
    rados_conf_set(ptr->cluster, "rbd_default_format", rbd_default_format);

225
    ptr->starttime = time(0);
W
Wido den Hollander 已提交
226
    if ((r = rados_connect(ptr->cluster)) < 0) {
227 228
        virReportSystemError(-r, _("failed to connect to the RADOS monitor on: %s"),
                             mon_buff);
229 230 231 232 233
        goto cleanup;
    }

    ret = 0;

234
 cleanup:
235 236
    VIR_FREE(secret_value);
    VIR_FREE(rados_key);
237

238
    virObjectUnref(secret);
239

240 241 242 243 244
    virBufferFreeAndReset(&mon_host);
    VIR_FREE(mon_buff);
    return ret;
}

W
Wido den Hollander 已提交
245 246 247
static int
virStorageBackendRBDOpenIoCTX(virStorageBackendRBDStatePtr ptr,
                              virStoragePoolObjPtr pool)
248 249 250 251 252 253 254 255 256
{
    int r = rados_ioctx_create(ptr->cluster, pool->def->source.name, &ptr->ioctx);
    if (r < 0) {
        virReportSystemError(-r, _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
                             pool->def->source.name);
    }
    return r;
}

W
Wido den Hollander 已提交
257 258
static int
virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
259 260 261
{
    int ret = 0;

E
Eric Blake 已提交
262
    if (ptr->ioctx != NULL) {
263
        VIR_DEBUG("Closing RADOS IoCTX");
E
Eric Blake 已提交
264
        rados_ioctx_destroy(ptr->ioctx);
265 266
        ret = -1;
    }
E
Eric Blake 已提交
267
    ptr->ioctx = NULL;
268

E
Eric Blake 已提交
269
    if (ptr->cluster != NULL) {
270
        VIR_DEBUG("Closing RADOS connection");
E
Eric Blake 已提交
271
        rados_shutdown(ptr->cluster);
272 273
        ret = -2;
    }
E
Eric Blake 已提交
274
    ptr->cluster = NULL;
275

E
Eric Blake 已提交
276
    time_t runtime = time(0) - ptr->starttime;
277 278 279 280 281
    VIR_DEBUG("RADOS connection existed for %ld seconds", runtime);

    return ret;
}

282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
static int
volStorageBackendRBDGetFeatures(rbd_image_t image,
                                const char *volname,
                                uint64_t *features)
{
    int r, ret = -1;

    if ((r = rbd_get_features(image, features)) < 0) {
        virReportSystemError(-r, _("failed to get the features of RBD image "
                                 "%s"), volname);
        goto cleanup;
    }
    ret = 0;

 cleanup:
    return ret;
}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
#if LIBRBD_VERSION_CODE > 265
static bool
volStorageBackendRBDUseFastDiff(uint64_t features)
{
    return features & RBD_FEATURE_FAST_DIFF;
}

static int
virStorageBackendRBDRefreshVolInfoCb(uint64_t offset ATTRIBUTE_UNUSED,
                                     size_t len,
                                     int exists,
                                     void *arg)
{
    uint64_t *used_size = (uint64_t *)(arg);
    if (exists)
        (*used_size) += len;

    return 0;
}

static int
virStorageBackendRBDSetAllocation(virStorageVolDefPtr vol,
                                  rbd_image_t *image,
                                  rbd_image_info_t *info)
{
    int r, ret = -1;
    uint64_t allocation = 0;

    if ((r = rbd_diff_iterate2(image, NULL, 0, info->size, 0, 1,
                               &virStorageBackendRBDRefreshVolInfoCb,
                               &allocation)) < 0) {
        virReportSystemError(-r, _("failed to iterate RBD image '%s'"),
                             vol->name);
        goto cleanup;
    }

    VIR_DEBUG("Found %zu bytes allocated for RBD image %s",
              allocation, vol->name);

    vol->target.allocation = allocation;
    ret = 0;

 cleanup:
    return ret;
}

#else
static int
volStorageBackendRBDUseFastDiff(uint64_t features ATTRIBUTE_UNUSED)
{
    return false;
}

static int
virStorageBackendRBDSetAllocation(virStorageVolDefPtr vol ATTRIBUTE_UNUSED,
                                  rbd_image_t *image ATTRIBUTE_UNUSED,
                                  rbd_image_info_t *info ATTRIBUTE_UNUSED)
{
    return false;
}
#endif

W
Wido den Hollander 已提交
362 363 364 365
static int
volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
                                   virStoragePoolObjPtr pool,
                                   virStorageBackendRBDStatePtr ptr)
366 367
{
    int ret = -1;
368
    int r = 0;
369
    rbd_image_t image = NULL;
W
Wido den Hollander 已提交
370
    rbd_image_info_t info;
371
    uint64_t features;
372

W
Wido den Hollander 已提交
373
    if ((r = rbd_open_read_only(ptr->ioctx, vol->name, &image, NULL)) < 0) {
374
        ret = -r;
375 376
        virReportSystemError(-r, _("failed to open the RBD image '%s'"),
                             vol->name);
377
        goto cleanup;
378 379
    }

W
Wido den Hollander 已提交
380
    if ((r = rbd_stat(image, &info, sizeof(info))) < 0) {
381
        ret = -r;
382 383
        virReportSystemError(-r, _("failed to stat the RBD image '%s'"),
                             vol->name);
384 385 386
        goto cleanup;
    }

387 388
    if (volStorageBackendRBDGetFeatures(image, vol->name, &features) < 0)
        goto cleanup;
389

390
    vol->target.capacity = info.size;
391
    vol->type = VIR_STORAGE_VOL_NETWORK;
392
    vol->target.format = VIR_STORAGE_FILE_RAW;
393

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    if (volStorageBackendRBDUseFastDiff(features)) {
        VIR_DEBUG("RBD image %s/%s has fast-diff feature enabled. "
                  "Querying for actual allocation",
                  pool->def->source.name, vol->name);

        if (virStorageBackendRBDSetAllocation(vol, image, &info) < 0)
            goto cleanup;
    } else {
        vol->target.allocation = info.obj_size * info.num_objs;
    }

    VIR_DEBUG("Refreshed RBD image %s/%s (capacity: %llu allocation: %llu "
                      "obj_size: %zu num_objs: %zu)",
              pool->def->source.name, vol->name, vol->target.capacity,
              vol->target.allocation, info.obj_size, info.num_objs);

410
    VIR_FREE(vol->target.path);
411
    if (virAsprintf(&vol->target.path, "%s/%s",
412
                    pool->def->source.name,
413
                    vol->name) == -1)
414 415 416 417 418
        goto cleanup;

    VIR_FREE(vol->key);
    if (virAsprintf(&vol->key, "%s/%s",
                    pool->def->source.name,
419
                    vol->name) == -1)
420 421 422 423
        goto cleanup;

    ret = 0;

424
 cleanup:
425 426
    if (image)
        rbd_close(image);
427 428 429
    return ret;
}

W
Wido den Hollander 已提交
430 431 432
static int
virStorageBackendRBDRefreshPool(virConnectPtr conn,
                                virStoragePoolObjPtr pool)
433 434 435 436
{
    size_t max_size = 1024;
    int ret = -1;
    int len = -1;
437
    int r = 0;
438
    char *name, *names = NULL;
E
Eric Blake 已提交
439
    virStorageBackendRBDState ptr;
440 441
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
W
Wido den Hollander 已提交
442 443
    struct rados_cluster_stat_t clusterstat;
    struct rados_pool_stat_t poolstat;
444

445
    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
446 447
        goto cleanup;

448
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
449 450
        goto cleanup;

W
Wido den Hollander 已提交
451
    if ((r = rados_cluster_stat(ptr.cluster, &clusterstat)) < 0) {
452
        virReportSystemError(-r, "%s", _("failed to stat the RADOS cluster"));
453 454 455
        goto cleanup;
    }

W
Wido den Hollander 已提交
456
    if ((r = rados_ioctx_pool_stat(ptr.ioctx, &poolstat)) < 0) {
457 458
        virReportSystemError(-r, _("failed to stat the RADOS pool '%s'"),
                             pool->def->source.name);
459 460 461
        goto cleanup;
    }

462 463
    pool->def->capacity = clusterstat.kb * 1024;
    pool->def->available = clusterstat.kb_avail * 1024;
464 465
    pool->def->allocation = poolstat.num_bytes;

466 467 468
    VIR_DEBUG("Utilization of RBD pool %s: (kb: %zu kb_avail: %zu num_bytes: %zu)",
              pool->def->source.name, clusterstat.kb, clusterstat.kb_avail,
              poolstat.num_bytes);
469 470 471

    while (true) {
        if (VIR_ALLOC_N(names, max_size) < 0)
472
            goto cleanup;
473 474 475 476 477

        len = rbd_list(ptr.ioctx, names, &max_size);
        if (len >= 0)
            break;
        if (len != -ERANGE) {
J
Ján Tomko 已提交
478
            VIR_WARN("%s", _("A problem occurred while listing RBD images"));
479 480
            goto cleanup;
        }
481
        VIR_FREE(names);
482 483
    }

484
    for (name = names; name < names + max_size;) {
485 486 487 488 489
        virStorageVolDefPtr vol;

        if (STREQ(name, ""))
            break;

490
        if (VIR_ALLOC(vol) < 0)
491
            goto cleanup;
492

493
        if (VIR_STRDUP(vol->name, name) < 0) {
494
            VIR_FREE(vol);
495
            goto cleanup;
496
        }
497 498 499

        name += strlen(name) + 1;

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
        r = volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr);

        /* It could be that a volume has been deleted through a different route
         * then libvirt and that will cause a -ENOENT to be returned.
         *
         * Another possibility is that there is something wrong with the placement
         * group (PG) that RBD image's header is in and that causes -ETIMEDOUT
         * to be returned.
         *
         * Do not error out and simply ignore the volume
         */
        if (r < 0) {
            if (r == -ENOENT || r == -ETIMEDOUT)
                continue;

515
            virStorageVolDefFree(vol);
516
            goto cleanup;
517
        }
518

519
        if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) {
520
            virStorageVolDefFree(vol);
521 522 523
            virStoragePoolObjClearVols(pool);
            goto cleanup;
        }
524 525
    }

526
    VIR_DEBUG("Found %zu images in RBD pool %s",
527 528 529 530
              pool->volumes.count, pool->def->source.name);

    ret = 0;

531
 cleanup:
532
    VIR_FREE(names);
E
Eric Blake 已提交
533
    virStorageBackendRBDCloseRADOSConn(&ptr);
534 535 536
    return ret;
}

W
Wido den Hollander 已提交
537 538 539 540
static int
virStorageBackendRBDCleanupSnapshots(rados_ioctx_t ioctx,
                                     virStoragePoolSourcePtr source,
                                     virStorageVolDefPtr vol)
541 542 543 544 545 546 547 548 549
{
    int ret = -1;
    int r = 0;
    int max_snaps = 128;
    int snap_count, protected;
    size_t i;
    rbd_snap_info_t *snaps = NULL;
    rbd_image_t image = NULL;

W
Wido den Hollander 已提交
550
    if ((r = rbd_open(ioctx, vol->name, &image, NULL)) < 0) {
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
       virReportSystemError(-r, _("failed to open the RBD image '%s'"),
                            vol->name);
       goto cleanup;
    }

    do {
        if (VIR_ALLOC_N(snaps, max_snaps))
            goto cleanup;

        snap_count = rbd_snap_list(image, snaps, &max_snaps);
        if (snap_count <= 0)
            VIR_FREE(snaps);

    } while (snap_count == -ERANGE);

    VIR_DEBUG("Found %d snapshots for volume %s/%s", snap_count,
              source->name, vol->name);

    if (snap_count > 0) {
        for (i = 0; i < snap_count; i++) {
W
Wido den Hollander 已提交
571
            if ((r = rbd_snap_is_protected(image, snaps[i].name, &protected)) < 0) {
572 573 574 575 576 577 578 579 580 581 582
                virReportSystemError(-r, _("failed to verify if snapshot '%s/%s@%s' is protected"),
                                     source->name, vol->name,
                                     snaps[i].name);
                goto cleanup;
            }

            if (protected == 1) {
                VIR_DEBUG("Snapshot %s/%s@%s is protected needs to be "
                          "unprotected", source->name, vol->name,
                          snaps[i].name);

W
Wido den Hollander 已提交
583
                if ((r = rbd_snap_unprotect(image, snaps[i].name)) < 0) {
584 585 586 587 588 589 590 591 592 593
                    virReportSystemError(-r, _("failed to unprotect snapshot '%s/%s@%s'"),
                                         source->name, vol->name,
                                         snaps[i].name);
                    goto cleanup;
                }
            }

            VIR_DEBUG("Removing snapshot %s/%s@%s", source->name,
                      vol->name, snaps[i].name);

W
Wido den Hollander 已提交
594
            if ((r = rbd_snap_remove(image, snaps[i].name)) < 0) {
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
                virReportSystemError(-r, _("failed to remove snapshot '%s/%s@%s'"),
                                     source->name, vol->name,
                                     snaps[i].name);
                goto cleanup;
            }
        }
    }

    ret = 0;

 cleanup:
    if (snaps)
        rbd_snap_list_end(snaps);

    VIR_FREE(snaps);

    if (image)
        rbd_close(image);

    return ret;
}

W
Wido den Hollander 已提交
617 618 619 620 621
static int
virStorageBackendRBDDeleteVol(virConnectPtr conn,
                              virStoragePoolObjPtr pool,
                              virStorageVolDefPtr vol,
                              unsigned int flags)
622 623
{
    int ret = -1;
624
    int r = 0;
E
Eric Blake 已提交
625
    virStorageBackendRBDState ptr;
626 627 628
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

629 630 631
    virCheckFlags(VIR_STORAGE_VOL_DELETE_ZEROED |
                  VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS, -1);

632 633
    VIR_DEBUG("Removing RBD image %s/%s", pool->def->source.name, vol->name);

634
    if (flags & VIR_STORAGE_VOL_DELETE_ZEROED)
635
        VIR_WARN("%s", _("This storage backend does not support zeroed removal of volumes"));
636

637
    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
638 639
        goto cleanup;

640
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
641 642
        goto cleanup;

643 644 645 646 647 648 649 650
    if (flags & VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS) {
        if (virStorageBackendRBDCleanupSnapshots(ptr.ioctx, &pool->def->source,
                                                 vol) < 0)
            goto cleanup;
    }

    VIR_DEBUG("Removing volume %s/%s", pool->def->source.name, vol->name);

651
    r = rbd_remove(ptr.ioctx, vol->name);
652
    if (r < 0 && (-r) != ENOENT) {
653 654
        virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
                             pool->def->source.name, vol->name);
655 656 657 658 659
        goto cleanup;
    }

    ret = 0;

660
 cleanup:
E
Eric Blake 已提交
661
    virStorageBackendRBDCloseRADOSConn(&ptr);
662 663 664
    return ret;
}

665 666 667 668 669 670 671 672

static int
virStorageBackendRBDCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                              virStoragePoolObjPtr pool,
                              virStorageVolDefPtr vol)
{
    vol->type = VIR_STORAGE_VOL_NETWORK;

673 674 675 676 677 678
    if (vol->target.format != VIR_STORAGE_FILE_RAW) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("only RAW volumes are supported by this storage pool"));
        return -VIR_ERR_NO_SUPPORT;
    }

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
    VIR_FREE(vol->target.path);
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->source.name,
                    vol->name) == -1)
        return -1;

    VIR_FREE(vol->key);
    if (virAsprintf(&vol->key, "%s/%s",
                    pool->def->source.name,
                    vol->name) == -1)
        return -1;

    return 0;
}

694 695 696 697
static int virStorageBackendRBDCreateImage(rados_ioctx_t io,
                                           char *name, long capacity)
{
    int order = 0;
698
    return rbd_create(io, name, capacity, &order);
699
}
700 701 702 703 704 705

static int
virStorageBackendRBDBuildVol(virConnectPtr conn,
                             virStoragePoolObjPtr pool,
                             virStorageVolDefPtr vol,
                             unsigned int flags)
706
{
E
Eric Blake 已提交
707
    virStorageBackendRBDState ptr;
708 709 710
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;
711
    int r = 0;
712 713 714

    VIR_DEBUG("Creating RBD image %s/%s with size %llu",
              pool->def->source.name,
715
              vol->name, vol->target.capacity);
716

717 718
    virCheckFlags(0, -1);

719 720 721 722 723 724
    if (!vol->target.capacity) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("volume capacity required for this storage pool"));
        goto cleanup;
    }

725 726 727 728 729 730
    if (vol->target.format != VIR_STORAGE_FILE_RAW) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("only RAW volumes are supported by this storage pool"));
        goto cleanup;
    }

731
    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
732 733
        goto cleanup;

734
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
735 736 737
        goto cleanup;

    if (vol->target.encryption != NULL) {
738 739
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("storage pool does not support encrypted volumes"));
740 741 742
        goto cleanup;
    }

W
Wido den Hollander 已提交
743 744
    if ((r = virStorageBackendRBDCreateImage(ptr.ioctx, vol->name,
                                             vol->target.capacity)) < 0) {
745 746 747
        virReportSystemError(-r, _("failed to create volume '%s/%s'"),
                             pool->def->source.name,
                             vol->name);
748 749 750 751 752
        goto cleanup;
    }

    ret = 0;

753
 cleanup:
E
Eric Blake 已提交
754
    virStorageBackendRBDCloseRADOSConn(&ptr);
755 756 757
    return ret;
}

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
static int
virStorageBackendRBDImageInfo(rbd_image_t image,
                              char *volname,
                              uint64_t *features,
                              uint64_t *stripe_unit,
                              uint64_t *stripe_count)
{
    int ret = -1;
    int r = 0;
    uint8_t oldformat;

    if ((r = rbd_get_old_format(image, &oldformat)) < 0) {
        virReportSystemError(-r, _("failed to get the format of RBD image %s"),
                             volname);
        goto cleanup;
    }

    if (oldformat != 0) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("RBD image %s is old format. Does not support "
                         "extended features and striping"),
                       volname);
        goto cleanup;
    }

783
    if (volStorageBackendRBDGetFeatures(image, volname, features) < 0)
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
        goto cleanup;

    if ((r = rbd_get_stripe_unit(image, stripe_unit)) < 0) {
        virReportSystemError(-r, _("failed to get the stripe unit of RBD image %s"),
                             volname);
        goto cleanup;
    }

    if ((r = rbd_get_stripe_count(image, stripe_count)) < 0) {
        virReportSystemError(-r, _("failed to get the stripe count of RBD image %s"),
                             volname);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    return ret;
}

/* Callback function for rbd_diff_iterate() */
static int
virStorageBackendRBDIterateCb(uint64_t offset ATTRIBUTE_UNUSED,
                              size_t length ATTRIBUTE_UNUSED,
                              int exists ATTRIBUTE_UNUSED,
                              void *arg)
{
    /*
     * Just set that there is a diff for this snapshot, we do not care where
     *
     * When it returns a negative number the rbd_diff_iterate() function will stop
     *
     * That's why we return -1, meaning that there is a difference and we can stop
     * searching any further.
     */
    *(int*) arg = 1;
    return -1;
}

static int
virStorageBackendRBDSnapshotFindNoDiff(rbd_image_t image,
                                       char *imgname,
                                       virBufferPtr snapname)
{
    int r = -1;
    int ret = -1;
    int snap_count;
    int max_snaps = 128;
    size_t i;
    int diff;
    rbd_snap_info_t *snaps = NULL;
    rbd_image_info_t info;

    if ((r = rbd_stat(image, &info, sizeof(info))) < 0) {
        virReportSystemError(-r, _("failed to stat the RBD image %s"),
                             imgname);
        goto cleanup;
    }

    do {
        if (VIR_ALLOC_N(snaps, max_snaps))
            goto cleanup;

        snap_count = rbd_snap_list(image, snaps, &max_snaps);
        if (snap_count <= 0)
            VIR_FREE(snaps);

    } while (snap_count == -ERANGE);

    if (snap_count <= 0) {
        if (snap_count == 0)
            ret = 0;
        goto cleanup;
    }

    VIR_DEBUG("Found %d snapshots for RBD image %s", snap_count, imgname);

    for (i = 0; i < snap_count; i++) {
        VIR_DEBUG("Querying diff for RBD snapshot %s@%s", imgname,
                  snaps[i].name);

        /* The callback will set diff to non-zero if there is a diff */
        diff = 0;

/*
 * rbd_diff_iterate2() is available in versions above Ceph 0.94 (Hammer)
 * It uses a object map inside Ceph which is faster than rbd_diff_iterate()
 * which iterates all objects.
872 873
 * LIBRBD_VERSION_CODE for Ceph 0.94 is 265. In 266 and upwards diff_iterate2
 * is available
874
 */
875
#if LIBRBD_VERSION_CODE > 265
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        r = rbd_diff_iterate2(image, snaps[i].name, 0, info.size, 0, 1,
                              virStorageBackendRBDIterateCb, (void *)&diff);
#else
        r = rbd_diff_iterate(image, snaps[i].name, 0, info.size,
                             virStorageBackendRBDIterateCb, (void *)&diff);
#endif

        if (r < 0) {
            virReportSystemError(-r, _("failed to iterate RBD snapshot %s@%s"),
                                 imgname, snaps[i].name);
            goto cleanup;
        }

        /* If diff is still set to zero we found a snapshot without deltas */
        if (diff == 0) {
            VIR_DEBUG("RBD snapshot %s@%s has no delta", imgname,
                      snaps[i].name);
            virBufferAsprintf(snapname, "%s", snaps[i].name);
            ret = 0;
            goto cleanup;
        }

        VIR_DEBUG("RBD snapshot %s@%s has deltas. Continuing search.",
                  imgname, snaps[i].name);
    }

    ret = 0;

 cleanup:
    if (snaps)
        rbd_snap_list_end(snaps);

    VIR_FREE(snaps);

    return ret;
}

static int
virStorageBackendRBDSnapshotCreate(rbd_image_t image,
                                   char *imgname,
                                   char *snapname)
{
    int ret = -1;
    int r = -1;

    VIR_DEBUG("Creating RBD snapshot %s@%s", imgname, snapname);

    if ((r = rbd_snap_create(image, snapname)) < 0) {
        virReportSystemError(-r, _("failed to create RBD snapshot %s@%s"),
                                   imgname, snapname);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    return ret;
}

static int
virStorageBackendRBDSnapshotProtect(rbd_image_t image,
                                    char *imgname,
                                    char *snapname)
{
    int r = -1;
    int ret = -1;
    int protected;

    VIR_DEBUG("Querying if RBD snapshot %s@%s is protected", imgname, snapname);

    if ((r = rbd_snap_is_protected(image, snapname, &protected)) < 0) {
        virReportSystemError(-r, _("failed verify if RBD snapshot %s@%s "
                                   "is protected"), imgname, snapname);
        goto cleanup;
    }

    if (protected == 0) {
        VIR_DEBUG("RBD Snapshot %s@%s is not protected, protecting",
                  imgname, snapname);

        if ((r = rbd_snap_protect(image, snapname)) < 0) {
            virReportSystemError(-r, _("failed protect RBD snapshot %s@%s"),
                                       imgname, snapname);
            goto cleanup;
        }
    } else {
        VIR_DEBUG("RBD Snapshot %s@%s is already protected", imgname, snapname);
    }

    ret = 0;

 cleanup:
    return ret;
}

static int
virStorageBackendRBDCloneImage(rados_ioctx_t io,
                               char *origvol,
                               char *newvol)
{
    int r = -1;
    int ret = -1;
    int order = 0;
    uint64_t features;
    uint64_t stripe_count;
    uint64_t stripe_unit;
    virBuffer snapname = VIR_BUFFER_INITIALIZER;
    char *snapname_buff = NULL;
    rbd_image_t image = NULL;

    if ((r = rbd_open(io, origvol, &image, NULL)) < 0) {
        virReportSystemError(-r, _("failed to open the RBD image %s"),
                             origvol);
        goto cleanup;
    }

    if ((virStorageBackendRBDImageInfo(image, origvol, &features, &stripe_unit,
                                       &stripe_count)) < 0)
        goto cleanup;

    /*
     * First we attempt to find a snapshot which has no differences between
     * the current state of the RBD image.
     *
     * This prevents us from creating a new snapshot for every clone operation
     * while it could be that the original volume has not changed
     */
    if (virStorageBackendRBDSnapshotFindNoDiff(image, origvol, &snapname) < 0)
        goto cleanup;

    /*
     * the virBuffer snapname will contain a snapshot's name if one without
     * deltas has been found.
     *
     * If it's NULL we have to create a new snapshot and clone from there
     */
    snapname_buff = virBufferContentAndReset(&snapname);

    if (snapname_buff == NULL) {
        VIR_DEBUG("No RBD snapshot with zero delta could be found for image %s",
                  origvol);

        virBufferAsprintf(&snapname, "libvirt-%d", (int)virRandomInt(65534));

        if (virBufferCheckError(&snapname) < 0)
            goto cleanup;

        snapname_buff = virBufferContentAndReset(&snapname);

        if (virStorageBackendRBDSnapshotCreate(image, origvol, snapname_buff) < 0)
            goto cleanup;

    }

    VIR_DEBUG("Using snapshot name %s for cloning RBD image %s to %s",
              snapname_buff, origvol, newvol);

    /*
     * RBD snapshots have to be 'protected' before they can be used
     * as a parent snapshot for a child image
     */
    if ((r = virStorageBackendRBDSnapshotProtect(image, origvol, snapname_buff)) < 0)
        goto cleanup;

    VIR_DEBUG("Performing RBD clone from %s to %s", origvol, newvol);

    if ((r = rbd_clone2(io, origvol, snapname_buff, io, newvol, features,
                        &order, stripe_unit, stripe_count)) < 0) {
        virReportSystemError(-r, _("failed to clone RBD volume %s to %s"),
                             origvol, newvol);
        goto cleanup;
    }

    VIR_DEBUG("Cloned RBD image %s to %s", origvol, newvol);

    ret = 0;

 cleanup:
    virBufferFreeAndReset(&snapname);
    VIR_FREE(snapname_buff);

    if (image)
        rbd_close(image);

    return ret;
}

static int
virStorageBackendRBDBuildVolFrom(virConnectPtr conn,
                                 virStoragePoolObjPtr pool,
                                 virStorageVolDefPtr newvol,
                                 virStorageVolDefPtr origvol,
                                 unsigned int flags)
{
    virStorageBackendRBDState ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;

    VIR_DEBUG("Creating clone of RBD image %s/%s with name %s",
              pool->def->source.name, origvol->name, newvol->name);

    virCheckFlags(0, -1);

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
        goto cleanup;

    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
        goto cleanup;

    if ((virStorageBackendRBDCloneImage(ptr.ioctx, origvol->name, newvol->name)) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virStorageBackendRBDCloseRADOSConn(&ptr);
    return ret;
}

W
Wido den Hollander 已提交
1096 1097 1098 1099
static int
virStorageBackendRBDRefreshVol(virConnectPtr conn,
                               virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                               virStorageVolDefPtr vol)
1100
{
E
Eric Blake 已提交
1101
    virStorageBackendRBDState ptr;
1102 1103 1104 1105
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;

1106
    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
1107 1108
        goto cleanup;

1109
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
1110 1111
        goto cleanup;

1112
    if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0)
1113 1114 1115 1116
        goto cleanup;

    ret = 0;

1117
 cleanup:
E
Eric Blake 已提交
1118
    virStorageBackendRBDCloseRADOSConn(&ptr);
1119 1120 1121
    return ret;
}

W
Wido den Hollander 已提交
1122 1123 1124 1125 1126 1127
static int
virStorageBackendRBDResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                              virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                              virStorageVolDefPtr vol,
                              unsigned long long capacity,
                              unsigned int flags)
1128
{
E
Eric Blake 已提交
1129
    virStorageBackendRBDState ptr;
1130 1131 1132 1133
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    int ret = -1;
1134
    int r = 0;
1135 1136 1137

    virCheckFlags(0, -1);

1138
    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
1139 1140
        goto cleanup;

1141
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
1142 1143
        goto cleanup;

W
Wido den Hollander 已提交
1144
    if ((r = rbd_open(ptr.ioctx, vol->name, &image, NULL)) < 0) {
1145 1146
       virReportSystemError(-r, _("failed to open the RBD image '%s'"),
                            vol->name);
1147 1148 1149
       goto cleanup;
    }

W
Wido den Hollander 已提交
1150
    if ((r = rbd_resize(image, capacity)) < 0) {
1151 1152
        virReportSystemError(-r, _("failed to resize the RBD image '%s'"),
                             vol->name);
1153 1154 1155 1156 1157
        goto cleanup;
    }

    ret = 0;

1158
 cleanup:
1159 1160
    if (image != NULL)
       rbd_close(image);
E
Eric Blake 已提交
1161
    virStorageBackendRBDCloseRADOSConn(&ptr);
1162 1163 1164
    return ret;
}

1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
static int
virStorageBackendRBDVolWipeZero(rbd_image_t image,
                                char *imgname,
                                rbd_image_info_t *info,
                                uint64_t stripe_count)
{
    int r = -1;
    int ret = -1;
    uint64_t offset = 0;
    uint64_t length;
    char *writebuf;

    if (VIR_ALLOC_N(writebuf, info->obj_size * stripe_count) < 0)
        goto cleanup;

    while (offset < info->size) {
        length = MIN((info->size - offset), (info->obj_size * stripe_count));

        if ((r = rbd_write(image, offset, length, writebuf)) < 0) {
            virReportSystemError(-r, _("writing %zu bytes failed on "
                                       "RBD image %s at offset %zu"),
                                       length, imgname, offset);
            goto cleanup;
        }

        VIR_DEBUG("Wrote %zu bytes to RBD image %s at offset %zu",
                  length, imgname, offset);

        offset += length;
    }

    ret = 0;

 cleanup:
    VIR_FREE(writebuf);

    return ret;
}

1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
static int
virStorageBackendRBDVolWipeDiscard(rbd_image_t image,
                                   char *imgname,
                                   rbd_image_info_t *info,
                                   uint64_t stripe_count)
{
    int r = -1;
    int ret = -1;
    uint64_t offset = 0;
    uint64_t length;

    VIR_DEBUG("Wiping RBD %s volume using discard)", imgname);

    while (offset < info->size) {
        length = MIN((info->size - offset), (info->obj_size * stripe_count));

        if ((r = rbd_discard(image, offset, length)) < 0) {
            virReportSystemError(-r, _("discarding %zu bytes failed on "
                                       "RBD image %s at offset %zu"),
                                     length, imgname, offset);
            goto cleanup;
        }

        VIR_DEBUG("Discarded %zu bytes of RBD image %s at offset %zu",
                  length, imgname, offset);

        offset += length;
    }

    ret = 0;

 cleanup:
    return ret;
}

1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
static int
virStorageBackendRBDVolWipe(virConnectPtr conn,
                            virStoragePoolObjPtr pool,
                            virStorageVolDefPtr vol,
                            unsigned int algorithm,
                            unsigned int flags)
{
    virStorageBackendRBDState ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    rbd_image_info_t info;
    uint64_t stripe_count;
    int r = -1;
    int ret = -1;

    virCheckFlags(0, -1);

    VIR_DEBUG("Wiping RBD image %s/%s", pool->def->source.name, vol->name);

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
        goto cleanup;

    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
        goto cleanup;

    if ((r = rbd_open(ptr.ioctx, vol->name, &image, NULL)) < 0) {
        virReportSystemError(-r, _("failed to open the RBD image %s"),
                             vol->name);
        goto cleanup;
    }

    if ((r = rbd_stat(image, &info, sizeof(info))) < 0) {
        virReportSystemError(-r, _("failed to stat the RBD image %s"),
                             vol->name);
        goto cleanup;
    }

    if ((r = rbd_get_stripe_count(image, &stripe_count)) < 0) {
        virReportSystemError(-r, _("failed to get stripe count of RBD image %s"),
                             vol->name);
        goto cleanup;
    }

    VIR_DEBUG("Need to wipe %zu bytes from RBD image %s/%s",
              info.size, pool->def->source.name, vol->name);

    switch ((virStorageVolWipeAlgorithm) algorithm) {
    case VIR_STORAGE_VOL_WIPE_ALG_ZERO:
        r = virStorageBackendRBDVolWipeZero(image, vol->name,
                                            &info, stripe_count);
1290 1291 1292 1293
            break;
    case VIR_STORAGE_VOL_WIPE_ALG_TRIM:
        r = virStorageBackendRBDVolWipeDiscard(image, vol->name,
                                               &info, stripe_count);
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
        break;
    case VIR_STORAGE_VOL_WIPE_ALG_NNSA:
    case VIR_STORAGE_VOL_WIPE_ALG_DOD:
    case VIR_STORAGE_VOL_WIPE_ALG_BSI:
    case VIR_STORAGE_VOL_WIPE_ALG_GUTMANN:
    case VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER:
    case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7:
    case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33:
    case VIR_STORAGE_VOL_WIPE_ALG_RANDOM:
    case VIR_STORAGE_VOL_WIPE_ALG_LAST:
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported algorithm %d"),
                       algorithm);
        goto cleanup;
    }

    if (r < 0) {
        virReportSystemError(-r, _("failed to wipe RBD image %s"),
                             vol->name);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    if (image)
        rbd_close(image);

    virStorageBackendRBDCloseRADOSConn(&ptr);

    return ret;
}

1326 1327 1328 1329 1330
virStorageBackend virStorageBackendRBD = {
    .type = VIR_STORAGE_POOL_RBD,

    .refreshPool = virStorageBackendRBDRefreshPool,
    .createVol = virStorageBackendRBDCreateVol,
1331
    .buildVol = virStorageBackendRBDBuildVol,
1332
    .buildVolFrom = virStorageBackendRBDBuildVolFrom,
1333 1334 1335
    .refreshVol = virStorageBackendRBDRefreshVol,
    .deleteVol = virStorageBackendRBDDeleteVol,
    .resizeVol = virStorageBackendRBDResizeVol,
1336
    .wipeVol = virStorageBackendRBDVolWipe
1337
};