storage_backend_rbd.c 22.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;
285 286 287 288 289

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

    rbd_image_info_t info;
294 295 296 297
    r = rbd_stat(image, &info, sizeof(info));
    if (r < 0) {
        virReportSystemError(-r, _("failed to stat the RBD image '%s'"),
                             vol->name);
298 299 300 301 302 303 304 305
        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);

306 307
    vol->target.capacity = info.size;
    vol->target.allocation = info.obj_size * info.num_objs;
308 309 310
    vol->type = VIR_STORAGE_VOL_NETWORK;

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

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

    ret = 0;

324
 cleanup:
325 326 327 328
    rbd_close(image);
    return ret;
}

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

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

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

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

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

362 363
    pool->def->capacity = clusterstat.kb * 1024;
    pool->def->available = clusterstat.kb_avail * 1024;
364 365 366
    pool->def->allocation = poolstat.num_bytes;

    VIR_DEBUG("Utilization of RBD pool %s: (kb: %llu kb_avail: %llu num_bytes: %llu)",
367 368
              pool->def->source.name, (unsigned long long)clusterstat.kb,
              (unsigned long long)clusterstat.kb_avail,
369 370 371 372
              (unsigned long long)poolstat.num_bytes);

    while (true) {
        if (VIR_ALLOC_N(names, max_size) < 0)
373
            goto cleanup;
374 375 376 377 378

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

385
    for (name = names; name < names + max_size;) {
386 387 388 389 390
        virStorageVolDefPtr vol;

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

391
        if (VIR_ALLOC(vol) < 0)
392
            goto cleanup;
393

394
        if (VIR_STRDUP(vol->name, name) < 0) {
395
            VIR_FREE(vol);
396
            goto cleanup;
397
        }
398 399 400

        name += strlen(name) + 1;

E
Eric Blake 已提交
401
        if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0) {
402
            virStorageVolDefFree(vol);
403
            goto cleanup;
404
        }
405

406
        if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) {
407
            virStorageVolDefFree(vol);
408 409 410
            virStoragePoolObjClearVols(pool);
            goto cleanup;
        }
411 412
    }

413
    VIR_DEBUG("Found %zu images in RBD pool %s",
414 415 416 417
              pool->volumes.count, pool->def->source.name);

    ret = 0;

418
 cleanup:
419
    VIR_FREE(names);
E
Eric Blake 已提交
420
    virStorageBackendRBDCloseRADOSConn(&ptr);
421 422 423
    return ret;
}

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 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
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;
}

505 506 507 508 509 510
static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
                                         virStoragePoolObjPtr pool,
                                         virStorageVolDefPtr vol,
                                         unsigned int flags)
{
    int ret = -1;
511
    int r = 0;
E
Eric Blake 已提交
512
    virStorageBackendRBDState ptr;
513 514 515
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

516 517 518
    virCheckFlags(VIR_STORAGE_VOL_DELETE_ZEROED |
                  VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS, -1);

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

521
    if (flags & VIR_STORAGE_VOL_DELETE_ZEROED)
522
        VIR_WARN("%s", _("This storage backend does not support zeroed removal of volumes"));
523

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

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

530 531 532 533 534 535 536 537
    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);

538
    r = rbd_remove(ptr.ioctx, vol->name);
539
    if (r < 0 && (-r) != ENOENT) {
540 541
        virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
                             pool->def->source.name, vol->name);
542 543 544 545 546
        goto cleanup;
    }

    ret = 0;

547
 cleanup:
E
Eric Blake 已提交
548
    virStorageBackendRBDCloseRADOSConn(&ptr);
549 550 551
    return ret;
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574

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

    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;
}

575 576 577 578
static int virStorageBackendRBDCreateImage(rados_ioctx_t io,
                                           char *name, long capacity)
{
    int order = 0;
579
    return rbd_create(io, name, capacity, &order);
580
}
581 582 583 584 585 586

static int
virStorageBackendRBDBuildVol(virConnectPtr conn,
                             virStoragePoolObjPtr pool,
                             virStorageVolDefPtr vol,
                             unsigned int flags)
587
{
E
Eric Blake 已提交
588
    virStorageBackendRBDState ptr;
589 590 591
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;
592
    int r = 0;
593 594 595

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

598 599
    virCheckFlags(0, -1);

600 601 602 603 604 605
    if (!vol->target.capacity) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("volume capacity required for this storage pool"));
        goto cleanup;
    }

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

609
    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
610 611 612
        goto cleanup;

    if (vol->target.encryption != NULL) {
613 614
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("storage pool does not support encrypted volumes"));
615 616 617
        goto cleanup;
    }

618 619
    r = virStorageBackendRBDCreateImage(ptr.ioctx, vol->name,
                                        vol->target.capacity);
620 621 622 623
    if (r < 0) {
        virReportSystemError(-r, _("failed to create volume '%s/%s'"),
                             pool->def->source.name,
                             vol->name);
624 625 626 627 628
        goto cleanup;
    }

    ret = 0;

629
 cleanup:
E
Eric Blake 已提交
630
    virStorageBackendRBDCloseRADOSConn(&ptr);
631 632 633 634 635 636 637
    return ret;
}

static int virStorageBackendRBDRefreshVol(virConnectPtr conn,
                                          virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                          virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
638
    virStorageBackendRBDState ptr;
639 640 641 642
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    int ret = -1;

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

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

649
    if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0)
650 651 652 653
        goto cleanup;

    ret = 0;

654
 cleanup:
E
Eric Blake 已提交
655
    virStorageBackendRBDCloseRADOSConn(&ptr);
656 657 658 659 660 661 662 663 664
    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 已提交
665
    virStorageBackendRBDState ptr;
666 667 668 669
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    int ret = -1;
670
    int r = 0;
671 672 673

    virCheckFlags(0, -1);

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

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

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

687 688 689 690
    r = rbd_resize(image, capacity);
    if (r < 0) {
        virReportSystemError(-r, _("failed to resize the RBD image '%s'"),
                             vol->name);
691 692 693 694 695
        goto cleanup;
    }

    ret = 0;

696
 cleanup:
697 698
    if (image != NULL)
       rbd_close(image);
E
Eric Blake 已提交
699
    virStorageBackendRBDCloseRADOSConn(&ptr);
700 701 702 703 704 705 706 707
    return ret;
}

virStorageBackend virStorageBackendRBD = {
    .type = VIR_STORAGE_POOL_RBD,

    .refreshPool = virStorageBackendRBDRefreshPool,
    .createVol = virStorageBackendRBDCreateVol,
708
    .buildVol = virStorageBackendRBDBuildVol,
709 710 711 712
    .refreshVol = virStorageBackendRBDRefreshVol,
    .deleteVol = virStorageBackendRBDDeleteVol,
    .resizeVol = virStorageBackendRBDResizeVol,
};