storage_backend_fs.c 42.6 KB
Newer Older
1 2 3
/*
 * storage_backend_fs.c: storage backend for FS and directory 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 25 26 27 28 29 30 31 32 33 34 35
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

36 37 38 39
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>

40
#if WITH_BLKID
O
Osier Yang 已提交
41 42 43
# include <blkid/blkid.h>
#endif

44
#include "virerror.h"
45 46
#include "storage_backend_fs.h"
#include "storage_conf.h"
47
#include "virstoragefile.h"
48
#include "vircommand.h"
49
#include "viralloc.h"
50
#include "virxml.h"
E
Eric Blake 已提交
51
#include "virfile.h"
52
#include "virlog.h"
53
#include "virstring.h"
54

55
#define VIR_FROM_THIS VIR_FROM_STORAGE
56

57 58
VIR_LOG_INIT("storage.storage_backend_fs");

59 60 61 62
#define VIR_STORAGE_VOL_FS_OPEN_FLAGS    (VIR_STORAGE_VOL_OPEN_DEFAULT | \
                                          VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_PROBE_FLAGS   (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
                                          VIR_STORAGE_VOL_OPEN_NOERROR)
63

E
Eric Blake 已提交
64
static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
65
virStorageBackendProbeTarget(virStorageSourcePtr target,
66
                             char **backingStore,
67
                             int *backingStoreFormat,
68 69
                             virStorageEncryptionPtr *encryption)
{
70 71
    int fd = -1;
    int ret = -1;
72
    virStorageFileMetadata *meta = NULL;
E
Eric Blake 已提交
73
    struct stat sb;
74 75
    char *header = NULL;
    ssize_t len = VIR_STORAGE_MAX_HEADER;
76

E
Eric Blake 已提交
77 78
    *backingStore = NULL;
    *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
79 80 81
    if (encryption)
        *encryption = NULL;

82
    if ((ret = virStorageBackendVolOpen(target->path, &sb,
83
                                        VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
84
        goto error; /* Take care to propagate ret, it is not always -1 */
85
    fd = ret;
86

87
    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb)) < 0) {
88
        goto error;
89 90
    }

91 92 93 94 95 96 97 98
    if (S_ISDIR(sb.st_mode)) {
        target->format = VIR_STORAGE_FILE_DIR;
    } else {
        if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) {
            virReportSystemError(errno, _("cannot read header '%s'"),
                                 target->path);
            goto error;
        }
99

100 101 102 103 104 105 106 107 108
        target->format = virStorageFileProbeFormatFromBuf(target->path,
                                                          header, len);
        if (target->format < 0) {
            ret = -1;
            goto error;
        }

        if (!(meta = virStorageFileGetMetadataFromBuf(target->path,
                                                      header, len,
109 110 111
                                                      target->format,
                                                      backingStore,
                                                      backingStoreFormat))) {
112 113 114
            ret = -1;
            goto error;
        }
115
    }
116

117
    VIR_FORCE_CLOSE(fd);
118

119 120 121 122 123 124 125 126 127 128 129
    if (meta && *backingStore &&
        *backingStoreFormat == VIR_STORAGE_FILE_AUTO &&
        virStorageIsFile(*backingStore)) {
        if ((ret = virStorageFileProbeFormat(*backingStore, -1, -1)) < 0) {
            /* If the backing file is currently unavailable, only log an error,
             * but continue. Returning -1 here would disable the whole storage
             * pool, making it unavailable for even maintenance. */
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot probe backing volume format: %s"),
                           *backingStore);
            ret = -3;
130
        } else {
131
            *backingStoreFormat = ret;
132
            ret = 0;
133
        }
E
Eric Blake 已提交
134
    } else {
135
        ret = 0;
136 137
    }

138 139
    if (meta && meta->capacity)
        target->capacity = meta->capacity;
140

