storage_backend_logical.c 25.1 KB
Newer Older
1
/*
2
 * storage_backend_logical.c: storage backend for logical volume handling
3
 *
4
 * Copyright (C) 2007-2009, 2011, 2013 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * 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 "virerror.h"
35 36
#include "storage_backend_logical.h"
#include "storage_conf.h"
37
#include "vircommand.h"
38
#include "viralloc.h"
39
#include "virlog.h"
E
Eric Blake 已提交
40
#include "virfile.h"
41
#include "virstring.h"
42

43 44
#define VIR_FROM_THIS VIR_FROM_STORAGE

45 46
VIR_LOG_INIT("storage.storage_backend_logical");

47 48 49 50
#define PV_BLANK_SECTOR_SIZE 512


static int
51
virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
52 53
                                  int on)
{
54 55 56 57 58 59 60 61 62 63
    int ret;
    virCommandPtr cmd =
        virCommandNewArgList(VGCHANGE,
                             on ? "-aly" : "-aln",
                             pool->def->source.name,
                             NULL);

    ret = virCommandRun(cmd, NULL);
    virCommandFree(cmd);
    return ret;
64 65 66
}


67 68
#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"

69 70 71 72 73
struct virStorageBackendLogicalPoolVolData {
    virStoragePoolObjPtr pool;
    virStorageVolDefPtr vol;
};

74
static int
75 76
virStorageBackendLogicalMakeVol(char **const groups,
                                void *opaque)
77
{
78 79
    struct virStorageBackendLogicalPoolVolData *data = opaque;
    virStoragePoolObjPtr pool = data->pool;
80
    virStorageVolDefPtr vol = NULL;
81
    bool is_new_vol = false;
82
    unsigned long long offset, size, length;
83 84 85 86 87
    const char *regex_unit = "(\\S+)\\((\\S+)\\)";
    char *regex = NULL;
    regex_t *reg = NULL;
    regmatch_t *vars = NULL;
    char *p = NULL;
88 89
    size_t i;
    int err, nextents, nvars, ret = -1;
O
Osier Yang 已提交
90 91 92 93 94
    const char *attrs = groups[9];

    /* Skip inactive volume */
    if (attrs[4] != 'a')
        return 0;
95

D
Dusty Mabe 已提交
96 97 98 99 100 101 102 103
    /*
     * Skip thin pools(t). These show up in normal lvs output
     * but do not have a corresponding /dev/$vg/$lv device that
     * is created by udev. This breaks assumptions in later code.
     */
    if (attrs[0] == 't')
        return 0;

104
    /* See if we're only looking for a specific volume */
105 106
    if (data->vol != NULL) {
        vol = data->vol;
107 108 109 110 111 112 113 114 115 116
        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) {
117
        if (VIR_ALLOC(vol) < 0)
118 119
            return -1;

120
        is_new_vol = true;
121 122
        vol->type = VIR_STORAGE_VOL_BLOCK;

123
        if (VIR_STRDUP(vol->name, groups[0]) < 0)
124
            goto cleanup;
125 126 127 128

    }

    if (vol->target.path == NULL) {
129
        if (virAsprintf(&vol->target.path, "%s/%s",
130
                        pool->def->target.path, vol->name) < 0)
131
            goto cleanup;
132 133
    }

134 135 136 137 138 139 140 141
    /* Skips the backingStore of lv created with "--virtualsize",
     * its original device "/dev/$vgname/$lvname_vorigin" is
     * just for lvm internal use, one should never use it.
     *
     * (lvs outputs "[$lvname_vorigin] for field "origin" if the
     *  lv is created with "--virtualsize").
     */
    if (groups[1] && !STREQ(groups[1], "") && (groups[1][0] != '[')) {
142
        if (virAsprintf(&vol->backingStore.path, "%s/%s",
143
                        pool->def->target.path, groups[1]) < 0)
144
            goto cleanup;
145 146

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
147 148
    }

149
    if (!vol->key && VIR_STRDUP(vol->key, groups[2]) < 0)
150
        goto cleanup;
151

