storage_backend_disk.c 26.7 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 50 51 52
                                 char **const groups,
                                 virStorageVolDefPtr vol)
{
    char *tmp, *devpath;

    if (vol == NULL) {
53
        if (VIR_ALLOC(vol) < 0)
54 55 56 57 58
            return -1;
        /* Prepended path will be same for all partitions, so we can
         * strip the path to form a reasonable pool-unique name
         */
        tmp = strrchr(groups[0], '/');
59
        if (VIR_STRDUP(vol->name, tmp ? tmp + 1 : groups[0]) < 0 ||
60 61
            VIR_APPEND_ELEMENT_COPY(pool->volumes.objs,
                                    pool->volumes.count, vol) < 0) {
62
            virStorageVolDefFree(vol);
63
            return -1;
64
        }
65 66 67
    }

    if (vol->target.path == NULL) {
68
        if (VIR_STRDUP(devpath, groups[0]) < 0)
69 70 71 72 73 74 75 76
            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...
         */
77
        vol->target.path = virStorageBackendStablePath(pool, devpath, true);
78
        VIR_FREE(devpath);
79 80
        if (vol->target.path == NULL)
            return -1;
81 82 83 84
    }

    if (vol->key == NULL) {
        /* XXX base off a unique key of the underlying disk */
85
        if (VIR_STRDUP(vol->key, vol->target.path) < 0)
86 87 88 89
            return -1;
    }

    if (vol->source.extents == NULL) {
90
        if (VIR_ALLOC(vol->source.extents) < 0)
91 92 93 94 95
            return -1;
        vol->source.nextent = 1;

        if (virStrToLong_ull(groups[3], NULL, 10,
                             &vol->source.extents[0].start) < 0) {
96 97
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device start location"));
98 99 100 101 102
            return -1;
        }

        if (virStrToLong_ull(groups[4], NULL, 10,
                             &vol->source.extents[0].end) < 0) {
103 104
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device end location"));
105 106 107
            return -1;
        }

108 109
        if (VIR_STRDUP(vol->source.extents[0].path,
                       pool->def->source.devices[0].path) < 0)
110 111 112 113
            return -1;
    }

    /* Refresh allocation/capacity/perms */
114
    if (virStorageBackendUpdateVolInfo(vol, true, false,
115
                                       VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
116 117
        return -1;

118
    /* set partition type */
E
Eric Blake 已提交
119
    if (STREQ(groups[1], "normal"))
120
       vol->source.partType = VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
E
Eric Blake 已提交
121
    else if (STREQ(groups[1], "logical"))
122
       vol->source.partType = VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
E
Eric Blake 已提交
123
    else if (STREQ(groups[1], "extended"))
124
       vol->source.partType = VIR_STORAGE_VOL_DISK_TYPE_EXTENDED;
125
    else
126
       vol->source.partType = VIR_STORAGE_VOL_DISK_TYPE_NONE;
127

128 129
    vol->type = VIR_STORAGE_VOL_BLOCK;

130 131
    /* The above gets allocation wrong for
     * extended partitions, so overwrite it */
132
    vol->target.allocation = vol->target.capacity =
133 134 135
        (vol->source.extents[0].end - vol->source.extents[0].start);

    if (STRNEQ(groups[2], "metadata"))
136
        pool->def->allocation += vol->target.allocation;
137 138 139 140 141 142 143
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}

static int
144
virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
145 146 147 148
                                    char **const groups)
{
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];

149 150
    if (VIR_REALLOC_N(dev->freeExtents,
                      dev->nfreeExtent + 1) < 0)
151 152 153
        return -1;

    memset(dev->freeExtents +
154 155
           dev->nfreeExtent, 0,
           sizeof(dev->freeExtents[0]));
156

157
    /* set type of free area */
E
Eric Blake 已提交
158
    if (STREQ(groups[1], "logical")) {
159 160 161 162 163 164
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_LOGICAL;
    } else {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_NORMAL;
    }


165 166 167 168 169 170 171 172
    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 */

173
    /* first block reported as free, even if it is not */
174
    if (dev->freeExtents[dev->nfreeExtent].start == 0)
175 176
        dev->freeExtents[dev->nfreeExtent].start = SECTOR_SIZE;

177 178 179 180 181 182 183 184 185 186 187 188
    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;
}


189 190 191 192 193
struct virStorageBackendDiskPoolVolData {
    virStoragePoolObjPtr pool;
    virStorageVolDefPtr vol;
};

194
static int
195
virStorageBackendDiskMakeVol(size_t ntok ATTRIBUTE_UNUSED,
196
                             char **const groups,
197
                             void *opaque)
