storage_driver.c 51.7 KB
Newer Older
1 2 3
/*
 * storage_driver.c: core driver for storage APIs
 *
4
 * Copyright (C) 2006-2009 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
R
Richard W.M. Jones 已提交
29
#if HAVE_PWD_H
30
#include <pwd.h>
R
Richard W.M. Jones 已提交
31
#endif
32 33 34
#include <errno.h>
#include <string.h>

35
#include "virterror_internal.h"
36
#include "datatypes.h"
37 38 39 40
#include "driver.h"
#include "util.h"
#include "storage_driver.h"
#include "storage_conf.h"
41
#include "memory.h"
42
#include "storage_backend.h"
43
#include "logging.h"
44

45 46
#define VIR_FROM_THIS VIR_FROM_STORAGE

47 48 49 50
static virStorageDriverStatePtr driverState;

static int storageDriverShutdown(void);

51 52
static void storageDriverLock(virStorageDriverStatePtr driver)
{
53
    virMutexLock(&driver->lock);
54 55 56
}
static void storageDriverUnlock(virStorageDriverStatePtr driver)
{
57
    virMutexUnlock(&driver->lock);
58
}
59 60 61

static void
storageDriverAutostart(virStorageDriverStatePtr driver) {
62
    unsigned int i;
63

64 65
    for (i = 0 ; i < driver->pools.count ; i++) {
        virStoragePoolObjPtr pool = driver->pools.objs[i];
66

67
        virStoragePoolObjLock(pool);
68 69 70 71
        if (pool->autostart &&
            !virStoragePoolObjIsActive(pool)) {
            virStorageBackendPtr backend;
            if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
72
                VIR_ERROR("Missing backend %d", pool->def->type);
73
                virStoragePoolObjUnlock(pool);
74 75 76 77 78 79
                continue;
            }

            if (backend->startPool &&
                backend->startPool(NULL, pool) < 0) {
                virErrorPtr err = virGetLastError();
80 81 82
                VIR_ERROR("Failed to autostart storage pool '%s': %s",
                          pool->def->name, err ? err->message :
                          "no error message found");
83
                virStoragePoolObjUnlock(pool);
84 85 86 87 88 89 90
                continue;
            }

            if (backend->refreshPool(NULL, pool) < 0) {
                virErrorPtr err = virGetLastError();
                if (backend->stopPool)
                    backend->stopPool(NULL, pool);
91 92 93
                VIR_ERROR("Failed to autostart storage pool '%s': %s",
                          pool->def->name, err ? err->message :
                          "no error message found");
94
                virStoragePoolObjUnlock(pool);
95 96 97 98
                continue;
            }
            pool->active = 1;
        }
99
        virStoragePoolObjUnlock(pool);
100 101 102 103 104 105 106 107 108
    }
}

/**
 * virStorageStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
109
storageDriverStartup(int privileged) {
110 111 112
    char *base = NULL;
    char driverConf[PATH_MAX];

113
    if (VIR_ALLOC(driverState) < 0)
114 115
        return -1;

116 117 118 119
    if (virMutexInit(&driverState->lock) < 0) {
        VIR_FREE(driverState);
        return -1;
    }
120 121
    storageDriverLock(driverState);

122
    if (privileged) {
123 124 125
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
            goto out_of_memory;
    } else {
126
        uid_t uid = geteuid();
127 128 129 130
        char *userdir = virGetUserDirectory(NULL, uid);

        if (!userdir)
            goto error;
131

132 133
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
134 135
            goto out_of_memory;
        }
136
        VIR_FREE(userdir);
137 138 139 140 141 142 143 144 145 146
    }

    /* Configuration paths are either ~/.libvirt/storage/... (session) or
     * /etc/libvirt/storage/... (system).
     */
    if (snprintf (driverConf, sizeof(driverConf),
                  "%s/storage.conf", base) == -1)
        goto out_of_memory;
    driverConf[sizeof(driverConf)-1] = '\0';

147 148
    if (virAsprintf(&driverState->configDir,
                    "%s/storage", base) == -1)
149 150
        goto out_of_memory;

151 152
    if (virAsprintf(&driverState->autostartDir,
                    "%s/storage/autostart", base) == -1)
153 154
        goto out_of_memory;

155
    VIR_FREE(base);
156 157 158 159 160 161 162 163

    /*
    if (virStorageLoadDriverConfig(driver, driverConf) < 0) {
        virStorageDriverShutdown();
        return -1;
    }
    */

164 165 166
    if (virStoragePoolLoadAllConfigs(NULL,
                                     &driverState->pools,
                                     driverState->configDir,
167 168
                                     driverState->autostartDir) < 0)
        goto error;
169 170
    storageDriverAutostart(driverState);

171
    storageDriverUnlock(driverState);
172 173
    return 0;

174
out_of_memory:
175
    virReportOOMError();
176 177 178 179
error:
    VIR_FREE(base);
    storageDriverUnlock(driverState);
    storageDriverShutdown();
180 181 182 183 184 185 186 187 188 189 190
    return -1;
}

/**
 * virStorageReload:
 *
 * Function to restart the storage driver, it will recheck the configuration
 * files and update its state
 */
static int
storageDriverReload(void) {
191 192 193
    if (!driverState)
        return -1;

194
    storageDriverLock(driverState);
195 196 197 198
    virStoragePoolLoadAllConfigs(NULL,
                                 &driverState->pools,
                                 driverState->configDir,
                                 driverState->autostartDir);
199
    storageDriverAutostart(driverState);
200
    storageDriverUnlock(driverState);
201 202 203 204 205 206 207 208 209 210 211 212 213

    return 0;
}

/**
 * virStorageActive:
 *
 * Checks if the storage driver is active, i.e. has an active pool
 *
 * Returns 1 if active, 0 otherwise
 */
static int
storageDriverActive(void) {
214
    unsigned int i;
215
    int active = 0;
216 217 218 219

    if (!driverState)
        return 0;

220 221 222 223
    storageDriverLock(driverState);

    for (i = 0 ; i < driverState->pools.count ; i++) {
        virStoragePoolObjLock(driverState->pools.objs[i]);
224
        if (virStoragePoolObjIsActive(driverState->pools.objs[i]))
225 226 227
            active = 1;
        virStoragePoolObjUnlock(driverState->pools.objs[i]);
    }
228

229 230
    storageDriverUnlock(driverState);
    return active;
231 232 233 234 235 236 237 238 239 240 241 242
}

