storage_backend_logical.c 25.5 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
        if (VIR_REALLOC_N(pool->volumes.objs,
119
                          pool->volumes.count + 1))
120
            goto cleanup;
121 122 123
    }

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

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

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
142 143
    }

144
    if (!vol->key && VIR_STRDUP(vol->key, groups[2]) < 0)
145
        goto cleanup;
146

147
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
148 149 150 151 152
        goto cleanup;

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

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

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

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

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

192
    if (VIR_ALLOC(reg) < 0)
193
        goto cleanup;
194

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

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

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

220
    p = groups[3];
221

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

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

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

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

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

254 255 256
    if (is_new_vol)
        pool->volumes.objs[pool->volumes.count++] = vol;

257 258 259 260
    ret = 0;

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

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

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

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

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


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

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

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

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

        thisSource->name = vgname;
372
    }
373 374
    else
        VIR_FREE(vgname);
375

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

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

    memset(dev, 0, sizeof(*dev));
    dev->path = pvname;
385 386

    return 0;
387

388
error:
389 390 391 392
    VIR_FREE(pvname);
    VIR_FREE(vgname);

    return -1;
393 394 395
}

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

E
Eric Blake 已提交
416 417
    virCheckFlags(0, NULL);

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

428
    memset(&sourceList, 0, sizeof(sourceList));
429 430
    sourceList.type = VIR_STORAGE_POOL_LOGICAL;

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

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

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

    return retval;
}


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

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

    return 0;
}


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

E
Eric Blake 已提交
490 491
    virCheckFlags(0, -1);

492 493
    memset(zeros, 0, sizeof(zeros));

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

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

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

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

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

550
    ret = 0;
551

552 553 554
cleanup:
    virCommandFree(vgcmd);
    return ret;
555 556 557 558
}


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

579
    virFileWaitForDevices();
580

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

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

605 606 607 608 609 610 611
    ret = 0;

cleanup:
    virCommandFree(cmd);
    if (ret < 0)
        virStoragePoolObjClearVols(pool);
    return ret;
612 613
}

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

    return 0;
}

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

E
Eric Blake 已提交
638 639
    virCheckFlags(0, -1);

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

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

663 664 665
cleanup:
    virCommandFree(cmd);
    return ret;
666 667 668 669
}


static int
670 671
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
672
                                  virStorageVolDefPtr vol,
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 700 701
                                  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;
}
702 703 704


static int
705 706 707 708
virStorageBackendLogicalBuildVol(virConnectPtr conn,
                                 virStoragePoolObjPtr pool,
                                 virStorageVolDefPtr vol,
                                 unsigned int flags)
709
{
710
    int fd = -1;
711
    virCommandPtr cmd = NULL;
712
    virErrorPtr err;
713

714
    virCheckFlags(0, -1);
715

716 717 718 719
    cmd = virCommandNewArgList(LVCREATE,
                               "--name", vol->name,
                               NULL);
    virCommandAddArg(cmd, "-L");
720
    if (vol->capacity != vol->allocation) {
721 722
        virCommandAddArgFormat(cmd, "%lluK",
                VIR_DIV_UP(vol->allocation ? vol->allocation : 1, 1024));
723 724
        virCommandAddArg(cmd, "--virtualsize");
    }
725 726
    virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
    if (vol->backingStore.path)
727
        virCommandAddArgList(cmd, "-s", vol->backingStore.path, NULL);
728 729 730 731
    else
        virCommandAddArg(cmd, pool->def->source.name);

    if (virCommandRun(cmd, NULL) < 0)
732
        goto error;
733

734 735 736 737 738
    virCommandFree(cmd);
    cmd = NULL;

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

    /* We can only chown/grp if root */
741
    if (geteuid() == 0) {
742
        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
743
            virReportSystemError(errno,
744 745
                                 _("cannot set file owner '%s'"),
                                 vol->target.path);
746
            goto error;
747 748 749
        }
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
750
        virReportSystemError(errno,
751 752
                             _("cannot set file mode '%s'"),
                             vol->target.path);
753
        goto error;
754 755
    }

756
    if (VIR_CLOSE(fd) < 0) {
757
        virReportSystemError(errno,
758 759
                             _("cannot close file '%s'"),
                             vol->target.path);
760
        goto error;
761 762 763
    }

    /* Fill in data about this new vol */
764
    if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
765
        virReportSystemError(errno,
766 767
                             _("cannot find newly created volume '%s'"),
                             vol->target.path);
768
        goto error;
769 770 771 772
    }

    return 0;

773
error:
774
    err = virSaveLastError();
775
    VIR_FORCE_CLOSE(fd);
776
    virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
777
    virCommandFree(cmd);
778
    virSetError(err);
779
    virFreeError(err);
780 781 782
    return -1;
}

783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812

static int
virStorageBackendLogicalCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol)
{
    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;

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

    if (virFileExists(vol->target.path)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("volume target path '%s' already exists"),
                       vol->target.path);
        return -1;
    }

    return 0;
}

813 814
static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
815
                                     virStoragePoolObjPtr pool,
816 817 818 819 820 821
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

822
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
823 824 825
    if (!build_func)
        return -1;

826
    return build_func(conn, pool, vol, inputvol, flags);
827 828
}

829 830 831 832

virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

833
    .findPoolSources = virStorageBackendLogicalFindPoolSources,
834
    .checkPool = virStorageBackendLogicalCheckPool,
835 836 837 838 839
    .startPool = virStorageBackendLogicalStartPool,
    .buildPool = virStorageBackendLogicalBuildPool,
    .refreshPool = virStorageBackendLogicalRefreshPool,
    .stopPool = virStorageBackendLogicalStopPool,
    .deletePool = virStorageBackendLogicalDeletePool,
840
    .buildVol = virStorageBackendLogicalBuildVol,
841
    .buildVolFrom = virStorageBackendLogicalBuildVolFrom,
842 843 844
    .createVol = virStorageBackendLogicalCreateVol,
    .deleteVol = virStorageBackendLogicalDeleteVol,
};