storage_backend_disk.c 29.3 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
    pool->def->allocation = pool->def->capacity = pool->def->available = 0;

314 315 316 317
    ret = virCommandRunNul(cmd,
                           6,
                           virStorageBackendDiskMakeVol,
                           &cbdata);
318
    virCommandFree(cmd);
319
    VIR_FREE(parthelper_path);
320
    return ret;
321 322
}

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

P
Peter Krempa 已提交
338
    return 0;
339 340 341
}

static int
342
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
343
{
344 345 346 347 348
    char *parthelper_path;
    virCommandPtr cmd;
    int ret;

    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
349
                                                abs_topbuilddir "/src",
350 351 352 353
                                                LIBEXECDIR)))
        return -1;

    cmd = virCommandNewArgList(parthelper_path,
354 355 356 357
                                             pool->def->source.devices[0].path,
                                             "-g",
                                             NULL);

358 359 360 361
    ret = virCommandRunNul(cmd,
                           3,
                           virStorageBackendDiskMakePoolGeometry,
                           pool);
362
    virCommandFree(cmd);
363
    VIR_FREE(parthelper_path);
364
    return ret;
365
}
366 367

static int
368
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
369 370
                                 virStoragePoolObjPtr pool)
{
371
    VIR_FREE(pool->def->source.devices[0].freeExtents);
372 373
    pool->def->source.devices[0].nfreeExtent = 0;

374
    virFileWaitForDevices();
375

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

383
    if (virStorageBackendDiskReadGeometry(pool) != 0)
384 385
        return -1;

386
    return virStorageBackendDiskReadPartitions(pool, NULL);
387 388 389
}


390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
/**
 * 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;
405
    char *error = NULL;
406 407 408 409 410
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);
411
    virCommandSetErrorBuffer(cmd, &error);
412 413 414 415

    /* if parted succeeds we have a valid partition table */
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
416 417
        if (strstr(output, "unrecognised disk label") ||
            strstr(error, "unrecognised disk label")) {
418
            ret = 1;
419
        }
420 421 422 423
    }

    virCommandFree(cmd);
    VIR_FREE(output);
424
    VIR_FREE(error);
425 426 427 428
    return ret;
}


429 430 431 432
/**
 * Write a new partition table header
 */
static int
433
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
434
                               virStoragePoolObjPtr pool,
E
Eric Blake 已提交
435
                               unsigned int flags)
436
{
437 438
    bool ok_to_mklabel = false;
    int ret = -1;
439
    virCommandPtr cmd = NULL;
440

441 442
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
443

444 445
    if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {
446
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
447 448
                       _("Overwrite and no overwrite flags"
                         " are mutually exclusive"));
449 450
        goto error;
    }
451

452
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
453
        ok_to_mklabel = true;
454
    } else {
455 456
        int check;

457
        check = virStorageBackendDiskFindLabel(
458 459 460 461
                    pool->def->source.devices[0].path);
        if (check > 0) {
            ok_to_mklabel = true;
        } else if (check < 0) {
462
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
463
                           _("Error checking for disk label"));
464
        } else {
465
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
466
                           _("Disk label already present"));
467 468 469
        }
    }

470
    if (ok_to_mklabel) {
471 472 473 474 475 476 477 478 479
        /* eg parted /dev/sda mklabel --script msdos */
        int format = pool->def->source.format;
        const char *fmt;
        if (format == VIR_STORAGE_POOL_DISK_UNKNOWN ||
            format == VIR_STORAGE_POOL_DISK_DOS)
            fmt = "msdos";
        else
            fmt = virStoragePoolFormatDiskTypeToString(format);

480 481 482 483
        cmd = virCommandNewArgList(PARTED,
                                   pool->def->source.devices[0].path,
                                   "mklabel",
                                   "--script",
484
                                   fmt,
485
                                   NULL);
486
        ret = virCommandRun(cmd, NULL);
487
    }
488

489
 error:
490
    virCommandFree(cmd);
491
    return ret;
492 493
}

494 495 496 497
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
498
static int
499 500 501
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
502
        /* count primary and extended partitions,
503
           can't be more than 3 to create a new primary partition */
504
        size_t i;
505 506
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
507 508 509 510
            int partType = pool->volumes.objs[i]->source.partType;
            if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED)
                count++;
511
        }
512
        if (count >= 4)
513 514 515 516 517 518 519 520
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    }

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

static int
521
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
522
                                virStorageVolDefPtr vol,
E
Eric Blake 已提交
523
                                char** partFormat)
524
{
525
    size_t i;
526
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
E
Eric Blake 已提交
527
        const char *partedFormat;
528
        partedFormat = virStoragePartedFsTypeToString(vol->target.format);
E
Eric Blake 已提交
529
        if (partedFormat == NULL) {
530 531
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Invalid partition type"));
E
Eric Blake 已提交
532
            return -1;
533 534 535 536
        }
        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++) {
537 538
                if (pool->volumes.objs[i]->source.partType ==
                    VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
539 540
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("extended partition already exists"));
E
Eric Blake 已提交
541 542
                    return -1;
                }
543
            }
