parallels_storage.c 43.7 KB
Newer Older
D
Dmitry Guryanov 已提交
1 2 3 4
/*
 * parallels_storage.c: core driver functions for managing
 * Parallels Cloud Server hosts
 *
5
 * Copyright (C) 2013-2014 Red Hat, Inc.
D
Dmitry Guryanov 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2012 Parallels, Inc.
 *
 * 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
19
 * License along with this library.  If not, see
D
Dmitry Guryanov 已提交
20 21 22 23 24 25 26 27 28
 * <http://www.gnu.org/licenses/>.
 *
 */

#include <config.h>

#include <stdlib.h>
#include <dirent.h>
#include <sys/statvfs.h>
29 30 31
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
D
Dmitry Guryanov 已提交
32 33

#include "datatypes.h"
34
#include "dirname.h"
35
#include "viralloc.h"
D
Dmitry Guryanov 已提交
36
#include "configmake.h"
37
#include "virstoragefile.h"
38
#include "virerror.h"
39
#include "virfile.h"
D
Dmitry Guryanov 已提交
40
#include "parallels_utils.h"
41
#include "virstring.h"
D
Dmitry Guryanov 已提交
42 43 44

#define VIR_FROM_THIS VIR_FROM_PARALLELS

45
#define vzPoolNotFoundError(pool_name)                    \
D
Dmitry Guryanov 已提交
46 47 48 49
    virReportError(VIR_ERR_INVALID_ARG,                          \
                   _("pool '%s' not found"), pool_name);

static virStorageVolDefPtr
50
vzStorageVolDefineXML(virStoragePoolObjPtr pool, const char *xmldesc,
D
Dmitry Guryanov 已提交
51 52
                             const char *xmlfile, bool is_new);
static virStorageVolPtr
53
vzStorageVolLookupByPath(virConnectPtr conn, const char *path);
D
Dmitry Guryanov 已提交
54 55

static int
56
vzStoragePoolGetAlloc(virStoragePoolDefPtr def);
D
Dmitry Guryanov 已提交
57 58

static void
59
vzStorageLock(virStorageDriverStatePtr driver)
D
Dmitry Guryanov 已提交
60 61 62 63 64
{
    virMutexLock(&driver->lock);
}

static void
65
vzStorageUnlock(virStorageDriverStatePtr driver)
D
Dmitry Guryanov 已提交
66 67 68 69
{
    virMutexUnlock(&driver->lock);
}

70
int
71
vzStorageClose(virConnectPtr conn)
D
Dmitry Guryanov 已提交
72
{
73
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
74

75 76 77
    if (!privconn)
        return 0;

78 79
    virStorageDriverStatePtr storageState = privconn->storageState;
    privconn->storageState = NULL;
D
Dmitry Guryanov 已提交
80

81 82 83
    if (!storageState)
        return 0;

84
    vzStorageLock(storageState);
D
Dmitry Guryanov 已提交
85 86 87
    virStoragePoolObjListFree(&privconn->pools);
    VIR_FREE(storageState->configDir);
    VIR_FREE(storageState->autostartDir);
88
    vzStorageUnlock(storageState);
D
Dmitry Guryanov 已提交
89 90 91 92 93 94 95
    virMutexDestroy(&storageState->lock);
    VIR_FREE(storageState);

    return 0;
}

static int
96
vzFindVolumes(virStoragePoolObjPtr pool)
D
Dmitry Guryanov 已提交
97 98 99
{
    DIR *dir;
    struct dirent *ent;
100 101
    char *path = NULL;
    int ret = -1;
E
Eric Blake 已提交
102
    int direrr;
D
Dmitry Guryanov 已提交
103 104 105 106 107

    if (!(dir = opendir(pool->def->target.path))) {
        virReportSystemError(errno,
                             _("cannot open path '%s'"),
                             pool->def->target.path);
108
        return -1;
D
Dmitry Guryanov 已提交
109 110
    }

E
Eric Blake 已提交
111
    while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) {
D
Dmitry Guryanov 已提交
112 113 114 115
        if (!virFileHasSuffix(ent->d_name, ".xml"))
            continue;

        if (!(path = virFileBuildPath(pool->def->target.path,
116
                                      ent->d_name, NULL)))
117
            goto cleanup;
118
        if (!vzStorageVolDefineXML(pool, NULL, path, false))
D
Dmitry Guryanov 已提交
119
            goto cleanup;
120

D
Dmitry Guryanov 已提交
121 122
        VIR_FREE(path);
    }
E
Eric Blake 已提交
123 124
    if (direrr < 0)
        goto cleanup;
D
Dmitry Guryanov 已提交
125

126
    ret = 0;
127
 cleanup:
128 129 130
    VIR_FREE(path);
    closedir(dir);
    return ret;
D
Dmitry Guryanov 已提交
131 132 133

}

134 135 136
/*
 * Generate unique pool name by path
 */
137
static char *vzMakePoolName(virConnectPtr conn, const char *path)
138
{
139
    vzConnPtr privconn = conn->privateData;
140
    char *name;
141
    size_t i;
142

143
    for (i = 0; i < UINT_MAX; i++) {
144
        bool found = false;
145
        size_t j;
146

147
        if ((!i && VIR_STRDUP(name, path) < 0) ||
148
            (i && virAsprintf(&name, "%s-%zu", path, i) < 0))
149 150
            return NULL;

151
        for (j = 0; j < strlen(name); j++)
152 153 154
            if (name[j] == '/')
                name[j] = '-';

155
        for (j = 0; j < privconn->pools.count; j++) {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
            if (STREQ(name, privconn->pools.objs[j]->def->name)) {
                found = true;
                break;
            }
        }

        if (!found)
            return name;

        VIR_FREE(name);
    }

    return NULL;
}

