storage_backend_fs.c 20.9 KB
Newer Older
1 2 3
/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
4
 * Copyright (C) 2007-2015 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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

30
#include "virerror.h"
31
#include "storage_backend_fs.h"
32
#include "storage_util.h"
33
#include "storage_conf.h"
34
#include "vircommand.h"
35
#include "viralloc.h"
E
Eric Blake 已提交
36
#include "virfile.h"
37
#include "virlog.h"
38
#include "virstring.h"
39

40
#define VIR_FROM_THIS VIR_FROM_STORAGE
41

42 43
VIR_LOG_INIT("storage.storage_backend_fs");

44
#if WITH_STORAGE_FS
45

46
# include <mntent.h>
47

48 49
struct _virNetfsDiscoverState {
    const char *host;
50
    virStoragePoolSourceList list;
51 52 53 54 55
};

typedef struct _virNetfsDiscoverState virNetfsDiscoverState;

static int
56
virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
57 58 59 60
                                                  void *data)
{
    virNetfsDiscoverState *state = data;
    const char *name, *path;
61 62
    virStoragePoolSource *src = NULL;
    int ret = -1;
63 64 65

    path = groups[0];

66
    if (!(name = strrchr(path, '/'))) {
67 68
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (no /): %s"), path);
69
        goto cleanup;
70 71 72
    }
    name += 1;
    if (*name == '\0') {
73 74
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid netfs path (ends in /): %s"), path);
75
        goto cleanup;
76 77
    }

78
    if (!(src = virStoragePoolSourceListNewSource(&state->list)))
79
        goto cleanup;
80

81
    if (VIR_ALLOC_N(src->hosts, 1) < 0)
82
        goto cleanup;
83
    src->nhost = 1;
84

85 86
    if (VIR_STRDUP(src->hosts[0].name, state->host) < 0 ||
        VIR_STRDUP(src->dir, path) < 0)
87
        goto cleanup;
88
    src->format = VIR_STORAGE_POOL_NETFS_NFS;
89

90
    ret = 0;
91
 cleanup:
92
    return ret;
93 94
}

95

96
static int
97
virStorageBackendFileSystemNetFindNFSPoolSources(virNetfsDiscoverState *state)
98
{
99 100
    int ret = -1;

101 102 103 104 105 106 107 108 109 110 111 112 113 114
    /*
     *  # 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
    };
115 116 117 118 119 120 121 122 123 124 125

    virCommandPtr cmd = NULL;

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

    if (virCommandRunRegex(cmd, 1, regexes, vars,
                           virStorageBackendFileSystemNetFindPoolSourcesFunc,
126
                           state, NULL, NULL) < 0)
127
        goto cleanup;
128

129 130 131
    ret = 0;

 cleanup:
132
    virCommandFree(cmd);
133
    return ret;
134 135 136 137
}


static char *
138
virStorageBackendFileSystemNetFindPoolSources(const char *srcSpec,
139 140
                                              unsigned int flags)
{
141 142 143 144 145 146 147 148
    virNetfsDiscoverState state = {
        .host = NULL,
        .list = {
            .type = VIR_STORAGE_POOL_NETFS,
            .nsources = 0,
            .sources = NULL
        }
    };
149
    virStoragePoolSourcePtr source = NULL;
150
    char *ret = NULL;
151
    size_t i;
152 153
    int retNFS = -1;
    int retGluster = 0;
154

E
Eric Blake 已提交
155 156
    virCheckFlags(0, NULL);

157
    if (!srcSpec) {
158 159
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("hostname must be specified for netfs sources"));
160 161 162 163 164 165
        return NULL;
    }

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

167
    if (source->nhost != 1) {
168 169
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Expected exactly 1 host for the storage pool"));
170 171 172 173
        goto cleanup;
    }

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

175
    retNFS = virStorageBackendFileSystemNetFindNFSPoolSources(&state);
176

177
    retGluster = virStorageBackendFindGlusterPoolSources(state.host,
178
                                                         VIR_STORAGE_POOL_NETFS,
179
                                                         &state.list, false);
180 181 182 183

    if (retGluster < 0)
        goto cleanup;

184
    /* If both fail, then we won't return an empty list - return an error */
185 186 187 188
    if (retNFS < 0 && retGluster == 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("no storage pools were found on host '%s'"),
                       state.host);
189
        goto cleanup;
190
    }
