You need to sign in or sign up before continuing.
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 47 48
#define PV_BLANK_SECTOR_SIZE 512


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

    ret = virCommandRun(cmd, NULL);
    virCommandFree(cmd);
    return ret;
62 63 64
}


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
    const char *regex_unit = "(\\S+)\\((\\S+)\\)";
    char *regex = NULL;
    regex_t *reg = NULL;
    regmatch_t *vars = NULL;
    char *p = NULL;
80 81
    size_t i;
    int err, nextents, nvars, ret = -1;
O
Osier Yang 已提交
82 83 84 85 86
    const char *attrs = groups[9];

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

D
Dusty Mabe 已提交
88 89 90 91 92 93 94 95
    /*
     * 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;

96 97 98 99 100 101 102 103 104 105 106 107 108
    /* 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) {
109
        if (VIR_ALLOC(vol) < 0)
110 111
            return -1;

112
        is_new_vol = true;
113 114
        vol->type = VIR_STORAGE_VOL_BLOCK;

115
        if (VIR_STRDUP(vol->name, groups[0]) < 0)
116
            goto cleanup;
117 118 119 120

    }

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

126 127 128 129 130 131 132 133
    /* 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] != '[')) {
134
        if (virAsprintf(&vol->backingStore.path, "%s/%s",
135
                        pool->def->target.path, groups[1]) < 0)
136
            goto cleanup;
137 138

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
139 140
    }

141
    if (!vol->key && VIR_STRDUP(vol->key, groups[2]) < 0)
142
        goto cleanup;
143

144
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
145 146 147 148 149
        goto cleanup;

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

    /* Finally fill in extents information */
157
    if (VIR_REALLOC_N(vol->source.extents,
158
                      vol->source.nextent + nextents) < 0)
159
        goto cleanup;
160

161
    if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
162 163
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent length value"));
164 165 166
        goto cleanup;
    }
    if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
167 168
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent size value"));
169 170
        goto cleanup;
    }
171
    if (virStrToLong_ull(groups[8], NULL, 10, &vol->allocation) < 0) {
172 173
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume allocation value"));
174 175
        goto cleanup;
    }
176

E
Eric Blake 已提交
177
    /* Now parse the "devices" field separately */
178 179
    if (VIR_STRDUP(regex, regex_unit) < 0)
        goto cleanup;
180 181

    for (i = 1; i < nextents; i++) {
182
        if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0)
183
            goto cleanup;
E
Eric Blake 已提交
184
        /* "," is the separator of "devices" field */
185 186 187 188
        strcat(regex, ",");
        strncat(regex, regex_unit, strlen(regex_unit));
    }

189
    if (VIR_ALLOC(reg) < 0)
190
        goto cleanup;
191

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

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

209 210 211
    err = regexec(reg, groups[3], nvars, vars, 0);
    regfree(reg);
    if (err != 0) {
212 213
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("malformed volume extent devices value"));
214
        goto cleanup;
215 216
    }

217
    p = groups[3];
218

219 220
    /* vars[0] is skipped */
    for (i = 0; i < nextents; i++) {
221 222
        size_t j;
        int len;
223
        char *offset_str = NULL;
224 225 226 227 228

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

229 230
        if (VIR_STRNDUP(vol->source.extents[vol->source.nextent].path,
                        p + vars[j].rm_so, len) < 0)
231 232 233
            goto cleanup;

        len = vars[j + 1].rm_eo - vars[j + 1].rm_so;
234
        if (VIR_STRNDUP(offset_str, p + vars[j + 1].rm_so, len) < 0)
235 236 237
            goto cleanup;

        if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) {
238 239
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("malformed volume extent offset value"));
E
Eric Blake 已提交
240
            VIR_FREE(offset_str);
241 242 243 244 245 246 247 248 249 250
            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++;
    }

251 252 253
    if (is_new_vol &&
        VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
        goto cleanup;
254

255 256 257 258
    ret = 0;

cleanup:
    VIR_FREE(regex);
259
    VIR_FREE(reg);
260 261 262 263
    VIR_FREE(vars);
    if (is_new_vol && (ret == -1))
        virStorageVolDefFree(vol);
    return ret;
264 265 266
}

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

    cmd = virCommandNewArgList(LVS,
                               "--separator", "#",
                               "--noheadings",
                               "--units", "b",
                               "--unbuffered",
                               "--nosuffix",
O
Osier Yang 已提交
307 308
                               "--options",
                               "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size,lv_attr",
309 310
                               pool->def->source.name,
                               NULL);