static virStoragePoolObjPtr
172
vzPoolCreateByPath(virConnectPtr conn, const char *path)
173
{
174
    vzConnPtr privconn = conn->privateData;
175 176 177 178 179
    virStoragePoolObjListPtr pools = &privconn->pools;
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool = NULL;

    if (VIR_ALLOC(def) < 0)
180
        goto error;
181

182
    if (!(def->name = vzMakePoolName(conn, path)))
183 184 185 186 187 188 189 190 191
        goto error;

    if (virUUIDGenerate(def->uuid)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Can't generate UUID"));
        goto error;
    }

    def->type = VIR_STORAGE_POOL_DIR;
192 193
    if (VIR_STRDUP(def->target.path, path) < 0)
        goto error;
194 195 196 197

    if (!(pool = virStoragePoolObjAssignDef(pools, def)))
        goto error;

198
    if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) {
199 200 201 202 203 204 205
        virStoragePoolObjRemove(pools, pool);
        goto error;
    }

    virStoragePoolObjUnlock(pool);

    return pool;
206
 error:
207 208 209 210 211 212 213 214
    virStoragePoolDefFree(def);
    if (pool)
        virStoragePoolObjUnlock(pool);
    return NULL;
}

/*
 * Create pool of type VIR_STORAGE_POOL_DIR with
215
 * path to the VM, if it does not exist.
216 217
 */
static virStoragePoolObjPtr
218
vzPoolAddByDomain(virConnectPtr conn, virDomainObjPtr dom)
219
{
220 221
    vzConnPtr privconn = conn->privateData;
    vzDomObjPtr pdom = dom->privateData;
222 223 224
    virStoragePoolObjListPtr pools = &privconn->pools;
    char *poolPath;
    virStoragePoolObjPtr pool = NULL;
225
    size_t j;
226

227 228
    poolPath = mdir_name(pdom->home);
    if (!poolPath) {
229 230 231 232
        virReportOOMError();
        return NULL;
    }

233
    for (j = 0; j < pools->count; j++) {
234 235 236 237 238 239 240
        if (STREQ(poolPath, pools->objs[j]->def->target.path)) {
            pool = pools->objs[j];
            break;
        }
    }

    if (!pool)
241
        pool = vzPoolCreateByPath(conn, poolPath);
242 243 244 245 246

    VIR_FREE(poolPath);
    return pool;
}

247
static int vzDiskDescParseNode(xmlDocPtr xml,
248 249 250 251
                                      xmlNodePtr root,
                                      virStorageVolDefPtr def)
{
    xmlXPathContextPtr ctxt = NULL;
252
    int ret = -1;
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

    if (STRNEQ((const char *)root->name, "Parallels_disk_image")) {
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("unknown root element for storage pool"));
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        virReportOOMError();
        goto cleanup;
    }

    ctxt->node = root;

    if (virXPathULongLong("string(./Disk_Parameters/Disk_size)",
269
                          ctxt, &def->target.capacity) < 0) {
270 271 272 273 274
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("failed to get disk size from "
                               "the disk descriptor xml"));
        goto cleanup;
    }
275

276 277
    def->target.capacity <<= 9;
    def->target.allocation = def->target.capacity;
278
    ret = 0;
279
 cleanup:
280 281 282 283 284
    xmlXPathFreeContext(ctxt);
    return ret;

}

285
static int vzDiskDescParse(const char *path, virStorageVolDefPtr def)
286 287 288 289 290 291 292
{
    xmlDocPtr xml;
    int ret = -1;

    if (!(xml = virXMLParse(path, NULL, NULL)))
        return -1;

293
    ret = vzDiskDescParseNode(xml, xmlDocGetRootElement(xml), def);
294 295 296 297
    xmlFreeDoc(xml);
    return ret;
}

298
static int vzAddDiskVolume(virStoragePoolObjPtr pool,
299 300
                                  virDomainObjPtr dom,
                                  const char *diskName,
301 302
                                  const char *diskPath,
                                  const char *diskDescPath)
303 304 305 306
{
    virStorageVolDefPtr def = NULL;

    if (VIR_ALLOC(def))
307
        goto error;
308

309
    if (virAsprintf(&def->name, "%s-%s", dom->def->name, diskName) < 0)
310
        goto error;
311 312 313

    def->type = VIR_STORAGE_VOL_FILE;

314
    if (vzDiskDescParse(diskDescPath, def) < 0)
315
        goto error;
316

317 318 319
    if (!(def->target.path = realpath(diskPath, NULL)))
        goto no_memory;

320 321
    if (VIR_STRDUP(def->key, def->target.path) < 0)
        goto error;
322

323
    if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, def) < 0)
324
        goto error;
325 326

    return 0;
327
 no_memory:
328
    virReportOOMError();
329
 error:
330
    virStorageVolDefFree(def);
331 332 333
    return -1;
}

334
static int vzFindVmVolumes(virStoragePoolObjPtr pool,
335 336
                                  virDomainObjPtr dom)
{
337
    vzDomObjPtr pdom = dom->privateData;
338 339 340 341 342
    DIR *dir;
    struct dirent *ent;
    char *diskPath = NULL, *diskDescPath = NULL;
    struct stat sb;
    int ret = -1;
E
Eric Blake 已提交
343
    int direrr;
344 345 346 347 348

    if (!(dir = opendir(pdom->home))) {
        virReportSystemError(errno,
                             _("cannot open path '%s'"),
                             pdom->home);
349
        return ret;
350 351
    }

E
Eric Blake 已提交
352
    while ((direrr = virDirRead(dir, &ent, pdom->home)) > 0) {
353 354 355
        VIR_FREE(diskPath);
        VIR_FREE(diskDescPath);

356
        if (!(diskPath = virFileBuildPath(pdom->home, ent->d_name, NULL)))
357 358 359 360 361 362 363 364 365 366 367 368 369
            goto cleanup;

        if (lstat(diskPath, &sb) < 0) {
            virReportSystemError(errno,
                                 _("cannot stat path '%s'"),
                                 ent->d_name);
            goto cleanup;
        }

        if (!S_ISDIR(sb.st_mode))
            continue;

        if (!(diskDescPath = virFileBuildPath(diskPath,
370
                                              "DiskDescriptor", ".xml")))
371 372
            goto cleanup;

373
        if (!virFileExists(diskDescPath))
374 375 376 377
            continue;

        /* here we know, that ent->d_name is a disk image directory */

378
        if (vzAddDiskVolume(pool, dom, ent->d_name,
379
                                   diskPath, diskDescPath))
380 381
            goto cleanup;
    }
E
Eric Blake 已提交
382 383
    if (direrr < 0)
        goto cleanup;
384 385

    ret = 0;
386
 cleanup:
387 388 389 390 391 392 393
    VIR_FREE(diskPath);
    VIR_FREE(diskDescPath);
    closedir(dir);
    return ret;

}

