storage_backend_disk.c 22.4 KB
Newer Older
1 2 3
/*
 * storage_backend_disk.c: storage backend for disk handling
 *
4
 * Copyright (C) 2007-2008, 2010 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * 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 "virterror_internal.h"
30
#include "logging.h"
31 32
#include "storage_backend_disk.h"
#include "util.h"
33
#include "memory.h"
34

35 36
#define VIR_FROM_THIS VIR_FROM_STORAGE

37 38
#define PARTHELPER BINDIR "/libvirt_parthelper"

39 40
#define SECTOR_SIZE 512

41
static int
42
virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
43 44 45 46 47 48
                                 char **const groups,
                                 virStorageVolDefPtr vol)
{
    char *tmp, *devpath;

    if (vol == NULL) {
49
        if (VIR_ALLOC(vol) < 0) {
50
            virReportOOMError();
51 52 53
            return -1;
        }

54 55
        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0) {
56
            virReportOOMError();
57 58 59 60
            virStorageVolDefFree(vol);
            return -1;
        }
        pool->volumes.objs[pool->volumes.count++] = vol;
61 62 63 64 65 66

        /* 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], '/');
        if ((vol->name = strdup(tmp ? tmp + 1 : groups[0])) == NULL) {
67
            virReportOOMError();
68 69 70 71 72 73
            return -1;
        }
    }

    if (vol->target.path == NULL) {
        if ((devpath = strdup(groups[0])) == NULL) {
74
            virReportOOMError();
75 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);
85
        VIR_FREE(devpath);
86 87
        if (vol->target.path == NULL)
            return -1;
88 89 90 91 92
    }

    if (vol->key == NULL) {
        /* XXX base off a unique key of the underlying disk */
        if ((vol->key = strdup(vol->target.path)) == NULL) {
93
            virReportOOMError();
94 95 96 97 98
            return -1;
        }
    }

    if (vol->source.extents == NULL) {
99
        if (VIR_ALLOC(vol->source.extents) < 0) {
100
            virReportOOMError();
101 102 103 104 105 106
            return -1;
        }
        vol->source.nextent = 1;

        if (virStrToLong_ull(groups[3], NULL, 10,
                             &vol->source.extents[0].start) < 0) {
107
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
108
                                  "%s", _("cannot parse device start location"));
109 110 111 112 113
            return -1;
        }

        if (virStrToLong_ull(groups[4], NULL, 10,
                             &vol->source.extents[0].end) < 0) {
114
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
115
                                  "%s", _("cannot parse device end location"));
116 117 118 119 120
            return -1;
        }

        if ((vol->source.extents[0].path =
             strdup(pool->def->source.devices[0].path)) == NULL) {
121
            virReportOOMError();
122 123 124 125 126
            return -1;
        }
    }

    /* Refresh allocation/capacity/perms */
127
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
128 129
        return -1;