198
{
199 200
    struct virStorageBackendDiskPoolVolData *data = opaque;
    virStoragePoolObjPtr pool = data->pool;
201 202 203 204 205 206 207 208 209 210 211 212
    /*
     * 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 已提交
213
    /* Remaining data / metadata parts get turn into volumes... */
214 215
    if (STREQ(groups[2], "metadata") ||
        STREQ(groups[2], "data")) {
216
        virStorageVolDefPtr vol = data->vol;
217 218 219 220 221 222 223 224 225 226 227 228

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

230
        return virStorageBackendDiskMakeDataVol(pool, groups, vol);
231 232
    } else if (STREQ(groups[2], "free")) {
        /* ....or free space extents */
233
        return virStorageBackendDiskMakeFreeExtent(pool, groups);
234
    } else {
R
Richard W.M. Jones 已提交
235
        /* This code path should never happen unless someone changed
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
         * 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
252
virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
253 254 255 256 257 258 259 260 261
                                    virStorageVolDefPtr vol)
{
    /*
     *  # libvirt_parthelper DEVICE
     * /dev/sda1      normal       data        32256    106928128    106896384
     * /dev/sda2      normal       data    106928640 100027629568  99920701440
     * -              normal   metadata 100027630080 100030242304      2612736
     *
     */
262 263 264

    char *parthelper_path;
    virCommandPtr cmd;
265 266 267 268
    struct virStorageBackendDiskPoolVolData cbdata = {
        .pool = pool,
        .vol = vol,
    };
269
    int ret;
270

271 272 273 274 275 276 277 278 279
    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
                                                "src",
                                                LIBEXECDIR)))
        return -1;

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

280 281
    pool->def->allocation = pool->def->capacity = pool->def->available = 0;

282 283 284 285
    ret = virCommandRunNul(cmd,
                           6,
                           virStorageBackendDiskMakeVol,
                           &cbdata);
286
    virCommandFree(cmd);
287
    VIR_FREE(parthelper_path);
288
    return ret;
289 290
}

291
static int
292
virStorageBackendDiskMakePoolGeometry(size_t ntok ATTRIBUTE_UNUSED,
293
                                      char **const groups,
294
                                      void *data)
295
{
296
    virStoragePoolObjPtr pool = data;
P
Peter Krempa 已提交
297 298 299 300 301 302 303 304
    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;
    }
305

P
Peter Krempa 已提交
306
    return 0;
307 308 309
}

static int
310
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
311
{
312 313 314 315 316 317 318 319 320 321
    char *parthelper_path;
    virCommandPtr cmd;
    int ret;

    if (!(parthelper_path = virFileFindResource("libvirt_parthelper",
                                                "src",
                                                LIBEXECDIR)))
        return -1;

    cmd = virCommandNewArgList(parthelper_path,
322 323 324 325
                                             pool->def->source.devices[0].path,
                                             "-g",
                                             NULL);

326 327 328 329
    ret = virCommandRunNul(cmd,
                           3,
                           virStorageBackendDiskMakePoolGeometry,
                           pool);
330
    virCommandFree(cmd);
331
    VIR_FREE(parthelper_path);
332
    return ret;
333
}
334 335

static int
336
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
337 338
                                 virStoragePoolObjPtr pool)
{
339
    VIR_FREE(pool->def->source.devices[0].freeExtents);
340 341
    pool->def->source.devices[0].nfreeExtent = 0;

342
    virFileWaitForDevices();
343

344
    if (!virFileExists(pool->def->source.devices[0].path)) {
345 346 347
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device path '%s' doesn't exist"),
                       pool->def->source.devices[0].path);
348 349 350
        return -1;
    }

351
    if (virStorageBackendDiskReadGeometry(pool) != 0)
352 353
        return -1;

354
    return virStorageBackendDiskReadPartitions(pool, NULL);
355 356 357
}


358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
/**
 * 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;
373
    char *error = NULL;
374 375 376 377 378
    int ret = -1;

    virCommandAddArgSet(cmd, args);
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &output);
379
    virCommandSetErrorBuffer(cmd, &error);
380 381 382 383

    /* if parted succeeds we have a valid partition table */
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
384 385
        if (strstr(output, "unrecognised disk label") ||
            strstr(error, "unrecognised disk label")) {
386
            ret = 1;
387
        }
388 389 390 391
    }

    virCommandFree(cmd);
    VIR_FREE(output);
392
    VIR_FREE(error);
393 394 395 396
    return ret;
}


397 398 399 400
/**
 * Write a new partition table header
 */
static int
401
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
402
                               virStoragePoolObjPtr pool,
E
Eric Blake 已提交
403
                               unsigned int flags)