191

192
    if (!(ret = virStoragePoolSourceListFormat(&state.list)))
193 194 195
        goto cleanup;

 cleanup:
196
    for (i = 0; i < state.list.nsources; i++)
197 198
        virStoragePoolSourceClear(&state.list.sources[i]);
    VIR_FREE(state.list.sources);
199

200
    virStoragePoolSourceFree(source);
201
    return ret;
202 203
}

204 205 206 207 208 209 210 211 212 213
/**
 * @pool storage pool to check FS types
 *
 * Determine if storage pool FS types are properly set up
 *
 * Return 0 if everything's OK, -1 on error
 */
static int
virStorageBackendFileSystemIsValid(virStoragePoolObjPtr pool)
{
214 215 216 217
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);

    if (def->type == VIR_STORAGE_POOL_NETFS) {
        if (def->source.nhost != 1) {
218 219 220 221
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("expected exactly 1 host for the storage pool"));
            return -1;
        }
222
        if (def->source.hosts[0].name == NULL) {
223 224 225 226
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source host"));
            return -1;
        }
227
        if (def->source.dir == NULL) {
228 229 230 231 232
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing source path"));
            return -1;
        }
    } else {
233 234
        if (def->source.ndevice != 1) {
            if (def->source.ndevice == 0)
235 236 237 238 239 240
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("missing source device"));
            else
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("expected exactly 1 device for the "
                                 "storage pool"));
241 242 243 244 245
            return -1;
        }
    }
    return 0;
}
246

247 248 249 250 251 252 253 254 255 256 257

/**
 * virStorageBackendFileSystemGetPoolSource
 * @pool: storage pool object pointer
 *
 * Allocate/return a string representing the FS storage pool source.
 * It is up to the caller to VIR_FREE the allocated string
 */
static char *
virStorageBackendFileSystemGetPoolSource(virStoragePoolObjPtr pool)
{
258
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
259 260
    char *src = NULL;

261 262
    if (def->type == VIR_STORAGE_POOL_NETFS) {
        if (def->source.format == VIR_STORAGE_POOL_NETFS_CIFS) {
263
            if (virAsprintf(&src, "//%s/%s",
264 265
                            def->source.hosts[0].name,
                            def->source.dir) < 0)
266 267 268
                return NULL;
        } else {
            if (virAsprintf(&src, "%s:%s",
269 270
                            def->source.hosts[0].name,
                            def->source.dir) < 0)
271 272 273
                return NULL;
        }
    } else {
274
        if (VIR_STRDUP(src, def->source.devices[0].path) < 0)
275 276 277 278 279 280
            return NULL;
    }
    return src;
}


281 282 283 284 285 286 287 288
/**
 * @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
289 290
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool)
{
291
    int ret = -1;
292
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
293
    char *src = NULL;
294
    FILE *mtab;
295 296
    struct mntent ent;
    char buf[1024];
297
    int rc1, rc2;
298 299

    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
300
        virReportSystemError(errno,
301 302
                             _("cannot read mount list '%s'"),
                             _PATH_MOUNTED);
303
        goto cleanup;
304 305
    }

306
    while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
307 308 309
        if (!(src = virStorageBackendFileSystemGetPoolSource(pool)))
            goto cleanup;

310 311 312
        /* compare both mount destinations and sources to be sure the mounted
         * FS pool is really the one we're looking for
         */
313
        if ((rc1 = virFileComparePaths(ent.mnt_dir, def->target.path)) < 0 ||
314 315 316 317
            (rc2 = virFileComparePaths(ent.mnt_fsname, src)) < 0)
            goto cleanup;

        if (rc1 && rc2) {
318 319
            ret = 1;
            goto cleanup;
320
        }
321 322

        VIR_FREE(src);
323 324
    }

325 326 327
    ret = 0;

 cleanup:
328
    VIR_FORCE_FCLOSE(mtab);
329
    VIR_FREE(src);
330
    return ret;
331 332 333 334 335 336 337 338 339 340 341
}

/**
 * @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
342 343
virStorageBackendFileSystemMount(virStoragePoolObjPtr pool)
{
344
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
345
    char *src = NULL;
346 347 348
    /* '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 */