152
    if (virStorageBackendUpdateVolInfo(vol, true, false,
153
                                       VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
154 155 156 157 158
        goto cleanup;

    nextents = 1;
    if (STREQ(groups[4], VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED)) {
        if (virStrToLong_i(groups[5], NULL, 10, &nextents) < 0) {
159 160
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("malformed volume extent stripes value"));
161 162 163
            goto cleanup;
        }
    }
164 165

    /* Finally fill in extents information */
166
    if (VIR_REALLOC_N(vol->source.extents,
167
                      vol->source.nextent + nextents) < 0)
168
        goto cleanup;
169

170
    if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
171 172
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent length value"));
173 174 175
        goto cleanup;
    }
    if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
176 177
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent size value"));
178 179
        goto cleanup;
    }
180
    if (virStrToLong_ull(groups[8], NULL, 10, &vol->allocation) < 0) {
181 182
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume allocation value"));
183 184
        goto cleanup;
    }
185

E
Eric Blake 已提交
186
    /* Now parse the "devices" field separately */
187 188
    if (VIR_STRDUP(regex, regex_unit) < 0)
        goto cleanup;
189 190

    for (i = 1; i < nextents; i++) {
191
        if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0)
192
            goto cleanup;
E
Eric Blake 已提交
193
        /* "," is the separator of "devices" field */
194 195 196 197
        strcat(regex, ",");
        strncat(regex, regex_unit, strlen(regex_unit));
    }

198
    if (VIR_ALLOC(reg) < 0)
199
        goto cleanup;
200

201 202 203 204
    /* Each extent has a "path:offset" pair, and vars[0] will
     * be the whole matched string.
     */
    nvars = (nextents * 2) + 1;
205
    if (VIR_ALLOC_N(vars, nvars) < 0)
206 207 208 209 210 211
        goto cleanup;

    err = regcomp(reg, regex, REG_EXTENDED);
    if (err != 0) {
        char error[100];
        regerror(err, reg, error, sizeof(error));
212 213 214
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to compile regex %s"),
                       error);
215
        goto cleanup;
216
    }
217

218 219 220
    err = regexec(reg, groups[3], nvars, vars, 0);
    regfree(reg);
    if (err != 0) {
221 222
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("malformed volume extent devices value"));
223
        goto cleanup;
224 225
    }

226
    p = groups[3];
227

228 229
    /* vars[0] is skipped */
    for (i = 0; i < nextents; i++) {
230 231
        size_t j;
        int len;
232
        char *offset_str = NULL;
233 234 235 236 237

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

238 239
        if (VIR_STRNDUP(vol->source.extents[vol->source.nextent].path,
                        p + vars[j].rm_so, len) < 0)
240 241 242
            goto cleanup;

        len = vars[j + 1].rm_eo - vars[j + 1].rm_so;
243
        if (VIR_STRNDUP(offset_str, p + vars[j + 1].rm_so, len) < 0)
244 245 246
            goto cleanup;

        if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) {
247 248
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("malformed volume extent offset value"));
E
Eric Blake 已提交
249
            VIR_FREE(offset_str);
250 251 252 253 254 255 256 257 258 259
            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++;
    }

260 261 262
    if (is_new_vol &&
        VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
        goto cleanup;
263

264 265
    ret = 0;

266
 cleanup:
267
    VIR_FREE(regex);
268
    VIR_FREE(reg);
269 270 271 272
    VIR_FREE(vars);
    if (is_new_vol && (ret == -1))
        virStorageVolDefFree(vol);
    return ret;
273 274 275
}