544
            if (VIR_STRDUP(*partFormat, partedFormat) < 0)
E
Eric Blake 已提交
545
                return -1;
546 547 548 549 550 551
        } 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 已提交
552
            case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
553
                if (virAsprintf(partFormat, "primary %s", partedFormat) < 0)
E
Eric Blake 已提交
554
                    return -1;
E
Eric Blake 已提交
555 556 557 558
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
559 560
                    if (pool->volumes.objs[i]->source.partType ==
                        VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
E
Eric Blake 已提交
561
                        if (virAsprintf(partFormat, "logical %s",
562
                                        partedFormat) < 0)
E
Eric Blake 已提交
563
                            return -1;
E
Eric Blake 已提交
564 565 566 567
                        break;
                    }
                }
                if (i == pool->volumes.count) {
568 569
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("no extended partition found and no primary partition available"));
E
Eric Blake 已提交
570 571 572 573
                    return -1;
                }
                break;
            default:
574 575
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("unknown partition type"));
E
Eric Blake 已提交
576
                return -1;
577 578 579
            }
        }
    } else {
580
        if (VIR_STRDUP(*partFormat, "primary") < 0)
E
Eric Blake 已提交
581
            return -1;
582 583 584 585 586
    }
    return 0;
}

/**
J
Ján Tomko 已提交
587
 * Aligns a new partition to nearest cylinder boundary
E
Eric Blake 已提交
588
 * when having a msdos partition table type
J
Ján Tomko 已提交
589
 * to avoid any problem with already existing
590 591 592
 * partitions
 */
static int
593 594 595 596
virStorageBackendDiskPartBoundaries(virStoragePoolObjPtr pool,
                                    unsigned long long *start,
                                    unsigned long long *end,
                                    unsigned long long allocation)
597
{
598
    size_t i;
599
    int smallestExtent = -1;
600 601 602
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
603
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
604
    unsigned long long cylinderSize = (unsigned long long)dev->geometry.heads *
605 606
                                      dev->geometry.sectors * SECTOR_SIZE;

607
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
608
          cylinderSize);
609 610 611
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

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

615
    for (i = 0; i < dev->nfreeExtent; i++) {
616 617 618 619 620 621
         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 已提交
622
             /* align to cylinder boundary */
623 624 625 626 627 628
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
629
             /* if we are creating a logical partition, we need one extra
630
                block between partitions (or actually move start one block) */
631
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL)
632 633 634 635 636 637 638 639 640 641 642 643
                 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 已提交
644 645 646
             } else if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                        dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                 continue;
647 648 649 650 651 652 653 654
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
655 656
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
657 658 659
        return -1;
    }

660
    VIR_DEBUG("aligned alloc %llu", alignedAllocation);
661 662 663 664 665 666 667 668 669
    *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 已提交
670
        /* adjust our allocation if start is not at a cylinder boundary */
671 672 673
        *end -= (*start % cylinderSize);
    }

674
    /* counting in bytes, we want the last byte of the current sector */
675
    *end -= 1;
676
    VIR_DEBUG("final aligned start %llu, end %llu", *start, *end);
677 678 679 680
    return 0;
}


681
static int
682
virStorageBackendDiskDeleteVol(virConnectPtr conn,
683 684 685 686 687 688 689 690 691 692 693 694 695
                               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);

696 697 698 699 700 701 702
    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;
    }

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
    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;
    }

749 750 751 752 753
    /* 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
754
     */
755
    if (vol->source.partType != VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
756 757 758 759 760
        virStoragePoolObjClearVols(pool);
        if (virStorageBackendDiskRefreshPool(conn, pool) < 0)
            goto cleanup;
    }

761 762 763 764 765 766 767 768
    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


769
static int
770
virStorageBackendDiskCreateVol(virConnectPtr conn,
771
                               virStoragePoolObjPtr pool,
772 773
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
774
    int res = -1;
775
    char *partFormat = NULL;
776
    unsigned long long startOffset = 0, endOffset = 0;
777 778 779 780 781
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
782

783 784 785 786
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
787
        goto cleanup;
788
    }
789

790
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
791
        goto cleanup;
792
    virCommandAddArg(cmd, partFormat);
793

794 795
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
796
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
797
        goto cleanup;
798 799
    }

800 801
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
802

803
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
804
        goto cleanup;
805

806
    /* wait for device node to show up */
807
    virFileWaitForDevices();
808

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

813 814 815 816
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
817 818 819 820 821 822 823 824
    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 已提交
825
        goto cleanup;
826
    }
827

E
Eric Blake 已提交
828 829
    res = 0;

830
 cleanup:
E
Eric Blake 已提交
831
    VIR_FREE(partFormat);
832
    virCommandFree(cmd);
E
Eric Blake 已提交
833
    return res;
834 835
}

836 837
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
838
                                  virStoragePoolObjPtr pool,
839 840 841 842 843 844
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

845
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
846 847 848
    if (!build_func)
        return -1;

849
    return build_func(conn, pool, vol, inputvol, flags);
850
}
851 852 853 854 855 856 857 858 859 860


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
861
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
862 863
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
864
    .wipeVol = virStorageBackendVolWipeLocal,
865
};