/**
 * virStorageShutdown:
 *
 * Shutdown the storage driver, it will stop all active storage pools
 */
static int
storageDriverShutdown(void) {
    if (!driverState)
        return -1;

243
    storageDriverLock(driverState);
244 245

    /* free inactive pools */
246 247 248 249
    virStoragePoolObjListFree(&driverState->pools);

    VIR_FREE(driverState->configDir);
    VIR_FREE(driverState->autostartDir);
250
    storageDriverUnlock(driverState);
251
    virMutexDestroy(&driverState->lock);
252
    VIR_FREE(driverState);
253 254 255 256 257 258 259 260 261

    return 0;
}



static virStoragePoolPtr
storagePoolLookupByUUID(virConnectPtr conn,
                        const unsigned char *uuid) {
262 263 264
    virStorageDriverStatePtr driver = conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    virStoragePoolPtr ret = NULL;
265

266
    storageDriverLock(driver);
267
    pool = virStoragePoolObjFindByUUID(&driver->pools, uuid);
268 269
    storageDriverUnlock(driver);

270 271
    if (!pool) {
        virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL,
J
Jim Meyering 已提交
272
                              "%s", _("no pool with matching uuid"));
273
        goto cleanup;
274 275 276
    }

    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
277 278

cleanup:
279 280
    if (pool)
        virStoragePoolObjUnlock(pool);
281 282 283 284 285 286
    return ret;
}

static virStoragePoolPtr
storagePoolLookupByName(virConnectPtr conn,
                        const char *name) {
287 288 289
    virStorageDriverStatePtr driver = conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    virStoragePoolPtr ret = NULL;
290

291
    storageDriverLock(driver);
292
    pool = virStoragePoolObjFindByName(&driver->pools, name);
293 294
    storageDriverUnlock(driver);

295 296
    if (!pool) {
        virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL,
297
                              _("no pool with matching name '%s'"), name);
298
        goto cleanup;
299 300 301
    }

    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
302 303

cleanup:
304 305
    if (pool)
        virStoragePoolObjUnlock(pool);
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
    return ret;
}

static virStoragePoolPtr
storagePoolLookupByVolume(virStorageVolPtr vol) {
    return storagePoolLookupByName(vol->conn, vol->pool);
}

static virDrvOpenStatus
storageOpen(virConnectPtr conn,
            virConnectAuthPtr auth ATTRIBUTE_UNUSED,
            int flags ATTRIBUTE_UNUSED) {
    if (!driverState)
        return VIR_DRV_OPEN_DECLINED;

    conn->storagePrivateData = driverState;
    return VIR_DRV_OPEN_SUCCESS;
}

static int
storageClose(virConnectPtr conn) {
    conn->storagePrivateData = NULL;
    return 0;
}

static int
storageNumPools(virConnectPtr conn) {
333
    virStorageDriverStatePtr driver = conn->storagePrivateData;
334 335
    unsigned int i, nactive = 0;

336 337 338
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
339 340
        if (virStoragePoolObjIsActive(driver->pools.objs[i]))
            nactive++;
341 342 343
        virStoragePoolObjUnlock(driver->pools.objs[i]);
    }
    storageDriverUnlock(driver);
344 345

    return nactive;
346 347 348 349 350 351
}

static int
storageListPools(virConnectPtr conn,
                 char **const names,
                 int nnames) {
352
    virStorageDriverStatePtr driver = conn->storagePrivateData;
353
    int got = 0, i;
354

355
    storageDriverLock(driver);
356
    for (i = 0 ; i < driver->pools.count && got < nnames ; i++) {
357
        virStoragePoolObjLock(driver->pools.objs[i]);
358 359
        if (virStoragePoolObjIsActive(driver->pools.objs[i])) {
            if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) {
360
                virStoragePoolObjUnlock(driver->pools.objs[i]);
361
                virReportOOMError();
362 363 364 365
                goto cleanup;
            }
            got++;
        }
366
        virStoragePoolObjUnlock(driver->pools.objs[i]);
367
    }
368
    storageDriverUnlock(driver);
369 370 371
    return got;

 cleanup:
372 373 374
    storageDriverUnlock(driver);
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
375
    memset(names, 0, nnames * sizeof(*names));
376 377 378 379 380
    return -1;
}

static int
storageNumDefinedPools(virConnectPtr conn) {
381
    virStorageDriverStatePtr driver = conn->storagePrivateData;
382 383
    unsigned int i, nactive = 0;

384 385 386
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
387 388
        if (!virStoragePoolObjIsActive(driver->pools.objs[i]))
            nactive++;
389 390 391
        virStoragePoolObjUnlock(driver->pools.objs[i]);
    }
    storageDriverUnlock(driver);
392 393

    return nactive;
394 395 396 397 398 399
}

static int
storageListDefinedPools(virConnectPtr conn,
                        char **const names,
                        int nnames) {
400
    virStorageDriverStatePtr driver = conn->storagePrivateData;
401
    int got = 0, i;
402

403
    storageDriverLock(driver);
404
    for (i = 0 ; i < driver->pools.count && got < nnames ; i++) {
405
        virStoragePoolObjLock(driver->pools.objs[i]);
406 407
        if (!virStoragePoolObjIsActive(driver->pools.objs[i])) {
            if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) {
408
                virStoragePoolObjUnlock(driver->pools.objs[i]);
409
                virReportOOMError();
410 411 412 413
                goto cleanup;
            }
            got++;
        }
414
        virStoragePoolObjUnlock(driver->pools.objs[i]);
415
    }
416
    storageDriverUnlock(driver);
417 418 419
    return got;

 cleanup:
420
    storageDriverUnlock(driver);
421
    for (i = 0 ; i < got ; i++) {
422
        VIR_FREE(names[i]);
423
    }
424
    memset(names, 0, nnames * sizeof(*names));
425 426 427
    return -1;
}

428 429
/* This method is required to be re-entrant / thread safe, so
   uses no driver lock */
430 431 432 433 434 435 436 437
static char *
storageFindPoolSources(virConnectPtr conn,
                       const char *type,
                       const char *srcSpec,
                       unsigned int flags)
{
    int backend_type;
    virStorageBackendPtr backend;
438
    char *ret = NULL;
439

440
    backend_type = virStoragePoolTypeFromString(type);
441 442 443
    if (backend_type < 0) {
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("unknown storage pool type %s"), type);
444
        goto cleanup;
445
    }
