storage_backend_logical.c 24.4 KB
Newer Older
1
/*
2
 * storage_backend_logical.c: storage backend for logical volume handling
3
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2007-2009, 2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * Copyright (C) 2007-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/wait.h>
#include <sys/stat.h>
#include <stdio.h>
#include <regex.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

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

42 43
#define VIR_FROM_THIS VIR_FROM_STORAGE

44 45 46 47
#define PV_BLANK_SECTOR_SIZE 512


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

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

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

    return 0;
}


65 66
#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped"

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

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

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

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

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

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

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

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

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

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

    if (vol->key == NULL &&
141
        (vol->key = strdup(groups[2])) == NULL) {
142
        virReportOOMError();
143
        goto cleanup;
144 145
    }

146
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
147 148 149 150 151 152 153 154 155 156
        goto cleanup;

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

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

165 166 167 168 169 170 171 172 173 174 175
    if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent length value"));
        goto cleanup;
    }
    if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent size value"));
        goto cleanup;
    }

E
Eric Blake 已提交
176
    /* Now parse the "devices" field separately */
177 178 179 180 181 182 183
    regex = strdup(regex_unit);

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

    if (VIR_ALLOC(reg) < 0) {
190
        virReportOOMError();
191
        goto cleanup;
192 193
    }

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

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

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

219
    p = groups[3];
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    /* vars[0] is skipped */
    for (i = 0; i < nextents; i++) {
        int j, len;
        const char *offset_str = NULL;

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

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

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

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

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

259 260 261 262 263 264 265 266 267
    ret = 0;

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

static int
271
virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
272 273 274
                                virStorageVolDefPtr vol)
{
    /*
275 276 277 278 279 280
     *  # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options "lv_name,origin,uuid,devices,seg_size,vg_extent_size" VGNAME
     *  RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432
     *  SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432
     *  Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432
     *  Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432
     *  Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432
281
     *
282
     * Pull out name, origin, & uuid, device, device extent start #, segment size, extent size.
283 284
     *
     * NB can be multiple rows per volume if they have many extents
285
     *
286 287 288 289
     * 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).
290 291
     * NB "devices" field has multiple device paths and "," if the volume is
     *    striped, so "," is not a suitable separator either (rhbz 727474).
292 293
     */
    const char *regexes[] = {
294
       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#?\\s*$"
295 296
    };
    int vars[] = {
297
        8
298 299
    };
    const char *prog[] = {
300
        LVS, "--separator", "#", "--noheadings", "--units", "b",
301
        "--unbuffered", "--nosuffix", "--options",
302
        "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
303
        pool->def->source.name, NULL
304 305
    };

306
    if (virStorageBackendRunProgRegex(pool,
307 308 309 310 311
                                      prog,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalMakeVol,
312
                                      vol, "lvs") < 0) {
313 314 315 316
        return -1;
    }

    return 0;
317 318 319
}

static int
320
virStorageBackendLogicalRefreshPoolFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
321 322 323 324 325 326 327 328 329 330 331 332 333
                                        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;
}


334
static int
335
virStorageBackendLogicalFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
336 337 338
                                            char **const groups,
                                            void *data)
{
339 340 341 342 343 344 345 346 347 348 349
    virStoragePoolSourceListPtr sourceList = data;
    char *pvname = NULL;
    char *vgname = NULL;
    int i;
    virStoragePoolSourceDevicePtr dev;
    virStoragePoolSource *thisSource;

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

    if (pvname == NULL || vgname == NULL) {
350
        virReportOOMError();
351 352 353 354 355 356 357 358 359 360
        goto err_no_memory;
    }

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

362
    if (thisSource == NULL) {
363
        if (!(thisSource = virStoragePoolSourceListNewSource(sourceList)))
364 365 366
            goto err_no_memory;

        thisSource->name = vgname;
367
    }
368 369
    else
        VIR_FREE(vgname);
370

371
    if (VIR_REALLOC_N(thisSource->devices, thisSource->ndevice + 1) != 0) {
372
        virReportOOMError();
373
        goto err_no_memory;
374 375
    }

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

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

    return 0;
384 385 386 387 388 389

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

    return -1;
390 391 392
}

