storage_driver.c 49.9 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 43
#include "storage_backend.h"

44 45
#define VIR_FROM_THIS VIR_FROM_STORAGE

46 47 48 49 50 51
#define storageLog(msg...) fprintf(stderr, msg)

static virStorageDriverStatePtr driverState;

static int storageDriverShutdown(void);

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

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

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

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

            if (backend->startPool &&
                backend->startPool(NULL, pool) < 0) {
                virErrorPtr err = virGetLastError();
                storageLog("Failed to autostart storage pool '%s': %s",
                           pool->def->name, err ? err->message : NULL);
84
                virStoragePoolObjUnlock(pool);
85 86 87 88 89 90 91 92 93
                continue;
            }

            if (backend->refreshPool(NULL, pool) < 0) {
                virErrorPtr err = virGetLastError();
                if (backend->stopPool)
                    backend->stopPool(NULL, pool);
                storageLog("Failed to autostart storage pool '%s': %s",
                           pool->def->name, err ? err->message : NULL);
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
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
133
            storageLog("out of memory in virAsprintf");
134
            VIR_FREE(userdir);
135 136
            goto out_of_memory;
        }
137
        VIR_FREE(userdir);
138 139 140 141 142 143 144 145 146 147
    }

    /* 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';

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

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

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

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

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

172
    storageDriverUnlock(driverState);
173 174
    return 0;

175
out_of_memory:
176
    storageLog("virStorageStartup: out of memory");
177 178 179 180
error:
    VIR_FREE(base);
    storageDriverUnlock(driverState);
    storageDriverShutdown();
181 182 183 184 185 186 187 188 189 190 191
    return -1;
}

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

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

    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) {
215
    unsigned int i;
216
    int active = 0;
217 218 219 220

    if (!driverState)
        return 0;

221 222 223 224
    storageDriverLock(driverState);

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

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

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

244
    storageDriverLock(driverState);
245 246

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

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

    return 0;
}



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

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

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

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

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

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

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

296 297
    if (!pool) {
        virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL,
J
Jim Meyering 已提交
298
                              "%s", _("no pool with matching name"));
299
        goto cleanup;
300 301 302
    }

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

cleanup:
305 306
    if (pool)
        virStoragePoolObjUnlock(pool);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    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) {
334
    virStorageDriverStatePtr driver = conn->storagePrivateData;
335 336
    unsigned int i, nactive = 0;

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

    return nactive;
347 348 349 350 351 352
}

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

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

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

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

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

    return nactive;
395 396 397 398 399 400
}

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

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

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

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

442
    backend_type = virStoragePoolTypeFromString(type);
443
    if (backend_type < 0)
444
        goto cleanup;
445 446 447

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

    if (backend->findPoolSources)
451
        ret = backend->findPoolSources(conn, srcSpec, flags);
452

453 454
cleanup:
    return ret;
455 456 457
}


458 459 460 461
static virStoragePoolPtr
storagePoolCreate(virConnectPtr conn,
                  const char *xml,
                  unsigned int flags ATTRIBUTE_UNUSED) {
462
    virStorageDriverStatePtr driver = conn->storagePrivateData;
463
    virStoragePoolDefPtr def;
464
    virStoragePoolObjPtr pool = NULL;
465
    virStoragePoolPtr ret = NULL;
466 467
    virStorageBackendPtr backend;

468
    storageDriverLock(driver);
469
    if (!(def = virStoragePoolDefParseString(conn, xml)))
470
        goto cleanup;
471

472 473 474 475 476
    pool = virStoragePoolObjFindByUUID(&driver->pools, def->uuid);
    if (!pool)
        pool = virStoragePoolObjFindByName(&driver->pools, def->name);

    if (pool) {
477
        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
478
                              "%s", _("storage pool already exists"));
479
        goto cleanup;
480 481
    }

482 483
    if ((backend = virStorageBackendForType(def->type)) == NULL)
        goto cleanup;
484

485 486 487
    if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def)))
        goto cleanup;
    def = NULL;
488

489 490
    if (backend->startPool &&
        backend->startPool(conn, pool) < 0)
491 492
        goto cleanup;

493 494 495
    if (backend->refreshPool(conn, pool) < 0) {
        if (backend->stopPool)
            backend->stopPool(conn, pool);
496
        goto cleanup;
497 498 499 500
    }
    pool->active = 1;

    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
501 502
    virStoragePoolObjUnlock(pool);
    pool = NULL;
503

504 505
cleanup:
    virStoragePoolDefFree(def);
506
    if (pool)
507
        virStoragePoolObjRemove(&driver->pools, pool);
508
    storageDriverUnlock(driver);
509 510 511 512 513 514 515
    return ret;
}

static virStoragePoolPtr
storagePoolDefine(virConnectPtr conn,
                  const char *xml,
                  unsigned int flags ATTRIBUTE_UNUSED) {
516
    virStorageDriverStatePtr driver = conn->storagePrivateData;
517
    virStoragePoolDefPtr def;
518
    virStoragePoolObjPtr pool = NULL;
519
    virStoragePoolPtr ret = NULL;
520 521
    virStorageBackendPtr backend;

522
    storageDriverLock(driver);
523
    if (!(def = virStoragePoolDefParseString(conn, xml)))
524
        goto cleanup;
525

526 527
    if ((backend = virStorageBackendForType(def->type)) == NULL)
        goto cleanup;
528

529 530
    if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def)))
        goto cleanup;
531 532

    if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) {
533
        virStoragePoolObjRemove(&driver->pools, pool);
534
        def = NULL;
535
        goto cleanup;
536
    }
537
    def = NULL;
538 539

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

cleanup:
    virStoragePoolDefFree(def);
543 544 545
    if (pool)
        virStoragePoolObjUnlock(pool);
    storageDriverUnlock(driver);
546 547 548 549 550
    return ret;
}

static int
storagePoolUndefine(virStoragePoolPtr obj) {
551 552 553
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
554

555
    storageDriverLock(driver);
556
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
557 558
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
559
                              "%s", _("no storage pool with matching uuid"));
560
        goto cleanup;
561 562 563 564
    }

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
565
                              "%s", _("pool is still active"));
566
        goto cleanup;
567 568
    }

569 570 571 572 573 574 575
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

576
    if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0)
577
        goto cleanup;
578

579 580
    if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
        char ebuf[1024];
581
        storageLog("Failed to delete autostart link '%s': %s",
582 583
                   pool->autostartLink, virStrerror(errno, ebuf, sizeof ebuf));
    }
584

585 586
    VIR_FREE(pool->configFile);
    VIR_FREE(pool->autostartLink);
587

588
    virStoragePoolObjRemove(&driver->pools, pool);
589
    pool = NULL;
590
    ret = 0;
591

592
cleanup:
593 594 595
    if (pool)
        virStoragePoolObjUnlock(pool);
    storageDriverUnlock(driver);
596
    return ret;
597 598 599 600 601
}

static int
storagePoolStart(virStoragePoolPtr obj,
                 unsigned int flags ATTRIBUTE_UNUSED) {
602 603
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
604
    virStorageBackendPtr backend;
605
    int ret = -1;
606

607
    storageDriverLock(driver);
608
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
609 610
    storageDriverUnlock(driver);

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 ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
619 620 621

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
622
                              "%s", _("pool already active"));
623
        goto cleanup;
624 625 626
    }
    if (backend->startPool &&
        backend->startPool(obj->conn, pool) < 0)
627 628
        goto cleanup;

629 630 631
    if (backend->refreshPool(obj->conn, pool) < 0) {
        if (backend->stopPool)
            backend->stopPool(obj->conn, pool);
632
        goto cleanup;
633 634 635
    }

    pool->active = 1;
636
    ret = 0;
637

638
cleanup:
639 640
    if (pool)
        virStoragePoolObjUnlock(pool);
641
    return ret;
642 643 644 645 646
}

static int
storagePoolBuild(virStoragePoolPtr obj,
                 unsigned int flags) {
647 648
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
649
    virStorageBackendPtr backend;
650
    int ret = -1;
651

652
    storageDriverLock(driver);
653
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
654 655
    storageDriverUnlock(driver);

656 657
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
658
                              "%s", _("no storage pool with matching uuid"));
659
        goto cleanup;
660 661
    }

662 663
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
664 665 666

    if (virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
667
                              "%s", _("storage pool is already active"));
668
        goto cleanup;
669 670 671 672
    }

    if (backend->buildPool &&
        backend->buildPool(obj->conn, pool, flags) < 0)
673 674
        goto cleanup;
    ret = 0;
675

676
cleanup:
677 678
    if (pool)
        virStoragePoolObjUnlock(pool);
679
    return ret;
680 681 682 683 684
}


static int
storagePoolDestroy(virStoragePoolPtr obj) {
685 686
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
687
    virStorageBackendPtr backend;
688
    int ret = -1;
689

690
    storageDriverLock(driver);
691
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
692

693 694
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
695
                              "%s", _("no storage pool with matching uuid"));
696
        goto cleanup;
697 698
    }

699 700
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
701 702 703

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

708 709 710 711 712 713 714
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

715 716
    if (backend->stopPool &&
        backend->stopPool(obj->conn, pool) < 0)
717
        goto cleanup;
718 719 720 721 722

    virStoragePoolObjClearVols(pool);

    pool->active = 0;

723
    if (pool->configFile == NULL) {
724
        virStoragePoolObjRemove(&driver->pools, pool);
725 726
        pool = NULL;
    }
727
    ret = 0;
728

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


static int
storagePoolDelete(virStoragePoolPtr obj,
                  unsigned int flags) {
740 741
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
742
    virStorageBackendPtr backend;
743
    int ret = -1;
744

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

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

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

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

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

771 772
    if (!backend->deletePool) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
773
                              "%s", _("pool does not support volume delete"));
774
        goto cleanup;
775 776
    }
    if (backend->deletePool(obj->conn, pool, flags) < 0)
777 778
        goto cleanup;
    ret = 0;
779

780
cleanup:
781 782
    if (pool)
        virStoragePoolObjUnlock(pool);
783
    return ret;
784 785 786 787 788 789
}


static int
storagePoolRefresh(virStoragePoolPtr obj,
                   unsigned int flags ATTRIBUTE_UNUSED) {
790 791
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
792
    virStorageBackendPtr backend;
793
    int ret = -1;
794

795
    storageDriverLock(driver);
796
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
797

798 799
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
800
                              "%s", _("no storage pool with matching uuid"));
801
        goto cleanup;
802 803
    }

804 805
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
806 807 808

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

813 814 815 816 817 818 819
    if (pool->asyncjobs > 0) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("pool '%s' has asynchronous jobs running."),
                              pool->def->name);
        goto cleanup;
    }

820
    virStoragePoolObjClearVols(pool);
821
    if (backend->refreshPool(obj->conn, pool) < 0) {
822 823 824 825 826
        if (backend->stopPool)
            backend->stopPool(obj->conn, pool);

        pool->active = 0;

827
        if (pool->configFile == NULL) {
828
            virStoragePoolObjRemove(&driver->pools, pool);
829 830
            pool = NULL;
        }
831
        goto cleanup;
832
    }
833
    ret = 0;
834

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


static int
storagePoolGetInfo(virStoragePoolPtr obj,
                   virStoragePoolInfoPtr info) {
846 847
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
848
    virStorageBackendPtr backend;
849
    int ret = -1;
850

851
    storageDriverLock(driver);
852
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
853 854
    storageDriverUnlock(driver);

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

861 862
    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
        goto cleanup;
863 864 865 866 867 868 869 870 871

    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;
872
    ret = 0;
873

874
cleanup:
875 876
    if (pool)
        virStoragePoolObjUnlock(pool);
877
    return ret;
878 879 880 881 882
}

static char *
storagePoolDumpXML(virStoragePoolPtr obj,
                   unsigned int flags ATTRIBUTE_UNUSED) {
883 884 885
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    char *ret = NULL;
886

887
    storageDriverLock(driver);
888
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
889 890
    storageDriverUnlock(driver);

891 892
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
893
                              "%s", _("no storage pool with matching uuid"));
894
        goto cleanup;
895 896
    }

897 898 899
    ret = virStoragePoolDefFormat(obj->conn, pool->def);

cleanup:
900 901
    if (pool)
        virStoragePoolObjUnlock(pool);
902
    return ret;
903 904 905 906 907
}

static int
storagePoolGetAutostart(virStoragePoolPtr obj,
                        int *autostart) {
908 909 910
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
911

912
    storageDriverLock(driver);
913
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
914 915
    storageDriverUnlock(driver);

916 917
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
918
                              "%s", _("no pool with matching uuid"));
919
        goto cleanup;
920 921 922 923 924 925 926
    }

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

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

static int
storagePoolSetAutostart(virStoragePoolPtr obj,
                        int autostart) {
938 939 940
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
941

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

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

    if (!pool->configFile) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
953
                              "%s", _("pool has no config file"));
954
        goto cleanup;
955 956 957 958
    }

    autostart = (autostart != 0);

959 960 961
    if (pool->autostart != autostart) {
        if (autostart) {
            int err;
962

963
            if ((err = virFileMakePath(driver->autostartDir))) {
964 965 966
                virReportSystemError(obj->conn, err,
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
967 968
                goto cleanup;
            }
969

970
            if (symlink(pool->configFile, pool->autostartLink) < 0) {
971 972 973
                virReportSystemError(obj->conn, errno,
                                     _("Failed to create symlink '%s' to '%s'"),
                                     pool->autostartLink, pool->configFile);
974 975 976 977 978
                goto cleanup;
            }
        } else {
            if (unlink(pool->autostartLink) < 0 &&
                errno != ENOENT && errno != ENOTDIR) {
979 980 981
                virReportSystemError(obj->conn, errno,
                                     _("Failed to delete symlink '%s'"),
                                     pool->autostartLink);
982 983
                goto cleanup;
            }
984
        }
985
        pool->autostart = autostart;
986
    }
987
    ret = 0;
988

989
cleanup:
990 991
    if (pool)
        virStoragePoolObjUnlock(pool);
992
    storageDriverUnlock(driver);
993
    return ret;
994 995 996 997 998
}


static int
storagePoolNumVolumes(virStoragePoolPtr obj) {
999 1000 1001
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
    int ret = -1;
1002

1003
    storageDriverLock(driver);
1004
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1005 1006
    storageDriverUnlock(driver);

1007 1008
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1009
                              "%s", _("no storage pool with matching uuid"));
1010
        goto cleanup;
1011 1012 1013 1014
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1015
                              "%s", _("storage pool is not active"));
1016
        goto cleanup;
1017
    }
1018
    ret = pool->volumes.count;
1019

1020
cleanup:
1021 1022
    if (pool)
        virStoragePoolObjUnlock(pool);
1023
    return ret;
1024 1025 1026 1027 1028 1029
}

static int
storagePoolListVolumes(virStoragePoolPtr obj,
                       char **const names,
                       int maxnames) {
1030 1031
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1032
    int i, n = 0;
1033

1034 1035
    memset(names, 0, maxnames * sizeof(*names));

1036
    storageDriverLock(driver);
1037
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1038 1039
    storageDriverUnlock(driver);

1040 1041
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1042
                              "%s", _("no storage pool with matching uuid"));
1043
        goto cleanup;
1044 1045 1046 1047
    }

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

1052 1053
    for (i = 0 ; i < pool->volumes.count && n < maxnames ; i++) {
        if ((names[n++] = strdup(pool->volumes.objs[i]->name)) == NULL) {
1054
            virReportOOMError(obj->conn);
1055 1056 1057 1058
            goto cleanup;
        }
    }

1059
    virStoragePoolObjUnlock(pool);
1060
    return n;
1061 1062

 cleanup:
1063 1064
    if (pool)
        virStoragePoolObjUnlock(pool);
1065
    for (n = 0 ; n < maxnames ; n++)
1066
        VIR_FREE(names[n]);
1067

1068
    memset(names, 0, maxnames * sizeof(*names));
1069 1070 1071 1072 1073 1074 1075
    return -1;
}


static virStorageVolPtr
storageVolumeLookupByName(virStoragePoolPtr obj,
                          const char *name) {
1076 1077
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1078
    virStorageVolDefPtr vol;
1079
    virStorageVolPtr ret = NULL;
1080

1081
    storageDriverLock(driver);
1082
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1083 1084
    storageDriverUnlock(driver);

1085 1086
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1087
                              "%s", _("no storage pool with matching uuid"));
1088
        goto cleanup;
1089 1090 1091 1092
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1093
                              "%s", _("storage pool is not active"));
1094
        goto cleanup;
1095 1096 1097 1098 1099 1100
    }

    vol = virStorageVolDefFindByName(pool, name);

    if (!vol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1101
                              "%s", _("no storage vol with matching name"));
1102
        goto cleanup;
1103 1104
    }

1105 1106 1107
    ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key);

cleanup:
1108 1109
    if (pool)
        virStoragePoolObjUnlock(pool);
1110
    return ret;
1111 1112 1113 1114 1115 1116
}


static virStorageVolPtr
storageVolumeLookupByKey(virConnectPtr conn,
                         const char *key) {
1117
    virStorageDriverStatePtr driver = conn->storagePrivateData;
1118
    unsigned int i;
1119
    virStorageVolPtr ret = NULL;
1120

1121 1122 1123
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count && !ret ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
1124 1125 1126
        if (virStoragePoolObjIsActive(driver->pools.objs[i])) {
            virStorageVolDefPtr vol =
                virStorageVolDefFindByKey(driver->pools.objs[i], key);
1127

1128
            if (vol)
1129
                ret = virGetStorageVol(conn,
1130 1131 1132
                                       driver->pools.objs[i]->def->name,
                                       vol->name,
                                       vol->key);
1133
        }
1134
        virStoragePoolObjUnlock(driver->pools.objs[i]);
1135
    }
1136
    storageDriverUnlock(driver);
1137

1138 1139 1140 1141 1142
    if (!ret)
        virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
                              "%s", _("no storage vol with matching key"));

    return ret;
1143 1144 1145 1146 1147
}

static virStorageVolPtr
storageVolumeLookupByPath(virConnectPtr conn,
                          const char *path) {
1148
    virStorageDriverStatePtr driver = conn->storagePrivateData;
1149
    unsigned int i;
1150
    virStorageVolPtr ret = NULL;
1151

1152 1153 1154
    storageDriverLock(driver);
    for (i = 0 ; i < driver->pools.count && !ret ; i++) {
        virStoragePoolObjLock(driver->pools.objs[i]);
1155
        if (virStoragePoolObjIsActive(driver->pools.objs[i])) {
1156
            virStorageVolDefPtr vol;
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
            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
             */
