storage_backend_logical.c 23.3 KB
Newer Older
1
/*
2
 * storage_backend_logical.c: storage backend for logical volume handling
3
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2007-2009, 2011 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 29 30 31 32 33
 * Copyright (C) 2007-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 <sys/wait.h>
#include <sys/stat.h>
#include <stdio.h>
#include <regex.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

34
#include "virterror_internal.h"
35 36
#include "storage_backend_logical.h"
#include "storage_conf.h"
37
#include "command.h"
38
#include "memory.h"
39
#include "logging.h"
E
Eric Blake 已提交
40
#include "virfile.h"
41

42 43
#define VIR_FROM_THIS VIR_FROM_STORAGE

44 45 46 47
#define PV_BLANK_SECTOR_SIZE 512


static int
48
virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
49 50 51 52 53 54
                                  int on)
{
    const char *cmdargv[4];

    cmdargv[0] = VGCHANGE;
    cmdargv[1] = on ? "-ay" : "-an";
55
    cmdargv[2] = pool->def->source.name;
56 57
    cmdargv[3] = NULL;

58
    if (virRun(cmdargv, NULL) < 0)
59 60 61 62 63 64
        return -1;

    return 0;
}


65 66
#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"

67
static int
68
virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
69 70 71 72
                                char **const groups,
                                void *data)
{
    virStorageVolDefPtr vol = NULL;
73
    bool is_new_vol = false;
74
    unsigned long long offset, size, length;
75 76 77 78 79 80
    const char *regex_unit = "(\\S+)\\((\\S+)\\)";
    char *regex = NULL;
    regex_t *reg = NULL;
    regmatch_t *vars = NULL;
    char *p = NULL;
    int i, err, nextents, nvars, ret = -1;
81 82 83 84 85 86 87 88 89 90 91 92 93 94

    /* See if we're only looking for a specific volume */
    if (data != NULL) {
        vol = data;
        if (STRNEQ(vol->name, groups[0]))
            return 0;
    }

    /* Or filling in more data on an existing volume */
    if (vol == NULL)
        vol = virStorageVolDefFindByName(pool, groups[0]);

    /* Or a completely new volume */
    if (vol == NULL) {
95
        if (VIR_ALLOC(vol) < 0) {
96
            virReportOOMError();
97 98 99
            return -1;
        }

100
        is_new_vol = true;
101 102
        vol->type = VIR_STORAGE_VOL_BLOCK;

103
        if ((vol->name = strdup(groups[0])) == NULL) {
104
            virReportOOMError();
105
            goto cleanup;
106 107
        }

108 109
        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count + 1)) {
110
            virReportOOMError();
111
            goto cleanup;
112 113
        }
        pool->volumes.objs[pool->volumes.count++] = vol;
114 115 116
    }

    if (vol->target.path == NULL) {
117 118
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path, vol->name) < 0) {
119
            virReportOOMError();
120
            goto cleanup;
121 122 123 124 125 126
        }
    }

    if (groups[1] && !STREQ(groups[1], "")) {
        if (virAsprintf(&vol->backingStore.path, "%s/%s",
                        pool->def->target.path, groups[1]) < 0) {
127
            virReportOOMError();
128
            goto cleanup;
129
        }
130 131

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
132 133 134
    }

    if (vol->key == NULL &&
135
        (vol->key = strdup(groups[2])) == NULL) {
136
        virReportOOMError();
137
        goto cleanup;
138 139
    }

140
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
141 142 143 144 145 146 147 148 149 150
        goto cleanup;

    nextents = 1;
    if (STREQ(groups[4], VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED)) {
        if (virStrToLong_i(groups[5], NULL, 10, &nextents) < 0) {
            virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                  _("malformed volume extent stripes value"));
            goto cleanup;
        }
    }
151 152

    /* Finally fill in extents information */
153
    if (VIR_REALLOC_N(vol->source.extents,
154
                      vol->source.nextent + nextents) < 0) {
155
        virReportOOMError();
156
        goto cleanup;
157 158
    }

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent length value"));
        goto cleanup;
    }
    if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent size value"));
        goto cleanup;
    }

    /* Now parse the "devices" feild seperately */
    regex = strdup(regex_unit);

    for (i = 1; i < nextents; i++) {
        if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0) {
            virReportOOMError();
            goto cleanup;
        }
        /* "," is the seperator of "devices" field */
        strcat(regex, ",");
        strncat(regex, regex_unit, strlen(regex_unit));
    }

    if (VIR_ALLOC(reg) < 0) {
184
        virReportOOMError();
185
        goto cleanup;
186 187
    }