394
static int
395
vzPoolsAdd(virDomainObjPtr dom,
396 397
                  void *opaque)
{
398
    virConnectPtr conn = opaque;
399 400
    virStoragePoolObjPtr pool;

401
    if (!(pool = vzPoolAddByDomain(conn, dom)))
402
        return -1;
403

404
    if (vzFindVmVolumes(pool, dom))
405
        return -1;
406

407
    return 0;
408 409
}

410
static int vzLoadPools(virConnectPtr conn)
D
Dmitry Guryanov 已提交
411
{
412
    vzConnPtr privconn = conn->privateData;
413
    virStorageDriverStatePtr storageState = privconn->storageState;
414
    char *base = NULL;
415 416
    size_t i;

417 418
    if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
        goto error;
D
Dmitry Guryanov 已提交
419

420
    /* Configuration path is /etc/libvirt/parallels-storage/... . */
D
Dmitry Guryanov 已提交
421 422
    if (virAsprintf(&storageState->configDir,
                    "%s/parallels-storage", base) == -1)
423
        goto error;
D
Dmitry Guryanov 已提交
424 425 426

    if (virAsprintf(&storageState->autostartDir,
                    "%s/parallels-storage/autostart", base) == -1)
427
        goto error;
D
Dmitry Guryanov 已提交
428 429 430 431 432 433 434 435 436 437 438

    VIR_FREE(base);

    if (virStoragePoolLoadAllConfigs(&privconn->pools,
                                     storageState->configDir,
                                     storageState->autostartDir) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to load pool configs"));
        goto error;
    }

439
    if (virDomainObjListForEach(privconn->domains, vzPoolsAdd, conn) < 0)
440 441
        goto error;

442
    for (i = 0; i < privconn->pools.count; i++) {
D
Dmitry Guryanov 已提交
443 444 445 446 447 448
        virStoragePoolObjLock(privconn->pools.objs[i]);
        virStoragePoolObjPtr pool;

        pool = privconn->pools.objs[i];
        pool->active = 1;

449
        if (vzStoragePoolGetAlloc(pool->def) < 0)
D
Dmitry Guryanov 已提交
450 451
            goto error;

452
        if (vzFindVolumes(pool) < 0)
D
Dmitry Guryanov 已提交
453 454 455 456 457
            goto error;

        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }

458 459
    return 0;

460
 error:
461 462 463 464
    VIR_FREE(base);
    return -1;
}

465
virDrvOpenStatus
466
vzStorageOpen(virConnectPtr conn,
467 468
                     unsigned int flags)
{
469
    vzConnPtr privconn = conn->privateData;
470 471 472
    virStorageDriverStatePtr storageState;
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

473 474
    if (STRNEQ(conn->driver->name, "vz") &&
        STRNEQ(conn->driver->name, "Parallels"))
475 476
        return VIR_DRV_OPEN_DECLINED;

477
    if (VIR_ALLOC(storageState) < 0)
478 479 480 481 482 483
        return VIR_DRV_OPEN_ERROR;

    if (virMutexInit(&storageState->lock) < 0) {
        VIR_FREE(storageState);
        return VIR_DRV_OPEN_ERROR;
    }
D
Dmitry Guryanov 已提交
484

485
    privconn->storageState = storageState;
486
    vzStorageLock(storageState);
487

488
    if (vzLoadPools(conn))
489 490
        goto error;

491
    vzStorageUnlock(storageState);
D
Dmitry Guryanov 已提交
492 493 494

    return VIR_DRV_OPEN_SUCCESS;

495
 error:
496 497
    vzStorageUnlock(storageState);
    vzStorageClose(conn);
498
    return VIR_DRV_OPEN_ERROR;
D
Dmitry Guryanov 已提交
499 500 501
}

static int
502
vzConnectNumOfStoragePools(virConnectPtr conn)
D
Dmitry Guryanov 已提交
503
{
504
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
505 506 507
    int numActive = 0;
    size_t i;

508
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
509 510 511
    for (i = 0; i < privconn->pools.count; i++)
        if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
            numActive++;
512
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
513 514 515 516 517

    return numActive;
}

static int
518
vzConnectListStoragePools(virConnectPtr conn, char **const names, int nnames)
D
Dmitry Guryanov 已提交
519
{
520
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
521 522 523
    int n = 0;
    size_t i;

524
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
525 526 527 528
    memset(names, 0, sizeof(*names) * nnames);
    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
        virStoragePoolObjLock(privconn->pools.objs[i]);
        if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
529
            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
D
Dmitry Guryanov 已提交
530
            virStoragePoolObjUnlock(privconn->pools.objs[i]);
531
            goto error;
D
Dmitry Guryanov 已提交
532 533 534
        }
        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }
535
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
536 537 538

    return n;

539
 error:
D
Dmitry Guryanov 已提交
540 541
    for (n = 0; n < nnames; n++)
        VIR_FREE(names[n]);
542
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
543 544 545 546
    return -1;
}

static int
547
vzConnectNumOfDefinedStoragePools(virConnectPtr conn)
D
Dmitry Guryanov 已提交
548
{
549
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
550 551 552
    int numInactive = 0;
    size_t i;

553
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
554 555 556 557 558 559
    for (i = 0; i < privconn->pools.count; i++) {
        virStoragePoolObjLock(privconn->pools.objs[i]);
        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
            numInactive++;
        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }
560
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
561 562 563 564 565

    return numInactive;
}

static int
566
vzConnectListDefinedStoragePools(virConnectPtr conn,
567
                                        char **const names, int nnames)
D
Dmitry Guryanov 已提交
568
{
569
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
570 571 572
    int n = 0;
    size_t i;

573
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
574 575 576 577
    memset(names, 0, sizeof(*names) * nnames);
    for (i = 0; i < privconn->pools.count && n < nnames; i++) {
        virStoragePoolObjLock(privconn->pools.objs[i]);
        if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
578
            VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
D
Dmitry Guryanov 已提交
579
            virStoragePoolObjUnlock(privconn->pools.objs[i]);
580
            goto error;
D
Dmitry Guryanov 已提交
581 582 583
        }
        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }
584
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
585 586 587

    return n;

588
 error:
D
Dmitry Guryanov 已提交
589 590
    for (n = 0; n < nnames; n++)
        VIR_FREE(names[n]);
591
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
592 593 594 595 596
    return -1;
}


static int
597
vzStoragePoolIsActive(virStoragePoolPtr pool)
D
Dmitry Guryanov 已提交
598
{
599
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
600 601 602
    virStoragePoolObjPtr obj;
    int ret = -1;

603
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
604
    obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
605
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
606 607 608 609 610 611
    if (!obj) {
        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
        goto cleanup;
    }
    ret = virStoragePoolObjIsActive(obj);

612
 cleanup:
D
Dmitry Guryanov 已提交
613 614 615 616 617 618
    if (obj)
        virStoragePoolObjUnlock(obj);
    return ret;
}

static int
619
vzStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
D
Dmitry Guryanov 已提交
620 621 622 623 624
{
    return 1;
}

static virStoragePoolPtr
625
vzStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
D
Dmitry Guryanov 已提交
626
{
627
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
628 629 630
    virStoragePoolObjPtr pool;
    virStoragePoolPtr ret = NULL;

631
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
632
    pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
633
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
634 635 636 637 638 639

    if (pool == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
        goto cleanup;
    }

640 641
    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
                            NULL, NULL);
D
Dmitry Guryanov 已提交
642

643
 cleanup:
D
Dmitry Guryanov 已提交
644 645 646 647 648 649
    if (pool)
        virStoragePoolObjUnlock(pool);
    return ret;
}

static virStoragePoolPtr
650
vzStoragePoolLookupByName(virConnectPtr conn, const char *name)
D
Dmitry Guryanov 已提交
651
{
652
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
653 654 655
    virStoragePoolObjPtr pool;
    virStoragePoolPtr ret = NULL;

656
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
657
    pool = virStoragePoolObjFindByName(&privconn->pools, name);
658
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
659 660 661 662 663 664

    if (pool == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
        goto cleanup;
    }

665 666
    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
                            NULL, NULL);
D
Dmitry Guryanov 已提交
667

668
 cleanup:
D
Dmitry Guryanov 已提交
669 670 671 672 673 674
    if (pool)
        virStoragePoolObjUnlock(pool);
    return ret;
}

static virStoragePoolPtr
675
vzStoragePoolLookupByVolume(virStorageVolPtr vol)
D
Dmitry Guryanov 已提交
676
{
677
    return vzStoragePoolLookupByName(vol->conn, vol->pool);
D
Dmitry Guryanov 已提交
678 679 680 681 682 683 684
}

/*
 * Fill capacity, available and allocation
 * fields in pool definition.
 */
static int
685
vzStoragePoolGetAlloc(virStoragePoolDefPtr def)
D
Dmitry Guryanov 已提交
686 687 688 689 690 691 692 693 694 695 696 697 698
{
    struct statvfs sb;

    if (statvfs(def->target.path, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot statvfs path '%s'"),
                             def->target.path);
        return -1;
    }

    def->capacity = ((unsigned long long)sb.f_frsize *
                     (unsigned long long)sb.f_blocks);
    def->available = ((unsigned long long)sb.f_bfree *
699
                      (unsigned long long)sb.f_frsize);
D
Dmitry Guryanov 已提交
700 701 702 703 704 705
    def->allocation = def->capacity - def->available;

    return 0;
}

static virStoragePoolPtr
706
vzStoragePoolDefineXML(virConnectPtr conn,
707
                              const char *xml, unsigned int flags)
D
Dmitry Guryanov 已提交
708
{
709
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
710 711 712 713 714 715
    virStoragePoolDefPtr def;
    virStoragePoolObjPtr pool = NULL;
    virStoragePoolPtr ret = NULL;

    virCheckFlags(0, NULL);

716
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
717 718 719 720 721 722 723 724 725 726 727 728
    if (!(def = virStoragePoolDefParseString(xml)))
        goto cleanup;

    if (def->type != VIR_STORAGE_POOL_DIR) {
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("Only local directories are supported"));
        goto cleanup;
    }

    if (virStoragePoolObjIsDuplicate(&privconn->pools, def, 0) < 0)
        goto cleanup;

729
    if (virStoragePoolSourceFindDuplicate(conn, &privconn->pools, def) < 0)
D
Dmitry Guryanov 已提交
730 731
        goto cleanup;

732
    if (vzStoragePoolGetAlloc(def))
D
Dmitry Guryanov 已提交
733 734 735 736 737
        goto cleanup;

    if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
        goto cleanup;

738
    if (virStoragePoolObjSaveDef(privconn->storageState, pool, def) < 0) {
D
Dmitry Guryanov 已提交
739 740 741 742 743 744
        virStoragePoolObjRemove(&privconn->pools, pool);
        def = NULL;
        goto cleanup;
    }
    def = NULL;

745
    if (VIR_STRDUP(pool->configFile, "\0") < 0)
D
Dmitry Guryanov 已提交
746 747
        goto cleanup;

748 749
    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
                            NULL, NULL);
D
Dmitry Guryanov 已提交
750

751
 cleanup:
D
Dmitry Guryanov 已提交
752 753 754
    virStoragePoolDefFree(def);
    if (pool)
        virStoragePoolObjUnlock(pool);
755
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
756 757 758 759
    return ret;
}

static int
760
vzStoragePoolUndefine(virStoragePoolPtr pool)
D
Dmitry Guryanov 已提交
761
{
762
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
763 764 765
    virStoragePoolObjPtr privpool;
    int ret = -1;

766
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
767 768 769
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);

    if (privpool == NULL) {
770
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
        goto cleanup;
    }

    if (virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is still active"), pool->name);
        goto cleanup;
    }

    if (virStoragePoolObjDeleteDef(privpool) < 0)
        goto cleanup;

    VIR_FREE(privpool->configFile);

    virStoragePoolObjRemove(&privconn->pools, privpool);
    ret = 0;