1167 1168
            if (stable_path == NULL) {
                virStoragePoolObjUnlock(driver->pools.objs[i]);
1169
                goto cleanup;
1170
            }
1171 1172 1173 1174

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

1176
            if (vol)
1177 1178 1179 1180
                ret = virGetStorageVol(conn,
                                       driver->pools.objs[i]->def->name,
                                       vol->name,
                                       vol->key);
1181
        }
1182
        virStoragePoolObjUnlock(driver->pools.objs[i]);
1183 1184
    }

1185 1186 1187 1188 1189
    if (!ret)
        virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
                              "%s", _("no storage vol with matching path"));

cleanup:
1190
    storageDriverUnlock(driver);
1191
    return ret;
1192 1193
}

1194 1195
static int storageVolumeDelete(virStorageVolPtr obj, unsigned int flags);

1196 1197 1198 1199
static virStorageVolPtr
storageVolumeCreateXML(virStoragePoolPtr obj,
                       const char *xmldesc,
                       unsigned int flags ATTRIBUTE_UNUSED) {
1200 1201
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1202
    virStorageBackendPtr backend;
1203 1204
    virStorageVolDefPtr voldef = NULL;
    virStorageVolPtr ret = NULL, volobj = NULL;
1205

1206
    storageDriverLock(driver);
1207
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
1208 1209
    storageDriverUnlock(driver);

1210 1211
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1212
                              "%s", _("no storage pool with matching uuid"));