404
{
405 406
    bool ok_to_mklabel = false;
    int ret = -1;
407
    virCommandPtr cmd = NULL;
408

409 410
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
E
Eric Blake 已提交
411

412 413
    if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {
414
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
415 416
                       _("Overwrite and no overwrite flags"
                         " are mutually exclusive"));
417 418
        goto error;
    }
419

420
    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
421
        ok_to_mklabel = true;
422
    } else {
423 424
        int check;

425
        check = virStorageBackendDiskFindLabel(
426 427 428 429
                    pool->def->source.devices[0].path);
        if (check > 0) {
            ok_to_mklabel = true;
        } else if (check < 0) {
430
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
431
                           _("Error checking for disk label"));
432
        } else {
433
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
434
                           _("Disk label already present"));
435 436 437
        }
    }

438 439 440 441 442 443 444 445 446
    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);
447
        ret = virCommandRun(cmd, NULL);
448
    }
449

450
 error:
451
    virCommandFree(cmd);
452
    return ret;
453 454
}

455 456 457 458
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
459
static int
460 461 462
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
463
        /* count primary and extended partitions,
464
           can't be more than 3 to create a new primary partition */
465
        size_t i;
466 467
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
468 469 470 471
            int partType = pool->volumes.objs[i]->source.partType;
            if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED)
                count++;
472
        }
473
        if (count >= 4)
474 475 476 477 478 479 480 481
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    }

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

static int
482
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
483
                                virStorageVolDefPtr vol,
E
Eric Blake 已提交
484
                                char** partFormat)
485
{
486
    size_t i;
487
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
E
Eric Blake 已提交
488
        const char *partedFormat;
489
        partedFormat = virStoragePartedFsTypeToString(vol->target.format);
E
Eric Blake 已提交
490
        if (partedFormat == NULL) {
491 492
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Invalid partition type"));
E
Eric Blake 已提交
493
            return -1;
494 495 496 497
        }
        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++) {
E
Eric Blake 已提交
498 499
                if (pool->volumes.objs[i]->target.format ==
                    VIR_STORAGE_VOL_DISK_EXTENDED) {
500 501
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("extended partition already exists"));
E
Eric Blake 已提交
502 503
                    return -1;
                }
504
            }
505
            if (VIR_STRDUP(*partFormat, partedFormat) < 0)
E
Eric Blake 已提交
506
                return -1;
507 508 509 510 511 512
        } 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 已提交
513
            case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
514
                if (virAsprintf(partFormat, "primary %s", partedFormat) < 0)
E
Eric Blake 已提交
515
                    return -1;
E
Eric Blake 已提交
516 517 518 519 520 521
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
                    if (pool->volumes.objs[i]->target.format ==
                        VIR_STORAGE_VOL_DISK_EXTENDED) {
E
Eric Blake 已提交
522
                        if (virAsprintf(partFormat, "logical %s",
523
                                        partedFormat) < 0)
E
Eric Blake 已提交
524
                            return -1;
E
Eric Blake 已提交
525 526 527 528
                        break;
                    }
                }
                if (i == pool->volumes.count) {
529 530
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("no extended partition found and no primary partition available"));
E
Eric Blake 已提交
531 532 533 534
                    return -1;
                }
                break;
            default:
535 536
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("unknown partition type"));
E
Eric Blake 已提交
537
                return -1;
538 539 540
            }
        }
    } else {
541
        if (VIR_STRDUP(*partFormat, "primary") < 0)
E
Eric Blake 已提交
542
            return -1;
543 544 545 546 547
    }
    return 0;
}

/**
J
Ján Tomko 已提交
548
 * Aligns a new partition to nearest cylinder boundary
E
Eric Blake 已提交
549
 * when having a msdos partition table type
J
Ján Tomko 已提交
550
 * to avoid any problem with already existing
551 552 553
 * partitions
 */
static int
554 555 556 557
virStorageBackendDiskPartBoundaries(virStoragePoolObjPtr pool,
                                    unsigned long long *start,
                                    unsigned long long *end,
                                    unsigned long long allocation)
558
{
559
    size_t i;
560
    int smallestExtent = -1;
561 562 563
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
564
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
565
    unsigned long long cylinderSize = (unsigned long long)dev->geometry.heads *
566 567
                                      dev->geometry.sectors * SECTOR_SIZE;

568
    VIR_DEBUG("find free area: allocation %llu, cyl size %llu", allocation,
E
Eric Blake 已提交
569
          cylinderSize);
570 571 572
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

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

576
    for (i = 0; i < dev->nfreeExtent; i++) {
577 578 579 580 581 582
         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 已提交
583
             /* align to cylinder boundary */
584 585 586 587 588 589
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
590
             /* if we are creating a logical partition, we need one extra
591
                block between partitions (or actually move start one block) */
592
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL)
593 594 595 596 597 598 599 600 601 602 603 604
                 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 已提交
605 606 607
             } else if (partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                        dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                 continue;
608 609 610 611 612 613 614 615
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
616 617
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no large enough free extent"));
618 619 620
        return -1;
    }