788
 cleanup:
D
Dmitry Guryanov 已提交
789 790
    if (privpool)
        virStoragePoolObjUnlock(privpool);
791
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
792 793 794 795
    return ret;
}

static int
796
vzStoragePoolCreate(virStoragePoolPtr pool, unsigned int flags)
D
Dmitry Guryanov 已提交
797
{
798
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
799 800 801 802 803
    virStoragePoolObjPtr privpool;
    int ret = -1;

    virCheckFlags(0, -1);

804
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
805
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
806
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
807 808

    if (privpool == NULL) {
809
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
810 811 812 813 814 815 816 817 818 819 820 821
        goto cleanup;
    }

    if (virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is already active"), pool->name);
        goto cleanup;
    }

    privpool->active = 1;
    ret = 0;

822
 cleanup:
D
Dmitry Guryanov 已提交
823 824 825 826 827 828
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static int
829
vzStoragePoolDestroy(virStoragePoolPtr pool)
D
Dmitry Guryanov 已提交
830
{
831
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
832 833 834
    virStoragePoolObjPtr privpool;
    int ret = -1;

835
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
836 837 838
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);

    if (privpool == NULL) {
839
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

    if (privpool->configFile == NULL) {
        virStoragePoolObjRemove(&privconn->pools, privpool);
        privpool = NULL;
    }
    ret = 0;

855
 cleanup:
D
Dmitry Guryanov 已提交
856 857
    if (privpool)
        virStoragePoolObjUnlock(privpool);
858
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
859 860 861 862
    return ret;
}

static int
863
vzStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
D
Dmitry Guryanov 已提交
864
{
865
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
866 867 868 869 870
    virStoragePoolObjPtr privpool;
    int ret = -1;

    virCheckFlags(0, -1);

871
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
872
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
873
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
874 875

    if (privpool == NULL) {
876
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
877 878 879 880 881 882 883 884 885 886
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }
    ret = 0;

887
 cleanup:
D
Dmitry Guryanov 已提交
888 889 890 891 892 893 894
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}


static int
895
vzStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
D
Dmitry Guryanov 已提交
896
{
897
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
898 899 900
    virStoragePoolObjPtr privpool;
    int ret = -1;

901
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
902
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
903
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
904 905

    if (privpool == NULL) {
906
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
907 908 909 910 911 912 913 914 915 916 917 918 919
        goto cleanup;
    }

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

920
 cleanup:
D
Dmitry Guryanov 已提交
921 922 923 924 925 926
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static char *
927
vzStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
D
Dmitry Guryanov 已提交
928
{
929
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
930 931 932 933 934
    virStoragePoolObjPtr privpool;
    char *ret = NULL;

    virCheckFlags(0, NULL);

935
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
936
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
937
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
938 939

    if (privpool == NULL) {
940
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
941 942 943 944 945
        goto cleanup;
    }

    ret = virStoragePoolDefFormat(privpool->def);

946
 cleanup:
D
Dmitry Guryanov 已提交
947 948 949 950 951 952
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static int
953
vzStoragePoolGetAutostart(virStoragePoolPtr pool, int *autostart)
D
Dmitry Guryanov 已提交
954
{
955
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
956 957 958
    virStoragePoolObjPtr privpool;
    int ret = -1;

959
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
960
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
961
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
962 963

    if (privpool == NULL) {
964
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
965 966 967 968 969 970 971 972 973 974
        goto cleanup;
    }

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

975
 cleanup:
D
Dmitry Guryanov 已提交
976 977 978 979 980 981
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static int
982
vzStoragePoolSetAutostart(virStoragePoolPtr pool, int autostart)
D
Dmitry Guryanov 已提交
983
{
984
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
985 986 987
    virStoragePoolObjPtr privpool;
    int ret = -1;

988
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
989
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
990
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
991 992

    if (privpool == NULL) {
993
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
994 995 996 997 998 999 1000 1001 1002 1003 1004
        goto cleanup;
    }

    if (!privpool->configFile) {
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("pool has no config file"));
        goto cleanup;
    }

    privpool->autostart = (autostart != 0);
    ret = 0;

1005
 cleanup:
D
Dmitry Guryanov 已提交
1006 1007 1008 1009 1010 1011
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static int
1012
vzStoragePoolNumOfVolumes(virStoragePoolPtr pool)
D
Dmitry Guryanov 已提交
1013
{
1014
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
1015 1016 1017
    virStoragePoolObjPtr privpool;
    int ret = -1;

1018
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1019
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
1020
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1021 1022

    if (privpool == NULL) {
1023
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

    ret = privpool->volumes.count;

1035
 cleanup:
D
Dmitry Guryanov 已提交
1036 1037 1038 1039 1040 1041
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static int
1042
vzStoragePoolListVolumes(virStoragePoolPtr pool,
D
Dmitry Guryanov 已提交
1043 1044
                                char **const names, int maxnames)
{
1045
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
1046 1047 1048 1049 1050 1051
    virStoragePoolObjPtr privpool;
    int n = 0;
    size_t i = 0;

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

1052
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1053
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
1054
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1055 1056

    if (privpool == NULL) {
1057
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
        goto error;
    }


    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                 _("storage pool '%s' is not active"), pool->name);
        goto error;
    }

    for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
1069
        if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
D
Dmitry Guryanov 已提交
1070 1071 1072 1073 1074 1075
            goto error;
    }

    virStoragePoolObjUnlock(privpool);
    return n;

1076
 error:
D
Dmitry Guryanov 已提交
1077 1078 1079 1080 1081 1082 1083 1084 1085
    for (n = 0; n < maxnames; n++)
        VIR_FREE(names[i]);

    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return -1;
}

static virStorageVolPtr
1086
vzStorageVolLookupByName(virStoragePoolPtr pool,
D
Dmitry Guryanov 已提交
1087 1088
                                   const char *name)
{
1089
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
1090 1091 1092 1093
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol;
    virStorageVolPtr ret = NULL;

1094
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1095
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
1096
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1097 1098

    if (privpool == NULL) {
1099
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
        goto cleanup;
    }


    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

    privvol = virStorageVolDefFindByName(privpool, name);

    if (!privvol) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"), name);
        goto cleanup;
    }

    ret = virGetStorageVol(pool->conn, privpool->def->name,
1119 1120
                           privvol->name, privvol->key,
                           NULL, NULL);
D
Dmitry Guryanov 已提交
1121

1122
 cleanup:
D
Dmitry Guryanov 已提交
1123 1124 1125 1126 1127 1128 1129
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}


static virStorageVolPtr
1130
vzStorageVolLookupByKey(virConnectPtr conn, const char *key)
D
Dmitry Guryanov 已提交
1131
{
1132
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
1133 1134 1135
    size_t i;
    virStorageVolPtr ret = NULL;

1136
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1137 1138 1139 1140 1141 1142 1143 1144 1145
    for (i = 0; i < privconn->pools.count; i++) {
        virStoragePoolObjLock(privconn->pools.objs[i]);
        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
            virStorageVolDefPtr privvol =
                virStorageVolDefFindByKey(privconn->pools.objs[i], key);

            if (privvol) {
                ret = virGetStorageVol(conn,
                                       privconn->pools.objs[i]->def->name,
1146 1147
                                       privvol->name, privvol->key,
                                       NULL, NULL);
D
Dmitry Guryanov 已提交
1148 1149 1150 1151 1152 1153
                virStoragePoolObjUnlock(privconn->pools.objs[i]);
                break;
            }
        }
        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }
1154
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1155 1156 1157 1158 1159 1160 1161 1162

    if (!ret)
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching key '%s'"), key);

    return ret;
}

1163
virStorageVolPtr
1164
vzStorageVolLookupByPathLocked(virConnectPtr conn, const char *path)
D
Dmitry Guryanov 已提交
1165
{
1166
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
    size_t i;
    virStorageVolPtr ret = NULL;

    for (i = 0; i < privconn->pools.count; i++) {
        virStoragePoolObjLock(privconn->pools.objs[i]);
        if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
            virStorageVolDefPtr privvol =
                virStorageVolDefFindByPath(privconn->pools.objs[i], path);

            if (privvol) {
                ret = virGetStorageVol(conn,
                                       privconn->pools.objs[i]->def->name,
1179 1180
                                       privvol->name, privvol->key,
                                       NULL, NULL);
D
Dmitry Guryanov 已提交
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
                virStoragePoolObjUnlock(privconn->pools.objs[i]);
                break;
            }
        }
        virStoragePoolObjUnlock(privconn->pools.objs[i]);
    }

    if (!ret)
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching path '%s'"), path);

    return ret;
}