1213
        goto cleanup;
1214 1215 1216 1217
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1218
                              "%s", _("storage pool is not active"));
1219
        goto cleanup;
1220 1221 1222
    }

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

1225
    voldef = virStorageVolDefParseString(obj->conn, pool->def, xmldesc);
1226
    if (voldef == NULL)
1227
        goto cleanup;
1228

1229
    if (virStorageVolDefFindByName(pool, voldef->name)) {
1230
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1231
                              "%s", _("storage vol already exists"));
1232
        goto cleanup;
1233 1234
    }

1235 1236
    if (VIR_REALLOC_N(pool->volumes.objs,
                      pool->volumes.count+1) < 0) {
1237
        virReportOOMError(obj->conn);
1238
        goto cleanup;
1239 1240
    }

1241 1242
    if (!backend->createVol) {
        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
1243 1244
                              "%s", _("storage pool does not support volume "
                                      "creation"));
1245
        goto cleanup;
1246 1247
    }

1248
    if (backend->createVol(obj->conn, pool, voldef) < 0) {
1249
        goto cleanup;
1250 1251
    }

1252 1253 1254
    pool->volumes.objs[pool->volumes.count++] = voldef;
    volobj = virGetStorageVol(obj->conn, pool->def->name, voldef->name,
                              voldef->key);
