storage_backend_disk.c 33.2 KB
Newer Older
1 2 3
/*
 * storage_backend_disk.c: storage backend for disk handling
 *
4
 * Copyright (C) 2007-2014 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 157 158 159 160 161
                                           VIR_STORAGE_VOL_OPEN_DEFAULT |
                                           VIR_STORAGE_VOL_OPEN_NOERROR) == -1)
            return -1;
        vol->target.allocation = vol->target.capacity =
            (vol->source.extents[0].end - vol->source.extents[0].start);
    } else {
162
        if (virStorageBackendUpdateVolInfo(vol, false,
163 164 165
                                           VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
            return -1;
    }
166 167

    if (STRNEQ(groups[2], "metadata"))
168
        pool->def->allocation += vol->target.allocation;
169 170 171 172 173 174 175
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}

static int
176
virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
177 178 179 180
                                    char **const groups)
{
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];

181 182
    if (VIR_REALLOC_N(dev->freeExtents,
                      dev->nfreeExtent + 1) < 0)
183 184 185
        return -1;

    memset(dev->freeExtents +
186 187
           dev->nfreeExtent, 0,
           sizeof(dev->freeExtents[0]));
188

189
    /* set type of free area */
E
Eric Blake 已提交
190
    if (STREQ(groups[1], "logical")) {
191 192 193 194 195 196
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_LOGICAL;
    } else {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_NORMAL;
    }


197 198 199 200 201 202 203 204
    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 */

205
    /* first block reported as free, even if it is not */
206
    if (dev->freeExtents[dev->nfreeExtent].start == 0)
207 208
        dev->freeExtents[dev->nfreeExtent].start = SECTOR_SIZE;

209 210 211 212 213 214 215 216 217 218 219 220
    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;
}


221 222 223 224 225
struct virStorageBackendDiskPoolVolData {
    virStoragePoolObjPtr pool;
    virStorageVolDefPtr vol;
};

226
static int
227
virStorageBackendDiskMakeVol(size_t ntok ATTRIBUTE_UNUSED,
228
                             char **const groups,
229
                             void *opaque)
230
{
231 232
    struct virStorageBackendDiskPoolVolData *data = opaque;
    virStoragePoolObjPtr pool = data->pool;
233 234 235 236 237 238 239 240 241 242 243 244
    /*
     * 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 已提交
245
    /* Remaining data / metadata parts get turn into volumes... */
246 247
    if (STREQ(groups[2], "metadata") ||
        STREQ(groups[2], "data")) {
248
        virStorageVolDefPtr vol = data->vol;
249 250 251 252 253 254 255 256 257 258 259 260

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

262
        return virStorageBackendDiskMakeDataVol(pool, groups, vol);
263 264
    } else if (STREQ(groups[2], "free")) {
        /* ....or free space extents */
265
        return virStorageBackendDiskMakeFreeExtent(pool, groups);
266
    } else {
R
Richard W.M. Jones 已提交
267
        /* This code path should never happen unless someone changed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
         * 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
284
virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
285 286 287 288 289 290 291 292 293
                                    virStorageVolDefPtr vol)
{
    /*
     *  # libvirt_parthelper DEVICE
     * /dev/sda1      normal       data        32256    106928128    106896384
     * /dev/sda2      normal       data    106928640 100027629568  99920701440
     * -              normal   metadata 100027630080 100030242304      2612736
     *
     */
294 295 296

    char *parthelper_path;
    virCommandPtr cmd;
297 298 299 300
    struct virStorageBackendDiskPoolVolData cbdata = {
        .pool = pool,
        .vol = vol,
    };
301
    int ret;
302

303
    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
304
                                                abs_topbuilddir "/src",
305 306 307 308 309 310 311
                                                LIBEXECDIR)))
        return -1;

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