static virStorageVolPtr
1196
vzStorageVolLookupByPath(virConnectPtr conn, const char *path)
D
Dmitry Guryanov 已提交
1197
{
1198
    vzConnPtr privconn = conn->privateData;
D
Dmitry Guryanov 已提交
1199 1200
    virStorageVolPtr ret = NULL;

1201 1202 1203
    vzDriverLock(privconn);
    ret = vzStorageVolLookupByPathLocked(conn, path);
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1204 1205 1206 1207 1208

    return ret;
}

static virStorageVolDefPtr
1209
vzStorageVolDefineXML(virStoragePoolObjPtr pool,
D
Dmitry Guryanov 已提交
1210 1211 1212 1213 1214 1215 1216 1217
                             const char *xmldesc,
                             const char *xmlfile, bool is_new)
{
    virStorageVolDefPtr privvol = NULL;
    virStorageVolDefPtr ret = NULL;
    char *xml_path = NULL;

    if (xmlfile)
1218
        privvol = virStorageVolDefParseFile(pool->def, xmlfile, 0);
D
Dmitry Guryanov 已提交
1219
    else
1220
        privvol = virStorageVolDefParseString(pool->def, xmldesc, 0);
D
Dmitry Guryanov 已提交
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232

    if (privvol == NULL)
        goto cleanup;

    if (virStorageVolDefFindByName(pool, privvol->name)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("storage vol already exists"));
        goto cleanup;
    }

    if (is_new) {
        /* Make sure enough space */
1233
        if ((pool->def->allocation + privvol->target.allocation) >
D
Dmitry Guryanov 已提交
1234 1235 1236 1237 1238 1239 1240 1241 1242
            pool->def->capacity) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Not enough free space in pool for volume '%s'"),
                           privvol->name);
            goto cleanup;
        }
    }

    if (virAsprintf(&privvol->target.path, "%s/%s",
1243
                    pool->def->target.path, privvol->name) < 0)
D
Dmitry Guryanov 已提交
1244 1245
        goto cleanup;

1246
    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0)
D
Dmitry Guryanov 已提交
1247 1248 1249
        goto cleanup;

    if (is_new) {
1250
        xml_path = vzAddFileExt(privvol->target.path, ".xml");
D
Dmitry Guryanov 已提交
1251 1252 1253
        if (!xml_path)
            goto cleanup;

J
Ján Tomko 已提交
1254
        if (virXMLSaveFile(xml_path, NULL, "volume-create", xmldesc)) {
D
Dmitry Guryanov 已提交
1255 1256 1257 1258 1259
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Can't create file with volume description"));
            goto cleanup;
        }

1260
        pool->def->allocation += privvol->target.allocation;
D
Dmitry Guryanov 已提交
1261 1262 1263 1264
        pool->def->available = (pool->def->capacity -
                                pool->def->allocation);
    }

1265 1266 1267
    if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs,
                                pool->volumes.count, privvol) < 0)
        goto cleanup;
D
Dmitry Guryanov 已提交
1268 1269 1270 1271

    ret = privvol;
    privvol = NULL;

1272
 cleanup:
D
Dmitry Guryanov 已提交
1273 1274 1275 1276 1277 1278
    virStorageVolDefFree(privvol);
    VIR_FREE(xml_path);
    return ret;
}