1255

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
    if (volobj && backend->buildVol) {
        int buildret;
        virStorageVolDefPtr buildvoldef = NULL;

        if (VIR_ALLOC(buildvoldef) < 0) {
            virReportOOMError(obj->conn);
            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);

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

1279
        storageDriverLock(driver);
1280
        virStoragePoolObjLock(pool);
1281 1282
        storageDriverUnlock(driver);

1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
        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;
1301

1302
cleanup:
1303 1304 1305
    if (volobj)
        virUnrefStorageVol(volobj);
    virStorageVolDefFree(voldef);
1306 1307
    if (pool)
        virStoragePoolObjUnlock(pool);
1308
    return ret;
1309 1310
}

1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
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;
    int buildret, diffpool;

    diffpool = !STREQ(obj->name, vobj->pool);

    storageDriverLock(driver);
    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
    if (diffpool)
        origpool = virStoragePoolObjFindByName(&driver->pools, vobj->pool);
    else
        origpool = pool;
    storageDriverUnlock(driver);

    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
                              "%s", _("no storage pool with matching uuid"));
        goto cleanup;
    }

    if (diffpool && !origpool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
                              "%s", _("no storage pool with matching name"));
        goto cleanup;
    }

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

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

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

    origvol = virStorageVolDefFindByName(origpool, vobj->name);
    if (!origvol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
                              "%s", _("no storage vol with matching name"));
        goto cleanup;
    }