188 189 190 191 192 193 194
    /* Each extent has a "path:offset" pair, and vars[0] will
     * be the whole matched string.
     */
    nvars = (nextents * 2) + 1;
    if (VIR_ALLOC_N(vars, nvars) < 0) {
        virReportOOMError();
        goto cleanup;
195
    }
196 197 198 199 200

    err = regcomp(reg, regex, REG_EXTENDED);
    if (err != 0) {
        char error[100];
        regerror(err, reg, error, sizeof(error));
201
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
202 203 204
                              _("Failed to compile regex %s"),
                              error);
        goto cleanup;
205
    }
206 207 208 209 210

    if (regexec(reg, groups[3], nvars, vars, 0) != 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                              _("malformed volume extent devices value"));
        goto cleanup;
211 212
    }

213
    p = groups[3];
214

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    /* vars[0] is skipped */
    for (i = 0; i < nextents; i++) {
        int j, len;
        const char *offset_str = NULL;

        j = (i * 2) + 1;
        len = vars[j].rm_eo - vars[j].rm_so;
        p[vars[j].rm_eo] = '\0';

        if ((vol->source.extents[vol->source.nextent].path =
            strndup(p + vars[j].rm_so, len)) == NULL) {
            virReportOOMError();
            goto cleanup;
        }

        len = vars[j + 1].rm_eo - vars[j + 1].rm_so;
        if (!(offset_str = strndup(p + vars[j + 1].rm_so, len))) {
            virReportOOMError();
            goto cleanup;
        }

        if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) {
            virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                  _("malformed volume extent offset value"));
            goto cleanup;
        }

        VIR_FREE(offset_str);

        vol->source.extents[vol->source.nextent].start = offset * size;
        vol->source.extents[vol->source.nextent].end = (offset * size) + length;
        vol->source.nextent++;
    }

    ret = 0;

cleanup:
    VIR_FREE(regex);
    VIR_FREE(reg);
    VIR_FREE(vars);
    if (is_new_vol && (ret == -1))
        virStorageVolDefFree(vol);
    return ret;
258 259 260
}

static int
261
virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
262 263 264
                                virStorageVolDefPtr vol)
{
    /*
265 266 267 268 269 270
     *  # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options "lv_name,origin,uuid,devices,seg_size,vg_extent_size" VGNAME
     *  RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432
     *  SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432
     *  Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432
     *  Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432
     *  Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432
271
     *
272
     * Pull out name, origin, & uuid, device, device extent start #, segment size, extent size.
273 274
     *
     * NB can be multiple rows per volume if they have many extents
275
     *
276 277 278 279
     * NB lvs from some distros (e.g. SLES10 SP2) outputs trailing "," on each line
     *
     * NB Encrypted logical volumes can print ':' in their name, so it is
     *    not a suitable separator (rhbz 470693).
280 281
     * NB "devices" field has multiple device paths and "," if the volume is
     *    striped, so "," is not a suitable separator either (rhbz 727474).
282 283
     */
    const char *regexes[] = {
284
       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#?\\s*$"
285 286
    };
    int vars[] = {
287
        8
288 289
    };
    const char *prog[] = {
290
        LVS, "--separator", "#", "--noheadings", "--units", "b",
291
        "--unbuffered", "--nosuffix", "--options",
292
        "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
293
        pool->def->source.name, NULL
294 295
    };

296
    if (virStorageBackendRunProgRegex(pool,
297 298 299 300 301
                                      prog,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalMakeVol,
302
                                      vol, "lvs") < 0) {
303 304 305 306
        return -1;
    }

    return 0;
307 308 309
}

static int
310
virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
311 312 313 314 315 316 317 318 319 320 321 322 323
                                        char **const groups,
                                        void *data ATTRIBUTE_UNUSED)
{
    if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
        return -1;
    if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
        return -1;
    pool->def->allocation = pool->def->capacity - pool->def->available;

    return 0;
}


