storage_backend_disk.c 26.1 KB
Newer Older
1 2 3
/*
 * storage_backend_disk.c: storage backend for disk handling
 *
4
 * Copyright (C) 2007-2008, 2010-2012 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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>
C
Cole Robinson 已提交
25
#include <string.h>
26
#include <unistd.h>
27
#include <stdio.h>
28

29
#include "virterror_internal.h"
30
#include "logging.h"
31 32
#include "storage_backend_disk.h"
#include "util.h"
33
#include "memory.h"
34
#include "command.h"
35
#include "configmake.h"
36

37 38
#define VIR_FROM_THIS VIR_FROM_STORAGE

39
#define PARTHELPER LIBEXECDIR "/libvirt_parthelper"
40

41 42
#define SECTOR_SIZE 512

43
static int
44
virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
45 46 47 48 49 50
                                 char **const groups,
                                 virStorageVolDefPtr vol)
{
    char *tmp, *devpath;

    if (vol == NULL) {
51
        if (VIR_ALLOC(vol) < 0) {
52
            virReportOOMError();
53 54 55
            return -1;
        }

56 57
        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0) {
58
            virReportOOMError();
59 60 61 62
            virStorageVolDefFree(vol);
            return -1;
        }
        pool->volumes.objs[pool->volumes.count++] = vol;
63 64 65 66 67 68

        /* Prepended path will be same for all partitions, so we can
         * strip the path to form a reasonable pool-unique name
         */
        tmp = strrchr(groups[0], '/');
        if ((vol->name = strdup(tmp ? tmp + 1 : groups[0])) == NULL) {
69
            virReportOOMError();
70 71 72 73 74 75
            return -1;
        }
    }

    if (vol->target.path == NULL) {
        if ((devpath = strdup(groups[0])) == NULL) {
76
            virReportOOMError();
77 78 79 80 81 82 83 84 85
            return -1;
        }

        /* Now figure out the stable path
         *
         * XXX this method is O(N) because it scans the pool target
         * dir every time its run. Should figure out a more efficient
         * way of doing this...
         */
86
        vol->target.path = virStorageBackendStablePath(pool, devpath);
87
        VIR_FREE(devpath);
88 89
        if (vol->target.path == NULL)
            return -1;
90 91 92 93 94
    }

    if (vol->key == NULL) {
        /* XXX base off a unique key of the underlying disk */
        if ((vol->key = strdup(vol->target.path)) == NULL) {
95
            virReportOOMError();
96 97 98 99 100
            return -1;
        }
    }

    if (vol->source.extents == NULL) {
101
        if (VIR_ALLOC(vol->source.extents) < 0) {
102
            virReportOOMError();
103 104 105 106 107 108
            return -1;
        }
        vol->source.nextent = 1;

        if (virStrToLong_ull(groups[3], NULL, 10,
                             &vol->source.extents[0].start) < 0) {
109 110
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device start location"));
111 112 113 114 115
            return -1;
        }

        if (virStrToLong_ull(groups[4], NULL, 10,
                             &vol->source.extents[0].end) < 0) {
116 117
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device end location"));
118 119 120 121 122
            return -1;
        }

        if ((vol->source.extents[0].path =
             strdup(pool->def->source.devices[0].path)) == NULL) {
123
            virReportOOMError();
124 125 126 127 128
            return -1;
        }
    }

    /* Refresh allocation/capacity/perms */
129
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
130 131
        return -1;

132
    /* set partition type */
E
Eric Blake 已提交
133
    if (STREQ(groups[1], "normal"))
134
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
E
Eric Blake 已提交
135
    else if (STREQ(groups[1], "logical"))
136
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
E
Eric Blake 已提交
137
    else if (STREQ(groups[1], "extended"))
138 139 140 141
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_EXTENDED;
    else
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_NONE;

142 143
    vol->type = VIR_STORAGE_VOL_BLOCK;

144 145 146 147 148 149 150 151 152 153 154 155 156 157
    /* The above gets allocation wrong for
     * extended partitions, so overwrite it */
    vol->allocation = vol->capacity =
        (vol->source.extents[0].end - vol->source.extents[0].start);

    if (STRNEQ(groups[2], "metadata"))
        pool->def->allocation += vol->allocation;
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}

static int
158
virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
159 160 161 162
                                    char **const groups)
{
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];

163 164
    if (VIR_REALLOC_N(dev->freeExtents,
                      dev->nfreeExtent + 1) < 0)