static virStorageVolPtr
1279
vzStorageVolCreateXML(virStoragePoolPtr pool,
D
Dmitry Guryanov 已提交
1280 1281
                                const char *xmldesc, unsigned int flags)
{
1282
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
1283 1284 1285 1286 1287 1288
    virStoragePoolObjPtr privpool;
    virStorageVolPtr ret = NULL;
    virStorageVolDefPtr privvol = NULL;

    virCheckFlags(0, NULL);

1289
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1290
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
1291
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1292 1293

    if (privpool == NULL) {
1294
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
1295 1296 1297 1298 1299 1300 1301 1302 1303
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

1304
    privvol = vzStorageVolDefineXML(privpool, xmldesc, NULL, true);
D
Dmitry Guryanov 已提交
1305 1306 1307 1308
    if (!privvol)
        goto cleanup;

    ret = virGetStorageVol(pool->conn, privpool->def->name,
1309 1310
                           privvol->name, privvol->key,
                           NULL, NULL);
1311
 cleanup:
D
Dmitry Guryanov 已提交
1312 1313 1314 1315 1316 1317
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static virStorageVolPtr
1318
vzStorageVolCreateXMLFrom(virStoragePoolPtr pool,
D
Dmitry Guryanov 已提交
1319 1320 1321 1322
                                    const char *xmldesc,
                                    virStorageVolPtr clonevol,
                                    unsigned int flags)
{
1323
    vzConnPtr privconn = pool->conn->privateData;
D
Dmitry Guryanov 已提交
1324 1325 1326 1327 1328 1329
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol = NULL, origvol = NULL;
    virStorageVolPtr ret = NULL;

    virCheckFlags(0, NULL);

1330
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1331
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
1332
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1333 1334

    if (privpool == NULL) {
1335
        vzPoolNotFoundError(pool->name);
D
Dmitry Guryanov 已提交
1336 1337 1338 1339 1340 1341 1342 1343 1344
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

1345
    privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
D
Dmitry Guryanov 已提交
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
    if (privvol == NULL)
        goto cleanup;

    if (virStorageVolDefFindByName(privpool, privvol->name)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("storage vol already exists"));
        goto cleanup;
    }

    origvol = virStorageVolDefFindByName(privpool, clonevol->name);
    if (!origvol) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"),
                       clonevol->name);
        goto cleanup;
    }

    /* Make sure enough space */
1364
    if ((privpool->def->allocation + privvol->target.allocation) >
D
Dmitry Guryanov 已提交
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
        privpool->def->capacity) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Not enough free space in pool for volume '%s'"),
                       privvol->name);
        goto cleanup;
    }
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

    if (virAsprintf(&privvol->target.path, "%s/%s",
1375
                    privpool->def->target.path, privvol->name) == -1)
D
Dmitry Guryanov 已提交
1376 1377
        goto cleanup;

1378
    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0)
D
Dmitry Guryanov 已提交
1379 1380
        goto cleanup;

1381
    privpool->def->allocation += privvol->target.allocation;
D
Dmitry Guryanov 已提交
1382 1383 1384
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

1385 1386 1387
    if (VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
                                privpool->volumes.count, privvol) < 0)
        goto cleanup;
D
Dmitry Guryanov 已提交
1388 1389

    ret = virGetStorageVol(pool->conn, privpool->def->name,
1390 1391
                           privvol->name, privvol->key,
                           NULL, NULL);
D
Dmitry Guryanov 已提交
1392 1393
    privvol = NULL;

1394
 cleanup:
D
Dmitry Guryanov 已提交
1395 1396 1397 1398 1399 1400
    virStorageVolDefFree(privvol);
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

1401
int vzStorageVolDefRemove(virStoragePoolObjPtr privpool,
1402
                                    virStorageVolDefPtr privvol)
D
Dmitry Guryanov 已提交
1403 1404 1405
{
    int ret = -1;
    char *xml_path = NULL;
1406
    size_t i;
D
Dmitry Guryanov 已提交
1407

1408
    privpool->def->allocation -= privvol->target.allocation;
D
Dmitry Guryanov 已提交
1409 1410 1411 1412 1413
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

    for (i = 0; i < privpool->volumes.count; i++) {
        if (privpool->volumes.objs[i] == privvol) {
1414
            xml_path = vzAddFileExt(privvol->target.path, ".xml");
D
Dmitry Guryanov 已提交
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
            if (!xml_path)
                goto cleanup;

            if (unlink(xml_path)) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Can't remove file '%s'"), xml_path);
                goto cleanup;
            }

            virStorageVolDefFree(privvol);

1426
            VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
D
Dmitry Guryanov 已提交
1427 1428 1429
            break;
        }
    }
1430 1431

    ret = 0;
1432
 cleanup:
1433 1434 1435 1436 1437
    VIR_FREE(xml_path);
    return ret;
}

static int
1438
vzStorageVolDelete(virStorageVolPtr vol, unsigned int flags)
1439
{
1440
    vzConnPtr privconn = vol->conn->privateData;
1441 1442 1443 1444 1445 1446
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol;
    int ret = -1;

    virCheckFlags(0, -1);

1447
    vzDriverLock(privconn);
1448
    privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
1449
    vzDriverUnlock(privconn);
1450 1451

    if (privpool == NULL) {
1452
        vzPoolNotFoundError(vol->pool);
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
        goto cleanup;
    }


    privvol = virStorageVolDefFindByName(privpool, vol->name);

    if (privvol == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"), vol->name);
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), vol->pool);
        goto cleanup;
    }


1472
    if (vzStorageVolDefRemove(privpool, privvol))
1473 1474
        goto cleanup;

D
Dmitry Guryanov 已提交
1475 1476
    ret = 0;

1477
 cleanup:
D
Dmitry Guryanov 已提交
1478 1479 1480 1481 1482 1483 1484
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}


static int
1485
vzStorageVolTypeForPool(int pooltype)
D
Dmitry Guryanov 已提交
1486 1487 1488 1489 1490 1491 1492
{

    switch (pooltype) {
        case VIR_STORAGE_POOL_DIR:
        case VIR_STORAGE_POOL_FS:
        case VIR_STORAGE_POOL_NETFS:
            return VIR_STORAGE_VOL_FILE;
1493
 default:
D
Dmitry Guryanov 已提交
1494 1495 1496 1497 1498
            return VIR_STORAGE_VOL_BLOCK;
    }
}