311
    if (virStorageBackendRunProgRegex(pool,
312
                                      cmd,
313 314 315 316
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalMakeVol,
317 318
                                      vol, "lvs") < 0)
        goto cleanup;
319

320 321 322 323
    ret = 0;
cleanup:
    virCommandFree(cmd);
    return ret;
324 325 326
}

static int
327
virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
328 329 330 331 332 333 334 335 336 337 338 339 340
                                        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;
}


341
static int
342
virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
343 344 345
                                            char **const groups,
                                            void *data)
{
346 347 348
    virStoragePoolSourceListPtr sourceList = data;
    char *pvname = NULL;
    char *vgname = NULL;
349
    size_t i;
350 351 352
    virStoragePoolSourceDevicePtr dev;
    virStoragePoolSource *thisSource;

353 354 355
    if (VIR_STRDUP(pvname, groups[0]) < 0 ||
        VIR_STRDUP(vgname, groups[1]) < 0)
        goto error;
356 357

    thisSource = NULL;
358
    for (i = 0; i < sourceList->nsources; i++) {
359 360 361 362 363
        if (STREQ(sourceList->sources[i].name, vgname)) {
            thisSource = &sourceList->sources[i];
            break;
        }
    }
364

365
    if (thisSource == NULL) {
366
        if (!(thisSource = virStoragePoolSourceListNewSource(sourceList)))
367
            goto error;
368 369

        thisSource->name = vgname;
370
    }
371 372
    else
        VIR_FREE(vgname);
373

374
    if (VIR_REALLOC_N(thisSource->devices, thisSource->ndevice + 1) != 0)
375
        goto error;
376

377 378
    dev = &thisSource->devices[thisSource->ndevice];
    thisSource->ndevice++;
379
    thisSource->format = VIR_STORAGE_POOL_LOGICAL_LVM2;
380 381 382

    memset(dev, 0, sizeof(*dev));
    dev->path = pvname;
383 384

    return 0;
385

386
error:
387 388 389 390
    VIR_FREE(pvname);
    VIR_FREE(vgname);

    return -1;
391 392 393
}

static char *
394
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
395
                                        const char *srcSpec ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
396
                                        unsigned int flags)
397 398
{
    /*
399 400 401
     * # pvs --noheadings -o pv_name,vg_name
     *   /dev/sdb
     *   /dev/sdc VolGroup00
402 403
     */
    const char *regexes[] = {
404
        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
405 406
    };
    int vars[] = {
407
        2
408
    };
409
    virCommandPtr cmd;
410
    char *retval = NULL;
411
    virStoragePoolSourceList sourceList;
412
    size_t i;
413

E
Eric Blake 已提交
414 415
    virCheckFlags(0, NULL);

416 417 418 419 420
    /*
     * 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
     */
421 422
    cmd = virCommandNew(VGSCAN);
    if (virCommandRun(cmd, NULL) < 0)
423
        VIR_WARN("Failure when running vgscan to refresh physical volumes");
424
    virCommandFree(cmd);
425

426
    memset(&sourceList, 0, sizeof(sourceList));
427 428
    sourceList.type = VIR_STORAGE_POOL_LOGICAL;

429 430 431 432 433 434 435 436
    cmd = virCommandNewArgList(PVS,
                               "--noheadings",
                               "-o", "pv_name,vg_name",
                               NULL);
    if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
                                      virStorageBackendLogicalFindPoolSourcesFunc,
                                      &sourceList, "pvs") < 0) {
        virCommandFree(cmd);
437
        return NULL;
438 439
    }
    virCommandFree(cmd);
440

441
    retval = virStoragePoolSourceListFormat(&sourceList);
442
    if (retval == NULL) {
443 444
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to get source from sourceList"));
445 446 447 448
        goto cleanup;
    }

 cleanup:
449
    for (i = 0; i < sourceList.nsources; i++)
450
        virStoragePoolSourceClear(&sourceList.sources[i]);