141 142 143
    if (encryption && meta && meta->encryption) {
        *encryption = meta->encryption;
        meta->encryption = NULL;
144 145 146 147 148 149 150 151 152 153 154

        switch (target->format) {
        case VIR_STORAGE_FILE_QCOW:
        case VIR_STORAGE_FILE_QCOW2:
            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
            break;
        default:
            break;
        }

        /* XXX ideally we'd fill in secret UUID here
E
Eric Blake 已提交
155
         * but we cannot guarantee 'conn' is non-NULL
156 157 158 159 160
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

161
    virBitmapFree(target->features);
162 163 164 165
    if (meta) {
        target->features = meta->features;
        meta->features = NULL;
    }
166

167
    if (meta && meta->compat) {
168 169 170 171 172
        VIR_FREE(target->compat);
        target->compat = meta->compat;
        meta->compat = NULL;
    }

173
    goto cleanup;
174

175
 error:
176 177
    VIR_FORCE_CLOSE(fd);

178
 cleanup:
179
    virStorageFileFreeMetadata(meta);
180
    VIR_FREE(header);
181 182
    return ret;

183 184 185
}

#if WITH_STORAGE_FS
186

187
# include <mntent.h>
188

189 190
struct _virNetfsDiscoverState {
    const char *host;
191
    virStoragePoolSourceList list;
192 193 194 195 196
};

typedef struct _virNetfsDiscoverState virNetfsDiscoverState;

static int
197
virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
198 199 200 201
                                                  void *data)
{
    virNetfsDiscoverState *state = data;
    const char *name, *path;
202 203
    virStoragePoolSource *src = NULL;
    int ret = -1;
204 205 206

    path = groups[0];

207
    if (!(name = strrchr(path, '/'))) {
208 209
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (no /): %s"), path);
210
        goto cleanup;
211 212 213
    }
    name += 1;
    if (*name == '\0') {
214 215
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (ends in /): %s"), path);
216
        goto cleanup;
217 218
    }

219
    if (!(src = virStoragePoolSourceListNewSource(&state->list)))
220
        goto cleanup;
221

222
    if (VIR_ALLOC_N(src->hosts, 1) < 0)
223
        goto cleanup;
224
    src->nhost = 1;
225

226 227
    if (VIR_STRDUP(src->hosts[0].name, state->host) < 0 ||
        VIR_STRDUP(src->dir, path) < 0)
228
        goto cleanup;
229
    src->format = VIR_STORAGE_POOL_NETFS_NFS;
230

231
    ret = 0;
232
 cleanup:
233
    return ret;
234 235
}

236

237
static int
238
virStorageBackendFileSystemNetFindNFSPoolSources(virNetfsDiscoverState *state)
239
{
240 241
    int ret = -1;

242 243 244 245 246 247 248 249 250 251 252 253 254 255
    /*
     *  # showmount --no-headers -e HOSTNAME
     *  /tmp   *
     *  /A dir demo1.foo.bar,demo2.foo.bar
     *
     * Extract directory name (including possible interior spaces ...).
     */

    const char *regexes[] = {
        "^(/.*\\S) +\\S+$"
    };
    int vars[] = {
        1
    };
256 257 258 259 260 261 262 263 264 265 266

    virCommandPtr cmd = NULL;

    cmd = virCommandNewArgList(SHOWMOUNT,
                               "--no-headers",
                               "--exports",
                               state->host,
                               NULL);

    if (virCommandRunRegex(cmd, 1, regexes, vars,
                           virStorageBackendFileSystemNetFindPoolSourcesFunc,
267
                           state, NULL) < 0)
268
        goto cleanup;
269

270 271 272
    ret = 0;

 cleanup:
273
    virCommandFree(cmd);
274
    return ret;
275 276 277 278 279 280 281 282
}


static char *
virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
                                              const char *srcSpec,
                                              unsigned int flags)
{
283 284 285 286 287 288 289 290
    virNetfsDiscoverState state = {
        .host = NULL,
        .list = {
            .type = VIR_STORAGE_POOL_NETFS,
            .nsources = 0,
            .sources = NULL
        }
    };
291
    virStoragePoolSourcePtr source = NULL;
292
    char *ret = NULL;
293
    size_t i;
294
    int retNFS = -1, retGluster = -1;
295

E
Eric Blake 已提交
296 297
    virCheckFlags(0, NULL);

298
    if (!srcSpec) {
299 300
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("hostname must be specified for netfs sources"));
301 302 303 304 305 306
        return NULL;
    }

    if (!(source = virStoragePoolDefParseSourceString(srcSpec,
                                                      VIR_STORAGE_POOL_NETFS)))
        return NULL;
307

308
    if (source->nhost != 1) {
309 310
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Expected exactly 1 host for the storage pool"));
311 312 313 314
        goto cleanup;
    }

    state.host = source->hosts[0].name;
315

316
    retNFS = virStorageBackendFileSystemNetFindNFSPoolSources(&state);
317

318 319 320
# ifdef GLUSTER_CLI
    retGluster =
        virStorageBackendFindGlusterPoolSources(state.host,
321
                                                VIR_STORAGE_POOL_NETFS_GLUSTERFS,
322 323 324 325
                                                &state.list);
# endif
    /* If both fail, then we won't return an empty list - return an error */
    if (retNFS < 0 && retGluster < 0)
326 327
        goto cleanup;

328
    if (!(ret = virStoragePoolSourceListFormat(&state.list)))
329 330 331
        goto cleanup;

 cleanup:
332
    for (i = 0; i < state.list.nsources; i++)
333 334
        virStoragePoolSourceClear(&state.list.sources[i]);
    VIR_FREE(state.list.sources);
335

336
    virStoragePoolSourceFree(source);
337
    return ret;
338 339 340
}


341 342 343 344 345 346 347 348 349
/**
 * @conn connection to report errors against
 * @pool storage pool to check for status
 *
 * Determine if a storage pool is already mounted
 *
 * Return 0 if not mounted, 1 if mounted, -1 on error
 */
static int
350 351
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool)
{
352
    FILE *mtab;
353 354
    struct mntent ent;
    char buf[1024];
355 356

    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
357
        virReportSystemError(errno,
358 359
                             _("cannot read mount list '%s'"),
                             _PATH_MOUNTED);
360 361 362
        return -1;
    }

363 364
    while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
        if (STREQ(ent.mnt_dir, pool->def->target.path)) {
365
            VIR_FORCE_FCLOSE(mtab);
366 367 368 369
            return 1;
        }
    }

370
    VIR_FORCE_FCLOSE(mtab);
371 372 373 374 375 376 377 378 379 380 381 382 383
    return 0;
}