130 131 132 133 134 135 136 137 138 139
    /* set partition type */
    if(STREQ(groups[1], "normal"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
    else if(STREQ(groups[1], "logical"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    else if(STREQ(groups[1], "extended"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_EXTENDED;
    else
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_NONE;

140 141
    vol->type = VIR_STORAGE_VOL_BLOCK;

142 143 144 145 146 147 148 149 150 151 152 153 154 155
    /* The above gets allocation wrong for
     * extended partitions, so overwrite it */
    vol->allocation = vol->capacity =
        (vol->source.extents[0].end - vol->source.extents[0].start);

    if (STRNEQ(groups[2], "metadata"))
        pool->def->allocation += vol->allocation;
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}

static int
156
virStorageBackendDiskMakeFreeExtent(virStoragePoolObjPtr pool,
157 158 159 160
                                    char **const groups)
{
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];

161 162
    if (VIR_REALLOC_N(dev->freeExtents,
                      dev->nfreeExtent + 1) < 0)
163 164 165
        return -1;

    memset(dev->freeExtents +
166 167
           dev->nfreeExtent, 0,
           sizeof(dev->freeExtents[0]));
168

169 170 171 172 173 174 175 176
    /* set type of free area */
    if(STREQ(groups[1], "logical")) {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_LOGICAL;
    } else {
        dev->freeExtents[dev->nfreeExtent].type = VIR_STORAGE_FREE_NORMAL;
    }


177 178 179 180 181 182 183 184
    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 */

185 186 187 188 189
    /* first block reported as free, even if it is not */
    if (dev->freeExtents[dev->nfreeExtent].start == 0) {
        dev->freeExtents[dev->nfreeExtent].start = SECTOR_SIZE;
    }

190 191 192 193 194 195 196 197 198 199 200 201 202
    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;
}


static int
203
virStorageBackendDiskMakeVol(virStoragePoolObjPtr pool,
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
                             size_t ntok ATTRIBUTE_UNUSED,
                             char **const groups,
                             void *data)
{
    /*
     * 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 已提交
220
    /* Remaining data / metadata parts get turn into volumes... */
221 222 223
    if (STREQ(groups[2], "metadata") ||
        STREQ(groups[2], "data")) {
        virStorageVolDefPtr vol = data;
224 225 226 227 228 229 230 231 232 233 234 235

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

237
        return virStorageBackendDiskMakeDataVol(pool, groups, vol);
238 239
    } else if (STREQ(groups[2], "free")) {
        /* ....or free space extents */
240
        return virStorageBackendDiskMakeFreeExtent(pool, groups);
241
    } else {
R
Richard W.M. Jones 已提交
242
        /* This code path should never happen unless someone changed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
         * 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
260
virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
                                    virStorageVolDefPtr vol)
{

    /*
     *  # libvirt_parthelper DEVICE
     * /dev/sda1      normal       data        32256    106928128    106896384
     * /dev/sda2      normal       data    106928640 100027629568  99920701440
     * -              normal   metadata 100027630080 100030242304      2612736
     *
     */
    const char *prog[] = {
        PARTHELPER, pool->def->source.devices[0].path, NULL,
    };

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

277
    return virStorageBackendRunProgNul(pool,
278 279 280 281 282 283
                                       prog,
                                       6,
                                       virStorageBackendDiskMakeVol,
                                       vol);
}

284
static int
285 286 287 288
virStorageBackendDiskMakePoolGeometry(virStoragePoolObjPtr pool,
                                      size_t ntok ATTRIBUTE_UNUSED,
                                      char **const groups,
                                      void *data ATTRIBUTE_UNUSED)
289 290 291 292 293 294 295 296 297 298
{

       pool->def->source.devices[0].geometry.cyliders = atoi(groups[0]);
       pool->def->source.devices[0].geometry.heads = atoi(groups[1]);
       pool->def->source.devices[0].geometry.sectors = atoi(groups[2]);

       return 0;
}

static int
299
virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
300 301 302 303 304
{
    const char *prog[] = {
        PARTHELPER, pool->def->source.devices[0].path, "-g", NULL,
    };

305
    return virStorageBackendRunProgNul(pool,
306 307 308 309 310
                                       prog,
                                       3,
                                       virStorageBackendDiskMakePoolGeometry,
                                       NULL);
}
311 312

static int
313
virStorageBackendDiskRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
314 315
                                 virStoragePoolObjPtr pool)
{
316
    VIR_FREE(pool->def->source.devices[0].freeExtents);
317 318
    pool->def->source.devices[0].nfreeExtent = 0;

319
    virFileWaitForDevices();
320

321
    if (virStorageBackendDiskReadGeometry(pool) != 0) {
322 323 324
        return -1;
    }

325
    return virStorageBackendDiskReadPartitions(pool, NULL);
326 327 328 329 330 331 332
}


/**
 * Write a new partition table header
 */
static int
333
virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
334 335 336 337 338 339 340 341
                               virStoragePoolObjPtr pool,
                               unsigned int flags ATTRIBUTE_UNUSED)
{
    /* eg parted /dev/sda mklabel msdos */
    const char *prog[] = {
        PARTED,
        pool->def->source.devices[0].path,
        "mklabel",
342
        "--script",
343
        ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" :
344
          virStoragePoolFormatDiskTypeToString(pool->def->source.format)),
345 346 347
        NULL,
    };

348
    if (virRun(prog, NULL) < 0)
349 350 351 352 353
        return -1;

    return 0;
}

354 355 356 357
/**
 * Decides what kind of partition type that should be created.
 * Important when the partition table is of msdos type
 */
358
static int
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
virStorageBackendDiskPartTypeToCreate(virStoragePoolObjPtr pool)
{
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
        /* count primary and extended paritions,
           can't be more than 3 to create a new primary partition */
        int i;
        int count = 0;
        for (i = 0; i < pool->volumes.count; i++) {
             if (pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY ||
                 pool->volumes.objs[i]->target.type == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
                     count++;
             }
        }
        if (count >= 4) {
            return VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
        }
    }

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

static int
382
virStorageBackendDiskPartFormat(virStoragePoolObjPtr pool,
383 384 385 386 387 388 389
                                virStorageVolDefPtr vol,
                                char* partFormat)
{
    int i;
    if (pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) {
        const char *partedFormat = virStoragePartedFsTypeTypeToString(vol->target.format);
        if(partedFormat == NULL) {
390
           virStorageReportError(VIR_ERR_INTERNAL_ERROR,
391 392 393 394 395 396 397
                                 "%s", _("Invalid partition type"));
           return -1;
        }
        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++) {
                 if (pool->volumes.objs[i]->target.format == VIR_STORAGE_VOL_DISK_EXTENDED) {
398
                     virStorageReportError(VIR_ERR_INTERNAL_ERROR,
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
                                           "%s", _("extended partition already exists"));
                     return -1;
                 }
            }
            sprintf(partFormat, "%s", partedFormat);
        } 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)) {
                    case VIR_STORAGE_VOL_DISK_TYPE_PRIMARY:
                         sprintf(partFormat, "primary %s", partedFormat);
                         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) {
                                  sprintf(partFormat, "logical %s", partedFormat);
                                  break;
                              }
                         }
                         if (i == pool->volumes.count) {
422
                             virStorageReportError(VIR_ERR_INTERNAL_ERROR,
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
                                                   "%s", _("no extended partition found and no primary partition available"));
                             return -1;
                         }
                         break;
                    default:
                         break;
            }
        }
    } else {
        sprintf(partFormat, "primary");
    }
    return 0;
}

