storage_backend_disk.c 34.0 KB
Newer Older
1 2 3
/*
 * storage_backend_disk.c: storage backend for disk handling
 *
4
 * Copyright (C) 2007-2016 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 "dirname.h"
30
#include "virerror.h"
31
#include "virlog.h"
32
#include "storage_backend_disk.h"
33
#include "viralloc.h"
34
#include "vircommand.h"
35
#include "virfile.h"
36
#include "configmake.h"
37
#include "virstring.h"
38

39 40
#define VIR_FROM_THIS VIR_FROM_STORAGE

41 42
VIR_LOG_INIT("storage.storage_backend_disk");

43 44
#define SECTOR_SIZE 512

45
static int
46
virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
47 48 49
                                 char **const groups,
                                 virStorageVolDefPtr vol)
{
50 51 52 53 54 55 56 57 58
    char *tmp, *devpath, *partname;

    /* Prepended path will be same for all partitions, so we can
     * strip the path to form a reasonable pool-unique name
     */
    if ((tmp = strrchr(groups[0], '/')))
        partname = tmp + 1;
    else
        partname = groups[0];
59 60

    if (vol == NULL) {
61 62 63
        /* This is typically a reload/restart/refresh path where
         * we're discovering the existing partitions for the pool
         */
64
        if (VIR_ALLOC(vol) < 0)
65
            return -1;
66
        if (VIR_STRDUP(vol->name, partname) < 0 ||
67 68
            VIR_APPEND_ELEMENT_COPY(pool->volumes.objs,
                                    pool->volumes.count, vol) < 0) {
69
            virStorageVolDefFree(vol);
70
            return -1;
71
        }
72 73 74
    }

    if (vol->target.path == NULL) {
75
        if (VIR_STRDUP(devpath, groups[0]) < 0)
76 77 78 79 80 81 82 83
            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...
         */
84
        vol->target.path = virStorageBackendStablePath(pool, devpath, true);
85
        VIR_FREE(devpath);
86 87
        if (vol->target.path == NULL)
            return -1;
88 89
    }

90 91 92 93 94 95 96 97 98 99 100
    /* Enforce provided vol->name is the same as what parted created.
     * We do this after filling target.path so that we have a chance at
     * deleting the partition with this failure from CreateVol path
     */
    if (STRNEQ(vol->name, partname)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid partition name '%s', expected '%s'"),
                       vol->name, partname);
        return -1;
    }

101 102
    if (vol->key == NULL) {
        /* XXX base off a unique key of the underlying disk */
103
        if (VIR_STRDUP(vol->key, vol->target.path) < 0)
104 105 106 107
            return -1;
    }

    if (vol->source.extents == NULL) {
108
        if (VIR_ALLOC(vol->source.extents) < 0)
109 110 111 112 113
            return -1;
        vol->source.nextent = 1;

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

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

126 127
        if (VIR_STRDUP(vol->source.extents[0].path,
                       pool->def->source.devices[0].path) < 0)
128 129 130
            return -1;
    }

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

141 142
    vol->type = VIR_STORAGE_VOL_BLOCK;

143 144 145 146 147 148 149 150 151 152 153 154
    /* Refresh allocation/capacity/perms
     *
     * For an extended partition, virStorageBackendUpdateVolInfo will
     * return incorrect values for allocation and capacity, so use the
     * extent information captured above instead.
     *
     * Also once a logical partition exists or another primary partition
     * after an extended partition is created an open on the extended
     * partition will fail, so pass the NOERROR flag and only error if a
     * -1 was returned indicating some other error than an open error.
     */
    if (vol->source.partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
155
        if (virStorageBackendUpdateVolInfo(vol, false,
156
                                           VIR_STORAGE_VOL_OPEN_DEFAULT |
157 158
                                           VIR_STORAGE_VOL_OPEN_NOERROR,
                                           0) == -1)
159
            return -1;
160 161
        vol->target.allocation = 0;
        vol->target.capacity =
162 163
            (vol->source.extents[0].end - vol->source.extents[0].start);
    } else {
164
        if (virStorageBackendUpdateVolInfo(vol, false,
165
                                           VIR_STORAGE_VOL_OPEN_DEFAULT, 0) < 0)
166 167
            return -1;
    }
