storage_backend_logical.c 25.0 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, 1) < 0)
153 154 155 156 157
        goto cleanup;

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

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

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

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

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

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

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

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

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

225
    p = groups[3];
226

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

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

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

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

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

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

263 264 265 266
    ret = 0;

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

static int
275
virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
276 277 278
                                virStorageVolDefPtr vol)
{
    /*
O
Osier Yang 已提交
279 280 281 282 283 284 285 286
     * # 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-
287
     *
O
Osier Yang 已提交
288 289
     * Pull out name, origin, & uuid, device, device extent start #,
     * segment size, extent size, size, attrs
290 291
     *
     * NB can be multiple rows per volume if they have many extents
292
     *
293 294 295 296
     * 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).
297 298
     * NB "devices" field has multiple device paths and "," if the volume is
     *    striped, so "," is not a suitable separator either (rhbz 727474).
299 300
     */
    const char *regexes[] = {
O
Osier Yang 已提交
301
       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#([0-9]+)#(\\S+)#?\\s*$"
302 303
    };
    int vars[] = {
O
Osier Yang 已提交
304
        10
305
    };
306 307
    int ret = -1;
    virCommandPtr cmd;
308 309 310 311
    struct virStorageBackendLogicalPoolVolData cbdata = {
        .pool = pool,
        .vol = vol,
    };
312 313 314 315 316 317 318

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

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

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


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

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

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

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

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

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

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

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

    return 0;
396

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

    return -1;
402 403 404
}

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

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

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

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

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

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

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

    return retval;
}


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

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

    return 0;
}


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

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

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

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

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

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

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

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

559
    ret = 0;
560

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


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

588
    virFileWaitForDevices();
589

590
    /* Get list of all logical volumes */
591 592 593 594 595 596 597 598 599 600 601 602
    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);
603 604

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

614 615 616 617 618 619 620
    ret = 0;

cleanup:
    virCommandFree(cmd);
    if (ret < 0)
        virStoragePoolObjClearVols(pool);
    return ret;
621 622
}

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

    return 0;
}

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

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

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

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

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


static int
679 680
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
681
                                  virStorageVolDefPtr vol,
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
                                  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;
cleanup:
    virCommandFree(lvchange_cmd);
    virCommandFree(lvremove_cmd);
    return ret;
}
711 712 713


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

722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
    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;
740

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

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

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

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

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

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

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

    return 0;

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

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

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

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

824 825 826 827

virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

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