/**
 * Aligns a new partition to nearest cylinder boundry
 * when haveing a msdos partition table type
 * to avoid any problem with all ready existing
 * partitions
 */
static int
444
virStorageBackendDiskPartBoundries(virStoragePoolObjPtr pool,
445 446 447
                                   unsigned long long *start,
                                   unsigned long long *end,
                                   unsigned long long allocation)
448 449 450
{
    int i;
    int smallestExtent = -1;
451 452 453
    unsigned long long smallestSize = 0;
    unsigned long long extraBytes = 0;
    unsigned long long alignedAllocation = allocation;
454
    virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
455 456 457
    unsigned long long cylinderSize = dev->geometry.heads *
                                      dev->geometry.sectors * SECTOR_SIZE;

458
    DEBUG("find free area: allocation %llu, cyl size %llu", allocation, cylinderSize);
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
    int partType = virStorageBackendDiskPartTypeToCreate(pool);

    /* how many extra bytes we have since we allocate
       aligned to the cylinder boundry */
    extraBytes = cylinderSize - (allocation % cylinderSize);

    for (i = 0 ; i < dev->nfreeExtent ; i++) {
         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) {
             /* align to cylinder boundry */
             neededSize += extraBytes;
             if ((*start % cylinderSize) > extraBytes) {
                 /* add an extra cylinder if the offset can't fit within
                    the extra bytes we have */
                 neededSize += cylinderSize;
             }
             /* if we are creating a logical patition, we need one extra
                block between partitions (or actually move start one block) */
             if (partType == VIR_STORAGE_VOL_DISK_TYPE_LOGICAL) {
                 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 */
             } else if(partType == VIR_STORAGE_VOL_DISK_TYPE_PRIMARY &&
                       dev->freeExtents[i].type != VIR_STORAGE_FREE_NORMAL) {
                       continue;
             }
             smallestSize = size;
             smallestExtent = i;
             alignedAllocation = neededSize;
         }
    }

    if (smallestExtent == -1) {
506
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
507 508 509 510
                              "%s", _("no large enough free extent"));
        return -1;
    }

511
    DEBUG("aligned alloc %llu", alignedAllocation);
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
    *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) {
        /* adjust our allocation if start is not at a cylinder boundry */
        *end -= (*start % cylinderSize);
    }

    /* counting in byte, we want the last byte of the current sector */
    *end -= 1;
527
    DEBUG("final aligned start %llu, end %llu", *start, *end);
528 529 530 531 532
    return 0;
}