349 350 351 352 353 354
    bool netauto = (def->type == VIR_STORAGE_POOL_NETFS &&
                    def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
    bool glusterfs = (def->type == VIR_STORAGE_POOL_NETFS &&
                      def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
    bool cifsfs = (def->type == VIR_STORAGE_POOL_NETFS &&
                   def->source.format == VIR_STORAGE_POOL_NETFS_CIFS);
355 356
    virCommandPtr cmd = NULL;
    int ret = -1;
357
    int rc;
358

359 360
    if (virStorageBackendFileSystemIsValid(pool) < 0)
        return -1;
361

362
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) < 0)
363
        return -1;
364 365 366

    /* Short-circuit if already mounted */
    if (rc == 1) {
367
        VIR_INFO("Target '%s' is already mounted", def->target.path);
368
        return 0;
369 370
    }

371 372
    if (!(src = virStorageBackendFileSystemGetPoolSource(pool)))
        return -1;
373

374 375 376
    if (netauto)
        cmd = virCommandNewArgList(MOUNT,
                                   src,
377
                                   def->target.path,
378 379
                                   NULL);
    else if (glusterfs)
380 381
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
382
                                   virStoragePoolFormatFileSystemNetTypeToString(def->source.format),
383 384 385
                                   src,
                                   "-o",
                                   "direct-io-mode=1",
386
                                   def->target.path,
387
                                   NULL);
388 389 390
    else if (cifsfs)
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
391
                                   virStoragePoolFormatFileSystemNetTypeToString(def->source.format),
392
                                   src,
393
                                   def->target.path,
394 395 396
                                   "-o",
                                   "guest",
                                   NULL);
397 398 399
    else
        cmd = virCommandNewArgList(MOUNT,
                                   "-t",
400 401 402
                                   (def->type == VIR_STORAGE_POOL_FS ?
                                    virStoragePoolFormatFileSystemTypeToString(def->source.format) :
                                    virStoragePoolFormatFileSystemNetTypeToString(def->source.format)),
403
                                   src,
404
                                   def->target.path,
405 406 407 408 409 410
                                   NULL);

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

    ret = 0;
411
 cleanup:
412
    virCommandFree(cmd);
413
    VIR_FREE(src);
414
    return ret;
415 416
}

417

418
/**
419 420 421 422 423 424 425 426
 * @pool storage pool to start
 *
 * Starts a directory or FS based storage pool.  The underlying source
 * device will be mounted for FS based pools.
 *
 * Returns 0 on success, -1 on error
 */
static int
427
virStorageBackendFileSystemStart(virStoragePoolObjPtr pool)
428
{
429 430 431
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);

    if (def->type != VIR_STORAGE_POOL_DIR &&
432 433 434 435 436 437 438 439
        virStorageBackendFileSystemMount(pool) < 0)
        return -1;

    return 0;
}


/**
440 441
 * @pool storage pool to unmount
 *
442 443 444
 * Stops a file storage pool.  The underlying source device is unmounted
 * for FS based pools.  Any cached data about volumes is released.
 *
445
 * Ensure that a FS storage pool is not mounted on its target location.
446
 * If already unmounted, this is a no-op.
447 448 449 450
 *
 * Returns 0 if successfully unmounted, -1 on error
 */
static int
451
virStorageBackendFileSystemStop(virStoragePoolObjPtr pool)
452
{
453
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
454 455
    virCommandPtr cmd = NULL;
    int ret = -1;
456
    int rc;
457

458 459
    if (virStorageBackendFileSystemIsValid(pool) < 0)
        return -1;
460 461

    /* Short-circuit if already unmounted */
462 463
    if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1)
        return rc;
464

465
    cmd = virCommandNewArgList(UMOUNT, def->target.path, NULL);
466 467 468 469 470 471 472
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virCommandFree(cmd);
    return ret;
473 474 475 476
}
#endif /* WITH_STORAGE_FS */


477
static int
478
virStorageBackendFileSystemCheck(virStoragePoolObjPtr pool,
479 480
                                 bool *isActive)
{
481 482 483 484
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);

    if (def->type == VIR_STORAGE_POOL_DIR) {
        *isActive = virFileExists(def->target.path);
485 486 487
#if WITH_STORAGE_FS
    } else {
        int ret;
488
        *isActive = false;
489 490 491 492

        if (virStorageBackendFileSystemIsValid(pool) < 0)
            return -1;

493 494 495 496 497 498 499 500 501 502 503
        if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
            if (ret < 0)
                return -1;
            *isActive = true;
        }
