storage_backend_disk.c 27.3 KB
Newer Older
1 2 3
/*
 * storage_backend_disk.c: storage backend for disk handling
 *
4
 * Copyright (C) 2007-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2007-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>
C
Cole Robinson 已提交
25
#include <string.h>
26
#include <unistd.h>
27
#include <stdio.h>
28

29
#include "dirname.h"
30
#include "virerror.h"
31
#include "virlog.h"
32
#include "storage_backend_disk.h"
33
#include "viralloc.h"
34
#include "vircommand.h"
35
#include "virfile.h"
36
#include "configmake.h"
37
#include "virstring.h"
38

39 40
#define VIR_FROM_THIS VIR_FROM_STORAGE

41 42
VIR_LOG_INIT("storage.storage_backend_disk");

43 44
#define SECTOR_SIZE 512

45
static int
46
virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
47 48 49 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++) {
498 499
                if (pool->volumes.objs[i]->source.partType ==
                    VIR_STORAGE_VOL_DISK_TYPE_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
                break;
            case VIR_STORAGE_VOL_DISK_TYPE_LOGICAL:
                /* make sure we have a extended partition */
                for (i = 0; i < pool->volumes.count; i++) {
520 521
                    if (pool->volumes.objs[i]->source.partType ==
                        VIR_STORAGE_VOL_DISK_TYPE_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
    return 0;
}


642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
static int
virStorageBackendDiskDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                               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);

657 658 659 660 661 662 663
    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;
    }

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
    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;
    }

    rc = 0;
 cleanup:
    VIR_FREE(devpath);
    virCommandFree(cmd);
    return rc;
}


718
static int
719
virStorageBackendDiskCreateVol(virConnectPtr conn,
720
                               virStoragePoolObjPtr pool,
721 722
                               virStorageVolDefPtr vol)
{
E
Eric Blake 已提交
723
    int res = -1;
724
    char *partFormat = NULL;
725
    unsigned long long startOffset = 0, endOffset = 0;
726 727 728 729 730
    virCommandPtr cmd = virCommandNewArgList(PARTED,
                                             pool->def->source.devices[0].path,
                                             "mkpart",
                                             "--script",
                                             NULL);
731

732 733 734 735
    if (vol->target.encryption != NULL) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("storage pool does not support encrypted "
                               "volumes"));
736
        goto cleanup;
737
    }
738

739
    if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0)
740
        goto cleanup;
741
    virCommandAddArg(cmd, partFormat);
742

743 744
    if (virStorageBackendDiskPartBoundaries(pool, &startOffset,
                                            &endOffset,
745
                                            vol->target.capacity) != 0) {
E
Eric Blake 已提交
746
        goto cleanup;
747 748
    }

749 750
    virCommandAddArgFormat(cmd, "%lluB", startOffset);
    virCommandAddArgFormat(cmd, "%lluB", endOffset);
751

752
    if (virCommandRun(cmd, NULL) < 0)
E
Eric Blake 已提交
753
        goto cleanup;
754

755
    /* wait for device node to show up */
756
    virFileWaitForDevices();
757

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

762 763 764 765
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
766 767 768 769 770 771 772 773
    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 已提交
774
        goto cleanup;
775
    }
776

E
Eric Blake 已提交
777 778
    res = 0;

779
 cleanup:
E
Eric Blake 已提交
780
    VIR_FREE(partFormat);
781
    virCommandFree(cmd);
E
Eric Blake 已提交
782
    return res;
783 784
}

785 786
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
787
                                  virStoragePoolObjPtr pool,
788 789 790 791 792 793
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

794
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
795 796 797
    if (!build_func)
        return -1;

798
    return build_func(conn, pool, vol, inputvol, flags);
799
}
800 801 802 803 804 805 806 807 808 809


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
810
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
811 812
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
813
    .wipeVol = virStorageBackendVolWipeLocal,
814
};