324
static int
325
virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
326 327 328
                                            char **const groups,
                                            void *data)
{
329 330 331 332 333 334 335 336 337 338 339
    virStoragePoolSourceListPtr sourceList = data;
    char *pvname = NULL;
    char *vgname = NULL;
    int i;
    virStoragePoolSourceDevicePtr dev;
    virStoragePoolSource *thisSource;

    pvname = strdup(groups[0]);
    vgname = strdup(groups[1]);

    if (pvname == NULL || vgname == NULL) {
340
        virReportOOMError();
341 342 343 344 345 346 347 348 349 350
        goto err_no_memory;
    }

    thisSource = NULL;
    for (i = 0 ; i < sourceList->nsources; i++) {
        if (STREQ(sourceList->sources[i].name, vgname)) {
            thisSource = &sourceList->sources[i];
            break;
        }
    }
351

352
    if (thisSource == NULL) {
353
        if (!(thisSource = virStoragePoolSourceListNewSource(sourceList)))
354 355 356
            goto err_no_memory;

        thisSource->name = vgname;
357
    }
358 359
    else
        VIR_FREE(vgname);
360

361
    if (VIR_REALLOC_N(thisSource->devices, thisSource->ndevice + 1) != 0) {
362
        virReportOOMError();
363
        goto err_no_memory;
364 365
    }

366 367
    dev = &thisSource->devices[thisSource->ndevice];
    thisSource->ndevice++;
368
    thisSource->format = VIR_STORAGE_POOL_LOGICAL_LVM2;
369 370 371

    memset(dev, 0, sizeof(*dev));
    dev->path = pvname;
372 373

    return 0;
374 375 376 377 378 379

 err_no_memory:
    VIR_FREE(pvname);
    VIR_FREE(vgname);

    return -1;
380 381 382
}

static char *
383
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
384
                                        const char *srcSpec ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
385
                                        unsigned int flags)
386 387
{
    /*
388 389 390
     * # pvs --noheadings -o pv_name,vg_name
     *   /dev/sdb
     *   /dev/sdc VolGroup00
391 392
     */
    const char *regexes[] = {
393
        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
394 395
    };
    int vars[] = {
396
        2
397
    };
398
    const char *const prog[] = { PVS, "--noheadings", "-o", "pv_name,vg_name", NULL };
399
    const char *const scanprog[] = { VGSCAN, NULL };
400
    char *retval = NULL;
401 402
    virStoragePoolSourceList sourceList;
    int i;
403

E
Eric Blake 已提交
404 405
    virCheckFlags(0, NULL);

406 407 408 409 410
    /*
     * NOTE: ignoring errors here; this is just to "touch" any logical volumes
     * that might be hanging around, so if this fails for some reason, the
     * worst that happens is that scanning doesn't pick everything up
     */
411
    if (virRun(scanprog, NULL) < 0) {
412
        VIR_WARN("Failure when running vgscan to refresh physical volumes");
413
    }
414

415
    memset(&sourceList, 0, sizeof(sourceList));
416 417
    sourceList.type = VIR_STORAGE_POOL_LOGICAL;

418
    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
419
                                virStorageBackendLogicalFindPoolSourcesFunc,
420
                                &sourceList, "pvs") < 0)
421 422
        return NULL;

423
    retval = virStoragePoolSourceListFormat(&sourceList);
424
    if (retval == NULL) {
425
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
426
                              _("failed to get source from sourceList"));
427 428 429 430
        goto cleanup;
    }

 cleanup:
431 432 433 434
    for (i = 0; i < sourceList.nsources; i++)
        virStoragePoolSourceFree(&sourceList.sources[i]);

    VIR_FREE(sourceList.sources);
435 436 437 438 439

    return retval;
}


440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
static int
virStorageBackendLogicalCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool,
                                  bool *isActive)
{
    char *path;

    *isActive = false;
    if (virAsprintf(&path, "/dev/%s", pool->def->source.name) < 0) {
        virReportOOMError();
        return -1;
    }

    if (access(path, F_OK) == 0)
        *isActive = true;

    VIR_FREE(path);

    return 0;
}

461
static int
462
virStorageBackendLogicalStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
463 464
                                  virStoragePoolObjPtr pool)
{
465
    if (virStorageBackendLogicalSetActive(pool, 1) < 0)
466 467 468 469 470 471 472
        return -1;

    return 0;
}


static int
473
virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
474
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
475
                                  unsigned int flags)