168

169 170 171 172 173 174 175 176 177 178 179 180 181 182
    /* Find the extended partition and increase the allocation value */
    if (vol->source.partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
        size_t i;

        for (i = 0; i < pool->volumes.count; i++) {
            if (pool->volumes.objs[i]->source.partType ==
                VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
                pool->volumes.objs[i]->target.allocation +=
                    vol->target.allocation;
                break;
            }
        }
    }

183
    if (STRNEQ(groups[2], "metadata"))
184
        pool->def->allocation += vol->target.allocation;
185 186 187 188 189 190 191
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}

static int
192
virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
193 194 195 196
                                    char **const groups)
{
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];

197 198
    if (VIR_REALLOC_N(dev->freeExtents,
                      dev->nfreeExtent + 1) < 0)
199 200 201
        return -1;

    memset(dev->freeExtents +
202 203
           dev->nfreeExtent, 0,
           sizeof(dev->freeExtents[0]));
204

205
    /* set type of free area */
E
Eric Blake 已提交
206
    if (STREQ(groups[1], "logical")) {
207 208 209 210 211 212
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_LOGICAL;
    } else {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_NORMAL;
    }


213 214 215 216 217 218 219 220
    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 */

221
    /* first block reported as free, even if it is not */
222
    if (dev->freeExtents[dev->nfreeExtent].start == 0)
223 224
        dev->freeExtents[dev->nfreeExtent].start = SECTOR_SIZE;

225 226 227 228 229 230 231 232 233 234 235 236
    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;
}


237 238 239 240 241
struct virStorageBackendDiskPoolVolData {
    virStoragePoolObjPtr pool;
    virStorageVolDefPtr vol;
};

242
static int
243
virStorageBackendDiskMakeVol(size_t ntok ATTRIBUTE_UNUSED,
244
                             char **const groups,
245
                             void *opaque)
246
{
247 248
    struct virStorageBackendDiskPoolVolData *data = opaque;
    virStoragePoolObjPtr pool = data->pool;
249 250 251 252 253 254 255 256 257 258 259 260
    /*
     * 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 已提交
261
    /* Remaining data / metadata parts get turn into volumes... */
262 263
    if (STREQ(groups[2], "metadata") ||
        STREQ(groups[2], "data")) {
264
        virStorageVolDefPtr vol = data->vol;
265 266 267 268 269 270 271 272 273 274 275 276

        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;
            }
        }
277

278
        return virStorageBackendDiskMakeDataVol(pool, groups, vol);
279 280
    } else if (STREQ(groups[2], "free")) {
        /* ....or free space extents */
281
        return virStorageBackendDiskMakeFreeExtent(pool, groups);
282
    } else {
R
Richard W.M. Jones 已提交
283
        /* This code path should never happen unless someone changed
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
         * 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
300
virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
301 302 303 304 305 306 307 308 309
                                    virStorageVolDefPtr vol)
{
    /*
     *  # libvirt_parthelper DEVICE
     * /dev/sda1      normal       data        32256    106928128    106896384
     * /dev/sda2      normal       data    106928640 100027629568  99920701440
     * -              normal   metadata 100027630080 100030242304      2612736
     *
     */
310 311 312

    char *parthelper_path;
    virCommandPtr cmd;
313 314 315 316
    struct virStorageBackendDiskPoolVolData cbdata = {
        .pool = pool,
        .vol = vol,
    };
317
    int ret;
318

319
    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
320
                                                abs_topbuilddir "/src",
321 322 323 324 325 326 327
                                                LIBEXECDIR)))
        return -1;

    cmd = virCommandNewArgList(parthelper_path,
                               pool->def->source.devices[0].path,
                               NULL);

328
    /* Check for the presence of the part_separator='yes'. Pass this
329
     * along to the libvirt_parthelper as option '-p'. This will cause
330 331 332
     * libvirt_parthelper to append the "p" partition separator to
     * the generated device name for a source device which ends with
     * a non-numeric value (e.g. mpatha would generate mpathap#).
333 334
     */
    if (pool->def->source.devices[0].part_separator ==
335
        VIR_TRISTATE_BOOL_YES)
336 337
        virCommandAddArg(cmd, "-p");