static int
276
virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
277 278 279
                                virStorageVolDefPtr vol)
{
    /*
O
Osier Yang 已提交
280 281 282 283 284 285 286 287
     * # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options \
     * "lv_name,origin,uuid,devices,seg_size,vg_extent_size,size,lv_attr" VGNAME
     *
     * RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432,5234491392,-wi-ao
     * SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432,1040187392,-wi-ao
     * Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432,1073741824,owi-a-
     * Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432,2181038080,-wi-a-
     * Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432,1040187392,swi-a-
288
     *
O
Osier Yang 已提交
289 290
     * Pull out name, origin, & uuid, device, device extent start #,
     * segment size, extent size, size, attrs
291 292
     *
     * NB can be multiple rows per volume if they have many extents
293
     *
294 295 296 297
     * 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).
298 299
     * NB "devices" field has multiple device paths and "," if the volume is
     *    striped, so "," is not a suitable separator either (rhbz 727474).
300 301
     */
    const char *regexes[] = {
O
Osier Yang 已提交
302
       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#([0-9]+)#(\\S+)#?\\s*$"
303 304
    };
    int vars[] = {
O
Osier Yang 已提交
305
        10
306
    };
307 308
    int ret = -1;
    virCommandPtr cmd;
309 310 311 312
    struct virStorageBackendLogicalPoolVolData cbdata = {
        .pool = pool,
        .vol = vol,
    };
313 314 315 316 317 318 319

    cmd = virCommandNewArgList(LVS,
                               "--separator", "#",
                               "--noheadings",
                               "--units", "b",
                               "--unbuffered",
                               "--nosuffix",
O
Osier Yang 已提交
320 321
                               "--options",
                               "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size,lv_attr",
322 323
                               pool->def->source.name,
                               NULL);
324 325 326 327 328 329 330
    if (virCommandRunRegex(cmd,
                           1,
                           regexes,
                           vars,
                           virStorageBackendLogicalMakeVol,
                           &cbdata,
                           "lvs") < 0)
331
        goto cleanup;
332

333
    ret = 0;
334
 cleanup:
335 336
    virCommandFree(cmd);
    return ret;
337 338 339
}

static int
340 341
virStorageBackendLogicalRefreshPoolFunc(char **const groups,
                                        void *data)
342
{
343
    virStoragePoolObjPtr pool = data;
344 345 346 347 348 349 350 351 352 353
    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;
}


354
static int
355
virStorageBackendLogicalFindPoolSourcesFunc(char **const groups,
356 357
                                            void *data)
{
358 359 360
    virStoragePoolSourceListPtr sourceList = data;
    char *pvname = NULL;
    char *vgname = NULL;
361
    size_t i;
362 363 364
    virStoragePoolSourceDevicePtr dev;
    virStoragePoolSource *thisSource;

365 366 367
    if (VIR_STRDUP(pvname, groups[0]) < 0 ||
        VIR_STRDUP(vgname, groups[1]) < 0)
        goto error;
368 369

    thisSource = NULL;
370
    for (i = 0; i < sourceList->nsources; i++) {
371 372 373 374 375
        if (STREQ(sourceList->sources[i].name, vgname)) {
            thisSource = &sourceList->sources[i];
            break;
        }
    }
376

377
    if (thisSource == NULL) {
378
        if (!(thisSource = virStoragePoolSourceListNewSource(sourceList)))
379
            goto error;
380 381

        thisSource->name = vgname;
382
    }
383 384
    else
        VIR_FREE(vgname);
385

386
    if (VIR_REALLOC_N(thisSource->devices, thisSource->ndevice + 1) != 0)
387
        goto error;
388

389 390
    dev = &thisSource->devices[thisSource->ndevice];
    thisSource->ndevice++;
391
    thisSource->format = VIR_STORAGE_POOL_LOGICAL_LVM2;
392 393 394

    memset(dev, 0, sizeof(*dev));
    dev->path = pvname;
395 396

    return 0;
397

398
 error:
399 400 401 402
    VIR_FREE(pvname);
    VIR_FREE(vgname);

    return -1;
403 404 405
}

static char *
406
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
407
                                        const char *srcSpec ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
408
                                        unsigned int flags)