/**
 * @conn connection to report errors against
 * @pool storage pool to mount
 *
 * Ensure that a FS storage pool is mounted on its target location.
 * If already mounted, this is a no-op
 *
 * Returns 0 if successfully mounted, -1 on error
 */
static int
384 385
virStorageBackendFileSystemMount(virStoragePoolObjPtr pool)
{
386
    char *src = NULL;
387 388 389
    /* 'mount -t auto' doesn't seem to auto determine nfs (or cifs),
     *  while plain 'mount' does. We have to craft separate argvs to
     *  accommodate this */
390 391 392 393 394 395
    bool netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                    pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
    bool glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                      pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
    virCommandPtr cmd = NULL;
    int ret = -1;
396
    int rc;
397 398

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
399
        if (pool->def->source.nhost != 1) {
400 401
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Expected exactly 1 host for the storage pool"));
402 403 404
            return -1;
        }
        if (pool->def->source.hosts[0].name == NULL) {
405 406
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source host"));
407 408 409
            return -1;
        }
        if (pool->def->source.dir == NULL) {
410 411
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source path"));
412 413 414 415
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
416 417
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source device"));
418 419 420 421
            return -1;
        }
    }

J
Jim Meyering 已提交
422
    /* Short-circuit if already mounted */
423 424 425 426 427 428
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 0) {
        if (rc == 1) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("Target '%s' is already mounted"),
                           pool->def->target.path);
        }
429
        return -1;
430 431 432
    }

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
433
        if (virAsprintf(&src, "%s:%s",
434
                        pool->def->source.hosts[0].name,
435
                        pool->def->source.dir) == -1)
436
            return -1;
437

438
    } else {
439
        if (VIR_STRDUP(src, pool->def->source.devices[0].path) < 0)
440
            return -1;
441 442
    }

443 444 445 446 447 448
    if (netauto)
        cmd = virCommandNewArgList(MOUNT,
                                   src,
                                   pool->def->target.path,
                                   NULL);
    else if (glusterfs)
449 450 451 452 453 454 455 456 457 458
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
                                   (pool->def->type == VIR_STORAGE_POOL_FS ?
                                    virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
                                    virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format)),
                                   src,
                                   "-o",
                                   "direct-io-mode=1",
                                   pool->def->target.path,
                                   NULL);
459 460 461 462 463 464 465 466 467 468 469 470 471 472
    else
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
                                   (pool->def->type == VIR_STORAGE_POOL_FS ?
                                    virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
                                    virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format)),
                                   src,
                                   pool->def->target.path,
                                   NULL);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
473
 cleanup:
474
    virCommandFree(cmd);
475
    VIR_FREE(src);
476
    return ret;
477 478 479 480 481 482 483
}

/**
 * @conn connection to report errors against
 * @pool storage pool to unmount
 *
 * Ensure that a FS storage pool is not mounted on its target location.
484
 * If already unmounted, this is a no-op.
485 486 487 488
 *
 * Returns 0 if successfully unmounted, -1 on error
 */
static int
489 490
virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool)
{
491 492
    virCommandPtr cmd = NULL;
    int ret = -1;
493
    int rc;
494 495

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
496
        if (pool->def->source.nhost != 1) {
497 498
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Expected exactly 1 host for the storage pool"));
499 500 501
            return -1;
        }
        if (pool->def->source.hosts[0].name == NULL) {
502 503
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source host"));
504 505 506
            return -1;
        }
        if (pool->def->source.dir == NULL) {
507 508
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source dir"));
509 510 511 512
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
513 514
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source device"));
515 516 517 518 519
            return -1;
        }
    }

    /* Short-circuit if already unmounted */
520 521
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1)
        return rc;
522

523 524 525
    cmd = virCommandNewArgList(UMOUNT,
                               pool->def->target.path,
                               NULL);
526

527 528 529 530
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
531
 cleanup:
532 533
    virCommandFree(cmd);
    return ret;
534 535 536 537
}
#endif /* WITH_STORAGE_FS */


538 539 540 541 542 543
static int
virStorageBackendFileSystemCheck(virConnectPtr conn ATTRIBUTE_UNUSED,
                                 virStoragePoolObjPtr pool,
                                 bool *isActive)
{
    if (pool->def->type == VIR_STORAGE_POOL_DIR) {
544
        *isActive = virFileExists(pool->def->target.path);
545 546 547
#if WITH_STORAGE_FS
    } else {
        int ret;
548
        *isActive = false;
549 550 551 552 553 554 555 556 557 558 559 560
        if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
            if (ret < 0)
                return -1;
            *isActive = true;
        }
#endif /* WITH_STORAGE_FS */
    }

    return 0;
}

#if WITH_STORAGE_FS
561 562 563 564
/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
565 566
 * Starts a directory or FS based storage pool.  The underlying source
 * device will be mounted for FS based pools.
567 568 569 570
 *
 * Returns 0 on success, -1 on error
 */
static int
571
virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED,
572 573 574
                                 virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
575
        virStorageBackendFileSystemMount(pool) < 0)
576 577 578 579 580 581
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */

582
#if WITH_BLKID
O
Osier Yang 已提交
583 584
static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device,
585 586
                                 const char *format)
{
O
Osier Yang 已提交
587 588 589 590 591 592 593 594 595 596

    virStoragePoolProbeResult ret = FILESYSTEM_PROBE_ERROR;
    blkid_probe probe = NULL;
    const char *fstype = NULL;
    char *names[2], *libblkid_format = NULL;

    VIR_DEBUG("Probing for existing filesystem of type %s on device %s",
              format, device);

    if (blkid_known_fstype(format) == 0) {
597 598 599 600
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                       _("Not capable of probing for "
                         "filesystem of type %s"),
                       format);
O
Osier Yang 已提交
601 602 603 604 605
        goto error;
    }

    probe = blkid_new_probe_from_filename(device);
    if (probe == NULL) {
606 607 608 609
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                       _("Failed to create filesystem probe "
                         "for device %s"),
                       device);
O
Osier Yang 已提交
610 611 612
        goto error;
    }

613
    if (VIR_STRDUP(libblkid_format, format) < 0)
O
Osier Yang 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627
        goto error;

    names[0] = libblkid_format;
    names[1] = NULL;

    blkid_probe_filter_superblocks_type(probe,
                                        BLKID_FLTR_ONLYIN,
                                        names);

    if (blkid_do_probe(probe) != 0) {
        VIR_INFO("No filesystem of type '%s' found on device '%s'",
                 format, device);
        ret = FILESYSTEM_PROBE_NOT_FOUND;
    } else if (blkid_probe_lookup_value(probe, "TYPE", &fstype, NULL) == 0) {
628 629 630 631
        virReportError(VIR_ERR_STORAGE_POOL_BUILT,
                       _("Existing filesystem of type '%s' found on "
                         "device '%s'"),
                       fstype, device);
O
Osier Yang 已提交
632 633 634 635
        ret = FILESYSTEM_PROBE_FOUND;
    }

    if (blkid_do_probe(probe) != 1) {
636
        virReportError(VIR_ERR_STORAGE_PROBE_FAILED, "%s",
637 638
                       _("Found additional probes to run, "
                         "filesystem probing may be incorrect"));
O
Osier Yang 已提交
639 640 641
        ret = FILESYSTEM_PROBE_ERROR;
    }

642
 error:
O
Osier Yang 已提交
643 644 645 646 647 648 649 650 651
    VIR_FREE(libblkid_format);

    if (probe != NULL) {
        blkid_free_probe(probe);
    }

    return ret;
}

652
#else /* #if WITH_BLKID */
O
Osier Yang 已提交
653 654 655 656 657

static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device ATTRIBUTE_UNUSED,
                                 const char *format ATTRIBUTE_UNUSED)
{
658
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
659 660
                   _("probing for filesystems is unsupported "
                     "by this build"));
O
Osier Yang 已提交
661 662 663 664

    return FILESYSTEM_PROBE_ERROR;
}

665
#endif /* #if WITH_BLKID */
O
Osier Yang 已提交
666

667 668
/* some platforms don't support mkfs */
#ifdef MKFS
O
Osier Yang 已提交
669 670 671 672 673 674 675
static int
virStorageBackendExecuteMKFS(const char *device,
                             const char *format)
{
    int ret = 0;
    virCommandPtr cmd = NULL;

J
Ján Tomko 已提交
676 677 678 679 680 681 682
    cmd = virCommandNewArgList(MKFS, "-t", format, NULL);

    /* use the force, otherwise mkfs.xfs won't overwrite existing fs */
    if (STREQ(format, "xfs"))
        virCommandAddArg(cmd, "-f");

    virCommandAddArg(cmd, device);
O
Osier Yang 已提交
683 684 685 686 687 688 689 690

    if (virCommandRun(cmd, NULL) < 0) {
        virReportSystemError(errno,
                             _("Failed to make filesystem of "
                               "type '%s' on device '%s'"),
                             format, device);
        ret = -1;
    }
691 692

    virCommandFree(cmd);
O
Osier Yang 已提交
693 694
    return ret;
}
695 696 697 698 699
#else /* #ifdef MKFS */
static int
virStorageBackendExecuteMKFS(const char *device ATTRIBUTE_UNUSED,
                             const char *format ATTRIBUTE_UNUSED)
{
700 701 702 703 704
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("mkfs is not supported on this platform: "
                     "Failed to make filesystem of "
                     "type '%s' on device '%s'"),
                   format, device);
705 706 707
    return -1;
}
#endif /* #ifdef MKFS */
O
Osier Yang 已提交
708 709 710 711 712 713 714 715 716 717

static int
virStorageBackendMakeFileSystem(virStoragePoolObjPtr pool,
                                unsigned int flags)
{
    const char *device = NULL, *format = NULL;
    bool ok_to_mkfs = false;
    int ret = -1;

    if (pool->def->source.devices == NULL) {
718 719 720
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("No source device specified when formatting pool '%s'"),
                       pool->def->name);
O
Osier Yang 已提交
721 722 723 724 725 726 727 728
        goto error;
    }

    device = pool->def->source.devices[0].path;
    format = virStoragePoolFormatFileSystemTypeToString(pool->def->source.format);
    VIR_DEBUG("source device: '%s' format: '%s'", device, format);

    if (!virFileExists(device)) {
729 730 731
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Source device does not exist when formatting pool '%s'"),
                       pool->def->name);