165 166 167
        return -1;

    memset(dev->freeExtents +
168 169
           dev->nfreeExtent, 0,
           sizeof(dev->freeExtents[0]));
170

171
    /* set type of free area */
E
Eric Blake 已提交
172
    if (STREQ(groups[1], "logical")) {
173 174 175 176 177 178
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_LOGICAL;
    } else {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_NORMAL;
    }


179 180 181 182 183 184 185 186
    if (virStrToLong_ull(groups[3], NULL, 10,
                         &dev->freeExtents[dev->nfreeExtent].start) < 0)
        return -1; /* Don't bother to re-alloc freeExtents - it'll be free'd shortly */

    if (virStrToLong_ull(groups[4], NULL, 10,
                         &dev->freeExtents[dev->nfreeExtent].end) < 0)
        return -1; /* Don't bother to re-alloc freeExtents - it'll be free'd shortly */

187 188 189 190 191
    /* first block reported as free, even if it is not */
    if (dev->freeExtents[dev->nfreeExtent].start == 0) {
        dev->freeExtents[dev->nfreeExtent].start = SECTOR_SIZE;
    }

192 193 194 195 196 197 198 199 200 201 202 203 204
    pool->def->available +=
        (dev->freeExtents[dev->nfreeExtent].end -
         dev->freeExtents[dev->nfreeExtent].start);
    if (dev->freeExtents[dev->nfreeExtent].end > pool->def->capacity)
        pool->def->capacity = dev->freeExtents[dev->nfreeExtent].end;

    dev->nfreeExtent++;

    return 0;
}


static int
205
virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
                             size_t ntok ATTRIBUTE_UNUSED,
                             char **const groups,
                             void *data)
{
    /*
     * Ignore normal+metadata, and logical+metadata partitions
     * since they're basically internal book-keeping regions
     * we have no control over. Do keep extended+metadata though
     * because that's the MS-DOS extended partition region we
     * need to be able to view/create/delete
     */
    if ((STREQ(groups[1], "normal") ||
         STREQ(groups[1], "logical")) &&
        STREQ(groups[2], "metadata"))
        return 0;

R
Richard W.M. Jones 已提交
222
    /* Remaining data / metadata parts get turn into volumes... */
223 224 225
    if (STREQ(groups[2], "metadata") ||
        STREQ(groups[2], "data")) {
        virStorageVolDefPtr vol = data;
226 227 228 229 230 231 232 233 234 235 236 237

        if (vol) {
            /* We're searching for a specific vol only */
            if (vol->key) {
                if (STRNEQ(vol->key, groups[0]))
                    return 0;
            } else if (virStorageVolDefFindByKey(pool, groups[0]) != NULL) {
                /* If no key, the volume must be newly created. If groups[0]
                 * isn't already a volume, assume it's the path we want */
                return 0;
            }
        }
238

239
        return virStorageBackendDiskMakeDataVol(pool, groups, vol);
240 241
    } else if (STREQ(groups[2], "free")) {
        /* ....or free space extents */
242
        return virStorageBackendDiskMakeFreeExtent(pool, groups);
243
    } else {
R
Richard W.M. Jones 已提交
244
        /* This code path should never happen unless someone changed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
         * libvirt_parthelper forgot to change this code */
        return -1;
    }
}


/* To get a list of partitions we run an external helper
 * tool which then uses parted APIs. This is because
 * parted's API is not compatible with libvirt's license
 * but we really really want to use parted because the
 * other options all suck :-)
 *
 * All the other storage backends run an external tool for
 * listing volumes so this really isn't too much of a pain,
 * and we can even ensure the output is friendly.
 */
static int
262
virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
263 264 265 266 267 268 269 270 271
                                    virStorageVolDefPtr vol)
{
    /*
     *  # libvirt_parthelper DEVICE
     * /dev/sda1      normal       data        32256    106928128    106896384
     * /dev/sda2      normal       data    106928640 100027629568  99920701440
     * -              normal   metadata 100027630080 100030242304      2612736
     *
     */
272 273 274 275
    virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
                                             pool->def->source.devices[0].path,
                                             NULL);
    int ret;
276 277 278

    pool->def->allocation = pool->def->capacity = pool->def->available = 0;

279 280 281 282 283 284 285
    ret = virStorageBackendRunProgNul(pool,
                                      cmd,
                                      6,
                                      virStorageBackendDiskMakeVol,
                                      vol);
    virCommandFree(cmd);
    return ret;
286 287
}