446 447 448

    backend = virStorageBackendForType(backend_type);
    if (backend == NULL)
449
        goto cleanup;
450

451 452 453 454 455 456 457 458
    if (!backend->findPoolSources) {
        virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
                              _("pool type '%s' does not support source "
                                "discovery"), type);
        goto cleanup;
    }

    ret = backend->findPoolSources(conn, srcSpec, flags);
459

460 461
cleanup:
    return ret;
462 463 464
}


465
static int storagePoolIsActive(virStoragePoolPtr pool)
466
{
467
    virStorageDriverStatePtr driver = pool->conn->storagePrivateData;
468 469 470 471
    virStoragePoolObjPtr obj;
    int ret = -1;

    storageDriverLock(driver);
472
    obj = virStoragePoolObjFindByUUID(&driver->pools, pool->uuid);
473 474
    storageDriverUnlock(driver);
    if (!obj) {
475
        virStorageReportError(pool->conn, VIR_ERR_NO_STORAGE_POOL, NULL);
476 477 478 479 480 481 482 483 484 485
        goto cleanup;
    }
    ret = virStoragePoolObjIsActive(obj);

cleanup:
    if (obj)
        virStoragePoolObjUnlock(obj);
    return ret;
}

486
static int storagePoolIsPersistent(virStoragePoolPtr pool)
487
{
488
    virStorageDriverStatePtr driver = pool->conn->storagePrivateData;
489 490 491 492
    virStoragePoolObjPtr obj;
    int ret = -1;

    storageDriverLock(driver);
493
    obj = virStoragePoolObjFindByUUID(&driver->pools, pool->uuid);
494 495
    storageDriverUnlock(driver);
    if (!obj) {
496
        virStorageReportError(pool->conn, VIR_ERR_NO_STORAGE_POOL, NULL);
497 498 499 500 501 502 503 504 505 506 507
        goto cleanup;
    }
    ret = obj->configFile ? 1 : 0;

cleanup:
    if (obj)
        virStoragePoolObjUnlock(obj);
    return ret;
}


508 509 510 511
static virStoragePoolPtr
storagePoolCreate(virConnectPtr conn,
                  const char *xml,
                  unsigned int flags ATTRIBUTE_UNUSED) {
512
    virStorageDriverStatePtr driver = conn->storagePrivateData;
513
    virStoragePoolDefPtr def;
514
    virStoragePoolObjPtr pool = NULL;
515
    virStoragePoolPtr ret = NULL;
516 517
    virStorageBackendPtr backend;

518
    storageDriverLock(driver);
519
    if (!(def = virStoragePoolDefParseString(conn, xml)))
520
        goto cleanup;
521

522 523 524 525 526
    pool = virStoragePoolObjFindByUUID(&driver->pools, def->uuid);
    if (!pool)
        pool = virStoragePoolObjFindByName(&driver->pools, def->name);

    if (pool) {
527
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
528
                              "%s", _("storage pool already exists"));
529 530
        virStoragePoolObjUnlock(pool);
        pool = NULL;
531
        goto cleanup;
532 533
    }

534 535
    if ((backend = virStorageBackendForType(def->type)) == NULL)
        goto cleanup;
536

537 538 539
    if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def)))
        goto cleanup;
    def = NULL;
540

541
    if (backend->startPool &&
542 543 544
        backend->startPool(conn, pool) < 0) {
        virStoragePoolObjRemove(&driver->pools, pool);
        pool = NULL;
545
        goto cleanup;
546
    }
547

548 549 550
    if (backend->refreshPool(conn, pool) < 0) {
        if (backend->stopPool)
            backend->stopPool(conn, pool);
551 552
        virStoragePoolObjRemove(&driver->pools, pool);
        pool = NULL;
553
        goto cleanup;
554 555 556 557 558
    }
    pool->active = 1;

    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);

559 560
cleanup:
    virStoragePoolDefFree(def);
561
    if (pool)
562
        virStoragePoolObjUnlock(pool);
563
    storageDriverUnlock(driver);
564 565 566 567 568 569 570
    return ret;
}

static virStoragePoolPtr
storagePoolDefine(virConnectPtr conn,
                  const char *xml,
                  unsigned int flags ATTRIBUTE_UNUSED) {
571
    virStorageDriverStatePtr driver = conn->storagePrivateData;
572
    virStoragePoolDefPtr def;
573
    virStoragePoolObjPtr pool = NULL;
574
    virStoragePoolPtr ret = NULL;
575

576
    storageDriverLock(driver);
577
    if (!(def = virStoragePoolDefParseString(conn, xml)))
578
        goto cleanup;
579

580
    if (virStorageBackendForType(def->type) == NULL)
581
        goto cleanup;
582

583 584
    if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def)))
        goto cleanup;
585 586

    if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) {
587
        virStoragePoolObjRemove(&driver->pools, pool);
588
        def = NULL;
589
        goto cleanup;
590
    }
591
    def = NULL;
592 593

    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
594 595 596

cleanup:
    virStoragePoolDefFree(def);
597 598 599
    if (pool)
        virStoragePoolObjUnlock(pool);
    storageDriverUnlock(driver);
600 601 602 603 604
    return ret;
}

static int
storagePoolUndefine(virStoragePoolPtr obj) {
605 606 607
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
608

609
    storageDriverLock(driver);
610
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
611 612
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
613
                              "%s", _("no storage pool with matching uuid"));
614
        goto cleanup;
615 616 617 618
    }

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
619
                              "%s", _("pool is still active"));
620
        goto cleanup;
621 622
    }

623 624 625 626 627 628 629
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

630
    if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0)
631
        goto cleanup;
632

633 634
    if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
        char ebuf[1024];
635
        VIR_ERROR("Failed to delete autostart link '%s': %s",
636 637
                   pool->autostartLink, virStrerror(errno, ebuf, sizeof ebuf));
    }
638

639 640
    VIR_FREE(pool->configFile);
    VIR_FREE(pool->autostartLink);
641

642
    virStoragePoolObjRemove(&driver->pools, pool);
643
    pool = NULL;
644
    ret = 0;
645

646
cleanup:
647 648 649
    if (pool)
        virStoragePoolObjUnlock(pool);
    storageDriverUnlock(driver);
650
    return ret;
651 652 653 654 655
}

