storage_backend_disk.c 29.4 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 399 400 401 402 403 404 405 406 407 408 409
/**
 * 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;
410
    char *error = NULL;
411 412 413 414 415
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);
416
    virCommandSetErrorBuffer(cmd, &error);
417 418 419 420

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

    virCommandFree(cmd);
    VIR_FREE(output);
429
    VIR_FREE(error);
430 431 432 433
    return ret;
}


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

446 447
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
448

449 450 451
    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                             VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                             error);
452

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

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

471
    if (ok_to_mklabel) {
472 473 474 475 476 477 478 479 480
        /* 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);

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

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