451
    VIR_FREE(sourceList.sources);
452 453 454 455 456

    return retval;
}


457 458 459 460 461
static int
virStorageBackendLogicalCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool,
                                  bool *isActive)
{
462
    *isActive = virFileExists(pool->def->target.path);
463 464 465
    return 0;
}

466
static int
467
virStorageBackendLogicalStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
468 469
                                  virStoragePoolObjPtr pool)
{
470
    if (virStorageBackendLogicalSetActive(pool, 1) < 0)
471 472 473 474 475 476 477
        return -1;

    return 0;
}


static int
478
virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
479
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
480
                                  unsigned int flags)
481
{
482 483
    virCommandPtr vgcmd;
    int fd;
484
    char zeros[PV_BLANK_SECTOR_SIZE];
485 486
    int ret = -1;
    size_t i;
487

E
Eric Blake 已提交
488 489
    virCheckFlags(0, -1);

490 491
    memset(zeros, 0, sizeof(zeros));

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

494
    for (i = 0; i < pool->def->source.ndevice; i++) {
495
        virCommandPtr pvcmd;
496 497 498 499 500 501
        /*
         * 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) {
502
            virReportSystemError(errno,
503 504
                                 _("cannot open device '%s'"),
                                 pool->def->source.devices[i].path);
505 506
            goto cleanup;
        }
507
        if (safewrite(fd, zeros, sizeof(zeros)) < 0) {
508
            virReportSystemError(errno,
509 510
                                 _("cannot clear device header of '%s'"),
                                 pool->def->source.devices[i].path);
511 512 513 514 515 516 517
            VIR_FORCE_CLOSE(fd);
            goto cleanup;
        }
        if (fsync(fd) < 0) {
            virReportSystemError(errno,
                                 _("cannot flush header of device'%s'"),
                                 pool->def->source.devices[i].path);
518
            VIR_FORCE_CLOSE(fd);
519 520
            goto cleanup;
        }
521
        if (VIR_CLOSE(fd) < 0) {
522
            virReportSystemError(errno,
523 524
                                 _("cannot close device '%s'"),
                                 pool->def->source.devices[i].path);
525 526 527 528 529 530 531
            goto cleanup;
        }

        /*
         * Initialize the physical volume because vgcreate is not
         * clever enough todo this for us :-(
         */
532 533 534 535 536
        pvcmd = virCommandNewArgList(PVCREATE,
                                     pool->def->source.devices[i].path,
                                     NULL);
        if (virCommandRun(pvcmd, NULL) < 0) {
            virCommandFree(pvcmd);
537
            goto cleanup;
538 539
        }
        virCommandFree(pvcmd);
540

541 542
        virCommandAddArg(vgcmd, pool->def->source.devices[i].path);
    }
543 544

    /* Now create the volume group itself */
545
    if (virCommandRun(vgcmd, NULL) < 0)
546 547
        goto cleanup;

548
    ret = 0;
549

550 551 552
cleanup:
    virCommandFree(vgcmd);
    return ret;
553 554 555 556
}


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

577
    virFileWaitForDevices();
578

579
    /* Get list of all logical volumes */
580 581 582 583 584 585 586 587 588 589 590 591
    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);
592 593

    /* Now get basic volgrp metadata */
594
    if (virStorageBackendRunProgRegex(pool,
595
                                      cmd,
596 597 598 599
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalRefreshPoolFunc,
600 601
                                      NULL, "vgs") < 0)
        goto cleanup;
602

603 604 605 606 607 608 609
    ret = 0;

cleanup:
    virCommandFree(cmd);
    if (ret < 0)
        virStoragePoolObjClearVols(pool);
    return ret;
610 611
}

612 613 614 615
/*
 * 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)"
616 617
 */
static int
618
virStorageBackendLogicalStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
619 620
                                 virStoragePoolObjPtr pool)
{
621
    if (virStorageBackendLogicalSetActive(pool, 0) < 0)
622 623 624 625 626 627
        return -1;

    return 0;
}

static int
628
virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
629
                                   virStoragePoolObjPtr pool,
E
Eric Blake 已提交
630
                                   unsigned int flags)