476 477 478 479 480 481
{
    const char **vgargv;
    const char *pvargv[3];
    int n = 0, i, fd;
    char zeros[PV_BLANK_SECTOR_SIZE];

E
Eric Blake 已提交
482 483
    virCheckFlags(0, -1);

484 485
    memset(zeros, 0, sizeof(zeros));

486
    if (VIR_ALLOC_N(vgargv, 3 + pool->def->source.ndevice) < 0) {
487
        virReportOOMError();
488 489 490 491
        return -1;
    }

    vgargv[n++] = VGCREATE;
492
    vgargv[n++] = pool->def->source.name;
493 494 495 496 497 498 499 500 501 502

    pvargv[0] = PVCREATE;
    pvargv[2] = NULL;
    for (i = 0 ; i < pool->def->source.ndevice ; i++) {
        /*
         * LVM requires that the first sector is blanked if using
         * a whole disk as a PV. So we just blank them out regardless
         * rather than trying to figure out if we're a disk or partition
         */
        if ((fd = open(pool->def->source.devices[i].path, O_WRONLY)) < 0) {
503
            virReportSystemError(errno,
504 505
                                 _("cannot open device '%s'"),
                                 pool->def->source.devices[i].path);
506 507
            goto cleanup;
        }
508
        if (safewrite(fd, zeros, sizeof(zeros)) < 0) {
509
            virReportSystemError(errno,
510 511
                                 _("cannot clear device header of '%s'"),
                                 pool->def->source.devices[i].path);
512 513 514 515 516 517 518
            VIR_FORCE_CLOSE(fd);
            goto cleanup;
        }
        if (fsync(fd) < 0) {
            virReportSystemError(errno,
                                 _("cannot flush header of device'%s'"),
                                 pool->def->source.devices[i].path);
519
            VIR_FORCE_CLOSE(fd);
520 521
            goto cleanup;
        }
522
        if (VIR_CLOSE(fd) < 0) {
523
            virReportSystemError(errno,
524 525
                                 _("cannot close device '%s'"),
                                 pool->def->source.devices[i].path);
526 527 528 529 530 531 532 533 534
            goto cleanup;
        }

        /*
         * Initialize the physical volume because vgcreate is not
         * clever enough todo this for us :-(
         */
        vgargv[n++] = pool->def->source.devices[i].path;
        pvargv[1] = pool->def->source.devices[i].path;
535
        if (virRun(pvargv, NULL) < 0)
536 537 538
            goto cleanup;
    }

539
    vgargv[n] = NULL;
540 541

    /* Now create the volume group itself */
542
    if (virRun(vgargv, NULL) < 0)
543 544
        goto cleanup;

545
    VIR_FREE(vgargv);
546 547 548 549

    return 0;

 cleanup:
550
    VIR_FREE(vgargv);
551 552 553 554 555
    return -1;
}


static int
556
virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
557 558 559 560 561 562 563
                                    virStoragePoolObjPtr pool)
{
    /*
     *  # vgs --separator : --noheadings --units b --unbuffered --nosuffix --options "vg_size,vg_free" VGNAME
     *    10603200512:4328521728
     *
     * Pull out size & free
564 565
     *
     * NB vgs from some distros (e.g. SLES10 SP2) outputs trailing ":" on each line
566 567
     */
    const char *regexes[] = {
568
        "^\\s*(\\S+):([0-9]+):?\\s*$"
569 570 571 572 573 574 575
    };
    int vars[] = {
        2
    };
    const char *prog[] = {
        VGS, "--separator", ":", "--noheadings", "--units", "b", "--unbuffered",
        "--nosuffix", "--options", "vg_size,vg_free",
576
        pool->def->source.name, NULL
577 578
    };

579
    virFileWaitForDevices();
580

581
    /* Get list of all logical volumes */
582
    if (virStorageBackendLogicalFindLVs(pool, NULL) < 0) {
583 584 585 586 587
        virStoragePoolObjClearVols(pool);
        return -1;
    }

    /* Now get basic volgrp metadata */
588
    if (virStorageBackendRunProgRegex(pool,
589 590 591 592 593
                                      prog,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalRefreshPoolFunc,
594
                                      NULL, "vgs") < 0) {
595 596 597 598 599 600 601
        virStoragePoolObjClearVols(pool);
        return -1;
    }

    return 0;
}

602 603 604 605
/*
 * This is actually relatively safe; if you happen to try to "stop" the
 * pool that your / is on, for instance, you will get failure like:
 * "Can't deactivate volume group "VolGroup00" with 3 open logical volume(s)"
606 607
 */
static int
608
virStorageBackendLogicalStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
609 610
                                 virStoragePoolObjPtr pool)
{
611
    if (virStorageBackendLogicalSetActive(pool, 0) < 0)
612 613 614 615 616 617
        return -1;

    return 0;
}

static int
618
virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
619
                                   virStoragePoolObjPtr pool,
E
Eric Blake 已提交
620
                                   unsigned int flags)
621 622
{
    const char *cmdargv[] = {
623
        VGREMOVE, "-f", pool->def->source.name, NULL
624
    };
625 626
    const char *pvargv[3];
    int i, error;
627

E
Eric Blake 已提交
628 629
    virCheckFlags(0, -1);

630
    /* first remove the volume group */
631
    if (virRun(cmdargv, NULL) < 0)
632 633
        return -1;

634 635 636 637 638 639
    /* now remove the pv devices and clear them out */
    error = 0;
    pvargv[0] = PVREMOVE;
    pvargv[2] = NULL;
    for (i = 0 ; i < pool->def->source.ndevice ; i++) {
        pvargv[1] = pool->def->source.devices[i].path;
640
        if (virRun(pvargv, NULL) < 0) {
641 642 643 644
            error = -1;
            break;
        }
    }
645

646
    return error;
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
}