338 339 340 341 342 343
    /* If a volume is passed, virStorageBackendDiskMakeVol only updates the
     * pool allocation for that single volume.
     */
    if (!vol)
        pool->def->allocation = 0;
    pool->def->capacity = pool->def->available = 0;
344

345 346 347 348
    ret = virCommandRunNul(cmd,
                           6,
                           virStorageBackendDiskMakeVol,
                           &cbdata);
349
    virCommandFree(cmd);
350
    VIR_FREE(parthelper_path);
351
    return ret;
352 353
}

354
static int
355
virStorageBackendDiskMakePoolGeometry(size_t ntok ATTRIBUTE_UNUSED,
356
                                      char **const groups,
357
                                      void *data)
358
{
359
    virStoragePoolObjPtr pool = data;
P
Peter Krempa 已提交
360 361 362 363 364 365 366 367
    virStoragePoolSourceDevicePtr device = &(pool->def->source.devices[0]);
    if (virStrToLong_i(groups[0], NULL, 0, &device->geometry.cylinders) < 0 ||
        virStrToLong_i(groups[1], NULL, 0, &device->geometry.heads) < 0 ||
        virStrToLong_i(groups[2], NULL, 0, &device->geometry.sectors) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to create disk pool geometry"));
        return -1;
    }
368

P
Peter Krempa 已提交
369
    return 0;
370 371 372
}

static int
373
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
374
{
375 376 377 378 379
    char *parthelper_path;
    virCommandPtr cmd;
    int ret;

    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
380
                                                abs_topbuilddir "/src",
381 382 383 384
                                                LIBEXECDIR)))
        return -1;

    cmd = virCommandNewArgList(parthelper_path,
385 386 387 388
                                             pool->def->source.devices[0].path,
                                             "-g",
                                             NULL);

389 390 391 392
    ret = virCommandRunNul(cmd,
                           3,
                           virStorageBackendDiskMakePoolGeometry,
                           pool);
393
    virCommandFree(cmd);
394
    VIR_FREE(parthelper_path);
395
    return ret;
396
}
397 398

static int
399
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
400 401
                                 virStoragePoolObjPtr pool)
{
402
    VIR_FREE(pool->def->source.devices[0].freeExtents);
403 404
    pool->def->source.devices[0].nfreeExtent = 0;

405
    virFileWaitForDevices();
406

407
    if (!virFileExists(pool->def->source.devices[0].path)) {
408 409 410
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device path '%s' doesn't exist"),
                       pool->def->source.devices[0].path);
411 412 413
        return -1;
    }

414
    if (virStorageBackendDiskReadGeometry(pool) != 0)
415 416
        return -1;

417
    return virStorageBackendDiskReadPartitions(pool, NULL);
418 419 420
}


421 422 423 424
/**
 * Check for a valid disk label (partition table) on device
 *
 * return: 0 - valid disk label found
425 426 427
 *         1 - no or unrecognized disk label
 *         2 - did not find the Partition Table type
 *         3 - Partition Table type unknown
428 429 430 431 432 433 434 435 436 437
 *        <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;
438
    char *error = NULL;
439
    char *start, *end;
440 441 442 443 444
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);
445
    virCommandSetErrorBuffer(cmd, &error);
446 447 448 449

    /* if parted succeeds we have a valid partition table */
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
450 451
        if ((output && strstr(output, "unrecognised disk label")) ||
            (error && strstr(error, "unrecognised disk label"))) {
452
            ret = 1;
453
        }
454
        goto cleanup;
455 456
    }

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    /* Search for "Partition Table:" in the output. If not present,
     * then we cannot validate the partition table type.
     */
    if (!(start = strstr(output, "Partition Table: ")) ||
        !(end = strstr(start, "\n"))) {
        VIR_DEBUG("Unable to find tag in output: %s", output);
        ret = 2;
        goto cleanup;
    }
    start += strlen("Partition Table: ");
    *end = '\0';

    /* on disk it's "msdos", but we document/use "dos" so deal with it here */
    if (STREQ(start, "msdos"))
        start += 2;

    /* Make sure we know about this type */
    if (virStoragePoolFormatDiskTypeFromString(start) < 0) {
        ret = 3;
        goto cleanup;
    }

    ret = 0;

 cleanup:
482 483
    virCommandFree(cmd);
    VIR_FREE(output);
484
    VIR_FREE(error);
485 486 487
    return ret;
}

488 489
/**
 * Determine whether the label on the disk is valid or in a known format
490 491
 * for the purpose of rewriting the label during build or being able to
 * start a pool on a device.
492
 *
493 494 495 496 497 498
 * When 'writelabel' is true, if we find a valid disk label on the device,
 * then we shouldn't be attempting to write as the volume may contain
 * data. Force the usage of the overwrite flag to the build command in
 * order to be certain. When the disk label is unrecognized, then it
 * should be safe to write.
 *
499 500 501 502
 * When 'writelabel' is false, only if we find a valid disk label on the
 * device should we allow the start since for this path we won't be
 * rewriting the label.
 *
503 504 505 506
 * Return: True if it's OK
 *         False if something's wrong
 */
static bool
507 508
virStorageBackendDiskValidLabel(const char *device,
                                bool writelabel)
509 510 511 512 513
{
    bool valid = false;
    int check;

    check = virStorageBackendDiskFindLabel(device);
514
    if (check == 1) {
515 516 517 518 519
        if (writelabel)
            valid = true;
        else
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Unrecognized disk label found, requires build"));
520 521 522 523 524 525 526
    } else if (check == 2) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Unable to determine Partition Type, "
                         "requires build --overwrite"));
    } else if (check == 3) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Unknown Partition Type, requires build --overwrite"));
527 528
    } else if (check < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
529 530
                       _("Error checking for disk label, failed to get "
                         "disk partition information"));
531
    } else {
532 533 534 535 536 537
        if (writelabel)
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Valid disk label already present, "
                             "requires --overwrite"));
        else
            valid = true;
538 539 540 541 542
    }
    return valid;
}


543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
static int
virStorageBackendDiskStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                               virStoragePoolObjPtr pool)
{
    virFileWaitForDevices();

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

    if (!virStorageBackendDiskValidLabel(pool->def->source.devices[0].path,
                                         false))
        return -1;

    return 0;
}


564 565 566 567
/**
 * Write a new partition table header
 */
static int
568
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
569
                               virStoragePoolObjPtr pool,
E
Eric Blake 已提交
570
                               unsigned int flags)
571
{
572 573
    bool ok_to_mklabel = false;
    int ret = -1;
574
    virCommandPtr cmd = NULL;
575

576 577
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
578

579 580 581
    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                             VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                             error);
582

583
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE)
584
        ok_to_mklabel = true;
585 586
    else
        ok_to_mklabel = virStorageBackendDiskValidLabel(
587 588
                                            pool->def->source.devices[0].path,
                                            true);
589

590
    if (ok_to_mklabel) {
591 592 593
        /* eg parted /dev/sda mklabel --script msdos */
        int format = pool->def->source.format;
        const char *fmt;
594 595 596
        if (format == VIR_STORAGE_POOL_DISK_UNKNOWN)
            format = pool->def->source.format = VIR_STORAGE_POOL_DISK_DOS;
        if (format == VIR_STORAGE_POOL_DISK_DOS)
597 598 599 600
            fmt = "msdos";
        else
            fmt = virStoragePoolFormatDiskTypeToString(format);

601 602 603 604
        cmd = virCommandNewArgList(PARTED,
                                   pool->def->source.devices[0].path,
                                   "mklabel",
                                   "--script",
605
                                   fmt,
606
                                   NULL);
607
        ret = virCommandRun(cmd, NULL);
608
    }
609

610
 error:
611
    virCommandFree(cmd);
612
    return ret;
613 614
}

615 616 617 618
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
619
static int
620 621 622
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
623
        /* count primary and extended partitions,
624
           can't be more than 3 to create a new primary partition */
625
        size_t i;
626 627
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
628 629 630 631
            int partType = pool->volumes.objs[i]->source.partType;
            if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED)
                count++;
632
        }
633
        if (count >= 4)
634 635 636 637 638 639 640 641
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    }

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

static int
642
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
643
                                virStorageVolDefPtr vol,
E
Eric Blake 已提交
644
                                char** partFormat)