312 313 314 315 316 317
    /* 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;
318

319 320 321 322
    ret = virCommandRunNul(cmd,
                           6,
                           virStorageBackendDiskMakeVol,
                           &cbdata);
323
    virCommandFree(cmd);
324
    VIR_FREE(parthelper_path);
325
    return ret;
326 327
}

328
static int
329
virStorageBackendDiskMakePoolGeometry(size_t ntok ATTRIBUTE_UNUSED,
330
                                      char **const groups,
331
                                      void *data)
332
{
333
    virStoragePoolObjPtr pool = data;
P
Peter Krempa 已提交
334 335 336 337 338 339 340 341
    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;
    }
342

P
Peter Krempa 已提交
343
    return 0;
344 345 346
}

static int
347
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
348
{
349 350 351 352 353
    char *parthelper_path;
    virCommandPtr cmd;
    int ret;

    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
354
                                                abs_topbuilddir "/src",
355 356 357 358
                                                LIBEXECDIR)))
        return -1;

    cmd = virCommandNewArgList(parthelper_path,
359 360 361 362
                                             pool->def->source.devices[0].path,
                                             "-g",
                                             NULL);

363 364 365 366
    ret = virCommandRunNul(cmd,
                           3,
                           virStorageBackendDiskMakePoolGeometry,
                           pool);
367
    virCommandFree(cmd);
368
    VIR_FREE(parthelper_path);
369
    return ret;
370
}
371 372

static int
373
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
374 375
                                 virStoragePoolObjPtr pool)
{
376
    VIR_FREE(pool->def->source.devices[0].freeExtents);
377 378
    pool->def->source.devices[0].nfreeExtent = 0;

379
    virFileWaitForDevices();
380

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

388
    if (virStorageBackendDiskReadGeometry(pool) != 0)
389 390
        return -1;

391
    return virStorageBackendDiskReadPartitions(pool, NULL);
392 393 394
}


395 396 397 398
/**
 * Check for a valid disk label (partition table) on device
 *
 * return: 0 - valid disk label found
399 400 401
 *         1 - no or unrecognized disk label
 *         2 - did not find the Partition Table type
 *         3 - Partition Table type unknown
402 403 404 405 406 407 408 409 410 411
 *        <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;
412
    char *error = NULL;
413
    char *start, *end;
414 415 416 417 418
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);
419
    virCommandSetErrorBuffer(cmd, &error);
420 421 422 423

    /* if parted succeeds we have a valid partition table */
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
424 425
        if ((output && strstr(output, "unrecognised disk label")) ||
            (error && strstr(error, "unrecognised disk label"))) {
426
            ret = 1;
427
        }
428
        goto cleanup;
429 430
    }

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
    /* 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:
456 457
    virCommandFree(cmd);
    VIR_FREE(output);
458
    VIR_FREE(error);
459 460 461
    return ret;
}

462 463
/**
 * Determine whether the label on the disk is valid or in a known format
464 465
 * for the purpose of rewriting the label during build or being able to
 * start a pool on a device.
466
 *
467 468 469 470 471 472
 * 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.
 *
473 474 475 476
 * 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.
 *
477 478 479 480
 * Return: True if it's OK
 *         False if something's wrong
 */
static bool
481 482
virStorageBackendDiskValidLabel(const char *device,
                                bool writelabel)
483 484 485 486 487
{
    bool valid = false;
    int check;

    check = virStorageBackendDiskFindLabel(device);
488
    if (check == 1) {
489 490 491 492 493
        if (writelabel)
            valid = true;
        else
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Unrecognized disk label found, requires build"));
494 495 496 497 498 499 500
    } 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"));
501 502
    } else if (check < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
503 504
                       _("Error checking for disk label, failed to get "
                         "disk partition information"));
505
    } else {
506 507 508 509 510 511
        if (writelabel)
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Valid disk label already present, "
                             "requires --overwrite"));
        else
            valid = true;
512 513 514 515 516
    }
    return valid;
}


517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
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;
}


538 539 540 541
/**
 * Write a new partition table header
 */
static int
542
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
543
                               virStoragePoolObjPtr pool,
E
Eric Blake 已提交
544
                               unsigned int flags)
