storage_backend_disk.c 29.0 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 155 156 157 158 159 160 161 162 163 164 165
    /* 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) {
        if (virStorageBackendUpdateVolInfo(vol, true, false,
                                           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 {
        if (virStorageBackendUpdateVolInfo(vol, true, false,
                                           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 304 305 306 307 308 309 310 311
    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
                                                "src",
                                                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 349 350 351 352 353
    char *parthelper_path;
    virCommandPtr cmd;
    int ret;

    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
                                                "src",
                                                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 471 472 473 474 475 476 477 478
    if (ok_to_mklabel) {
        /* eg parted /dev/sda mklabel msdos */
        cmd = virCommandNewArgList(PARTED,
                                   pool->def->source.devices[0].path,
                                   "mklabel",
                                   "--script",
                                   ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" :
                                   virStoragePoolFormatDiskTypeToString(pool->def->source.format)),
                                   NULL);
479
        ret = virCommandRun(cmd, NULL);
480
    }
481

482
 error:
483
    virCommandFree(cmd);
484
    return ret;
485 486
}

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

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

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

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

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

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

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

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

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

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


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

689 690 691 692 693 694 695
    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;
    }

696 697 698 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
    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;
    }

742 743 744 745 746 747 748 749 750
    /* If this was the extended partition, then all the logical partitions
     * are then lost. Make it easy on ourselves and just refresh the pool
     */
    if (vol->source.partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
        virStoragePoolObjClearVols(pool);
        if (virStorageBackendDiskRefreshPool(conn, pool) < 0)
            goto cleanup;
    }

751 752 753 754 755 756 757 758
    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


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

773 774 775 776
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
777
        goto cleanup;
778
    }
779

780
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
781
        goto cleanup;
782
    virCommandAddArg(cmd, partFormat);
783

784 785
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
786
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
787
        goto cleanup;
788 789
    }

790 791
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
792

793
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
794
        goto cleanup;
795

796
    /* wait for device node to show up */
797
    virFileWaitForDevices();
798

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

803 804 805 806
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
807 808 809 810 811 812 813 814
    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 已提交
815
        goto cleanup;
816
    }
817

E
Eric Blake 已提交
818 819
    res = 0;

820
 cleanup:
E
Eric Blake 已提交
821
    VIR_FREE(partFormat);
822
    virCommandFree(cmd);
E
Eric Blake 已提交
823
    return res;
824 825
}

826 827
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
828
                                  virStoragePoolObjPtr pool,
829 830 831 832 833 834
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

835
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
836 837 838
    if (!build_func)
        return -1;

839
    return build_func(conn, pool, vol, inputvol, flags);
840
}
841 842 843 844 845 846 847 848 849 850


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
851
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
852 853
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
854
    .wipeVol = virStorageBackendVolWipeLocal,
855
};