static int
1499
vzStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
D
Dmitry Guryanov 已提交
1500
{
1501
    vzConnPtr privconn = vol->conn->privateData;
D
Dmitry Guryanov 已提交
1502 1503 1504 1505
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol;
    int ret = -1;

1506
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1507
    privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
1508
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1509 1510

    if (privpool == NULL) {
1511
        vzPoolNotFoundError(vol->pool);
D
Dmitry Guryanov 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
        goto cleanup;
    }

    privvol = virStorageVolDefFindByName(privpool, vol->name);

    if (privvol == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"), vol->name);
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), vol->pool);
        goto cleanup;
    }

    memset(info, 0, sizeof(*info));
1530
    info->type = vzStorageVolTypeForPool(privpool->def->type);
1531 1532
    info->capacity = privvol->target.capacity;
    info->allocation = privvol->target.allocation;
D
Dmitry Guryanov 已提交
1533 1534
    ret = 0;

1535
 cleanup:
D
Dmitry Guryanov 已提交
1536 1537 1538 1539 1540 1541
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static char *
1542
vzStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
D
Dmitry Guryanov 已提交
1543
{
1544
    vzConnPtr privconn = vol->conn->privateData;
D
Dmitry Guryanov 已提交
1545 1546 1547 1548 1549 1550
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol;
    char *ret = NULL;

    virCheckFlags(0, NULL);

1551
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1552
    privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
1553
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1554 1555

    if (privpool == NULL) {
1556
        vzPoolNotFoundError(vol->pool);
D
Dmitry Guryanov 已提交
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
        goto cleanup;
    }

    privvol = virStorageVolDefFindByName(privpool, vol->name);

    if (privvol == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"), vol->name);
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), vol->pool);
        goto cleanup;
    }

    ret = virStorageVolDefFormat(privpool->def, privvol);

1576
 cleanup:
D
Dmitry Guryanov 已提交
1577 1578 1579 1580 1581 1582
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

static char *
1583
vzStorageVolGetPath(virStorageVolPtr vol)
D
Dmitry Guryanov 已提交
1584
{
1585
    vzConnPtr privconn = vol->conn->privateData;
D
Dmitry Guryanov 已提交
1586 1587 1588 1589
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol;
    char *ret = NULL;

1590
    vzDriverLock(privconn);
D
Dmitry Guryanov 已提交
1591
    privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
1592
    vzDriverUnlock(privconn);
D
Dmitry Guryanov 已提交
1593 1594

    if (privpool == NULL) {
1595
        vzPoolNotFoundError(vol->pool);
D
Dmitry Guryanov 已提交
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
        goto cleanup;
    }

    privvol = virStorageVolDefFindByName(privpool, vol->name);

    if (privvol == NULL) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"), vol->name);
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), vol->pool);
        goto cleanup;
    }

1613
    ignore_value(VIR_STRDUP(ret, privvol->target.path));
D
Dmitry Guryanov 已提交
1614

1615
 cleanup:
D
Dmitry Guryanov 已提交
1616 1617 1618 1619 1620
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}

1621
virStorageDriver vzStorageDriver = {
D
Dmitry Guryanov 已提交
1622
    .name = "Parallels",
1623

1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
    .connectNumOfStoragePools = vzConnectNumOfStoragePools,   /* 0.10.0 */
    .connectListStoragePools = vzConnectListStoragePools,   /* 0.10.0 */
    .connectNumOfDefinedStoragePools = vzConnectNumOfDefinedStoragePools,     /* 0.10.0 */
    .connectListDefinedStoragePools = vzConnectListDefinedStoragePools,     /* 0.10.0 */
    .storagePoolLookupByName = vzStoragePoolLookupByName,     /* 0.10.0 */
    .storagePoolLookupByUUID = vzStoragePoolLookupByUUID,     /* 0.10.0 */
    .storagePoolLookupByVolume = vzStoragePoolLookupByVolume, /* 0.10.0 */
    .storagePoolDefineXML = vzStoragePoolDefineXML,      /* 0.10.0 */
    .storagePoolUndefine = vzStoragePoolUndefine,     /* 0.10.0 */
    .storagePoolCreate = vzStoragePoolCreate,  /* 0.10.0 */
    .storagePoolDestroy = vzStoragePoolDestroy,       /* 0.10.0 */
    .storagePoolRefresh = vzStoragePoolRefresh,       /* 0.10.0 */
    .storagePoolGetInfo = vzStoragePoolGetInfo,       /* 0.10.0 */
    .storagePoolGetXMLDesc = vzStoragePoolGetXMLDesc, /* 0.10.0 */
    .storagePoolGetAutostart = vzStoragePoolGetAutostart,     /* 0.10.0 */
    .storagePoolSetAutostart = vzStoragePoolSetAutostart,     /* 0.10.0 */
    .storagePoolNumOfVolumes = vzStoragePoolNumOfVolumes,       /* 0.10.0 */
    .storagePoolListVolumes = vzStoragePoolListVolumes,       /* 0.10.0 */

    .storageVolLookupByName = vzStorageVolLookupByName,    /* 0.10.0 */
    .storageVolLookupByKey = vzStorageVolLookupByKey,      /* 0.10.0 */
    .storageVolLookupByPath = vzStorageVolLookupByPath,    /* 0.10.0 */
    .storageVolCreateXML = vzStorageVolCreateXML,  /* 0.10.0 */
    .storageVolCreateXMLFrom = vzStorageVolCreateXMLFrom,  /* 0.10.0 */
    .storageVolDelete = vzStorageVolDelete,        /* 0.10.0 */
    .storageVolGetInfo = vzStorageVolGetInfo,      /* 0.10.0 */
    .storageVolGetXMLDesc = vzStorageVolGetXMLDesc,        /* 0.10.0 */
    .storageVolGetPath = vzStorageVolGetPath,      /* 0.10.0 */
    .storagePoolIsActive = vzStoragePoolIsActive,     /* 0.10.0 */
    .storagePoolIsPersistent = vzStoragePoolIsPersistent,     /* 0.10.0 */
D
Dmitry Guryanov 已提交
1654
};