static int
storagePoolStart(virStoragePoolPtr obj,
                 unsigned int flags ATTRIBUTE_UNUSED) {
656 657
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
658
    virStorageBackendPtr backend;
659
    int ret = -1;
660

661
    storageDriverLock(driver);
662
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
663 664
    storageDriverUnlock(driver);

665 666
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
667
                              "%s", _("no storage pool with matching uuid"));
668
        goto cleanup;
669 670
    }

671 672
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
673 674 675

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
676
                              "%s", _("pool already active"));
677
        goto cleanup;
678 679 680
    }
    if (backend->startPool &&
        backend->startPool(obj->conn, pool) < 0)
681 682
        goto cleanup;

683 684 685
    if (backend->refreshPool(obj->conn, pool) < 0) {
        if (backend->stopPool)
            backend->stopPool(obj->conn, pool);
686
        goto cleanup;
687 688 689
    }

    pool->active = 1;
690
    ret = 0;
691

692
cleanup:
693 694
    if (pool)
        virStoragePoolObjUnlock(pool);
695
    return ret;
696 697 698 699 700
}

static int
storagePoolBuild(virStoragePoolPtr obj,
                 unsigned int flags) {
701 702
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
703
    virStorageBackendPtr backend;
704
    int ret = -1;
705

706
    storageDriverLock(driver);
707
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
708 709
    storageDriverUnlock(driver);

710 711
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
712
                              "%s", _("no storage pool with matching uuid"));
713
        goto cleanup;
714 715
    }

716 717
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
718 719 720

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
721
                              "%s", _("storage pool is already active"));
722
        goto cleanup;
723 724 725 726
    }

    if (backend->buildPool &&
        backend->buildPool(obj->conn, pool, flags) < 0)
727 728
        goto cleanup;
    ret = 0;
729

730
cleanup:
731 732
    if (pool)
        virStoragePoolObjUnlock(pool);
733
    return ret;
734 735 736 737 738
}


static int
storagePoolDestroy(virStoragePoolPtr obj) {
739 740
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
741
    virStorageBackendPtr backend;
742
    int ret = -1;
743

744
    storageDriverLock(driver);
745
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
746

747 748
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
749
                              "%s", _("no storage pool with matching uuid"));
750
        goto cleanup;
751 752
    }

753 754
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
755 756 757

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
758
                              "%s", _("storage pool is not active"));
759
        goto cleanup;
760 761
    }

762 763 764 765 766 767 768
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

769 770
    if (backend->stopPool &&
        backend->stopPool(obj->conn, pool) < 0)
771
        goto cleanup;
772 773 774 775 776

    virStoragePoolObjClearVols(pool);

    pool->active = 0;

777
    if (pool->configFile == NULL) {
778
        virStoragePoolObjRemove(&driver->pools, pool);
779 780
        pool = NULL;
    }
781
    ret = 0;
782

783
cleanup:
784 785 786
    if (pool)
        virStoragePoolObjUnlock(pool);
    storageDriverUnlock(driver);
787
    return ret;
788 789 790 791 792 793
}


static int
storagePoolDelete(virStoragePoolPtr obj,
                  unsigned int flags) {
794 795
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
796
    virStorageBackendPtr backend;
797
    int ret = -1;
798

799
    storageDriverLock(driver);
800
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
801 802
    storageDriverUnlock(driver);

803 804
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
805
                              "%s", _("no storage pool with matching uuid"));
806
        goto cleanup;
807 808
    }

809 810
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
811 812 813

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
814
                              "%s", _("storage pool is still active"));
815
        goto cleanup;
816 817
    }

818 819 820 821 822 823 824
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

825 826
    if (!backend->deletePool) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
827
                              "%s", _("pool does not support volume delete"));
828
        goto cleanup;
829 830
    }
    if (backend->deletePool(obj->conn, pool, flags) < 0)
831 832
        goto cleanup;
    ret = 0;
833

834
cleanup:
835 836
    if (pool)
        virStoragePoolObjUnlock(pool);
837
    return ret;
838 839 840 841 842 843
}


static int
storagePoolRefresh(virStoragePoolPtr obj,
                   unsigned int flags ATTRIBUTE_UNUSED) {
844 845
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
846
    virStorageBackendPtr backend;
847
    int ret = -1;
848

849
    storageDriverLock(driver);
850
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
851

852 853
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
854
                              "%s", _("no storage pool with matching uuid"));
855
        goto cleanup;
856 857
    }

858 859
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
860 861 862

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
863
                              "%s", _("storage pool is not active"));
864
        goto cleanup;
865 866
    }

867 868 869 870 871 872 873
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

874
    virStoragePoolObjClearVols(pool);
875
    if (backend->refreshPool(obj->conn, pool) < 0) {
876 877 878 879 880
        if (backend->stopPool)
            backend->stopPool(obj->conn, pool);

        pool->active = 0;

881
        if (pool->configFile == NULL) {
882
            virStoragePoolObjRemove(&driver->pools, pool);
883 884
            pool = NULL;
        }
885
        goto cleanup;
886
    }
887
    ret = 0;
888

889
cleanup:
890 891
    if (pool)
        virStoragePoolObjUnlock(pool);
892
    storageDriverUnlock(driver);
893 894 895 896 897 898 899
    return ret;
}


static int
storagePoolGetInfo(virStoragePoolPtr obj,
                   virStoragePoolInfoPtr info) {
900 901 902
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
903

904
    storageDriverLock(driver);
905
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
906 907
    storageDriverUnlock(driver);

908 909
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
910
                              "%s", _("no storage pool with matching uuid"));
911
        goto cleanup;
912 913
    }

914
    if (virStorageBackendForType(pool->def->type) == NULL)
915
        goto cleanup;
916 917 918 919 920 921 922 923 924

    memset(info, 0, sizeof(virStoragePoolInfo));
    if (pool->active)
        info->state = VIR_STORAGE_POOL_RUNNING;
    else
        info->state = VIR_STORAGE_POOL_INACTIVE;
    info->capacity = pool->def->capacity;
    info->allocation = pool->def->allocation;
    info->available = pool->def->available;
925
    ret = 0;
926

927
cleanup:
928 929
    if (pool)
        virStoragePoolObjUnlock(pool);
930
    return ret;
931 932 933 934 935
}

