storage_backend_fs.c 42.7 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
    if (ret < 0)
        return ret;

N
Nehal J Wani 已提交
1199
    /* Load any secrets if possible */
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 (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 */