645
{
646
    size_t i;
647
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
E
Eric Blake 已提交
648
        const char *partedFormat;
649
        partedFormat = virStoragePartedFsTypeToString(vol->target.format);
E
Eric Blake 已提交
650
        if (partedFormat == NULL) {
651 652
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Invalid partition type"));
E
Eric Blake 已提交
653
            return -1;
654 655 656 657
        }
        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++) {
658 659
                if (pool->volumes.objs[i]->source.partType ==
                    VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
660 661
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("extended partition already exists"));
E
Eric Blake 已提交
662 663
                    return -1;
                }
664
            }
665
            if (VIR_STRDUP(*partFormat, partedFormat) < 0)
E
Eric Blake 已提交
666
                return -1;
667 668 669 670 671 672
        } 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 已提交
673
            case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
674
                if (virAsprintf(partFormat, "primary %s", partedFormat) < 0)
E
Eric Blake 已提交
675
                    return -1;
E
Eric Blake 已提交
676 677 678 679
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
680 681
                    if (pool->volumes.objs[i]->source.partType ==
                        VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
E
Eric Blake 已提交
682
                        if (virAsprintf(partFormat, "logical %s",
683
                                        partedFormat) < 0)
E
Eric Blake 已提交
684
                            return -1;
E
Eric Blake 已提交
685 686 687 688
                        break;
                    }
                }
                if (i == pool->volumes.count) {
689 690
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("no extended partition found and no primary partition available"));
E
Eric Blake 已提交
691 692 693 694
                    return -1;
                }
                break;
            default:
695 696
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("unknown partition type"));
E
Eric Blake 已提交
697
                return -1;
698 699 700
            }
        }
    } else {
701
        if (VIR_STRDUP(*partFormat, "primary") < 0)
E
Eric Blake 已提交
702
            return -1;
703 704 705 706 707
    }
    return 0;
}

/**
J
Ján Tomko 已提交
708
 * Aligns a new partition to nearest cylinder boundary
E
Eric Blake 已提交
709
 * when having a msdos partition table type
J
Ján Tomko 已提交
710
 * to avoid any problem with already existing
711 712 713
 * partitions
 */
static int
714 715 716 717
virStorageBackendDiskPartBoundaries(virStoragePoolObjPtr pool,
                                    unsigned long long *start,
                                    unsigned long long *end,
                                    unsigned long long allocation)
718
{
719
    size_t i;
720
    int smallestExtent = -1;
721 722 723
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
724
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
725
    unsigned long long cylinderSize = (unsigned long long)dev->geometry.heads *
726 727
                                      dev->geometry.sectors * SECTOR_SIZE;

728
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
729
          cylinderSize);
730 731 732
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

    /* how many extra bytes we have since we allocate
J
Ján Tomko 已提交
733
       aligned to the cylinder boundary */
734 735
    extraBytes = cylinderSize - (allocation % cylinderSize);

736
    for (i = 0; i < dev->nfreeExtent; i++) {
737 738 739 740 741 742
         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) {
J
Ján Tomko 已提交
743
             /* align to cylinder boundary */
744 745 746 747 748 749
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
750
             /* if we are creating a logical partition, we need one extra
751
                block between partitions (or actually move start one block) */
752
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL)
753 754 755 756 757 758 759 760 761 762 763 764
                 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 已提交
765 766 767
             } else if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                        dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                 continue;
768 769 770 771 772 773 774 775
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
776 777
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
778 779 780
        return -1;
    }

781
    VIR_DEBUG("aligned alloc %llu", alignedAllocation);
782 783 784 785 786 787 788 789 790
    *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) {
J
Ján Tomko 已提交
791
        /* adjust our allocation if start is not at a cylinder boundary */
792 793 794
        *end -= (*start % cylinderSize);
    }

795
    /* counting in bytes, we want the last byte of the current sector */
796
    *end -= 1;
797
    VIR_DEBUG("final aligned start %llu, end %llu", *start, *end);
798 799 800 801
    return 0;
}


802
static int
803
virStorageBackendDiskDeleteVol(virConnectPtr conn,
804 805 806 807 808 809 810 811 812 813 814 815 816
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol,
                               unsigned int flags)
{
    char *part_num = NULL;
    char *devpath = NULL;
    char *dev_name, *srcname;
    virCommandPtr cmd = NULL;
    bool isDevMapperDevice;
    int rc = -1;

    virCheckFlags(0, -1);

817 818 819 820 821 822 823
    if (!vol->target.path) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("volume target path empty for source path '%s'"),
                      pool->def->source.devices[0].path);
        return -1;
    }