409 410
{
    /*
411 412 413
     * # pvs --noheadings -o pv_name,vg_name
     *   /dev/sdb
     *   /dev/sdc VolGroup00
414 415
     */
    const char *regexes[] = {
416
        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
417 418
    };
    int vars[] = {
419
        2
420
    };
421
    virCommandPtr cmd;
422
    char *retval = NULL;
423
    virStoragePoolSourceList sourceList;
424
    size_t i;
425

E
Eric Blake 已提交
426 427
    virCheckFlags(0, NULL);

428 429 430 431 432
    /*
     * 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
     */
433 434
    cmd = virCommandNew(VGSCAN);
    if (virCommandRun(cmd, NULL) < 0)
435
        VIR_WARN("Failure when running vgscan to refresh physical volumes");
436
    virCommandFree(cmd);
437

438
    memset(&sourceList, 0, sizeof(sourceList));
439 440
    sourceList.type = VIR_STORAGE_POOL_LOGICAL;

441 442 443 444
    cmd = virCommandNewArgList(PVS,
                               "--noheadings",
                               "-o", "pv_name,vg_name",
                               NULL);
445 446 447
    if (virCommandRunRegex(cmd, 1, regexes, vars,
                           virStorageBackendLogicalFindPoolSourcesFunc,
                           &sourceList, "pvs") < 0) {
448
        virCommandFree(cmd);
449
        return NULL;
450 451
    }
    virCommandFree(cmd);
452

453
    retval = virStoragePoolSourceListFormat(&sourceList);
454
    if (retval == NULL) {
455 456
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to get source from sourceList"));
457 458 459 460
        goto cleanup;
    }

 cleanup:
461
    for (i = 0; i < sourceList.nsources; i++)
462
        virStoragePoolSourceClear(&sourceList.sources[i]);
463
    VIR_FREE(sourceList.sources);
464 465 466 467 468

    return retval;
}


469 470 471 472 473
static int
virStorageBackendLogicalCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool,
                                  bool *isActive)
{
474
    *isActive = virFileExists(pool->def->target.path);
475 476 477
    return 0;
}

478
static int
479
virStorageBackendLogicalStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
480 481
                                  virStoragePoolObjPtr pool)
{
482
    if (virStorageBackendLogicalSetActive(pool, 1) < 0)
483 484 485 486 487 488 489
        return -1;

    return 0;
}


static int
490
virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
491
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
492
                                  unsigned int flags)
493
{
494 495
    virCommandPtr vgcmd;
    int fd;
496
    char zeros[PV_BLANK_SECTOR_SIZE];
497 498
    int ret = -1;
    size_t i;
499

E
Eric Blake 已提交
500 501
    virCheckFlags(0, -1);

502 503
    memset(zeros, 0, sizeof(zeros));

504
    vgcmd = virCommandNewArgList(VGCREATE, pool->def->source.name, NULL);
505

506
    for (i = 0; i < pool->def->source.ndevice; i++) {
507
        virCommandPtr pvcmd;
508 509 510 511 512 513
        /*
         * 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) {
514
            virReportSystemError(errno,
515 516
                                 _("cannot open device '%s'"),
                                 pool->def->source.devices[i].path);
517 518
            goto cleanup;
        }
519
        if (safewrite(fd, zeros, sizeof(zeros)) < 0) {
520
            virReportSystemError(errno,
521 522
                                 _("cannot clear device header of '%s'"),
                                 pool->def->source.devices[i].path);
523 524 525 526 527 528 529
            VIR_FORCE_CLOSE(fd);
            goto cleanup;
        }
        if (fsync(fd) < 0) {
            virReportSystemError(errno,
                                 _("cannot flush header of device'%s'"),
                                 pool->def->source.devices[i].path);
530
            VIR_FORCE_CLOSE(fd);
531 532
            goto cleanup;
        }
533
        if (VIR_CLOSE(fd) < 0) {
534
            virReportSystemError(errno,
535 536
                                 _("cannot close device '%s'"),
                                 pool->def->source.devices[i].path);
537 538 539 540 541 542 543
            goto cleanup;
        }

        /*
         * Initialize the physical volume because vgcreate is not
         * clever enough todo this for us :-(
         */
544 545 546 547 548
        pvcmd = virCommandNewArgList(PVCREATE,
                                     pool->def->source.devices[i].path,
                                     NULL);
        if (virCommandRun(pvcmd, NULL) < 0) {
            virCommandFree(pvcmd);
549
            goto cleanup;
550 551
        }
        virCommandFree(pvcmd);
552

553 554
        virCommandAddArg(vgcmd, pool->def->source.devices[i].path);
    }
555 556

    /* Now create the volume group itself */
557
    if (virCommandRun(vgcmd, NULL) < 0)
558 559
        goto cleanup;

560
    ret = 0;
561

562
 cleanup:
563 564
    virCommandFree(vgcmd);
    return ret;
565 566 567 568
}