631
{
632 633 634
    virCommandPtr cmd = NULL;
    size_t i;
    int ret = -1;
635

E
Eric Blake 已提交
636 637
    virCheckFlags(0, -1);

638
    /* first remove the volume group */
639 640 641 642 643 644
    cmd = virCommandNewArgList(VGREMOVE,
                               "-f", pool->def->source.name,
                               NULL);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
    virCommandFree(cmd);
645
    cmd = NULL;
646

647
    /* now remove the pv devices and clear them out */
648
    ret = 0;
649
    for (i = 0; i < pool->def->source.ndevice; i++) {
650 651 652 653 654
        cmd = virCommandNewArgList(PVREMOVE,
                                   pool->def->source.devices[i].path,
                                   NULL);
        if (virCommandRun(cmd, NULL) < 0) {
            ret = -1;
655 656
            break;
        }
657 658
        virCommandFree(cmd);
        cmd = NULL;
659
    }
660

661 662 663
cleanup:
    virCommandFree(cmd);
    return ret;
664 665 666 667
}


static int
668 669
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
670
                                  virStorageVolDefPtr vol,
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
                                  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;
}
700 701 702


static int
703 704 705
virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol)
706
{
707
    int fd = -1;
708
    virCommandPtr cmd = NULL;
709
    virErrorPtr err;
710

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    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;
729

730 731 732 733
    cmd = virCommandNewArgList(LVCREATE,
                               "--name", vol->name,
                               NULL);
    virCommandAddArg(cmd, "-L");
734
    if (vol->capacity != vol->allocation) {
735 736
        virCommandAddArgFormat(cmd, "%lluK",
                VIR_DIV_UP(vol->allocation ? vol->allocation : 1, 1024));
737 738
        virCommandAddArg(cmd, "--virtualsize");
    }
739 740
    virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
    if (vol->backingStore.path)
741
        virCommandAddArgList(cmd, "-s", vol->backingStore.path, NULL);
742 743 744 745
    else
        virCommandAddArg(cmd, pool->def->source.name);

    if (virCommandRun(cmd, NULL) < 0)
746
        goto error;
747

748 749 750 751 752
    virCommandFree(cmd);
    cmd = NULL;

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

    /* We can only chown/grp if root */
755
    if (geteuid() == 0) {
756
        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
757
            virReportSystemError(errno,
758 759
                                 _("cannot set file owner '%s'"),
                                 vol->target.path);
760
            goto error;
761 762 763
        }
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
764
        virReportSystemError(errno,
765 766
                             _("cannot set file mode '%s'"),
                             vol->target.path);
767
        goto error;
768 769
    }

770
    if (VIR_CLOSE(fd) < 0) {
771
        virReportSystemError(errno,
772 773
                             _("cannot close file '%s'"),
                             vol->target.path);
774
        goto error;
775 776 777
    }

    /* Fill in data about this new vol */
778
    if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
779
        virReportSystemError(errno,
780 781
                             _("cannot find newly created volume '%s'"),
                             vol->target.path);
782
        goto error;
783 784 785 786
    }

    return 0;

787
 error:
788
    err = virSaveLastError();
789
    VIR_FORCE_CLOSE(fd);
790
    virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
791
    virCommandFree(cmd);
792
    virSetError(err);
793
    virFreeError(err);
794 795 796
    return -1;
}

797 798
static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
799
                                     virStoragePoolObjPtr pool,
800 801 802 803 804 805
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

806
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
807 808 809
    if (!build_func)
        return -1;

810
    return build_func(conn, pool, vol, inputvol, flags);
811 812
}

813 814 815 816

virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

817
    .findPoolSources = virStorageBackendLogicalFindPoolSources,
818
    .checkPool = virStorageBackendLogicalCheckPool,
819 820 821 822 823
    .startPool = virStorageBackendLogicalStartPool,
    .buildPool = virStorageBackendLogicalBuildPool,
    .refreshPool = virStorageBackendLogicalRefreshPool,
    .stopPool = virStorageBackendLogicalStopPool,
    .deletePool = virStorageBackendLogicalDeletePool,
824
    .buildVol = NULL,
825
    .buildVolFrom = virStorageBackendLogicalBuildVolFrom,
826 827 828
    .createVol = virStorageBackendLogicalCreateVol,
    .deleteVol = virStorageBackendLogicalDeleteVol,
};