288
static int
289 290 291 292
virStorageBackendDiskMakePoolGeometry(virStoragePoolObjPtr pool,
                                      size_t ntok ATTRIBUTE_UNUSED,
                                      char **const groups,
                                      void *data ATTRIBUTE_UNUSED)
293 294 295 296 297 298 299 300 301 302
{

       pool->def->source.devices[0].geometry.cyliders = atoi(groups[0]);
       pool->def->source.devices[0].geometry.heads = atoi(groups[1]);
       pool->def->source.devices[0].geometry.sectors = atoi(groups[2]);

       return 0;
}

static int
303
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
304
{
305 306 307 308 309 310 311 312 313 314 315 316 317
    virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
                                             pool->def->source.devices[0].path,
                                             "-g",
                                             NULL);
    int ret;

    ret = virStorageBackendRunProgNul(pool,
                                      cmd,
                                      3,
                                      virStorageBackendDiskMakePoolGeometry,
                                      NULL);
    virCommandFree(cmd);
    return ret;
318
}
319 320

static int
321
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
322 323
                                 virStoragePoolObjPtr pool)
{
324
    VIR_FREE(pool->def->source.devices[0].freeExtents);
325 326
    pool->def->source.devices[0].nfreeExtent = 0;

327
    virFileWaitForDevices();
328

329
    if (!virFileExists(pool->def->source.devices[0].path)) {
330 331 332
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device path '%s' doesn't exist"),
                       pool->def->source.devices[0].path);
333 334 335
        return -1;
    }

336
    if (virStorageBackendDiskReadGeometry(pool) != 0) {
337 338 339
        return -1;
    }

340
    return virStorageBackendDiskReadPartitions(pool, NULL);
341 342 343
}


344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
/**
 * Check for a valid disk label (partition table) on device
 *
 * return: 0 - valid disk label found
 *        >0 - no or unrecognized disk label
 *        <0 - error finding the disk label
 */
static int
virStorageBackendDiskFindLabel(const char* device)
{
    const char *const args[] = {
        device, "print", "--script", NULL,
    };
    virCommandPtr cmd = virCommandNew(PARTED);
    char *output = NULL;
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);

    /* if parted succeeds we have a valid partition table */
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
        if (strstr (output, "unrecognised disk label"))
            ret = 1;
    }

    virCommandFree(cmd);
    VIR_FREE(output);
    return ret;
}


378 379 380 381
/**
 * Write a new partition table header
 */
static int
382
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
383
                               virStoragePoolObjPtr pool,
E
Eric Blake 已提交
384
                               unsigned int flags)
385
{
386 387
    bool ok_to_mklabel = false;
    int ret = -1;
388
    /* eg parted /dev/sda mklabel msdos */
389 390 391 392 393 394 395
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mklabel",
                                             "--script",
                                             ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" :
                                              virStoragePoolFormatDiskTypeToString(pool->def->source.format)),
                                             NULL);
396

397 398
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
399

400 401
    if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {
402
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
403 404
                       _("Overwrite and no overwrite flags"
                         " are mutually exclusive"));
405 406
        goto error;
    }
407

408 409 410 411 412 413 414 415 416 417
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE)
        ok_to_mklabel = true;
    else {
        int check;

        check = virStorageBackendDiskFindLabel (
                    pool->def->source.devices[0].path);
        if (check > 0) {
            ok_to_mklabel = true;
        } else if (check < 0) {
418
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
419
                           _("Error checking for disk label"));
420
        } else {
421
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
422
                           _("Disk label already present"));
423 424 425 426
        }
    }

    if (ok_to_mklabel)
427
        ret = virCommandRun(cmd, NULL);
428 429

error:
430
    virCommandFree(cmd);
431
    return ret;
432 433
}

434 435 436 437
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
438
static int
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
        /* count primary and extended paritions,
           can't be more than 3 to create a new primary partition */
        int i;
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
             if (pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                 pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
                     count++;
             }
        }
        if (count >= 4) {
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
        }
    }

    /* for all other cases, all partitions are primary */
    return VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
}

static int
462
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
463
                                virStorageVolDefPtr vol,
E
Eric Blake 已提交
464
                                char** partFormat)