static char *
393
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
394
                                        const char *srcSpec ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
395
                                        unsigned int flags)
396 397
{
    /*
398 399 400
     * # pvs --noheadings -o pv_name,vg_name
     *   /dev/sdb
     *   /dev/sdc VolGroup00
401 402
     */
    const char *regexes[] = {
403
        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
404 405
    };
    int vars[] = {
406
        2
407
    };
408
    const char *const prog[] = { PVS, "--noheadings", "-o", "pv_name,vg_name", NULL };
409
    const char *const scanprog[] = { VGSCAN, NULL };
410
    char *retval = NULL;
411 412
    virStoragePoolSourceList sourceList;
    int 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
    if (virRun(scanprog, NULL) < 0) {
422
        VIR_WARN("Failure when running vgscan to refresh physical volumes");
423
    }
424

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

428
    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
429
                                virStorageBackendLogicalFindPoolSourcesFunc,
430
                                &sourceList, "pvs") < 0)
431 432
        return NULL;

433
    retval = virStoragePoolSourceListFormat(&sourceList);
434
    if (retval == NULL) {
435
        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
436
                              _("failed to get source from sourceList"));
437 438 439 440
        goto cleanup;
    }

 cleanup:
441
    for (i = 0; i < sourceList.nsources; i++)
442
        virStoragePoolSourceClear(&sourceList.sources[i]);
443
    VIR_FREE(sourceList.sources);
444 445 446 447 448

    return retval;
}


449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
static int
virStorageBackendLogicalCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool,
                                  bool *isActive)
{
    char *path;

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

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

    VIR_FREE(path);

    return 0;
}

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

    return 0;
}


static int
482
virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
483
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
484
                                  unsigned int flags)
485 486 487 488 489 490
{
    const char **vgargv;
    const char *pvargv[3];
    int n = 0, i, fd;
    char zeros[PV_BLANK_SECTOR_SIZE];

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

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

495
    if (VIR_ALLOC_N(vgargv, 3 + pool->def->source.ndevice) < 0) {
496
        virReportOOMError();
497 498 499 500
        return -1;
    }

    vgargv[n++] = VGCREATE;
501
    vgargv[n++] = pool->def->source.name;
502 503 504 505 506 507 508 509 510 511

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

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

548
    vgargv[n] = NULL;
549 550

    /* Now create the volume group itself */
551
    if (virRun(vgargv, NULL) < 0)
552 553
        goto cleanup;

554
    VIR_FREE(vgargv);
555 556 557 558

    return 0;

 cleanup:
559
    VIR_FREE(vgargv);
560 561 562 563 564
    return -1;
}


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

588
    virFileWaitForDevices();
589

590
    /* Get list of all logical volumes */
591
    if (virStorageBackendLogicalFindLVs(pool, NULL) < 0) {
592 593 594 595 596
        virStoragePoolObjClearVols(pool);
        return -1;
    }

    /* Now get basic volgrp metadata */
597
    if (virStorageBackendRunProgRegex(pool,
598 599 600 601 602
                                      prog,
                                      1,
                                      regexes,
                                      vars,
                                      virStorageBackendLogicalRefreshPoolFunc,
603
                                      NULL, "vgs") < 0) {
604 605 606 607 608 609 610
        virStoragePoolObjClearVols(pool);
        return -1;
    }

    return 0;
}

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

    return 0;
}

static int
627
virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
628
                                   virStoragePoolObjPtr pool,
E
Eric Blake 已提交
629
                                   unsigned int flags)
630 631
{
    const char *cmdargv[] = {
632
        VGREMOVE, "-f", pool->def->source.name, NULL
633
    };
634 635
    const char *pvargv[3];
    int i, error;
636

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

639
    /* first remove the volume group */
640
    if (virRun(cmdargv, NULL) < 0)
641 642
        return -1;

643 644 645 646 647 648
    /* now remove the pv devices and clear them out */
    error = 0;
    pvargv[0] = PVREMOVE;
    pvargv[2] = NULL;
    for (i = 0 ; i < pool->def->source.ndevice ; i++) {
        pvargv[1] = pool->def->source.devices[i].path;
649
        if (virRun(pvargv, NULL) < 0) {
650 651 652 653
            error = -1;
            break;
        }
    }
654

655
    return error;
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
}


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