static char *
storagePoolDumpXML(virStoragePoolPtr obj,
                   unsigned int flags ATTRIBUTE_UNUSED) {
936 937 938
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    char *ret = NULL;
939

940
    storageDriverLock(driver);
941
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
942 943
    storageDriverUnlock(driver);

944 945
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
946
                              "%s", _("no storage pool with matching uuid"));
947
        goto cleanup;
948 949
    }

950 951 952
    ret = virStoragePoolDefFormat(obj->conn, pool->def);

cleanup:
953 954
    if (pool)
        virStoragePoolObjUnlock(pool);
955
    return ret;
956 957 958 959 960
}

static int
storagePoolGetAutostart(virStoragePoolPtr obj,
                        int *autostart) {
961 962 963
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
964

965
    storageDriverLock(driver);
966
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
967 968
    storageDriverUnlock(driver);

969 970
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
971
                              "%s", _("no pool with matching uuid"));
972
        goto cleanup;
973 974 975 976 977 978 979
    }

    if (!pool->configFile) {
        *autostart = 0;
    } else {
        *autostart = pool->autostart;
    }
980
    ret = 0;
981

982
cleanup:
983 984
    if (pool)
        virStoragePoolObjUnlock(pool);
985
    return ret;
986 987 988 989 990
}

static int
storagePoolSetAutostart(virStoragePoolPtr obj,
                        int autostart) {
991 992 993
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
994

995
    storageDriverLock(driver);
996
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
997

998 999
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1000
                              "%s", _("no pool with matching uuid"));
1001
        goto cleanup;
1002 1003 1004 1005
    }

    if (!pool->configFile) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
1006
                              "%s", _("pool has no config file"));
1007
        goto cleanup;
1008 1009 1010 1011
    }

    autostart = (autostart != 0);

1012 1013 1014
    if (pool->autostart != autostart) {
        if (autostart) {
            int err;
1015

1016
            if ((err = virFileMakePath(driver->autostartDir))) {
1017 1018 1019
                virReportSystemError(obj->conn, err,
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
1020 1021
                goto cleanup;
            }
1022

1023
            if (symlink(pool->configFile, pool->autostartLink) < 0) {
1024 1025 1026
                virReportSystemError(obj->conn, errno,
                                     _("Failed to create symlink '%s' to '%s'"),
                                     pool->autostartLink, pool->configFile);
1027 1028 1029 1030 1031
                goto cleanup;
            }
        } else {
            if (unlink(pool->autostartLink) < 0 &&
                errno != ENOENT && errno != ENOTDIR) {
1032 1033 1034
                virReportSystemError(obj->conn, errno,
                                     _("Failed to delete symlink '%s'"),
                                     pool->autostartLink);
1035 1036
                goto cleanup;
            }
1037
        }
1038
        pool->autostart = autostart;
1039
    }
1040
    ret = 0;
1041

1042
cleanup:
1043 1044
    if (pool)
        virStoragePoolObjUnlock(pool);
1045
    storageDriverUnlock(driver);
1046
    return ret;
1047 1048 1049 1050 1051
}


static int
storagePoolNumVolumes(virStoragePoolPtr obj) {
1052 1053 1054
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
1055

1056
    storageDriverLock(driver);
1057
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1058 1059
    storageDriverUnlock(driver);

1060 1061
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1062
                              "%s", _("no storage pool with matching uuid"));
1063
        goto cleanup;
1064 1065 1066 1067
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1068
                              "%s", _("storage pool is not active"));
1069
        goto cleanup;
1070
    }
1071
    ret = pool->volumes.count;
1072

1073
cleanup:
1074 1075
    if (pool)
        virStoragePoolObjUnlock(pool);
1076
    return ret;
1077 1078 1079 1080 1081 1082
}

static int
storagePoolListVolumes(virStoragePoolPtr obj,
                       char **const names,
                       int maxnames) {
1083 1084
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1085
    int i, n = 0;
1086

1087 1088
    memset(names, 0, maxnames * sizeof(*names));

1089
    storageDriverLock(driver);
1090
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1091 1092
    storageDriverUnlock(driver);

1093 1094
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1095
                              "%s", _("no storage pool with matching uuid"));
1096
        goto cleanup;
1097 1098 1099 1100
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1101
                              "%s", _("storage pool is not active"));
1102
        goto cleanup;
1103 1104
    }

1105 1106
    for (i = 0 ; i < pool->volumes.count && n < maxnames ; i++) {
        if ((names[n++] = strdup(pool->volumes.objs[i]->name)) == NULL) {
1107
            virReportOOMError();
1108 1109 1110 1111
            goto cleanup;
        }
    }

1112
    virStoragePoolObjUnlock(pool);
1113
    return n;
1114 1115

 cleanup:
1116 1117
    if (pool)
        virStoragePoolObjUnlock(pool);
1118
    for (n = 0 ; n < maxnames ; n++)
1119
        VIR_FREE(names[n]);
1120

1121
    memset(names, 0, maxnames * sizeof(*names));
1122 1123 1124 1125 1126 1127 1128
    return -1;
}


static virStorageVolPtr
storageVolumeLookupByName(virStoragePoolPtr obj,
                          const char *name) {
1129 1130
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1131
    virStorageVolDefPtr vol;
1132
    virStorageVolPtr ret = NULL;
1133

1134
    storageDriverLock(driver);
1135
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1136 1137
    storageDriverUnlock(driver);

1138 1139
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1140
                              "%s", _("no storage pool with matching uuid"));
1141
        goto cleanup;
1142 1143 1144 1145
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1146
                              "%s", _("storage pool is not active"));
1147
        goto cleanup;
1148 1149 1150 1151 1152
    }

    vol = virStorageVolDefFindByName(pool, name);

    if (!vol) {
1153 1154 1155
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              name);
1156
        goto cleanup;
1157 1158
    }

1159 1160 1161
    ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key);

cleanup:
1162 1163
    if (pool)
        virStoragePoolObjUnlock(pool);
1164
    return ret;
1165 1166 1167 1168 1169 1170
}