O
Osier Yang 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
        goto error;
    }

    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
        ok_to_mkfs = true;
    } else if (flags & VIR_STORAGE_POOL_BUILD_NO_OVERWRITE &&
               virStorageBackendFileSystemProbe(device, format) ==
               FILESYSTEM_PROBE_NOT_FOUND) {
        ok_to_mkfs = true;
    }

    if (ok_to_mkfs) {
        ret = virStorageBackendExecuteMKFS(device, format);
    }

747
 error:
O
Osier Yang 已提交
748 749 750
    return ret;
}

751 752 753 754

/**
 * @conn connection to report errors against
 * @pool storage pool to build
E
Eric Blake 已提交
755
 * @flags controls the pool formatting behaviour
756 757 758
 *
 * Build a directory or FS based storage pool.
 *
O
Osier Yang 已提交
759 760 761 762 763 764 765
 * If no flag is set, it only makes the directory; If
 * VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it probes to determine if
 * filesystem already exists on the target device, renurning an error
 * if exists, or using mkfs to format the target device if not; If
 * VIR_STORAGE_POOL_BUILD_OVERWRITE is set, mkfs is always executed,
 * any existed data on the target device is overwritten unconditionally.
 *
766
 * The underlying source device is mounted for FS based pools.
767 768 769 770
 *
 * Returns 0 on success, -1 on error
 */
static int
771
virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
772
                                 virStoragePoolObjPtr pool,
E
Eric Blake 已提交
773
                                 unsigned int flags)
774
{
775
    int err, ret = -1;
O
Osier Yang 已提交
776 777
    char *parent = NULL;
    char *p = NULL;
778

O
Osier Yang 已提交
779 780 781 782 783 784
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);

    if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {

785
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
786 787
                       _("Overwrite and no overwrite flags"
                         " are mutually exclusive"));
O
Osier Yang 已提交
788 789
        goto error;
    }
E
Eric Blake 已提交
790

791
    if (VIR_STRDUP(parent, pool->def->target.path) < 0)
792 793
        goto error;
    if (!(p = strrchr(parent, '/'))) {
794 795 796
        virReportError(VIR_ERR_INVALID_ARG,
                       _("path '%s' is not absolute"),
                       pool->def->target.path);
797
        goto error;
798 799
    }

800 801 802 803
    if (p != parent) {
        /* assure all directories in the path prior to the final dir
         * exist, with default uid/gid/mode. */
        *p = '\0';
804 805
        if (virFileMakePath(parent) < 0) {
            virReportSystemError(errno, _("cannot create path '%s'"),
806 807 808 809 810 811 812 813
                                 parent);
            goto error;
        }
    }

    /* Now create the final dir in the path with the uid/gid/mode
     * requested in the config. If the dir already exists, just set
     * the perms. */
814 815
    if ((err = virDirCreate(pool->def->target.path,
                            pool->def->target.perms.mode,
816 817
                            pool->def->target.perms.uid,
                            pool->def->target.perms.gid,
818 819 820 821 822 823 824
                            VIR_DIR_CREATE_FORCE_PERMS |
                            VIR_DIR_CREATE_ALLOW_EXIST |
                            (pool->def->type == VIR_STORAGE_POOL_NETFS
                            ? VIR_DIR_CREATE_AS_UID : 0)) < 0)) {
        virReportSystemError(-err, _("cannot create path '%s'"),
                             pool->def->target.path);
        goto error;
825
    }
O
Osier Yang 已提交
826

827 828
    /* Reflect the actual uid and gid to the config. */
    if (pool->def->target.perms.uid == (uid_t) -1)
829
        pool->def->target.perms.uid = geteuid();
830
    if (pool->def->target.perms.gid == (gid_t) -1)
831
        pool->def->target.perms.gid = getegid();
832

O
Osier Yang 已提交
833 834 835 836 837 838
    if (flags != 0) {
        ret = virStorageBackendMakeFileSystem(pool, flags);
    } else {
        ret = 0;
    }

839
 error:
840 841
    VIR_FREE(parent);
    return ret;
842 843 844 845 846 847 848 849
}


/**
 * Iterate over the pool's directory and enumerate all disk images
 * within it. This is non-recursive.
 */
static int
850
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
851 852 853 854 855
                                   virStoragePoolObjPtr pool)
{
    DIR *dir;
    struct dirent *ent;
    struct statvfs sb;
856
    virStorageVolDefPtr vol = NULL;
857 858

    if (!(dir = opendir(pool->def->target.path))) {
859
        virReportSystemError(errno,
860 861
                             _("cannot open path '%s'"),
                             pool->def->target.path);
862 863 864 865 866
        goto cleanup;
    }

    while ((ent = readdir(dir)) != NULL) {
        int ret;
867
        char *backingStore;
868
        int backingStoreFormat;
869

870
        if (VIR_ALLOC(vol) < 0)
871
            goto cleanup;
872

873 874
        if (VIR_STRDUP(vol->name, ent->d_name) < 0)
            goto cleanup;
875

876
        vol->type = VIR_STORAGE_VOL_FILE;
877
        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
878 879 880
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path,
                        vol->name) == -1)
881
            goto cleanup;
882

883 884
        if (VIR_STRDUP(vol->key, vol->target.path) < 0)
            goto cleanup;
885