static int
virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                  virStoragePoolObjPtr pool,
                                  virStorageVolDefPtr vol)
{
671
    int fdret, fd = -1;
672
    char size[100];
673
    const char *cmdargvnew[] = {
674 675 676
        LVCREATE, "--name", vol->name, "-L", size,
        pool->def->target.path, NULL
    };
677 678 679 680 681 682
    const char *cmdargvsnap[] = {
        LVCREATE, "--name", vol->name, "-L", size,
        "-s", vol->backingStore.path, NULL
    };
    const char **cmdargv = cmdargvnew;

683
    if (vol->target.encryption != NULL) {
O
Osier Yang 已提交
684
        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
685 686 687 688 689
                              "%s", _("storage pool does not support encrypted "
                                      "volumes"));
        return -1;
    }

690 691 692
    if (vol->backingStore.path) {
        cmdargv = cmdargvsnap;
    }
693

694
    snprintf(size, sizeof(size)-1, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
695 696
    size[sizeof(size)-1] = '\0';

697 698
    vol->type = VIR_STORAGE_VOL_BLOCK;

699 700 701 702
    if (vol->target.path != NULL) {
        /* A target path passed to CreateVol has no meaning */
        VIR_FREE(vol->target.path);
    }
703 704 705 706

    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
                    vol->name) == -1) {
707
        virReportOOMError();
708 709 710
        return -1;
    }

711
    if (virRun(cmdargv, NULL) < 0)
712 713
        return -1;

714
    if ((fdret = virStorageBackendVolOpen(vol->target.path)) < 0)
715
        goto cleanup;
716
    fd = fdret;
717 718 719 720

    /* We can only chown/grp if root */
    if (getuid() == 0) {
        if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
721
            virReportSystemError(errno,
722 723
                                 _("cannot set file owner '%s'"),
                                 vol->target.path);
724 725 726 727
            goto cleanup;
        }
    }
    if (fchmod(fd, vol->target.perms.mode) < 0) {
728
        virReportSystemError(errno,
729 730
                             _("cannot set file mode '%s'"),
                             vol->target.path);
731 732 733
        goto cleanup;
    }

734
    if (VIR_CLOSE(fd) < 0) {
735
        virReportSystemError(errno,
736 737
                             _("cannot close file '%s'"),
                             vol->target.path);
738 739 740 741 742
        goto cleanup;
    }
    fd = -1;

    /* Fill in data about this new vol */
743
    if (virStorageBackendLogicalFindLVs(pool, vol) < 0) {
744
        virReportSystemError(errno,
745 746
                             _("cannot find newly created volume '%s'"),
                             vol->target.path);
747 748 749 750 751 752
        goto cleanup;
    }

    return 0;

 cleanup:
753
    VIR_FORCE_CLOSE(fd);
754 755 756 757
    virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
    return -1;
}

758 759
static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
760
                                     virStoragePoolObjPtr pool,
761 762 763 764 765 766
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

767
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
768 769 770
    if (!build_func)
        return -1;

771
    return build_func(conn, pool, vol, inputvol, flags);
772 773
}

774
static int
775
virStorageBackendLogicalDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
776 777
                                  virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                  virStorageVolDefPtr vol,
E
Eric Blake 已提交
778
                                  unsigned int flags)
779
{
780 781 782 783
    int ret = -1;

    virCommandPtr lvchange_cmd = NULL;
    virCommandPtr lvremove_cmd = NULL;
784

E
Eric Blake 已提交
785 786
    virCheckFlags(0, -1);

787 788
    virFileWaitForDevices();

789 790 791 792
    lvchange_cmd = virCommandNewArgList(LVCHANGE,
                                        "-aln",
                                        vol->target.path,
                                        NULL);
793

794 795 796 797
    lvremove_cmd = virCommandNewArgList(LVREMOVE,
                                        "-f",
                                        vol->target.path,
                                        NULL);
798

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    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;
}
814 815 816 817

virStorageBackend virStorageBackendLogical = {
    .type = VIR_STORAGE_POOL_LOGICAL,

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