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>

E
Eric Blake 已提交
26
#include <inttypes.h>
27
#include "datatypes.h"
28
#include "virerror.h"
29 30
#include "storage_backend_rbd.h"
#include "storage_conf.h"
31
#include "viralloc.h"
32
#include "virlog.h"
33
#include "base64.h"
34
#include "viruuid.h"
35
#include "virstring.h"
36
#include "virrandom.h"
37 38 39 40 41
#include "rados/librados.h"
#include "rbd/librbd.h"

#define VIR_FROM_THIS VIR_FROM_STORAGE

42 43
VIR_LOG_INIT("storage.storage_backend_rbd");

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

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

W
Wido den Hollander 已提交
53 54 55 56
static int
virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr,
                                  virConnectPtr conn,
                                  virStoragePoolSourcePtr source)
57 58
{
    int ret = -1;
59
    int r = 0;
60
    virStorageAuthDefPtr authdef = source->auth;
61 62 63 64 65 66
    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];
67
    size_t i;
68
    char *mon_buff = NULL;
69 70 71
    const char *client_mount_timeout = "30";
    const char *mon_op_timeout = "30";
    const char *osd_op_timeout = "30";
72
    const char *rbd_default_format = "2";
73

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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 已提交
198 199 200
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to set RADOS option: %s"),
                       "mon_host");
201 202 203
        goto cleanup;
    }

204 205 206 207 208 209 210 211 212 213 214 215 216 217
    /*
     * 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);

218 219 220 221 222 223 224 225
    /*
     * 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);

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

    ret = 0;

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

239
    virObjectUnref(secret);
240

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

W
Wido den Hollander 已提交
246 247 248
static int
virStorageBackendRBDOpenIoCTX(virStorageBackendRBDStatePtr ptr,
                              virStoragePoolObjPtr pool)
249 250 251 252 253 254 255 256 257
{
    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 已提交
258 259
static int
virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
260 261 262
{
    int ret = 0;

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

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

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

    return ret;
}

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
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;
}

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

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

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

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

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

395 396 397 398 399 400 401 402 403 404 405 406
    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 "
E
Eric Blake 已提交
407
                      "obj_size: %"PRIu64" num_objs: %"PRIu64")",
408 409 410
              pool->def->source.name, vol->name, vol->target.capacity,
              vol->target.allocation, info.obj_size, info.num_objs);

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

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

    ret = 0;

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

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

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

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

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

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

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

E
Eric Blake 已提交
467 468
    VIR_DEBUG("Utilization of RBD pool %s: (kb: %"PRIu64" kb_avail: %"PRIu64
              " num_bytes: %"PRIu64")",
469 470
              pool->def->source.name, clusterstat.kb, clusterstat.kb_avail,
              poolstat.num_bytes);
471 472 473

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

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

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

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

492
        if (VIR_ALLOC(vol) < 0)
493
            goto cleanup;
494

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

        name += strlen(name) + 1;

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
        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;

517
            virStorageVolDefFree(vol);
518
            goto cleanup;
519
        }
520

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

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

    ret = 0;

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

W
Wido den Hollander 已提交
539 540 541 542
static int
virStorageBackendRBDCleanupSnapshots(rados_ioctx_t ioctx,
                                     virStoragePoolSourcePtr source,
                                     virStorageVolDefPtr vol)
543 544 545 546 547 548 549 550 551
{
    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 已提交
552
    if ((r = rbd_open(ioctx, vol->name, &image, NULL)) < 0) {
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);

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

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

584 585
            if ((r = rbd_snap_unprotect(image, snaps[i].name)) < 0) {
                virReportSystemError(-r, _("failed to unprotect snapshot '%s/%s@%s'"),
586 587 588 589 590
                                     source->name, vol->name,
                                     snaps[i].name);
                goto cleanup;
            }
        }
591 592 593 594 595 596 597 598 599 600

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

        if ((r = rbd_snap_remove(image, snaps[i].name)) < 0) {
            virReportSystemError(-r, _("failed to remove snapshot '%s/%s@%s'"),
                                 source->name, vol->name,
                                 snaps[i].name);
            goto cleanup;
        }
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
    }

    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
static int
virStorageBackendRBDVolWipeZero(rbd_image_t image,
                                char *imgname,
                                rbd_image_info_t *info,
                                uint64_t stripe_count)
{
    int r = -1;
    int ret = -1;
E
Eric Blake 已提交
1173 1174
    unsigned long long offset = 0;
    unsigned long long length;
1175 1176 1177 1178 1179 1180 1181 1182 1183
    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) {
E
Eric Blake 已提交
1184 1185
            virReportSystemError(-r, _("writing %llu bytes failed on "
                                       "RBD image %s at offset %llu"),
1186 1187 1188 1189
                                       length, imgname, offset);
            goto cleanup;
        }

E
Eric Blake 已提交
1190
        VIR_DEBUG("Wrote %llu bytes to RBD image %s at offset %llu",
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
                  length, imgname, offset);

        offset += length;
    }

    ret = 0;

 cleanup:
    VIR_FREE(writebuf);

    return ret;
}

1204 1205 1206 1207 1208 1209 1210 1211
static int
virStorageBackendRBDVolWipeDiscard(rbd_image_t image,
                                   char *imgname,
                                   rbd_image_info_t *info,
                                   uint64_t stripe_count)
{
    int r = -1;
    int ret = -1;
E
Eric Blake 已提交
1212 1213
    unsigned long long offset = 0;
    unsigned long long length;
1214 1215 1216 1217 1218 1219 1220

    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) {
E
Eric Blake 已提交
1221 1222
            virReportSystemError(-r, _("discarding %llu bytes failed on "
                                       "RBD image %s at offset %llu"),
1223 1224 1225 1226
                                     length, imgname, offset);
            goto cleanup;
        }

E
Eric Blake 已提交
1227
        VIR_DEBUG("Discarded %llu bytes of RBD image %s at offset %llu",
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
                  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
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;
    }

E
Eric Blake 已提交
1283
    VIR_DEBUG("Need to wipe %"PRIu64" bytes from RBD image %s/%s",
1284 1285 1286 1287 1288 1289
              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
};