886
        if ((ret = virStorageBackendProbeTarget(&vol->target,
887
                                                &backingStore,
888
                                                &backingStoreFormat,
889
                                                &vol->target.encryption)) < 0) {
890
            if (ret == -2) {
891
                /* Silently ignore non-regular files,
892
                 * eg '.' '..', 'lost+found', dangling symbolic link */
893 894
                virStorageVolDefFree(vol);
                vol = NULL;
895
                continue;
896 897 898 899 900 901 902 903 904
            } else if (ret == -3) {
                /* The backing file is currently unavailable, its format is not
                 * explicitly specified, the probe to auto detect the format
                 * failed: continue with faked RAW format, since AUTO will
                 * break virStorageVolTargetDefFormat() generating the line
                 * <format type='...'/>. */
                backingStoreFormat = VIR_STORAGE_FILE_RAW;
            } else
                goto cleanup;
905 906
        }

907 908 909 910
        /* directory based volume */
        if (vol->target.format == VIR_STORAGE_FILE_DIR)
            vol->type = VIR_STORAGE_VOL_DIR;

911
        if (backingStore != NULL) {
912 913 914
            vol->backingStore.path = backingStore;
            vol->backingStore.format = backingStoreFormat;

915 916 917 918 919 920
            ignore_value(virStorageBackendUpdateVolTargetInfo(
                                               &vol->backingStore, false,
                                               VIR_STORAGE_VOL_OPEN_DEFAULT));
            /* If this failed, the backing file is currently unavailable,
             * the capacity, allocation, owner, group and mode are unknown.
             * An error message was raised, but we just continue. */
921 922 923
        }


924
        if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
925
            goto cleanup;
926 927 928 929 930
    }
    closedir(dir);


    if (statvfs(pool->def->target.path, &sb) < 0) {
931
        virReportSystemError(errno,
932 933
                             _("cannot statvfs path '%s'"),
                             pool->def->target.path);
934 935 936 937 938
        return -1;
    }
    pool->def->capacity = ((unsigned long long)sb.f_frsize *
                           (unsigned long long)sb.f_blocks);
    pool->def->available = ((unsigned long long)sb.f_bfree *
939
                            (unsigned long long)sb.f_frsize);
940 941 942 943 944
    pool->def->allocation = pool->def->capacity - pool->def->available;

    return 0;

 cleanup:
945 946
    if (dir)
        closedir(dir);
947
    virStorageVolDefFree(vol);
948 949 950 951 952 953 954
    virStoragePoolObjClearVols(pool);
    return -1;
}


/**
 * @conn connection to report errors against
955
 * @pool storage pool to stop
956
 *
957 958
 * Stops a file storage pool.  The underlying source device is unmounted
 * for FS based pools.  Any cached data about volumes is released.
959
 *
960
 * Returns 0 on success, -1 on error.
961 962 963
 */
#if WITH_STORAGE_FS
static int
964
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
965 966
                                virStoragePoolObjPtr pool)
{
967
    if (virStorageBackendFileSystemUnmount(pool) < 0)
968 969 970 971 972 973 974 975 976
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */


/**
 * @conn connection to report errors against
977
 * @pool storage pool to delete
978
 *
979
 * Delete a directory based storage pool
980 981 982 983
 *
 * Returns 0 on success, -1 on error
 */
static int
984
virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
985
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
986
                                  unsigned int flags)
987
{
E
Eric Blake 已提交
988 989
    virCheckFlags(0, -1);

990 991
    /* XXX delete all vols first ? */

992
    if (rmdir(pool->def->target.path) < 0) {
993
        virReportSystemError(errno,
994
                             _("failed to remove pool '%s'"),
995
                             pool->def->target.path);
996 997 998 999 1000 1001 1002 1003
        return -1;
    }

    return 0;
}


/**
1004 1005 1006 1007
 * Set up a volume definition to be added to a pool's volume list, but
 * don't do any file creation or allocation. By separating the two processes,
 * we allow allocation progress reporting (by polling the volume's 'info'
 * function), and can drop the parent pool lock during the (slow) allocation.
1008 1009
 */
static int
1010
virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
1011 1012 1013 1014
                                     virStoragePoolObjPtr pool,
                                     virStorageVolDefPtr vol)
{

1015 1016
    vol->type = VIR_STORAGE_VOL_FILE;

R
Ryota Ozaki 已提交
1017
    VIR_FREE(vol->target.path);
1018 1019
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
1020
                    vol->name) == -1)
1021
        return -1;
1022

1023 1024 1025 1026 1027 1028 1029
    if (virFileExists(vol->target.path)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("volume target path '%s' already exists"),
                       vol->target.path);
        return -1;
    }

R
Ryota Ozaki 已提交
1030
    VIR_FREE(vol->key);
1031
    return VIR_STRDUP(vol->key, vol->target.path);
1032 1033
}

1034
static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
1035
                         virStoragePoolObjPtr pool,
1036
                         virStorageVolDefPtr vol,
1037
                         virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1038 1039
                         unsigned int flags)
{
1040 1041
    int err;

E
Eric Blake 已提交
1042 1043
    virCheckFlags(0, -1);

1044
    if (inputvol) {
1045 1046 1047
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("cannot copy from volume to a directory volume"));
1048 1049 1050
        return -1;
    }