824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
    if (virFileResolveLink(vol->target.path, &devpath) < 0) {
        virReportSystemError(errno,
                             _("Couldn't read volume target path '%s'"),
                             vol->target.path);
        goto cleanup;
    }

    dev_name = last_component(devpath);
    srcname = last_component(pool->def->source.devices[0].path);
    VIR_DEBUG("dev_name=%s, srcname=%s", dev_name, srcname);

    isDevMapperDevice = virIsDevMapperDevice(devpath);

    if (!isDevMapperDevice && !STRPREFIX(dev_name, srcname)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume path '%s' did not start with parent "
                         "pool source device name."), dev_name);
        goto cleanup;
    }

    if (!isDevMapperDevice) {
        part_num = dev_name + strlen(srcname);

        if (*part_num == 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse partition number from target "
                             "'%s'"), dev_name);
            goto cleanup;
        }

        /* 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);

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }

870 871 872 873
    /* Refreshing the pool is the easiest option as LOGICAL and EXTENDED
     * partition allocation/capacity management is handled within
     * virStorageBackendDiskMakeDataVol and trying to redo that logic
     * here is pointless
874
     */
875 876 877
    virStoragePoolObjClearVols(pool);
    if (virStorageBackendDiskRefreshPool(conn, pool) < 0)
        goto cleanup;
878

879 880 881 882 883 884 885 886
    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


887
static int
888
virStorageBackendDiskCreateVol(virConnectPtr conn,
889
                               virStoragePoolObjPtr pool,
890 891
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
892
    int res = -1;
893
    char *partFormat = NULL;
894
    unsigned long long startOffset = 0, endOffset = 0;
895 896 897 898 899
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
900

901 902 903 904
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
905
        goto cleanup;
906
    }
907

908
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
909
        goto cleanup;
910
    virCommandAddArg(cmd, partFormat);
911

912 913
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
914
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
915
        goto cleanup;
916 917
    }

918 919
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
920

921
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
922
        goto cleanup;
923

924
    /* wait for device node to show up */
925
    virFileWaitForDevices();
926

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

931 932 933 934
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
935 936 937 938 939 940 941 942
    if (virStorageBackendDiskReadPartitions(pool, vol) < 0) {
        /* Best effort to remove the partition. Ignore any errors
         * since we could be calling this with vol->target.path == NULL
         */
        virErrorPtr save_err = virSaveLastError();
        ignore_value(virStorageBackendDiskDeleteVol(conn, pool, vol, 0));
        virSetError(save_err);
        virFreeError(save_err);
E
Eric Blake 已提交
943
        goto cleanup;
944
    }
945

E
Eric Blake 已提交
946 947
    res = 0;

948
 cleanup:
E
Eric Blake 已提交
949
    VIR_FREE(partFormat);
950
    virCommandFree(cmd);
E
Eric Blake 已提交
951
    return res;
952 953
}

954 955
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
956
                                  virStoragePoolObjPtr pool,
957 958 959 960 961 962
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

963
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
964 965 966
    if (!build_func)
        return -1;

967
    return build_func(conn, pool, vol, inputvol, flags);
968
}
969 970


971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
static int
virStorageBackendDiskVolWipe(virConnectPtr conn,
                             virStoragePoolObjPtr pool,
                             virStorageVolDefPtr vol,
                             unsigned int algorithm,
                             unsigned int flags)
{
    if (vol->source.partType != VIR_STORAGE_VOL_DISK_TYPE_EXTENDED)
        return virStorageBackendVolWipeLocal(conn, pool, vol, algorithm, flags);

    /* Wiping an extended partition is not support */
    virReportError(VIR_ERR_NO_SUPPORT,
                   _("cannot wipe extended partition '%s'"),
                   vol->target.path);
    return -1;
}


989 990 991
virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

992
    .startPool = virStorageBackendDiskStartPool,
993 994 995 996 997
    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
998
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
999 1000
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
1001
    .wipeVol = virStorageBackendDiskVolWipe,
1002
};