static virStorageVolPtr
storageVolumeLookupByKey(virConnectPtr conn,
                         const char *key) {
1171
    virStorageDriverStatePtr driver = conn->storagePrivateData;
1172
    unsigned int i;
1173
    virStorageVolPtr ret = NULL;
1174

1175 1176 1177
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count && !ret ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
1178 1179 1180
        if (virStoragePoolObjIsActive(driver->pools.objs[i])) {
            virStorageVolDefPtr vol =
                virStorageVolDefFindByKey(driver->pools.objs[i], key);
1181

1182
            if (vol)
1183
                ret = virGetStorageVol(conn,
1184 1185 1186
                                       driver->pools.objs[i]->def->name,
                                       vol->name,
                                       vol->key);
1187
        }
1188
        virStoragePoolObjUnlock(driver->pools.objs[i]);
1189
    }
1190
    storageDriverUnlock(driver);
1191

1192 1193 1194 1195 1196
    if (!ret)
        virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
                              "%s", _("no storage vol with matching key"));

    return ret;
1197 1198 1199 1200 1201
}

static virStorageVolPtr
storageVolumeLookupByPath(virConnectPtr conn,
                          const char *path) {
1202
    virStorageDriverStatePtr driver = conn->storagePrivateData;
1203
    unsigned int i;
1204
    virStorageVolPtr ret = NULL;
1205

1206 1207 1208
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count && !ret ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
1209
        if (virStoragePoolObjIsActive(driver->pools.objs[i])) {
1210
            virStorageVolDefPtr vol;
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
            const char *stable_path;

            stable_path = virStorageBackendStablePath(conn,
                                                      driver->pools.objs[i],
                                                      path);
            /*
             * virStorageBackendStablePath already does
             * virStorageReportError if it fails; we just need to keep
             * propagating the return code
             */
1221 1222
            if (stable_path == NULL) {
                virStoragePoolObjUnlock(driver->pools.objs[i]);
1223
                goto cleanup;
1224
            }
1225 1226 1227 1228

            vol = virStorageVolDefFindByPath(driver->pools.objs[i],
                                             stable_path);
            VIR_FREE(stable_path);
1229

1230
            if (vol)
1231 1232 1233 1234
                ret = virGetStorageVol(conn,
                                       driver->pools.objs[i]->def->name,
                                       vol->name,
                                       vol->key);
1235
        }
1236
        virStoragePoolObjUnlock(driver->pools.objs[i]);
1237 1238
    }

1239 1240 1241 1242 1243
    if (!ret)
        virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
                              "%s", _("no storage vol with matching path"));

cleanup:
1244
    storageDriverUnlock(driver);
1245
    return ret;
1246 1247
}

1248 1249
static int storageVolumeDelete(virStorageVolPtr obj, unsigned int flags);

1250 1251 1252 1253
static virStorageVolPtr
storageVolumeCreateXML(virStoragePoolPtr obj,
                       const char *xmldesc,
                       unsigned int flags ATTRIBUTE_UNUSED) {
1254 1255
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1256
    virStorageBackendPtr backend;
1257 1258
    virStorageVolDefPtr voldef = NULL;
    virStorageVolPtr ret = NULL, volobj = NULL;
1259

1260
    storageDriverLock(driver);
1261
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1262 1263
    storageDriverUnlock(driver);

1264 1265
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1266
                              "%s", _("no storage pool with matching uuid"));
1267
        goto cleanup;
1268 1269 1270 1271
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1272
                              "%s", _("storage pool is not active"));
1273
        goto cleanup;
1274 1275 1276
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1277
        goto cleanup;
1278

1279
    voldef = virStorageVolDefParseString(obj->conn, pool->def, xmldesc);
1280
    if (voldef == NULL)
1281
        goto cleanup;
1282

1283
    if (virStorageVolDefFindByName(pool, voldef->name)) {
1284
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1285
                              "%s", _("storage vol already exists"));
1286
        goto cleanup;
1287 1288
    }

1289 1290
    if (VIR_REALLOC_N(pool->volumes.objs,
                      pool->volumes.count+1) < 0) {
1291
        virReportOOMError();
1292
        goto cleanup;
1293 1294
    }

1295 1296
    if (!backend->createVol) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
1297 1298
                              "%s", _("storage pool does not support volume "
                                      "creation"));
1299
        goto cleanup;
1300 1301
    }

1302
    if (backend->createVol(obj->conn, pool, voldef) < 0) {
1303
        goto cleanup;
1304 1305
    }

1306 1307 1308
    pool->volumes.objs[pool->volumes.count++] = voldef;
    volobj = virGetStorageVol(obj->conn, pool->def->name, voldef->name,
                              voldef->key);
1309

1310 1311 1312 1313 1314
    if (volobj && backend->buildVol) {
        int buildret;
        virStorageVolDefPtr buildvoldef = NULL;

        if (VIR_ALLOC(buildvoldef) < 0) {
1315
            virReportOOMError();
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
            voldef = NULL;
            goto cleanup;
        }

        /* Make a shallow copy of the 'defined' volume definition, since the
         * original allocation value will change as the user polls 'info',
         * but we only need the initial requested values
         */
        memcpy(buildvoldef, voldef, sizeof(*voldef));

        /* Drop the pool lock during volume allocation */
        pool->asyncjobs++;
        voldef->building = 1;
        virStoragePoolObjUnlock(pool);

1331
        buildret = backend->buildVol(obj->conn, pool, buildvoldef);
1332

1333
        storageDriverLock(driver);
1334
        virStoragePoolObjLock(pool);
1335 1336
        storageDriverUnlock(driver);

1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
        voldef->building = 0;
        pool->asyncjobs--;

        voldef = NULL;
        VIR_FREE(buildvoldef);

        if (buildret < 0) {
            virStoragePoolObjUnlock(pool);
            storageVolumeDelete(volobj, 0);
            pool = NULL;
            goto cleanup;
        }

    }

    ret = volobj;
    volobj = NULL;
    voldef = NULL;
1355

1356
cleanup:
1357 1358 1359
    if (volobj)
        virUnrefStorageVol(volobj);
    virStorageVolDefFree(voldef);
1360 1361
    if (pool)
        virStoragePoolObjUnlock(pool);
1362
    return ret;
1363 1364
}

1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
static virStorageVolPtr
storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
                           const char *xmldesc,
                           virStorageVolPtr vobj,
                           unsigned int flags ATTRIBUTE_UNUSED) {
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool, origpool = NULL;
    virStorageBackendPtr backend;
    virStorageVolDefPtr origvol = NULL, newvol = NULL;
    virStorageVolPtr ret = NULL, volobj = NULL;
1375
    int buildret;
1376 1377 1378

    storageDriverLock(driver);
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1379
    if (pool && STRNEQ(obj->name, vobj->pool)) {
1380
        virStoragePoolObjUnlock(pool);
1381
        origpool = virStoragePoolObjFindByName(&driver->pools, vobj->pool);
1382
        virStoragePoolObjLock(pool);
1383
    }
1384 1385 1386 1387 1388 1389 1390
    storageDriverUnlock(driver);
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
                              "%s", _("no storage pool with matching uuid"));
        goto cleanup;
    }