621
    VIR_DEBUG("aligned alloc %llu", alignedAllocation);
622 623 624 625 626 627 628 629 630
    *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 已提交
631
        /* adjust our allocation if start is not at a cylinder boundary */
632 633 634
        *end -= (*start % cylinderSize);
    }

635
    /* counting in bytes, we want the last byte of the current sector */
636
    *end -= 1;
637
    VIR_DEBUG("final aligned start %llu, end %llu", *start, *end);
638 639 640 641 642
    return 0;
}


static int
643
virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
644
                               virStoragePoolObjPtr pool,
645 646
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
647
    int res = -1;
648
    char *partFormat = NULL;
649
    unsigned long long startOffset = 0, endOffset = 0;
650 651 652 653 654
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
655

656 657 658 659
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
660
        goto cleanup;
661
    }
662

663
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
664
        goto cleanup;
665
    virCommandAddArg(cmd, partFormat);
666

667 668
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
669
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
670
        goto cleanup;
671 672
    }

673 674
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
675

676
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
677
        goto cleanup;
678

679
    /* wait for device node to show up */
680
    virFileWaitForDevices();
681

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

686 687 688 689
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
690
    if (virStorageBackendDiskReadPartitions(pool, vol) < 0)
E
Eric Blake 已提交
691
        goto cleanup;
692

E
Eric Blake 已提交
693 694
    res = 0;

695
 cleanup:
E
Eric Blake 已提交
696
    VIR_FREE(partFormat);
697
    virCommandFree(cmd);
E
Eric Blake 已提交
698
    return res;
699 700
}

701 702
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
703
                                  virStoragePoolObjPtr pool,
704 705 706 707 708 709
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

710
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
711 712 713
    if (!build_func)
        return -1;

714
    return build_func(conn, pool, vol, inputvol, flags);
715
}
716 717

static int
718
virStorageBackendDiskDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
C
Cole Robinson 已提交
719 720
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol,
E
Eric Blake 已提交
721
                               unsigned int flags)
722
{
C
Cole Robinson 已提交
723
    char *part_num = NULL;
D
Daniel P. Berrange 已提交
724
    char *devpath = NULL;
725
    char *dev_name, *srcname;
726 727
    virCommandPtr cmd = NULL;
    bool isDevMapperDevice;
D
Daniel P. Berrange 已提交
728
    int rc = -1;
C
Cole Robinson 已提交
729

E
Eric Blake 已提交
730 731
    virCheckFlags(0, -1);

732 733
    if (virFileResolveLink(vol->target.path, &devpath) < 0) {
        virReportSystemError(errno,
734 735
                             _("Couldn't read volume target path '%s'"),
                             vol->target.path);
D
Daniel P. Berrange 已提交
736
        goto cleanup;
C
Cole Robinson 已提交
737 738
    }

739 740
    dev_name = last_component(devpath);
    srcname = last_component(pool->def->source.devices[0].path);
741
    VIR_DEBUG("dev_name=%s, srcname=%s", dev_name, srcname);
C
Cole Robinson 已提交
742

743 744
    isDevMapperDevice = virIsDevMapperDevice(devpath);

745
    if (!isDevMapperDevice && !STRPREFIX(dev_name, srcname)) {
746 747 748
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume path '%s' did not start with parent "
                         "pool source device name."), dev_name);
D
Daniel P. Berrange 已提交
749
        goto cleanup;
C
Cole Robinson 已提交
750 751
    }

752
    if (!isDevMapperDevice) {
753
        part_num = dev_name + strlen(srcname);
C
Cole Robinson 已提交
754

755
        if (*part_num == 0) {
756 757 758
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse partition number from target "
                             "'%s'"), dev_name);
759 760
            goto cleanup;
        }
C
Cole Robinson 已提交
761

762 763 764 765 766 767 768 769 770 771 772
        /* 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);
C
Cole Robinson 已提交
773

774 775 776
        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;
    }
C
Cole Robinson 已提交
777

D
Daniel P. Berrange 已提交
778
    rc = 0;
779
 cleanup:
D
Daniel P. Berrange 已提交
780
    VIR_FREE(devpath);
781
    virCommandFree(cmd);
D
Daniel P. Berrange 已提交
782
    return rc;
783 784 785 786 787 788 789 790 791 792 793
}


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
794
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
795 796
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
797
    .wipeVol = virStorageBackendVolWipeLocal,
798
};