545
{
546 547
    bool ok_to_mklabel = false;
    int ret = -1;
548
    virCommandPtr cmd = NULL;
549

550 551
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
552

553 554 555
    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                             VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                             error);
556

557
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE)
558
        ok_to_mklabel = true;
559 560
    else
        ok_to_mklabel = virStorageBackendDiskValidLabel(
561 562
                                            pool->def->source.devices[0].path,
                                            true);
563

564
    if (ok_to_mklabel) {
565 566 567
        /* eg parted /dev/sda mklabel --script msdos */
        int format = pool->def->source.format;
        const char *fmt;
568 569 570
        if (format == VIR_STORAGE_POOL_DISK_UNKNOWN)
            format = pool->def->source.format = VIR_STORAGE_POOL_DISK_DOS;
        if (format == VIR_STORAGE_POOL_DISK_DOS)
571 572 573 574
            fmt = "msdos";
        else
            fmt = virStoragePoolFormatDiskTypeToString(format);

575 576 577 578
        cmd = virCommandNewArgList(PARTED,
                                   pool->def->source.devices[0].path,
                                   "mklabel",
                                   "--script",
579
                                   fmt,
580
                                   NULL);
581
        ret = virCommandRun(cmd, NULL);
582
    }
583

584
 error:
585
    virCommandFree(cmd);
586
    return ret;
587 588
}

589 590 591 592
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
593
static int
594 595 596
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
597
        /* count primary and extended partitions,
598
           can't be more than 3 to create a new primary partition */
599
        size_t i;
600 601
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
602 603 604 605
            int partType = pool->volumes.objs[i]->source.partType;
            if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED)
                count++;
606
        }
607
        if (count >= 4)
608 609 610 611 612 613 614 615
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    }

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

static int
616
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
617
                                virStorageVolDefPtr vol,
E
Eric Blake 已提交
618
                                char** partFormat)
619
{
620
    size_t i;
621
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
E
Eric Blake 已提交
622
        const char *partedFormat;
623
        partedFormat = virStoragePartedFsTypeToString(vol->target.format);
E
Eric Blake 已提交
624
        if (partedFormat == NULL) {
625 626
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Invalid partition type"));
E
Eric Blake 已提交
627
            return -1;
628 629 630 631
        }
        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++) {
632 633
                if (pool->volumes.objs[i]->source.partType ==
                    VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
634 635
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("extended partition already exists"));
E
Eric Blake 已提交
636 637
                    return -1;
                }
638
            }
639
            if (VIR_STRDUP(*partFormat, partedFormat) < 0)
E
Eric Blake 已提交
640
                return -1;
641 642 643 644 645 646
        } 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 已提交
647
            case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
648
                if (virAsprintf(partFormat, "primary %s", partedFormat) < 0)
E
Eric Blake 已提交
649
                    return -1;
E
Eric Blake 已提交
650 651 652 653
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
654 655
                    if (pool->volumes.objs[i]->source.partType ==
                        VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
E
Eric Blake 已提交
656
                        if (virAsprintf(partFormat, "logical %s",
657
                                        partedFormat) < 0)
E
Eric Blake 已提交
658
                            return -1;
E
Eric Blake 已提交
659 660 661 662
                        break;
                    }
                }
                if (i == pool->volumes.count) {
663 664
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("no extended partition found and no primary partition available"));
E
Eric Blake 已提交
665 666 667 668
                    return -1;
                }
                break;
            default:
669 670
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("unknown partition type"));
E
Eric Blake 已提交
671
                return -1;
672 673 674
            }
        }
    } else {
675
        if (VIR_STRDUP(*partFormat, "primary") < 0)
E
Eric Blake 已提交
676
            return -1;
677 678 679 680 681
    }
    return 0;
}

/**
J
Ján Tomko 已提交
682
 * Aligns a new partition to nearest cylinder boundary
E
Eric Blake 已提交
683
 * when having a msdos partition table type
J
Ján Tomko 已提交
684
 * to avoid any problem with already existing
685 686 687
 * partitions
 */