1391
    if (STRNEQ(obj->name, vobj->pool) && !origpool) {
1392 1393 1394
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_POOL,
                             _("no storage pool with matching name '%s'"),
                              vobj->pool);
1395 1396 1397 1398 1399 1400 1401 1402 1403
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("storage pool is not active"));
        goto cleanup;
    }

1404
    if (origpool && !virStoragePoolObjIsActive(origpool)) {
1405 1406 1407 1408 1409 1410 1411 1412
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("storage pool is not active"));
        goto cleanup;
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;

1413
    origvol = virStorageVolDefFindByName(origpool ? origpool : pool, vobj->name);
1414
    if (!origvol) {
1415 1416 1417
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              vobj->name);
1418 1419 1420
        goto cleanup;
    }

1421
    newvol = virStorageVolDefParseString(obj->conn, pool->def, xmldesc);
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
    if (newvol == NULL)
        goto cleanup;

    if (virStorageVolDefFindByName(pool, newvol->name)) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
                              _("storage volume name '%s' already in use."),
                              newvol->name);
        goto cleanup;
    }

    /* Is there ever a valid case for this? */
    if (newvol->capacity < origvol->capacity)
        newvol->capacity = origvol->capacity;

1436 1437 1438 1439 1440
    /* Make sure allocation is at least as large as the destination cap,
     * to make absolutely sure we copy all possible contents */
    if (newvol->allocation < origvol->capacity)
        newvol->allocation = origvol->capacity;

1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
    if (!backend->buildVolFrom) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
                              "%s", _("storage pool does not support volume creation from an existing volume"));
        goto cleanup;
    }

    if (origvol->building) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("volume '%s' is still being allocated."),
                              origvol->name);
        goto cleanup;
    }

    if (backend->refreshVol &&
        backend->refreshVol(obj->conn, pool, origvol) < 0)
        goto cleanup;

    if (VIR_REALLOC_N(pool->volumes.objs,
                      pool->volumes.count+1) < 0) {
1460
        virReportOOMError();
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
        goto cleanup;
    }

    /* 'Define' the new volume so we get async progress reporting */
    if (backend->createVol(obj->conn, pool, newvol) < 0) {
        goto cleanup;
    }

    pool->volumes.objs[pool->volumes.count++] = newvol;
    volobj = virGetStorageVol(obj->conn, pool->def->name, newvol->name,
                              newvol->key);

    /* Drop the pool lock during volume allocation */
    pool->asyncjobs++;
    origvol->building = 1;
    newvol->building = 1;
    virStoragePoolObjUnlock(pool);

1479
    if (origpool) {
1480 1481 1482 1483
        origpool->asyncjobs++;
        virStoragePoolObjUnlock(origpool);
    }

1484
    buildret = backend->buildVolFrom(obj->conn, pool, newvol, origvol, flags);
1485 1486 1487

    storageDriverLock(driver);
    virStoragePoolObjLock(pool);
1488
    if (origpool)
1489 1490 1491 1492 1493 1494 1495 1496
        virStoragePoolObjLock(origpool);
    storageDriverUnlock(driver);

    origvol->building = 0;
    newvol->building = 0;
    newvol = NULL;
    pool->asyncjobs--;

1497
    if (origpool) {
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
        origpool->asyncjobs--;
        virStoragePoolObjUnlock(origpool);
        origpool = NULL;
    }

    if (buildret < 0) {
        virStoragePoolObjUnlock(pool);
        storageVolumeDelete(volobj, 0);
        pool = NULL;
        goto cleanup;
    }

    ret = volobj;
    volobj = NULL;

cleanup:
    if (volobj)
        virUnrefStorageVol(volobj);
    virStorageVolDefFree(newvol);
    if (pool)
        virStoragePoolObjUnlock(pool);
1519
    if (origpool)
1520 1521 1522 1523
        virStoragePoolObjUnlock(origpool);
    return ret;
}

1524 1525 1526
static int
storageVolumeDelete(virStorageVolPtr obj,
                    unsigned int flags) {
1527 1528
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1529
    virStorageBackendPtr backend;
1530
    virStorageVolDefPtr vol = NULL;
1531
    unsigned int i;
1532
    int ret = -1;
1533

1534
    storageDriverLock(driver);
1535
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1536 1537
    storageDriverUnlock(driver);

1538 1539
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1540
                              "%s", _("no storage pool with matching uuid"));
1541
        goto cleanup;
1542 1543 1544 1545
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1546
                              "%s", _("storage pool is not active"));
1547
        goto cleanup;
1548 1549 1550
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1551
        goto cleanup;
1552 1553 1554 1555

    vol = virStorageVolDefFindByName(pool, obj->name);

    if (!vol) {
1556 1557 1558
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              obj->name);
1559
        goto cleanup;
1560 1561
    }

1562 1563 1564 1565 1566 1567 1568
    if (vol->building) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("volume '%s' is still being allocated."),
                              vol->name);
        goto cleanup;
    }

1569 1570
    if (!backend->deleteVol) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1571
                              "%s", _("storage pool does not support vol deletion"));
1572

1573
        goto cleanup;
1574 1575
    }

1576 1577 1578
    if (backend->deleteVol(obj->conn, pool, vol, flags) < 0)
        goto cleanup;

1579 1580 1581
    for (i = 0 ; i < pool->volumes.count ; i++) {
        if (pool->volumes.objs[i] == vol) {
            virStorageVolDefFree(vol);
1582
            vol = NULL;
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592

            if (i < (pool->volumes.count - 1))
                memmove(pool->volumes.objs + i, pool->volumes.objs + i + 1,
                        sizeof(*(pool->volumes.objs)) * (pool->volumes.count - (i + 1)));

            if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            pool->volumes.count--;

1593 1594 1595
            break;
        }
    }
1596
    ret = 0;
1597

1598
cleanup:
1599 1600
    if (pool)
        virStoragePoolObjUnlock(pool);
1601
    return ret;
1602 1603 1604 1605 1606
}