static int
virStorageBackendLogicalDeleteVol(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol,
                                  unsigned int flags);


static int
virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol)
{
662
    int fdret, fd = -1;
663
    char size[100];
664
    const char *cmdargvnew[] = {
665 666 667
        LVCREATE, "--name", vol->name, "-L", size,
        pool->def->target.path, NULL
    };
668 669 670 671 672 673
    const char *cmdargvsnap[] = {
        LVCREATE, "--name", vol->name, "-L", size,
        "-s", vol->backingStore.path, NULL
    };
    const char **cmdargv = cmdargvnew;

674
    if (vol->target.encryption != NULL) {
O
Osier Yang 已提交
675
        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
676 677 678 679 680
                              "%s", _("storage pool does not support encrypted "
                                      "volumes"));
        return -1;
    }

681 682 683
    if (vol->backingStore.path) {
        cmdargv = cmdargvsnap;
    }
684

685
    snprintf(size, sizeof(size)-1, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
686 687
    size[sizeof(size)-1] = '\0';

688 689
    vol->type = VIR_STORAGE_VOL_BLOCK;

690 691 692 693
    if (vol->target.path != NULL) {
        /* A target path passed to CreateVol has no meaning */
        VIR_FREE(vol->target.path);
    }
694 695 696 697

    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
                    vol->name) == -1) {
698
        virReportOOMError();
699 700 701
        return -1;
    }

702
    if (virRun(cmdargv, NULL) < 0)
703 704
        return -1;

705
    if ((fdret = virStorageBackendVolOpen(vol->target.path)) < 0)
706
        goto cleanup;
707
    fd = fdret;
708 709 710 711

    /* We can only chown/grp if root */
    if (getuid() == 0) {
        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
712
            virReportSystemError(errno,
713 714
                                 _("cannot set file owner '%s'"),
                                 vol->target.path);
715 716 717 718
            goto cleanup;
        }
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
719
        virReportSystemError(errno,
720 721
                             _("cannot set file mode '%s'"),
                             vol->target.path);
722 723 724
        goto cleanup;
    }

725
    if (VIR_CLOSE(fd) < 0) {
726
        virReportSystemError(errno,
727 728
                             _("cannot close file '%s'"),
                             vol->target.path);
729 730 731 732 733
        goto cleanup;
    }
    fd = -1;

    /* Fill in data about this new vol */
734
    if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
735
        virReportSystemError(errno,
736 737
                             _("cannot find newly created volume '%s'"),
                             vol->target.path);
738 739 740 741 742 743
        goto cleanup;
    }

    return 0;

 cleanup:
744
    VIR_FORCE_CLOSE(fd);
745 746 747 748
    virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
    return -1;
}

749 750
static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
751
                                     virStoragePoolObjPtr pool,
752 753 754 755 756 757
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

758
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
759 760 761
    if (!build_func)
        return -1;

762
    return build_func(conn, pool, vol, inputvol, flags);
763 764
}

765
static int
766
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
767 768
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                  virStorageVolDefPtr vol,
E
Eric Blake 已提交
769
                                  unsigned int flags)
770 771 772 773 774
{
    const char *cmdargv[] = {
        LVREMOVE, "-f", vol->target.path, NULL
    };

E
Eric Blake 已提交
775 776
    virCheckFlags(0, -1);

777 778
    virFileWaitForDevices();

779
    if (virRun(cmdargv, NULL) < 0)
780 781 782 783 784 785 786 787 788
        return -1;

    return 0;
}


virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

789
    .findPoolSources = virStorageBackendLogicalFindPoolSources,
790
    .checkPool = virStorageBackendLogicalCheckPool,
791 792 793 794 795
    .startPool = virStorageBackendLogicalStartPool,
    .buildPool = virStorageBackendLogicalBuildPool,
    .refreshPool = virStorageBackendLogicalRefreshPool,
    .stopPool = virStorageBackendLogicalStopPool,
    .deletePool = virStorageBackendLogicalDeletePool,
796 797
    .buildVol = NULL,
    .buildVolFrom = virStorageBackendLogicalBuildVolFrom,
798 799 800
    .createVol = virStorageBackendLogicalCreateVol,
    .deleteVol = virStorageBackendLogicalDeleteVol,
};