static int
569
virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
570 571 572 573 574 575 576
                                    virStoragePoolObjPtr pool)
{
    /*
     *  # vgs --separator : --noheadings --units b --unbuffered --nosuffix --options "vg_size,vg_free" VGNAME
     *    10603200512:4328521728
     *
     * Pull out size & free
577 578
     *
     * NB vgs from some distros (e.g. SLES10 SP2) outputs trailing ":" on each line
579 580
     */
    const char *regexes[] = {
581
        "^\\s*(\\S+):([0-9]+):?\\s*$"
582 583 584 585
    };
    int vars[] = {
        2
    };
586 587
    virCommandPtr cmd = NULL;
    int ret = -1;
588

589
    virFileWaitForDevices();
590

591
    /* Get list of all logical volumes */
592 593 594 595 596 597 598 599 600 601 602 603
    if (virStorageBackendLogicalFindLVs(pool, NULL) < 0)
        goto cleanup;

    cmd = virCommandNewArgList(VGS,
                               "--separator", ":",
                               "--noheadings",
                               "--units", "b",
                               "--unbuffered",
                               "--nosuffix",
                               "--options", "vg_size,vg_free",
                               pool->def->source.name,
                               NULL);
604 605

    /* Now get basic volgrp metadata */
606 607 608 609 610 611 612
    if (virCommandRunRegex(cmd,
                           1,
                           regexes,
                           vars,
                           virStorageBackendLogicalRefreshPoolFunc,
                           pool,
                           "vgs") < 0)
613
        goto cleanup;
614

615 616
    ret = 0;

617
 cleanup:
618 619 620 621
    virCommandFree(cmd);
    if (ret < 0)
        virStoragePoolObjClearVols(pool);
    return ret;
622 623
}

624 625 626 627
/*
 * 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)"
628 629
 */
static int
630
virStorageBackendLogicalStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
631 632
                                 virStoragePoolObjPtr pool)
{
633
    if (virStorageBackendLogicalSetActive(pool, 0) < 0)
634 635 636 637 638 639
        return -1;

    return 0;
}

static int
640
virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
641
                                   virStoragePoolObjPtr pool,
E
Eric Blake 已提交
642
                                   unsigned int flags)
643
{
644 645 646
    virCommandPtr cmd = NULL;
    size_t i;
    int ret = -1;
647

E
Eric Blake 已提交
648 649
    virCheckFlags(0, -1);

650
    /* first remove the volume group */
651 652 653 654 655 656
    cmd = virCommandNewArgList(VGREMOVE,
                               "-f", pool->def->source.name,
                               NULL);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
    virCommandFree(cmd);
657
    cmd = NULL;
658

659
    /* now remove the pv devices and clear them out */
660
    ret = 0;
661
    for (i = 0; i < pool->def->source.ndevice; i++) {
662 663 664 665 666
        cmd = virCommandNewArgList(PVREMOVE,
                                   pool->def->source.devices[i].path,
                                   NULL);
        if (virCommandRun(cmd, NULL) < 0) {
            ret = -1;
667 668
            break;
        }
669 670
        virCommandFree(cmd);
        cmd = NULL;
671
    }
672

673
 cleanup:
674 675
    virCommandFree(cmd);
    return ret;
676 677 678 679
}