static int
688 689 690 691
virStorageBackendDiskPartBoundaries(virStoragePoolObjPtr pool,
                                    unsigned long long *start,
                                    unsigned long long *end,
                                    unsigned long long allocation)
692
{
693
    size_t i;
694
    int smallestExtent = -1;
695 696 697
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
698
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
699
    unsigned long long cylinderSize = (unsigned long long)dev->geometry.heads *
700 701
                                      dev->geometry.sectors * SECTOR_SIZE;

702
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
703
          cylinderSize);
704 705 706
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

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

710
    for (i = 0; i < dev->nfreeExtent; i++) {
711 712 713 714 715 716
         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 已提交
717
             /* align to cylinder boundary */
718 719 720 721 722 723
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
724
             /* if we are creating a logical partition, we need one extra
725
                block between partitions (or actually move start one block) */
726
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL)
727 728 729 730 731 732 733 734 735 736 737 738
                 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 已提交
739 740 741
             } else if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                        dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                 continue;
742 743 744 745 746 747 748 749
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
750 751
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
752 753 754
        return -1;
    }

755
    VIR_DEBUG("aligned alloc %llu", alignedAllocation);
756 757 758 759 760 761 762 763 764
    *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 已提交
765
        /* adjust our allocation if start is not at a cylinder boundary */
766 767 768
        *end -= (*start % cylinderSize);
    }

769
    /* counting in bytes, we want the last byte of the current sector */
770
    *end -= 1;
771
    VIR_DEBUG("final aligned start %llu, end %llu", *start, *end);
772 773 774 775
    return 0;
}


776
static int
777
virStorageBackendDiskDeleteVol(virConnectPtr conn,
778 779 780 781 782 783 784 785 786 787 788 789 790
                               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);

791 792 793 794 795 796 797
    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;
    }

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
    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;
    }

844 845 846 847 848
    /* If this is not a logical partition, then either we've removed an
     * extended partition or a primary partion - refresh the pool which
     * includes resetting the [n]freeExtents data so a subsequent allocation
     * might be able to use what was deleted.  A logical partition is part
     * of an extended partition and handled differently
849
     */
850
    if (vol->source.partType != VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
851 852 853 854 855
        virStoragePoolObjClearVols(pool);
        if (virStorageBackendDiskRefreshPool(conn, pool) < 0)
            goto cleanup;
    }

856 857 858 859 860 861 862 863
    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


864
static int
865
virStorageBackendDiskCreateVol(virConnectPtr conn,
866
                               virStoragePoolObjPtr pool,
867 868
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
869
    int res = -1;
870
    char *partFormat = NULL;
871
    unsigned long long startOffset = 0, endOffset = 0;
872 873 874 875 876
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
877

878 879 880 881
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
882
        goto cleanup;
883
    }
884

885
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
886
        goto cleanup;
887
    virCommandAddArg(cmd, partFormat);
888

889 890
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
891
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
892
        goto cleanup;
893 894
    }

895 896
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
897

898
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
899
        goto cleanup;
900

901
    /* wait for device node to show up */
902
    virFileWaitForDevices();
903

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

908 909 910 911
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
912 913 914 915 916 917 918 919
    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 已提交
920
        goto cleanup;
921
    }
922

E
Eric Blake 已提交
923 924
    res = 0;

925
 cleanup:
E
Eric Blake 已提交
926
    VIR_FREE(partFormat);
927
    virCommandFree(cmd);
E
Eric Blake 已提交
928
    return res;
929 930
}

931 932
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
933
                                  virStoragePoolObjPtr pool,
934 935 936 937 938 939
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

940
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
941 942 943
    if (!build_func)
        return -1;

944
    return build_func(conn, pool, vol, inputvol, flags);
945
}
946 947


948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
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;
}


966 967 968
virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

969
    .startPool = virStorageBackendDiskStartPool,
970 971 972 973 974
    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
975
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
976 977
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
978
    .wipeVol = virStorageBackendDiskVolWipe,
979
};