storage_backend_disk.c 29.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
    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 ((output && strstr(output, "unrecognised disk label")) ||
            (error && 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 446
    VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                             VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                             error);
447

448
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
449
        ok_to_mklabel = true;
450
    } else {
451 452
        int check;

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

466
    if (ok_to_mklabel) {
467 468 469 470 471 472 473 474 475
        /* 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);

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

485
 error:
486
    virCommandFree(cmd);
487
    return ret;
488 489
}

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

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

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

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

603
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
604
          cylinderSize);
605 606 607
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

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

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

    if (smallestExtent == -1) {
651 652
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
653 654 655
        return -1;
    }

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

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


677
static int
678
virStorageBackendDiskDeleteVol(virConnectPtr conn,
679 680 681 682 683 684 685 686 687 688 689 690 691
                               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);

692 693 694 695 696 697 698
    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;
    }

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

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

757 758 759 760 761 762 763 764
    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


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

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

786
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
787
        goto cleanup;
788
    virCommandAddArg(cmd, partFormat);
789

790 791
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
792
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
793
        goto cleanup;
794 795
    }

796 797
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
798

799
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
800
        goto cleanup;
801

802
    /* wait for device node to show up */
803
    virFileWaitForDevices();
804

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

809 810 811 812
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
813 814 815 816 817 818 819 820
    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 已提交
821
        goto cleanup;
822
    }
823

E
Eric Blake 已提交
824 825
    res = 0;

826
 cleanup:
E
Eric Blake 已提交
827
    VIR_FREE(partFormat);
828
    virCommandFree(cmd);
E
Eric Blake 已提交
829
    return res;
830 831
}

832 833
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
834
                                  virStoragePoolObjPtr pool,
835 836 837 838 839 840
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

841
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
842 843 844
    if (!build_func)
        return -1;

845
    return build_func(conn, pool, vol, inputvol, flags);
846
}
847 848 849 850 851 852 853 854 855 856


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
857
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
858 859
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
860
    .wipeVol = virStorageBackendVolWipeLocal,
861
};