465 466 467
{
    int i;
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
E
Eric Blake 已提交
468 469 470
        const char *partedFormat;
        partedFormat = virStoragePartedFsTypeTypeToString(vol->target.format);
        if (partedFormat == NULL) {
471 472
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Invalid partition type"));
E
Eric Blake 已提交
473
            return -1;
474 475 476 477
        }
        if (vol->target.format == VIR_STORAGE_VOL_DISK_EXTENDED) {
            /* make sure we don't have a extended partition already */
            for (i = 0; i < pool->volumes.count; i++) {
E
Eric Blake 已提交
478 479
                if (pool->volumes.objs[i]->target.format ==
                    VIR_STORAGE_VOL_DISK_EXTENDED) {
480 481
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("extended partition already exists"));
E
Eric Blake 已提交
482 483
                    return -1;
                }
484
            }
E
Eric Blake 已提交
485 486 487 488
            if ((*partFormat = strdup(partedFormat)) == NULL) {
                virReportOOMError();
                return -1;
            }
489 490 491 492 493 494
        } else {
            /* create primary partition as long as it is possible
               and after that check if an extended partition exists
               to create logical partitions. */
            /* XXX Only support one extended partition */
            switch (virStorageBackendDiskPartTypeToCreate(pool)) {
E
Eric Blake 已提交
495
            case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
E
Eric Blake 已提交
496 497 498 499
                if (virAsprintf(partFormat, "primary %s", partedFormat) < 0) {
                    virReportOOMError();
                    return -1;
                }
E
Eric Blake 已提交
500 501 502 503 504 505
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
                    if (pool->volumes.objs[i]->target.format ==
                        VIR_STORAGE_VOL_DISK_EXTENDED) {
E
Eric Blake 已提交
506 507 508 509 510
                        if (virAsprintf(partFormat, "logical %s",
                                        partedFormat) < 0) {
                            virReportOOMError();
                            return -1;
                        }
E
Eric Blake 已提交
511 512 513 514
                        break;
                    }
                }
                if (i == pool->volumes.count) {
515 516
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("no extended partition found and no primary partition available"));
E
Eric Blake 已提交
517 518 519 520
                    return -1;
                }
                break;
            default:
521 522
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("unknown partition type"));
E
Eric Blake 已提交
523
                return -1;
524 525 526
            }
        }
    } else {
E
Eric Blake 已提交
527 528 529 530
        if ((*partFormat = strdup("primary")) == NULL) {
            virReportOOMError();
            return -1;
        }
531 532 533 534 535 536
    }
    return 0;
}

/**
 * Aligns a new partition to nearest cylinder boundry
E
Eric Blake 已提交
537
 * when having a msdos partition table type
538 539 540 541
 * to avoid any problem with all ready existing
 * partitions
 */
static int
542
virStorageBackendDiskPartBoundries(virStoragePoolObjPtr pool,
543 544 545
                                   unsigned long long *start,
                                   unsigned long long *end,
                                   unsigned long long allocation)
546 547 548
{
    int i;
    int smallestExtent = -1;
549 550 551
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
552
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
553 554 555
    unsigned long long cylinderSize = dev->geometry.heads *
                                      dev->geometry.sectors * SECTOR_SIZE;

556
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
557
          cylinderSize);
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

    /* how many extra bytes we have since we allocate
       aligned to the cylinder boundry */
    extraBytes = cylinderSize - (allocation % cylinderSize);

    for (i = 0 ; i < dev->nfreeExtent ; i++) {
         unsigned long long size =
             dev->freeExtents[i].end -
             dev->freeExtents[i].start;
         unsigned long long neededSize = allocation;

         if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
             /* align to cylinder boundry */
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
             /* if we are creating a logical patition, we need one extra
                block between partitions (or actually move start one block) */
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
                 size -= SECTOR_SIZE;
             }
         }
         if (size > neededSize &&
             (smallestSize == 0 ||
             size < smallestSize)) {
             /* for logical partition, the free extent
                must be within a logical free area */
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL &&
                 dev->freeExtents[i].type != VIR_STORAGE_FREE_LOGICAL) {
                 continue;
                 /* for primary partition, the free extent
                    must not be within a logical free area */
E
Eric Blake 已提交
594 595 596
             } else if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                        dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                 continue;
597 598 599 600 601 602 603 604
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
605 606
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
607 608 609
        return -1;
    }

610
    VIR_DEBUG("aligned alloc %llu", alignedAllocation);
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
    *start = dev->freeExtents[smallestExtent].start;

    if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
        /* for logical partition, skip one block */
        *start += SECTOR_SIZE;
    }

    *end = *start + alignedAllocation;
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
        /* adjust our allocation if start is not at a cylinder boundry */
        *end -= (*start % cylinderSize);
    }

    /* counting in byte, we want the last byte of the current sector */
    *end -= 1;
626
    VIR_DEBUG("final aligned start %llu, end %llu", *start, *end);
