storage_backend_rbd.c 23.4 KB
Newer Older
1 2 3
/*
 * storage_backend_rbd.c: storage backend for RBD (RADOS Block Device) handling
 *
4
 * Copyright (C) 2013-2015 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 36 37 38 39
#include "rados/librados.h"
#include "rbd/librbd.h"

#define VIR_FROM_THIS VIR_FROM_STORAGE

40 41
VIR_LOG_INIT("storage.storage_backend_rbd");

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

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

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

71 72 73
    if (authdef) {
        VIR_DEBUG("Using cephx authorization, username: %s", authdef->username);
        r = rados_create(&ptr->cluster, authdef->username);
74 75
        if (r < 0) {
            virReportSystemError(-r, "%s", _("failed to initialize RADOS"));
76 77 78
            goto cleanup;
        }

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

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

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

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

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

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

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

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

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

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

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

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

189 190
    if (virBufferCheckError(&mon_host) < 0)
        goto cleanup;
191 192 193 194

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

201 202 203 204 205 206 207 208 209 210 211 212 213 214
    /*
     * 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);

215 216 217 218 219 220 221 222
    /*
     * 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);

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

    ret = 0;

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

237
    virObjectUnref(secret);
238

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

244 245 246 247 248 249 250 251 252 253
static int virStorageBackendRBDOpenIoCTX(virStorageBackendRBDStatePtr ptr, virStoragePoolObjPtr pool)
{
    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;
}

254 255 256 257
static int virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
{
    int ret = 0;

E
Eric Blake 已提交
258
    if (ptr->ioctx != NULL) {
259
        VIR_DEBUG("Closing RADOS IoCTX");
E
Eric Blake 已提交
260
        rados_ioctx_destroy(ptr->ioctx);
261 262
        ret = -1;
    }
E
Eric Blake 已提交
263
    ptr->ioctx = NULL;
264

E
Eric Blake 已提交
265
    if (ptr->cluster != NULL) {
266
        VIR_DEBUG("Closing RADOS connection");
E
Eric Blake 已提交
267
        rados_shutdown(ptr->cluster);
268 269
        ret = -2;
    }
E
Eric Blake 已提交
270
    ptr->cluster = NULL;
271

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

    return ret;
}

static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
                                              virStoragePoolObjPtr pool,
                                              virStorageBackendRBDStatePtr ptr)
{
    int ret = -1;
283
    int r = 0;
284
    rbd_image_t image = NULL;
285 286 287

    r = rbd_open(ptr->ioctx, vol->name, &image, NULL);
    if (r < 0) {
288
        ret = -r;
289 290
        virReportSystemError(-r, _("failed to open the RBD image '%s'"),
                             vol->name);
291
        goto cleanup;
292 293 294
    }

    rbd_image_info_t info;
295 296
    r = rbd_stat(image, &info, sizeof(info));
    if (r < 0) {
297
        ret = -r;
298 299
        virReportSystemError(-r, _("failed to stat the RBD image '%s'"),
                             vol->name);
300 301 302 303 304 305 306 307
        goto cleanup;
    }

    VIR_DEBUG("Refreshed RBD image %s/%s (size: %llu obj_size: %llu num_objs: %llu)",
              pool->def->source.name, vol->name, (unsigned long long)info.size,
              (unsigned long long)info.obj_size,
              (unsigned long long)info.num_objs);

308 309
    vol->target.capacity = info.size;
    vol->target.allocation = info.obj_size * info.num_objs;
310
    vol->type = VIR_STORAGE_VOL_NETWORK;
311
    vol->target.format = VIR_STORAGE_FILE_RAW;
312 313

    VIR_FREE(vol->target.path);
314
    if (virAsprintf(&vol->target.path, "%s/%s",
315
                    pool->def->source.name,
316
                    vol->name) == -1)
317 318 319 320 321
        goto cleanup;

    VIR_FREE(vol->key);
    if (virAsprintf(&vol->key, "%s/%s",
                    pool->def->source.name,
322
                    vol->name) == -1)
323 324 325 326
        goto cleanup;

    ret = 0;

327
 cleanup:
328 329
    if (image)
        rbd_close(image);
330 331 332
    return ret;
}

333
static int virStorageBackendRBDRefreshPool(virConnectPtr conn,
334 335 336 337 338
                                           virStoragePoolObjPtr pool)
{
    size_t max_size = 1024;
    int ret = -1;
    int len = -1;
339
    int r = 0;
340
    char *name, *names = NULL;
E
Eric Blake 已提交
341
    virStorageBackendRBDState ptr;
342 343 344
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

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

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

351
    struct rados_cluster_stat_t clusterstat;
352 353 354
    r = rados_cluster_stat(ptr.cluster, &clusterstat);
    if (r < 0) {
        virReportSystemError(-r, "%s", _("failed to stat the RADOS cluster"));
355 356 357 358
        goto cleanup;
    }

    struct rados_pool_stat_t poolstat;
359 360 361 362
    r = rados_ioctx_pool_stat(ptr.ioctx, &poolstat);
    if (r < 0) {
        virReportSystemError(-r, _("failed to stat the RADOS pool '%s'"),
                             pool->def->source.name);
363 364 365
        goto cleanup;
    }

366 367
    pool->def->capacity = clusterstat.kb * 1024;
    pool->def->available = clusterstat.kb_avail * 1024;
368 369 370
    pool->def->allocation = poolstat.num_bytes;

    VIR_DEBUG("Utilization of RBD pool %s: (kb: %llu kb_avail: %llu num_bytes: %llu)",
371 372
              pool->def->source.name, (unsigned long long)clusterstat.kb,
              (unsigned long long)clusterstat.kb_avail,
373 374 375 376
              (unsigned long long)poolstat.num_bytes);

    while (true) {
        if (VIR_ALLOC_N(names, max_size) < 0)
377
            goto cleanup;
378 379 380 381 382

        len = rbd_list(ptr.ioctx, names, &max_size);
        if (len >= 0)
            break;
        if (len != -ERANGE) {
J
Ján Tomko 已提交
383
            VIR_WARN("%s", _("A problem occurred while listing RBD images"));
384 385
            goto cleanup;
        }
386
        VIR_FREE(names);
387 388
    }

389
    for (name = names; name < names + max_size;) {
390 391 392 393 394
        virStorageVolDefPtr vol;

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

395
        if (VIR_ALLOC(vol) < 0)
396
            goto cleanup;
397

398
        if (VIR_STRDUP(vol->name, name) < 0) {
399
            VIR_FREE(vol);
400
            goto cleanup;
401
        }
402 403 404

        name += strlen(name) + 1;

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
        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;

420
            virStorageVolDefFree(vol);
421
            goto cleanup;
422
        }
423

424
        if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) {
425
            virStorageVolDefFree(vol);
426 427 428
            virStoragePoolObjClearVols(pool);
            goto cleanup;
        }
429 430
    }

431
    VIR_DEBUG("Found %zu images in RBD pool %s",
432 433 434 435
              pool->volumes.count, pool->def->source.name);

    ret = 0;

436
 cleanup:
437
    VIR_FREE(names);
E
Eric Blake 已提交
438
    virStorageBackendRBDCloseRADOSConn(&ptr);
439 440 441
    return ret;
}

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
static int virStorageBackendRBDCleanupSnapshots(rados_ioctx_t ioctx,
                                                virStoragePoolSourcePtr source,
                                                virStorageVolDefPtr vol)
{
    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;

    r = rbd_open(ioctx, vol->name, &image, NULL);
    if (r < 0) {
       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++) {
            if (rbd_snap_is_protected(image, snaps[i].name, &protected)) {
                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);

                if (rbd_snap_unprotect(image, snaps[i].name) < 0) {
                    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);

            r = rbd_snap_remove(image, snaps[i].name);
            if (r < 0) {
                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;
}

523 524 525 526 527 528
static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
                                         virStoragePoolObjPtr pool,
                                         virStorageVolDefPtr vol,
                                         unsigned int flags)
{
    int ret = -1;
529
    int r = 0;
E
Eric Blake 已提交
530
    virStorageBackendRBDState ptr;
531 532 533
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

534 535 536
    virCheckFlags(VIR_STORAGE_VOL_DELETE_ZEROED |
                  VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS, -1);

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

539
    if (flags & VIR_STORAGE_VOL_DELETE_ZEROED)
540
        VIR_WARN("%s", _("This storage backend does not support zeroed removal of volumes"));
541

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

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

548 549 550 551 552 553 554 555
    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);

556
    r = rbd_remove(ptr.ioctx, vol->name);
557
    if (r < 0 && (-r) != ENOENT) {
558 559
        virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
                             pool->def->source.name, vol->name);
560 561 562 563 564
        goto cleanup;
    }

    ret = 0;

565
 cleanup:
E
Eric Blake 已提交
566
    virStorageBackendRBDCloseRADOSConn(&ptr);
567 568 569
    return ret;
}

570 571 572 573 574 575 576 577

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

578 579 580 581 582 583
    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;
    }

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
    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;
}

599 600 601 602
static int virStorageBackendRBDCreateImage(rados_ioctx_t io,
                                           char *name, long capacity)
{
    int order = 0;
603
    return rbd_create(io, name, capacity, &order);
604
}
605 606 607 608 609 610

static int
virStorageBackendRBDBuildVol(virConnectPtr conn,
                             virStoragePoolObjPtr pool,
                             virStorageVolDefPtr vol,
                             unsigned int flags)
611
{
E
Eric Blake 已提交
612
    virStorageBackendRBDState ptr;
613 614 615
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;
616
    int r = 0;
617 618 619

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

622 623
    virCheckFlags(0, -1);

624 625 626 627 628 629
    if (!vol->target.capacity) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("volume capacity required for this storage pool"));
        goto cleanup;
    }

630 631 632 633 634 635
    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;
    }

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

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

    if (vol->target.encryption != NULL) {
643 644
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("storage pool does not support encrypted volumes"));
645 646 647
        goto cleanup;
    }

648 649
    r = virStorageBackendRBDCreateImage(ptr.ioctx, vol->name,
                                        vol->target.capacity);
650 651 652 653
    if (r < 0) {
        virReportSystemError(-r, _("failed to create volume '%s/%s'"),
                             pool->def->source.name,
                             vol->name);
654 655 656 657 658
        goto cleanup;
    }

    ret = 0;

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

static int virStorageBackendRBDRefreshVol(virConnectPtr conn,
                                          virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                          virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
668
    virStorageBackendRBDState ptr;
669 670 671 672
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;

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

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

679
    if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0)
680 681 682 683
        goto cleanup;

    ret = 0;

684
 cleanup:
E
Eric Blake 已提交
685
    virStorageBackendRBDCloseRADOSConn(&ptr);
686 687 688 689 690 691 692 693 694
    return ret;
}

static int virStorageBackendRBDResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
                                     unsigned long long capacity,
                                     unsigned int flags)
{
E
Eric Blake 已提交
695
    virStorageBackendRBDState ptr;
696 697 698 699
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    int ret = -1;
700
    int r = 0;
701 702 703

    virCheckFlags(0, -1);

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

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

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

717 718 719 720
    r = rbd_resize(image, capacity);
    if (r < 0) {
        virReportSystemError(-r, _("failed to resize the RBD image '%s'"),
                             vol->name);
721 722 723 724 725
        goto cleanup;
    }

    ret = 0;

726
 cleanup:
727 728
    if (image != NULL)
       rbd_close(image);
E
Eric Blake 已提交
729
    virStorageBackendRBDCloseRADOSConn(&ptr);
730 731 732 733 734 735 736 737
    return ret;
}

virStorageBackend virStorageBackendRBD = {
    .type = VIR_STORAGE_POOL_RBD,

    .refreshPool = virStorageBackendRBDRefreshPool,
    .createVol = virStorageBackendRBDCreateVol,
738
    .buildVol = virStorageBackendRBDBuildVol,
739 740 741 742
    .refreshVol = virStorageBackendRBDRefreshVol,
    .deleteVol = virStorageBackendRBDDeleteVol,
    .resizeVol = virStorageBackendRBDResizeVol,
};