static int
533
virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
534 535 536 537 538
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol)
{
    char start[100], end[100], partFormat[100];
    unsigned long long startOffset = 0, endOffset = 0;
539 540 541 542 543
    const char *cmdargv[] = {
        PARTED,
        pool->def->source.devices[0].path,
        "mkpart",
        "--script",
544
        partFormat,
545 546 547 548 549
        start,
        end,
        NULL
    };

550
    if (vol->target.encryption != NULL) {
551
        virStorageReportError(VIR_ERR_NO_SUPPORT,
552 553 554 555 556
                              "%s", _("storage pool does not support encrypted "
                                      "volumes"));
        return -1;
    }

557
    if (virStorageBackendDiskPartFormat(pool, vol, partFormat) != 0) {
558 559 560
        return -1;
    }

561
    if (virStorageBackendDiskPartBoundries(pool, &startOffset,
562
                                           &endOffset,
563
                                           vol->capacity) != 0) {
564
       return -1;
565 566 567 568 569 570 571
    }

    snprintf(start, sizeof(start)-1, "%lluB", startOffset);
    start[sizeof(start)-1] = '\0';
    snprintf(end, sizeof(end)-1, "%lluB", endOffset);
    end[sizeof(end)-1] = '\0';

572
    if (virRun(cmdargv, NULL) < 0)
573 574
        return -1;

575
    /* wait for device node to show up */
576
    virFileWaitForDevices();
577

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

582 583 584 585
    /* Specifying a target path is meaningless */
    VIR_FREE(vol->target.path);

    /* Fetch actual extent info, generate key */
586
    if (virStorageBackendDiskReadPartitions(pool, vol) < 0)
587 588 589 590 591
        return -1;

    return 0;
}

592 593
static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
594
                                  virStoragePoolObjPtr pool,
595 596 597 598 599 600
                                  virStorageVolDefPtr vol,
                                  virStorageVolDefPtr inputvol,
                                  unsigned int flags)
{
    virStorageBackendBuildVolFrom build_func;

601
    build_func = virStorageBackendGetBuildVolFromFunction(vol, inputvol);
602 603 604
    if (!build_func)
        return -1;

605
    return build_func(conn, pool, vol, inputvol, flags);
606
}
607 608

static int
609
virStorageBackendDiskDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
C
Cole Robinson 已提交
610 611
                               virStoragePoolObjPtr pool,
                               virStorageVolDefPtr vol,
612 613
                               unsigned int flags ATTRIBUTE_UNUSED)
{
C
Cole Robinson 已提交
614
    char *part_num = NULL;
D
Daniel P. Berrange 已提交
615
    char *devpath = NULL;
C
Cole Robinson 已提交
616
    char *devname, *srcname;
D
Daniel P. Berrange 已提交
617
    int rc = -1;
C
Cole Robinson 已提交
618

619 620
    if (virFileResolveLink(vol->target.path, &devpath) < 0) {
        virReportSystemError(errno,
621 622
                             _("Couldn't read volume target path '%s'"),
                             vol->target.path);
D
Daniel P. Berrange 已提交
623
        goto cleanup;
C
Cole Robinson 已提交
624 625 626 627 628 629 630
    }

    devname = basename(devpath);
    srcname = basename(pool->def->source.devices[0].path);
    DEBUG("devname=%s, srcname=%s", devname, srcname);

    if (!STRPREFIX(devname, srcname)) {
631
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
C
Cole Robinson 已提交
632 633
                              _("Volume path '%s' did not start with parent "
                                "pool source device name."), devname);
D
Daniel P. Berrange 已提交
634
        goto cleanup;
C
Cole Robinson 已提交
635 636 637 638
    }

    part_num = devname + strlen(srcname);

639
    if (*part_num == 0) {
640
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
C
Cole Robinson 已提交
641 642
                              _("cannot parse partition number from target "
                                "'%s'"), devname);
D
Daniel P. Berrange 已提交
643
        goto cleanup;
C
Cole Robinson 已提交
644 645 646 647 648 649 650 651 652 653 654 655
    }

    /* eg parted /dev/sda rm 2 */
    const char *prog[] = {
        PARTED,
        pool->def->source.devices[0].path,
        "rm",
        "--script",
        part_num,
        NULL,
    };

656
    if (virRun(prog, NULL) < 0)
D
Daniel P. Berrange 已提交
657
        goto cleanup;
C
Cole Robinson 已提交
658

D
Daniel P. Berrange 已提交
659 660 661 662
    rc = 0;
cleanup:
    VIR_FREE(devpath);
    return rc;
663 664 665 666 667 668 669 670 671 672 673
}


virStorageBackend virStorageBackendDisk = {
    .type = VIR_STORAGE_POOL_DISK,

    .buildPool = virStorageBackendDiskBuildPool,
    .refreshPool = virStorageBackendDiskRefreshPool,

    .createVol = virStorageBackendDiskCreateVol,
    .deleteVol = virStorageBackendDiskDeleteVol,
674
    .buildVolFrom = virStorageBackendDiskBuildVolFrom,
675
};