#endif /* WITH_STORAGE_FS */
    }

    return 0;
}

504 505
/* some platforms don't support mkfs */
#ifdef MKFS
O
Osier Yang 已提交
506 507 508 509 510 511 512
static int
virStorageBackendExecuteMKFS(const char *device,
                             const char *format)
{
    int ret = 0;
    virCommandPtr cmd = NULL;

J
Ján Tomko 已提交
513 514
    cmd = virCommandNewArgList(MKFS, "-t", format, NULL);

515 516 517
    /* use the force, otherwise mkfs.xfs won't overwrite existing fs.
     * Similarly mkfs.ext2, mkfs.ext3, and mkfs.ext4 require supplying -F
     * and mkfs.vfat uses -I */
J
Ján Tomko 已提交
518 519
    if (STREQ(format, "xfs"))
        virCommandAddArg(cmd, "-f");
520 521 522 523 524 525
    else if (STREQ(format, "ext2") ||
             STREQ(format, "ext3") ||
             STREQ(format, "ext4"))
        virCommandAddArg(cmd, "-F");
    else if (STREQ(format, "vfat"))
        virCommandAddArg(cmd, "-I");
J
Ján Tomko 已提交
526 527

    virCommandAddArg(cmd, device);
O
Osier Yang 已提交
528 529 530 531 532 533 534 535

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

    virCommandFree(cmd);
O
Osier Yang 已提交
538 539
    return ret;
}
540 541 542 543 544
#else /* #ifdef MKFS */
static int
virStorageBackendExecuteMKFS(const char *device ATTRIBUTE_UNUSED,
                             const char *format ATTRIBUTE_UNUSED)
{
545 546 547 548 549
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("mkfs is not supported on this platform: "
                     "Failed to make filesystem of "
                     "type '%s' on device '%s'"),
                   format, device);
550 551 552
    return -1;
}
#endif /* #ifdef MKFS */
O
Osier Yang 已提交
553 554 555 556 557

static int
virStorageBackendMakeFileSystem(virStoragePoolObjPtr pool,
                                unsigned int flags)
{
558
    virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
O
Osier Yang 已提交
559 560 561 562
    const char *device = NULL, *format = NULL;
    bool ok_to_mkfs = false;
    int ret = -1;

563
    if (def->source.devices == NULL) {
564 565
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("No source device specified when formatting pool '%s'"),
566
                       def->name);
O
Osier Yang 已提交
567 568 569
        goto error;
    }

570 571
    device = def->source.devices[0].path;
    format = virStoragePoolFormatFileSystemTypeToString(def->source.format);
O
Osier Yang 已提交
572 573 574
    VIR_DEBUG("source device: '%s' format: '%s'", device, format);

    if (!virFileExists(device)) {
575 576
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Source device does not exist when formatting pool '%s'"),
577
                       def->name);
O
Osier Yang 已提交
578 579 580 581 582 583
        goto error;
    }

    if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
        ok_to_mkfs = true;
    } else if (flags & VIR_STORAGE_POOL_BUILD_NO_OVERWRITE &&
584
               virStorageBackendDeviceIsEmpty(device, format, true)) {
O
Osier Yang 已提交
585 586 587
        ok_to_mkfs = true;
    }

588
    if (ok_to_mkfs)
O
Osier Yang 已提交
589 590
        ret = virStorageBackendExecuteMKFS(device, format);

591
 error:
O
Osier Yang 已提交
592 593 594
    return ret;
}

595 596 597

/**
 * @pool storage pool to build
E
Eric Blake 已提交
598
 * @flags controls the pool formatting behaviour
599 600 601
 *
 * Build a directory or FS based storage pool.
 *
602 603 604 605 606 607 608 609 610
 * If no flag is set, it only makes the directory.
 *
 * If VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it probes to determine if
 * any filesystem already exists on the target device, returning an error
 * if one exists. If no filesystem already exists, use mkfs to format the
 * target device.
 *
 * If VIR_STORAGE_POOL_BUILD_OVERWRITE is set, mkfs is always executed and
 * any existing data on the target device is overwritten unconditionally.
O
Osier Yang 已提交
611
 *
612
 * The underlying source device is mounted for FS based pools.
613 614 615 616
 *
 * Returns 0 on success, -1 on error
 */