1367
    newvol = virStorageVolDefParseString(obj->conn, pool->def, xmldesc);
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
    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;

1382 1383 1384 1385 1386
    /* 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;

1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
    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) {
        virReportOOMError(obj->conn);
        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);

    if (diffpool) {
        origpool->asyncjobs++;
        virStoragePoolObjUnlock(origpool);
    }

    buildret = backend->buildVolFrom(obj->conn, newvol, origvol, flags);

    storageDriverLock(driver);
    virStoragePoolObjLock(pool);
    if (diffpool)
        virStoragePoolObjLock(origpool);
    storageDriverUnlock(driver);

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

    if (diffpool) {
        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);
    if (diffpool && origpool)
        virStoragePoolObjUnlock(origpool);
    return ret;
}

1470 1471 1472
static int
storageVolumeDelete(virStorageVolPtr obj,
                    unsigned int flags) {
1473 1474
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1475
    virStorageBackendPtr backend;
1476
    virStorageVolDefPtr vol = NULL;
1477
    unsigned int i;
1478
    int ret = -1;
1479

1480
    storageDriverLock(driver);
1481
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1482 1483
    storageDriverUnlock(driver);

1484 1485
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1486
                              "%s", _("no storage pool with matching uuid"));
1487
        goto cleanup;
1488 1489 1490 1491
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1492
                              "%s", _("storage pool is not active"));
1493
        goto cleanup;
1494 1495 1496
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1497
        goto cleanup;
1498 1499 1500 1501 1502

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

    if (!vol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1503
                              "%s", _("no storage vol with matching name"));
1504
        goto cleanup;
1505 1506
    }

1507 1508 1509 1510 1511 1512 1513
    if (vol->building) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
                              _("volume '%s' is still being allocated."),
                              vol->name);
        goto cleanup;
    }

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

1518
        goto cleanup;
1519 1520
    }

1521 1522 1523
    if (backend->deleteVol(obj->conn, pool, vol, flags) < 0)
        goto cleanup;

1524 1525 1526
    for (i = 0 ; i < pool->volumes.count ; i++) {
        if (pool->volumes.objs[i] == vol) {
            virStorageVolDefFree(vol);
1527
            vol = NULL;
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537

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

1538 1539 1540
            break;
        }
    }
1541
    ret = 0;
1542

1543
cleanup:
1544 1545
    if (pool)
        virStoragePoolObjUnlock(pool);
1546
    return ret;
1547 1548 1549 1550 1551
}

static int
storageVolumeGetInfo(virStorageVolPtr obj,
                     virStorageVolInfoPtr info) {
1552 1553
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1554 1555
    virStorageBackendPtr backend;
    virStorageVolDefPtr vol;
1556
    int ret = -1;
1557

1558
    storageDriverLock(driver);
1559
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1560 1561
    storageDriverUnlock(driver);

1562 1563
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1564
                              "%s", _("no storage pool with matching uuid"));
1565
        goto cleanup;
1566 1567 1568 1569
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1570
                              "%s", _("storage pool is not active"));
1571
        goto cleanup;
1572 1573 1574 1575 1576 1577
    }

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

    if (!vol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1578
                              "%s", _("no storage vol with matching name"));
1579
        goto cleanup;
1580 1581 1582
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1583
        goto cleanup;
1584 1585 1586

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

    memset(info, 0, sizeof(*info));
1590
    info->type = vol->type;
1591 1592
    info->capacity = vol->capacity;
    info->allocation = vol->allocation;
1593
    ret = 0;
1594

1595
cleanup:
1596 1597
    if (pool)
        virStoragePoolObjUnlock(pool);
1598
    return ret;
1599 1600 1601 1602 1603
}

static char *
storageVolumeGetXMLDesc(virStorageVolPtr obj,
                        unsigned int flags ATTRIBUTE_UNUSED) {
1604 1605
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
    virStoragePoolObjPtr pool;
1606 1607
    virStorageBackendPtr backend;
    virStorageVolDefPtr vol;
1608
    char *ret = NULL;
1609

1610
    storageDriverLock(driver);
1611
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
1612 1613
    storageDriverUnlock(driver);

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

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

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

    if (!vol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1630
                              "%s", _("no storage vol with matching name"));
1631
        goto cleanup;
1632 1633 1634
    }

    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
1635
        goto cleanup;
1636 1637 1638 1639

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

1641 1642 1643
    ret = virStorageVolDefFormat(obj->conn, pool->def, vol);

cleanup:
1644 1645 1646
    if (pool)
        virStoragePoolObjUnlock(pool);

1647
    return ret;
1648 1649 1650 1651
}

static char *
storageVolumeGetPath(virStorageVolPtr obj) {
1652
    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
1653
    virStoragePoolObjPtr pool;
1654
    virStorageVolDefPtr vol;
1655
    char *ret = NULL;
1656

1657 1658 1659
    storageDriverLock(driver);
    pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
    storageDriverUnlock(driver);
1660 1661
    if (!pool) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1662
                              "%s", _("no storage pool with matching uuid"));
1663
        goto cleanup;
1664 1665 1666 1667
    }

    if (!virStoragePoolObjIsActive(pool)) {
        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1668
                              "%s", _("storage pool is not active"));
1669
        goto cleanup;
1670 1671 1672 1673 1674 1675
    }

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

    if (!vol) {
        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
J
Jim Meyering 已提交
1676
                              "%s", _("no storage vol with matching name"));
1677
        goto cleanup;
1678 1679 1680
    }

    ret = strdup(vol->target.path);
1681
    if (ret == NULL)
1682
        virReportOOMError(obj->conn);
1683 1684

cleanup:
1685 1686
    if (pool)
        virStoragePoolObjUnlock(pool);
1687 1688 1689 1690
    return ret;
}

static virStorageDriver storageDriver = {
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
    .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,
1721
    .volCreateXMLFrom = storageVolumeCreateXMLFrom,
1722 1723 1724 1725
    .volDelete = storageVolumeDelete,
    .volGetInfo = storageVolumeGetInfo,
    .volGetXMLDesc = storageVolumeGetXMLDesc,
    .volGetPath = storageVolumeGetPath,
1726 1727 1728 1729
};


static virStateDriver stateDriver = {
1730 1731 1732 1733
    .initialize = storageDriverStartup,
    .cleanup = storageDriverShutdown,
    .reload = storageDriverReload,
    .active = storageDriverActive,
1734 1735 1736 1737 1738 1739 1740
};

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