1051 1052 1053
    if ((err = virDirCreate(vol->target.path, vol->target.perms->mode,
                            vol->target.perms->uid,
                            vol->target.perms->gid,
1054
                            VIR_DIR_CREATE_FORCE_PERMS |
1055
                            (pool->def->type == VIR_STORAGE_POOL_NETFS
1056 1057
                             ? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
        virReportSystemError(-err, _("cannot create path '%s'"),
1058 1059 1060
                             vol->target.path);
        return -1;
    }
1061

1062 1063
    return 0;
}
1064

1065
static int
1066
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1067
                                     virStoragePoolObjPtr pool,
1068
                                     virStorageVolDefPtr vol,
1069 1070
                                     virStorageVolDefPtr inputvol,
                                     unsigned int flags)
1071
{
1072
    virStorageBackendBuildVolFrom create_func;
1073
    int tool_type;
1074

1075
    if (inputvol) {
1076
        if (vol->target.encryption != NULL) {
1077 1078 1079 1080
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("storage pool does not support "
                                   "building encrypted volumes from "
                                   "other volumes"));
1081 1082
            return -1;
        }
1083
        create_func = virStorageBackendGetBuildVolFromFunction(vol,
1084
                                                               inputvol);
1085 1086
        if (!create_func)
            return -1;
1087
    } else if (vol->target.format == VIR_STORAGE_FILE_RAW) {
1088
        create_func = virStorageBackendCreateRaw;
1089
    } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
1090
        create_func = createFileDir;
1091
    } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
1092
        create_func = virStorageBackendFSImageToolTypeToFunc(tool_type);
1093 1094

        if (!create_func)
1095
            return -1;
1096
    } else {
1097 1098 1099
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("creation of non-raw images "
                               "is not supported without qemu-img"));
1100 1101 1102
        return -1;
    }

1103
    if (create_func(conn, pool, vol, inputvol, flags) < 0)
1104
        return -1;
1105 1106 1107
    return 0;
}

1108 1109 1110 1111 1112 1113 1114
/**
 * Allocate a new file as a volume. This is either done directly
 * for raw/sparse files, or by calling qemu-img/qcow-create for
 * special kinds of files
 */
static int
virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1115
                                    virStoragePoolObjPtr pool,
1116
                                    virStorageVolDefPtr vol,
1117 1118
                                    unsigned int flags)
{
1119 1120 1121
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);

    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags);
1122 1123 1124 1125 1126 1127 1128
}

/*
 * Create a storage vol using 'inputvol' as input
 */
static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
1129
                                        virStoragePoolObjPtr pool,
1130 1131
                                        virStorageVolDefPtr vol,
                                        virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1132 1133
                                        unsigned int flags)
{
1134
    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
E
Eric Blake 已提交
1135

1136
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags);
1137
}
1138 1139

/**
1140
 * Remove a volume - no support for BLOCK and NETWORK yet
1141 1142
 */
static int
1143
virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
1144 1145
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
E
Eric Blake 已提交
1146
                                     unsigned int flags)
1147
{
E
Eric Blake 已提交
1148 1149
    virCheckFlags(0, -1);

1150
    switch ((virStorageVolType) vol->type) {
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
    case VIR_STORAGE_VOL_FILE:
        if (unlink(vol->target.path) < 0) {
            /* Silently ignore failures where the vol has already gone away */
            if (errno != ENOENT) {
                virReportSystemError(errno,
                                     _("cannot unlink file '%s'"),
                                     vol->target.path);
                return -1;
            }
        }
        break;
    case VIR_STORAGE_VOL_DIR:
        if (rmdir(vol->target.path) < 0) {
1164
            virReportSystemError(errno,
1165
                                 _("cannot remove directory '%s'"),
1166
                                 vol->target.path);
1167 1168
            return -1;
        }
1169 1170 1171
        break;
    case VIR_STORAGE_VOL_BLOCK:
    case VIR_STORAGE_VOL_NETWORK:
1172 1173
    case VIR_STORAGE_VOL_NETDIR:
    case VIR_STORAGE_VOL_LAST:
1174 1175 1176
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("removing block or network volumes is not supported: %s"),
                       vol->target.path);
1177
        return -1;
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    }
    return 0;
}


/**
 * Update info about a volume's capacity/allocation
 */
static int
virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
                                      virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                      virStorageVolDefPtr vol)
{
1191 1192
    int ret;

1193
    /* Refresh allocation / permissions info in case its changed */
1194
    ret = virStorageBackendUpdateVolInfo(vol, false,
1195
                                         VIR_STORAGE_VOL_FS_OPEN_FLAGS);
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
    if (ret < 0)
        return ret;

    /* Load any secrets if posible */
    if (vol->target.encryption &&
        vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_QCOW &&
        vol->target.encryption->nsecrets == 0) {
        virSecretPtr sec;
        virStorageEncryptionSecretPtr encsec = NULL;

        sec = virSecretLookupByUsage(conn,
                                     VIR_SECRET_USAGE_TYPE_VOLUME,
                                     vol->target.path);
        if (sec) {
            if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 ||
                VIR_ALLOC(encsec) < 0) {
                VIR_FREE(vol->target.encryption->secrets);
                virSecretFree(sec);
                return -1;
            }

            vol->target.encryption->nsecrets = 1;
            vol->target.encryption->secrets[0] = encsec;

            encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
            virSecretGetUUID(sec, encsec->uuid);
            virSecretFree(sec);
        }
    }

    return 0;