627 628 629 630 631
    return 0;
}


static int
632
virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
633 634 635
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
636 637
    int res = -1;
    char *partFormat;
638
    unsigned long long startOffset = 0, endOffset = 0;
639 640 641 642 643
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
644

645
    if (vol->target.encryption != NULL) {
646 647 648
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
649 650 651
        return -1;
    }

E
Eric Blake 已提交
652
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0) {
653 654
        return -1;
    }
655
    virCommandAddArg(cmd, partFormat);
656

657
    if (virStorageBackendDiskPartBoundries(pool, &startOffset,
658
                                           &endOffset,
659
                                           vol->capacity) != 0) {
E
Eric Blake 已提交
660
        goto cleanup;
661 662
    }

663 664
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
665

666
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
667
        goto cleanup;
668

669
    /* wait for device node to show up */
670
    virFileWaitForDevices();
671

672
    /* Blow away free extent info, as we're about to re-populate it */
673
    VIR_FREE(pool->def->source.devices[0].freeExtents);
674 675
    pool->def->source.devices[0].nfreeExtent = 0;

676 677 678 679
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
680
    if (virStorageBackendDiskReadPartitions(pool, vol) < 0)
E
Eric Blake 已提交
681
        goto cleanup;
682

E
Eric Blake 已提交
683 684 685 686
    res = 0;

cleanup:
    VIR_FREE(partFormat);
687
    virCommandFree(cmd);
E
Eric Blake 已提交
688
    return res;
689 690
}

691 692
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
693
                                  virStoragePoolObjPtr pool,
694 695 696 697 698 699
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

700
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
701 702 703
    if (!build_func)
        return -1;

704
    return build_func(conn, pool, vol, inputvol, flags);
705
}
706 707

static int
708
virStorageBackendDiskDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
C
Cole Robinson 已提交
709 710
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol,
E
Eric Blake 已提交
711
                               unsigned int flags)
712
{
C
Cole Robinson 已提交
713
    char *part_num = NULL;
D
Daniel P. Berrange 已提交
714
    char *devpath = NULL;
715
    char *dev_name, *srcname;
716 717
    virCommandPtr cmd = NULL;
    bool isDevMapperDevice;
D
Daniel P. Berrange 已提交
718
    int rc = -1;
C
Cole Robinson 已提交
719

E
Eric Blake 已提交
720 721
    virCheckFlags(0, -1);

722 723
    if (virFileResolveLink(vol->target.path, &devpath) < 0) {
        virReportSystemError(errno,
724 725
                             _("Couldn't read volume target path '%s'"),
                             vol->target.path);
D
Daniel P. Berrange 已提交
726
        goto cleanup;
C
Cole Robinson 已提交
727 728
    }

729
    dev_name = basename(devpath);
C
Cole Robinson 已提交
730
    srcname = basename(pool->def->source.devices[0].path);
731
    VIR_DEBUG("dev_name=%s, srcname=%s", dev_name, srcname);
C
Cole Robinson 已提交
732

733 734
    isDevMapperDevice = virIsDevMapperDevice(devpath);

735
    if (!isDevMapperDevice && !STRPREFIX(dev_name, srcname)) {
736 737 738
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume path '%s' did not start with parent "
                         "pool source device name."), dev_name);
D
Daniel P. Berrange 已提交
739
        goto cleanup;
C
Cole Robinson 已提交
740 741
    }

742
    if (!isDevMapperDevice) {
743
        part_num = dev_name + strlen(srcname);
C
Cole Robinson 已提交
744

745
        if (*part_num == 0) {
746 747 748
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse partition number from target "
                             "'%s'"), dev_name);
749 750
            goto cleanup;
        }
C
Cole Robinson 已提交
751

752 753 754 755 756 757 758 759 760 761 762
        /* eg parted /dev/sda rm 2 */
        cmd = virCommandNewArgList(PARTED,
                                   pool->def->source.devices[0].path,
                                   "rm",
                                   "--script",
                                   part_num,
                                   NULL);
        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    } else {
        cmd = virCommandNewArgList(DMSETUP, "remove", "--force", devpath, NULL);
C
Cole Robinson 已提交
763

764 765 766
        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }
C
Cole Robinson 已提交
767

D
Daniel P. Berrange 已提交
768 769 770
    rc = 0;
cleanup:
    VIR_FREE(devpath);
771
    virCommandFree(cmd);
D
Daniel P. Berrange 已提交
772
    return rc;
773 774 775 776 777 778 779 780 781 782 783
}


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
784
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
785
};