static int
storageVolumeGetInfo(virStorageVolPtr obj,
                     virStorageVolInfoPtr info) {
1607 1608
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1609 1610
    virStorageBackendPtr backend;
    virStorageVolDefPtr vol;
1611
    int ret = -1;
1612

1613
    storageDriverLock(driver);
1614
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1615 1616
    storageDriverUnlock(driver);

1617 1618
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1619
                              "%s", _("no storage pool with matching uuid"));
1620
        goto cleanup;
1621 1622 1623 1624
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1625
                              "%s", _("storage pool is not active"));
1626
        goto cleanup;
1627 1628 1629 1630 1631
    }

    vol = virStorageVolDefFindByName(pool, obj->name);

    if (!vol) {
1632 1633 1634
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              obj->name);
1635
        goto cleanup;
1636 1637 1638
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1639
        goto cleanup;
1640 1641 1642

    if (backend->refreshVol &&
        backend->refreshVol(obj->conn, pool, vol) < 0)
1643
        goto cleanup;
1644 1645

    memset(info, 0, sizeof(*info));
1646
    info->type = vol->type;
1647 1648
    info->capacity = vol->capacity;
    info->allocation = vol->allocation;
1649
    ret = 0;
1650

1651
cleanup:
1652 1653
    if (pool)
        virStoragePoolObjUnlock(pool);
1654
    return ret;
1655 1656 1657 1658 1659
}

static char *
storageVolumeGetXMLDesc(virStorageVolPtr obj,
                        unsigned int flags ATTRIBUTE_UNUSED) {
1660 1661
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1662 1663
    virStorageBackendPtr backend;
    virStorageVolDefPtr vol;
1664
    char *ret = NULL;
1665

1666
    storageDriverLock(driver);
1667
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1668 1669
    storageDriverUnlock(driver);

1670 1671
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1672
                              "%s", _("no storage pool with matching uuid"));
1673
        goto cleanup;
1674 1675 1676 1677
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1678
                              "%s", _("storage pool is not active"));
1679
        goto cleanup;
1680 1681 1682 1683 1684
    }

    vol = virStorageVolDefFindByName(pool, obj->name);

    if (!vol) {
1685 1686 1687
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              obj->name);
1688
        goto cleanup;
1689 1690 1691
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1692
        goto cleanup;
1693 1694 1695 1696

    if (backend->refreshVol &&
        backend->refreshVol(obj->conn, pool, vol) < 0)
        goto cleanup;
1697

1698 1699 1700
    ret = virStorageVolDefFormat(obj->conn, pool->def, vol);

cleanup:
1701 1702 1703
    if (pool)
        virStoragePoolObjUnlock(pool);

1704
    return ret;
1705 1706 1707 1708
}

static char *
storageVolumeGetPath(virStorageVolPtr obj) {
1709
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
1710
    virStoragePoolObjPtr pool;
1711
    virStorageVolDefPtr vol;
1712
    char *ret = NULL;
1713

1714 1715 1716
    storageDriverLock(driver);
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
    storageDriverUnlock(driver);
1717 1718
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1719
                              "%s", _("no storage pool with matching uuid"));
1720
        goto cleanup;
1721 1722 1723 1724
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1725
                              "%s", _("storage pool is not active"));
1726
        goto cleanup;
1727 1728 1729 1730 1731
    }

    vol = virStorageVolDefFindByName(pool, obj->name);

    if (!vol) {
1732 1733 1734
        virStorageReportError(obj->conn, VIR_ERR_NO_STORAGE_VOL,
                             _("no storage vol with matching name '%s'"),
                              obj->name);
1735
        goto cleanup;
1736 1737 1738
    }

    ret = strdup(vol->target.path);
1739
    if (ret == NULL)
1740
        virReportOOMError();
1741 1742

cleanup:
1743 1744
    if (pool)
        virStoragePoolObjUnlock(pool);
1745 1746 1747 1748
    return ret;
}

static virStorageDriver storageDriver = {
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
    .name = "storage",
    .open = storageOpen,
    .close = storageClose,
    .numOfPools = storageNumPools,
    .listPools = storageListPools,
    .numOfDefinedPools = storageNumDefinedPools,
    .listDefinedPools = storageListDefinedPools,
    .findPoolSources = storageFindPoolSources,
    .poolLookupByName = storagePoolLookupByName,
    .poolLookupByUUID = storagePoolLookupByUUID,
    .poolLookupByVolume = storagePoolLookupByVolume,
    .poolCreateXML = storagePoolCreate,
    .poolDefineXML = storagePoolDefine,
    .poolBuild = storagePoolBuild,
    .poolUndefine = storagePoolUndefine,
    .poolCreate = storagePoolStart,
    .poolDestroy = storagePoolDestroy,
    .poolDelete = storagePoolDelete,
    .poolRefresh = storagePoolRefresh,
    .poolGetInfo = storagePoolGetInfo,
    .poolGetXMLDesc = storagePoolDumpXML,
    .poolGetAutostart = storagePoolGetAutostart,
    .poolSetAutostart = storagePoolSetAutostart,
    .poolNumOfVolumes = storagePoolNumVolumes,
    .poolListVolumes = storagePoolListVolumes,

    .volLookupByName = storageVolumeLookupByName,
    .volLookupByKey = storageVolumeLookupByKey,
    .volLookupByPath = storageVolumeLookupByPath,
    .volCreateXML = storageVolumeCreateXML,
1779
    .volCreateXMLFrom = storageVolumeCreateXMLFrom,
1780 1781 1782 1783
    .volDelete = storageVolumeDelete,
    .volGetInfo = storageVolumeGetInfo,
    .volGetXMLDesc = storageVolumeGetXMLDesc,
    .volGetPath = storageVolumeGetPath,
1784 1785 1786

    .poolIsActive = storagePoolIsActive,
    .poolIsPersistent = storagePoolIsPersistent,
1787 1788 1789 1790
};


static virStateDriver stateDriver = {
1791
    .name = "Storage",
1792 1793 1794 1795
    .initialize = storageDriverStartup,
    .cleanup = storageDriverShutdown,
    .reload = storageDriverReload,
    .active = storageDriverActive,
1796 1797 1798 1799 1800 1801 1802
};

int storageRegister(void) {
    virRegisterStorageDriver(&storageDriver);
    virRegisterStateDriver(&stateDriver);
    return 0;
}