static int
680 681
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
682
                                  virStorageVolDefPtr vol,
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
                                  unsigned int flags)
{
    int ret = -1;

    virCommandPtr lvchange_cmd = NULL;
    virCommandPtr lvremove_cmd = NULL;

    virCheckFlags(0, -1);

    virFileWaitForDevices();

    lvchange_cmd = virCommandNewArgList(LVCHANGE, "-aln", vol->target.path, NULL);
    lvremove_cmd = virCommandNewArgList(LVREMOVE, "-f", vol->target.path, NULL);

    if (virCommandRun(lvremove_cmd, NULL) < 0) {
        if (virCommandRun(lvchange_cmd, NULL) < 0) {
            goto cleanup;
        } else {
            if (virCommandRun(lvremove_cmd, NULL) < 0)
                goto cleanup;
        }
    }

    ret = 0;
707
 cleanup:
708 709 710 711
    virCommandFree(lvchange_cmd);
    virCommandFree(lvremove_cmd);
    return ret;
}
712 713 714


static int
715 716 717
virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol)
718
{
719
    int fd = -1;
720
    virCommandPtr cmd = NULL;
721
    virErrorPtr err;
722

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
        return -1;
    }

    vol->type = VIR_STORAGE_VOL_BLOCK;

    if (vol->target.path != NULL) {
        /* A target path passed to CreateVol has no meaning */
        VIR_FREE(vol->target.path);
    }

    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
                    vol->name) == -1)
        return -1;
741

742 743 744 745
    cmd = virCommandNewArgList(LVCREATE,
                               "--name", vol->name,
                               NULL);
    virCommandAddArg(cmd, "-L");
746
    if (vol->capacity != vol->allocation) {
747 748
        virCommandAddArgFormat(cmd, "%lluK",
                VIR_DIV_UP(vol->allocation ? vol->allocation : 1, 1024));
749 750
        virCommandAddArg(cmd, "--virtualsize");
    }
751 752
    virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
    if (vol->backingStore.path)
753
        virCommandAddArgList(cmd, "-s", vol->backingStore.path, NULL);
754 755 756 757
    else
        virCommandAddArg(cmd, pool->def->source.name);

    if (virCommandRun(cmd, NULL) < 0)
758
        goto error;
759

760 761 762 763 764
    virCommandFree(cmd);
    cmd = NULL;

    if ((fd = virStorageBackendVolOpen(vol->target.path)) < 0)
        goto error;
765 766

    /* We can only chown/grp if root */
767
    if (geteuid() == 0) {
768
        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
769
            virReportSystemError(errno,
770 771
                                 _("cannot set file owner '%s'"),
                                 vol->target.path);
772
            goto error;
773 774 775
        }
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
776
        virReportSystemError(errno,
777 778
                             _("cannot set file mode '%s'"),
                             vol->target.path);
779
        goto error;
780 781
    }

782
    if (VIR_CLOSE(fd) < 0) {
783
        virReportSystemError(errno,
784 785
                             _("cannot close file '%s'"),
                             vol->target.path);
786
        goto error;
787 788 789
    }

    /* Fill in data about this new vol */
790
    if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
791
        virReportSystemError(errno,
792 793
                             _("cannot find newly created volume '%s'"),
                             vol->target.path);
794
        goto error;
795 796 797 798
    }

    return 0;

799
 error:
800
    err = virSaveLastError();
801
    VIR_FORCE_CLOSE(fd);
802
    virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
803
    virCommandFree(cmd);
804
    virSetError(err);
805
    virFreeError(err);
806 807 808
    return -1;
}

809 810
static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
811
                                     virStoragePoolObjPtr pool,
812 813 814 815 816 817
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

818
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
819 820 821
    if (!build_func)
        return -1;

822
    return build_func(conn, pool, vol, inputvol, flags);
823 824
}

825 826 827 828

virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

829
    .findPoolSources = virStorageBackendLogicalFindPoolSources,
830
    .checkPool = virStorageBackendLogicalCheckPool,
831 832 833 834 835
    .startPool = virStorageBackendLogicalStartPool,
    .buildPool = virStorageBackendLogicalBuildPool,
    .refreshPool = virStorageBackendLogicalRefreshPool,
    .stopPool = virStorageBackendLogicalStopPool,
    .deletePool = virStorageBackendLogicalDeletePool,
836
    .buildVol = NULL,
837
    .buildVolFrom = virStorageBackendLogicalBuildVolFrom,
838 839 840
    .createVol = virStorageBackendLogicalCreateVol,
    .deleteVol = virStorageBackendLogicalDeleteVol,
};