1227 1228
}

1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
static int
virStorageBackendFilesystemResizeQemuImg(const char *path,
                                         unsigned long long capacity)
{
    int ret = -1;
    char *img_tool;
    virCommandPtr cmd = NULL;

    /* KVM is usually ahead of qemu on features, so try that first */
    img_tool = virFindFileInPath("kvm-img");
    if (!img_tool)
        img_tool = virFindFileInPath("qemu-img");

    if (!img_tool) {
1243 1244
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to find kvm-img or qemu-img"));
1245 1246 1247
        return -1;
    }

1248 1249 1250 1251
    /* Round capacity as qemu-img resize errors out on sizes which are not
     * a multiple of 512 */
    capacity = VIR_ROUND_UP(capacity, 512);

1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
    cmd = virCommandNew(img_tool);
    virCommandAddArgList(cmd, "resize", path, NULL);
    virCommandAddArgFormat(cmd, "%llu", capacity);

    ret = virCommandRun(cmd, NULL);

    VIR_FREE(img_tool);
    virCommandFree(cmd);

    return ret;
}

/**
 * Resize a volume
 */
static int
virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
                                     unsigned long long capacity,
                                     unsigned int flags)
{
1274 1275 1276 1277 1278 1279
    virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1);

    bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE;

    if (vol->target.format == VIR_STORAGE_FILE_RAW) {
        return virStorageFileResize(vol->target.path, capacity,
1280
                                    vol->target.allocation, pre_allocate);
1281 1282 1283 1284 1285 1286 1287
    } else {
        if (pre_allocate) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("preallocate is only supported for raw "
                             "type volume"));
            return -1;
        }
1288 1289 1290

        return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
                                                        capacity);
1291
    }
1292 1293
}

1294 1295 1296 1297
virStorageBackend virStorageBackendDirectory = {
    .type = VIR_STORAGE_POOL_DIR,

    .buildPool = virStorageBackendFileSystemBuild,
1298
    .checkPool = virStorageBackendFileSystemCheck,
1299 1300
    .refreshPool = virStorageBackendFileSystemRefresh,
    .deletePool = virStorageBackendFileSystemDelete,
1301
    .buildVol = virStorageBackendFileSystemVolBuild,
1302
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1303 1304 1305
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1306
    .resizeVol = virStorageBackendFileSystemVolResize,
1307 1308 1309 1310 1311 1312 1313
};

#if WITH_STORAGE_FS
virStorageBackend virStorageBackendFileSystem = {
    .type = VIR_STORAGE_POOL_FS,

    .buildPool = virStorageBackendFileSystemBuild,
1314
    .checkPool = virStorageBackendFileSystemCheck,
1315 1316 1317 1318
    .startPool = virStorageBackendFileSystemStart,
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1319
    .buildVol = virStorageBackendFileSystemVolBuild,
1320
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1321 1322 1323
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1324
    .resizeVol = virStorageBackendFileSystemVolResize,
1325 1326 1327 1328 1329
};
virStorageBackend virStorageBackendNetFileSystem = {
    .type = VIR_STORAGE_POOL_NETFS,

    .buildPool = virStorageBackendFileSystemBuild,
1330
    .checkPool = virStorageBackendFileSystemCheck,
1331
    .startPool = virStorageBackendFileSystemStart,
1332
    .findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
1333 1334 1335
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1336
    .buildVol = virStorageBackendFileSystemVolBuild,
1337
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1338 1339 1340
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
1341
    .resizeVol = virStorageBackendFileSystemVolResize,
1342
};
1343 1344 1345


static int
1346
virStorageFileBackendFileUnlink(virStorageSourcePtr src)
1347 1348 1349
{
    int ret;

1350
    ret = unlink(src->path);
1351 1352 1353
    /* preserve errno */

    VIR_DEBUG("removing storage file %p(%s): ret=%d, errno=%d",
1354
              src, src->path, ret, errno);
1355 1356 1357 1358 1359 1360

    return ret;
}


static int
1361
virStorageFileBackendFileStat(virStorageSourcePtr src,
1362 1363 1364 1365
                              struct stat *st)
{
    int ret;

1366
    ret = stat(src->path, st);
1367 1368 1369
    /* preserve errno */

    VIR_DEBUG("stat of storage file %p(%s): ret=%d, errno=%d",
1370
              src, src->path, ret, errno);
1371 1372 1373 1374 1375 1376

    return ret;
}


virStorageFileBackend virStorageFileBackendFile = {
E
Eric Blake 已提交
1377
    .type = VIR_STORAGE_TYPE_FILE,
1378 1379 1380 1381 1382 1383 1384

    .storageFileUnlink = virStorageFileBackendFileUnlink,
    .storageFileStat = virStorageFileBackendFileStat,
};


virStorageFileBackend virStorageFileBackendBlock = {
E
Eric Blake 已提交
1385
    .type = VIR_STORAGE_TYPE_BLOCK,
1386 1387 1388 1389 1390

    .storageFileStat = virStorageFileBackendFileStat,
};


1391
#endif /* WITH_STORAGE_FS */