static int
617
virStorageBackendFileSystemBuild(virStoragePoolObjPtr pool,
E
Eric Blake 已提交
618
                                 unsigned int flags)
619
{
O
Osier Yang 已提交
620
    virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
621
                  VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1);
O
Osier Yang 已提交
622

623 624 625
    VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE,
                            VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
                            -1);
626

627
    if (virStorageBackendBuildLocal(pool) < 0)
628
        return -1;
629 630 631

    if (flags != 0)
        return virStorageBackendMakeFileSystem(pool, flags);
632 633 634 635 636 637 638 639 640

    return 0;
}


virStorageBackend virStorageBackendDirectory = {
    .type = VIR_STORAGE_POOL_DIR,

    .buildPool = virStorageBackendFileSystemBuild,
641
    .checkPool = virStorageBackendFileSystemCheck,
642 643
    .refreshPool = virStorageBackendRefreshLocal,
    .deletePool = virStorageBackendDeleteLocal,
644 645 646 647 648 649
    .buildVol = virStorageBackendVolBuildLocal,
    .buildVolFrom = virStorageBackendVolBuildFromLocal,
    .createVol = virStorageBackendVolCreateLocal,
    .refreshVol = virStorageBackendVolRefreshLocal,
    .deleteVol = virStorageBackendVolDeleteLocal,
    .resizeVol = virStorageBackendVolResizeLocal,
650 651
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
652
    .wipeVol = virStorageBackendVolWipeLocal,
653 654 655 656 657 658 659
};

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

    .buildPool = virStorageBackendFileSystemBuild,
660
    .checkPool = virStorageBackendFileSystemCheck,
661
    .startPool = virStorageBackendFileSystemStart,
662
    .refreshPool = virStorageBackendRefreshLocal,
663
    .stopPool = virStorageBackendFileSystemStop,
664
    .deletePool = virStorageBackendDeleteLocal,
665 666 667 668 669 670
    .buildVol = virStorageBackendVolBuildLocal,
    .buildVolFrom = virStorageBackendVolBuildFromLocal,
    .createVol = virStorageBackendVolCreateLocal,
    .refreshVol = virStorageBackendVolRefreshLocal,
    .deleteVol = virStorageBackendVolDeleteLocal,
    .resizeVol = virStorageBackendVolResizeLocal,
671 672
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
673
    .wipeVol = virStorageBackendVolWipeLocal,
674 675 676 677 678
};
virStorageBackend virStorageBackendNetFileSystem = {
    .type = VIR_STORAGE_POOL_NETFS,

    .buildPool = virStorageBackendFileSystemBuild,
679
    .checkPool = virStorageBackendFileSystemCheck,
680
    .startPool = virStorageBackendFileSystemStart,
681
    .findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
682
    .refreshPool = virStorageBackendRefreshLocal,
683
    .stopPool = virStorageBackendFileSystemStop,
684
    .deletePool = virStorageBackendDeleteLocal,
685 686 687 688 689 690
    .buildVol = virStorageBackendVolBuildLocal,
    .buildVolFrom = virStorageBackendVolBuildFromLocal,
    .createVol = virStorageBackendVolCreateLocal,
    .refreshVol = virStorageBackendVolRefreshLocal,
    .deleteVol = virStorageBackendVolDeleteLocal,
    .resizeVol = virStorageBackendVolResizeLocal,
691 692
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
693
    .wipeVol = virStorageBackendVolWipeLocal,
694
};
695
#endif /* WITH_STORAGE_FS */
696 697


698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
int
virStorageBackendFsRegister(void)
{
    if (virStorageBackendRegister(&virStorageBackendDirectory) < 0)
        return -1;

#if WITH_STORAGE_FS
    if (virStorageBackendRegister(&virStorageBackendFileSystem) < 0)
        return -1;

    if (virStorageBackendRegister(&virStorageBackendNetFileSystem) < 0)
        return -1;
#endif /* WITH_STORAGE_FS */

    return 0;
}