storage_backend_fs.c 37.5 KB
Newer Older
1 2 3
/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
4
 * Copyright (C) 2007-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Copyright (C) 2007-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#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>

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

44
#include "virterror_internal.h"
45 46
#include "storage_backend_fs.h"
#include "storage_conf.h"
47
#include "storage_file.h"
48
#include "command.h"
49
#include "memory.h"
50
#include "xml.h"
E
Eric Blake 已提交
51
#include "virfile.h"
O
Osier Yang 已提交
52
#include "logging.h"
53

54
#define VIR_FROM_THIS VIR_FROM_STORAGE
55

56 57 58 59 60
#define VIR_STORAGE_VOL_FS_OPEN_FLAGS       (VIR_STORAGE_VOL_OPEN_DEFAULT   |\
                                             VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_REFRESH_FLAGS    (VIR_STORAGE_VOL_FS_OPEN_FLAGS  &\
                                             ~VIR_STORAGE_VOL_OPEN_ERROR)

E
Eric Blake 已提交
61
static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
62
virStorageBackendProbeTarget(virStorageVolTargetPtr target,
63
                             char **backingStore,
64
                             int *backingStoreFormat,
65 66 67 68
                             unsigned long long *allocation,
                             unsigned long long *capacity,
                             virStorageEncryptionPtr *encryption)
{
69 70 71 72 73 74 75 76
    int fd = -1;
    int ret = -1;
    virStorageFileMetadata *meta;

    if (VIR_ALLOC(meta) < 0) {
        virReportOOMError();
        return ret;
    }
77

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

83
    if ((ret = virStorageBackendVolOpenCheckMode(target->path,
84
                                        VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0)
85
        goto error; /* Take care to propagate ret, it is not always -1 */
86
    fd = ret;
87

88
    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd,
89 90
                                                      allocation,
                                                      capacity)) < 0) {
91
        goto error;
92 93
    }

94
    if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) {
95 96
        ret = -1;
        goto error;
97 98
    }

99 100
    if (virStorageFileGetMetadataFromFD(target->path, fd,
                                        target->format,
101 102 103
                                        meta) < 0) {
        ret = -1;
        goto error;
104
    }
105

106
    VIR_FORCE_CLOSE(fd);
107

108 109 110 111
    if (meta->backingStore) {
        *backingStore = meta->backingStore;
        meta->backingStore = NULL;
        if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO) {
112 113 114 115 116 117 118 119 120 121 122
            if ((ret = virStorageFileProbeFormat(*backingStore)) < 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. */
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                      _("cannot probe backing volume format: %s"),
                                      *backingStore);
                ret = -3;
            } else {
                *backingStoreFormat = ret;
                ret = 0;
123 124
            }
        } else {
125
            *backingStoreFormat = meta->backingStoreFormat;
126
            ret = 0;
127
        }
E
Eric Blake 已提交
128
    } else {
129
        ret = 0;
130 131
    }

132 133
    if (capacity && meta->capacity)
        *capacity = meta->capacity;
134

135
    if (encryption != NULL && meta->encrypted) {
136
        if (VIR_ALLOC(*encryption) < 0) {
137
            virReportOOMError();
138
            goto cleanup;
139 140 141 142 143 144 145 146 147 148 149 150
        }

        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 已提交
151
         * but we cannot guarantee 'conn' is non-NULL
152 153 154 155 156
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

157 158
    virStorageFileFreeMetadata(meta);

159
    return ret;
160

161 162 163
error:
    VIR_FORCE_CLOSE(fd);

164
cleanup:
165 166 167
    virStorageFileFreeMetadata(meta);
    return ret;

168 169 170
}

#if WITH_STORAGE_FS
171

172
# include <mntent.h>
173

174 175
struct _virNetfsDiscoverState {
    const char *host;
176
    virStoragePoolSourceList list;
177 178 179 180 181
};

typedef struct _virNetfsDiscoverState virNetfsDiscoverState;

static int
182
virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
183 184 185 186 187
                                                  char **const groups,
                                                  void *data)
{
    virNetfsDiscoverState *state = data;
    const char *name, *path;
188 189
    virStoragePoolSource *src = NULL;
    int ret = -1;
190 191 192 193 194

    path = groups[0];

    name = strrchr(path, '/');
    if (name == NULL) {
195
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
196
                              _("invalid netfs path (no /): %s"), path);
197
        goto cleanup;
198 199 200
    }
    name += 1;
    if (*name == '\0') {
201
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
202
                              _("invalid netfs path (ends in /): %s"), path);
203
        goto cleanup;
204 205
    }

206
    if (!(src = virStoragePoolSourceListNewSource(&state->list)))
207
        goto cleanup;
208

209
    if (!(src->host.name = strdup(state->host)) ||
210
        !(src->dir = strdup(path))) {
211
        virReportOOMError();
212 213
        goto cleanup;
    }
214
    src->format = VIR_STORAGE_POOL_NETFS_NFS;
215

216 217 218
    src = NULL;
    ret = 0;
cleanup:
219 220
    virStoragePoolSourceFree(src);
    VIR_FREE(src);
221
    return ret;
222 223
}

224

225
static char *
226
virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
227
                                              const char *srcSpec,
E
Eric Blake 已提交
228
                                              unsigned int flags)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
{
    /*
     *  # 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
    };
244 245 246 247 248 249 250 251
    virNetfsDiscoverState state = {
        .host = NULL,
        .list = {
            .type = VIR_STORAGE_POOL_NETFS,
            .nsources = 0,
            .sources = NULL
        }
    };
252
    const char *prog[] = { SHOWMOUNT, "--no-headers", "--exports", NULL, NULL };
253
    virStoragePoolSourcePtr source = NULL;
254
    char *retval = NULL;
255
    unsigned int i;
256

E
Eric Blake 已提交
257 258
    virCheckFlags(0, NULL);

259
    source = virStoragePoolDefParseSourceString(srcSpec,
260 261
                                                VIR_STORAGE_POOL_NETFS);
    if (!source)
262 263
        goto cleanup;

264 265
    state.host = source->host.name;
    prog[3] = source->host.name;
266

267
    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
268 269
                            virStorageBackendFileSystemNetFindPoolSourcesFunc,
                            &state) < 0)
270 271
        goto cleanup;

272
    retval = virStoragePoolSourceListFormat(&state.list);
273
    if (retval == NULL) {
274
        virReportOOMError();
275 276 277 278
        goto cleanup;
    }

 cleanup:
279 280 281
    for (i = 0; i < state.list.nsources; i++)
        virStoragePoolSourceFree(&state.list.sources[i]);

282 283
    virStoragePoolSourceFree(source);
    VIR_FREE(source);
284

285
    VIR_FREE(state.list.sources);
286 287 288 289 290

    return retval;
}


291 292 293 294 295 296 297 298 299
/**
 * @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
300
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool) {
301
    FILE *mtab;
302 303
    struct mntent ent;
    char buf[1024];
304 305

    if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
306
        virReportSystemError(errno,
307 308
                             _("cannot read mount list '%s'"),
                             _PATH_MOUNTED);
309 310 311
        return -1;
    }

312 313
    while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
        if (STREQ(ent.mnt_dir, pool->def->target.path)) {
314
            VIR_FORCE_FCLOSE(mtab);
315 316 317 318
            return 1;
        }
    }

319
    VIR_FORCE_FCLOSE(mtab);
320 321 322 323 324 325 326 327 328 329 330 331 332
    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
333
virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
334
    char *src;
335 336 337 338 339 340 341
    const char **mntargv;

    /* '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 */
    int netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                   pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
342 343 344
    int glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
                 pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);

345 346 347 348 349 350 351 352 353 354
    int source_index;

    const char *netfs_auto_argv[] = {
        MOUNT,
        NULL, /* source path */
        pool->def->target.path,
        NULL,
    };

    const char *fs_argv[] =  {
355 356 357
        MOUNT,
        "-t",
        pool->def->type == VIR_STORAGE_POOL_FS ?
358 359
        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
360 361
        NULL, /* Fill in shortly - careful not to add extra fields
                 before this */
362 363 364
        pool->def->target.path,
        NULL,
    };
365

366 367 368 369 370 371 372 373
    const char *glusterfs_argv[] = {
        MOUNT,
        "-t",
        pool->def->type == VIR_STORAGE_POOL_FS ?
        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
        NULL,
        "-o",
E
Eric Blake 已提交
374
        "direct-io-mode=1",
375 376 377 378
        pool->def->target.path,
        NULL,
    };

379 380 381
    if (netauto) {
        mntargv = netfs_auto_argv;
        source_index = 1;
382 383 384
    } else if (glusterfs) {
        mntargv = glusterfs_argv;
        source_index = 3;
385 386 387 388 389
    } else {
        mntargv = fs_argv;
        source_index = 3;
    }

390 391 392 393
    int ret;

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
        if (pool->def->source.host.name == NULL) {
394
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
395
                                  "%s", _("missing source host"));
396 397 398
            return -1;
        }
        if (pool->def->source.dir == NULL) {
399
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
400
                                  "%s", _("missing source path"));
401 402 403 404
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
405
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
406
                                  "%s", _("missing source device"));
407 408 409 410
            return -1;
        }
    }

J
Jim Meyering 已提交
411
    /* Short-circuit if already mounted */
412
    if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
413 414 415 416 417 418 419
        if (ret < 0)
            return -1;
        else
            return 0;
    }

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
420 421 422
        if (virAsprintf(&src, "%s:%s",
                        pool->def->source.host.name,
                        pool->def->source.dir) == -1) {
423
            virReportOOMError();
424 425
            return -1;
        }
426

427
    } else {
428
        if ((src = strdup(pool->def->source.devices[0].path)) == NULL) {
429
            virReportOOMError();
430 431
            return -1;
        }
432
    }
433
    mntargv[source_index] = src;
434

435
    if (virRun(mntargv, NULL) < 0) {
436
        VIR_FREE(src);
437 438
        return -1;
    }
439
    VIR_FREE(src);
440 441 442 443 444 445 446 447 448 449 450 451 452
    return 0;
}

/**
 * @conn connection to report errors against
 * @pool storage pool to unmount
 *
 * Ensure that a FS storage pool is not mounted on its target location.
 * If already unmounted, this is a no-op
 *
 * Returns 0 if successfully unmounted, -1 on error
 */
static int
453
virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
454 455 456 457 458
    const char *mntargv[3];
    int ret;

    if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
        if (pool->def->source.host.name == NULL) {
459
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
460
                                  "%s", _("missing source host"));
461 462 463
            return -1;
        }
        if (pool->def->source.dir == NULL) {
464
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
465
                                  "%s", _("missing source dir"));
466 467 468 469
            return -1;
        }
    } else {
        if (pool->def->source.ndevice != 1) {
470
            virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
471
                                  "%s", _("missing source device"));
472 473 474 475 476
            return -1;
        }
    }

    /* Short-circuit if already unmounted */
477
    if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 1) {
478 479 480 481 482 483 484 485 486 487
        if (ret < 0)
            return -1;
        else
            return 0;
    }

    mntargv[0] = UMOUNT;
    mntargv[1] = pool->def->target.path;
    mntargv[2] = NULL;

488
    if (virRun(mntargv, NULL) < 0) {
489 490 491 492 493 494 495
        return -1;
    }
    return 0;
}
#endif /* WITH_STORAGE_FS */


496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
static int
virStorageBackendFileSystemCheck(virConnectPtr conn ATTRIBUTE_UNUSED,
                                 virStoragePoolObjPtr pool,
                                 bool *isActive)
{
    *isActive = false;
    if (pool->def->type == VIR_STORAGE_POOL_DIR) {
        if (access(pool->def->target.path, F_OK) == 0)
            *isActive = true;
#if WITH_STORAGE_FS
    } else {
        int ret;
        if ((ret = virStorageBackendFileSystemIsMounted(pool)) != 0) {
            if (ret < 0)
                return -1;
            *isActive = true;
        }
#endif /* WITH_STORAGE_FS */
    }

    return 0;
}

#if WITH_STORAGE_FS
520 521 522 523 524 525 526 527 528 529 530
/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
 * Starts a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
531
virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED,
532 533 534
                                 virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
535
        virStorageBackendFileSystemMount(pool) < 0)
536 537 538 539 540 541
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */

O
Osier Yang 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
#if HAVE_LIBBLKID
static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device,
                                 const char *format) {

    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) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                              _("Not capable of probing for "
                                "filesystem of type %s"),
                              format);
        goto error;
    }

    probe = blkid_new_probe_from_filename(device);
    if (probe == NULL) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Failed to create filesystem probe "
                                  "for device %s"),
                                  device);
        goto error;
    }

    if ((libblkid_format = strdup(format)) == NULL) {
        virReportOOMError();
        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) {
        virStorageReportError(VIR_ERR_STORAGE_POOL_BUILT,
                              _("Existing filesystem of type '%s' found on "
                                "device '%s'"),
                              fstype, device);
        ret = FILESYSTEM_PROBE_FOUND;
    }

    if (blkid_do_probe(probe) != 1) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Found additional probes to run, "
                                    "filesystem probing may be incorrect"));
        ret = FILESYSTEM_PROBE_ERROR;
    }

error:
    VIR_FREE(libblkid_format);

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

    return ret;
}

#else /* #if HAVE_LIBBLKID */

static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device ATTRIBUTE_UNUSED,
                                 const char *format ATTRIBUTE_UNUSED)
{
    virStorageReportError(VIR_ERR_OPERATION_INVALID,
                          _("probing for filesystems is unsupported "
                            "by this build"));

    return FILESYSTEM_PROBE_ERROR;
}

#endif /* #if HAVE_LIBBLKID */

static int
virStorageBackendExecuteMKFS(const char *device,
                             const char *format)
{
    int ret = 0;
    virCommandPtr cmd = NULL;

    cmd = virCommandNewArgList(MKFS,
                               "-t",
                               format,
                               device,
                               NULL);

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

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) {
        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("No source device specified when formatting pool '%s'"),
                              pool->def->name);
        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)) {
        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("Source device does not exist when formatting pool '%s'"),
                              pool->def->name);
        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);
    }

error:
    return ret;
}

693 694 695 696

/**
 * @conn connection to report errors against
 * @pool storage pool to build
O
Osier Yang 已提交
697
 * @flags controls the pool formating behaviour
698 699 700
 *
 * Build a directory or FS based storage pool.
 *
O
Osier Yang 已提交
701 702 703 704 705 706 707
 * 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.
 *
708 709 710 711 712
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
713
virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
714
                                 virStoragePoolObjPtr pool,
E
Eric Blake 已提交
715
                                 unsigned int flags)
716
{
717
    int err, ret = -1;
O
Osier Yang 已提交
718 719
    char *parent = NULL;
    char *p = NULL;
720

O
Osier Yang 已提交
721 722 723 724 725 726 727 728 729 730 731
    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)) {

        virStorageReportError(VIR_ERR_OPERATION_INVALID,
                              _("Overwrite and no overwrite flags"
                                " are mutually exclusive"));
        goto error;
    }
E
Eric Blake 已提交
732

733
    if ((parent = strdup(pool->def->target.path)) == NULL) {
734
        virReportOOMError();
735 736 737
        goto error;
    }
    if (!(p = strrchr(parent, '/'))) {
738
        virStorageReportError(VIR_ERR_INVALID_ARG,
739 740 741
                              _("path '%s' is not absolute"),
                              pool->def->target.path);
        goto error;
742 743
    }

744 745 746 747
    if (p != parent) {
        /* assure all directories in the path prior to the final dir
         * exist, with default uid/gid/mode. */
        *p = '\0';
748 749
        if (virFileMakePath(parent) < 0) {
            virReportSystemError(errno, _("cannot create path '%s'"),
750 751 752 753 754 755 756 757
                                 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. */
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774

    struct stat st;

    if ((stat(pool->def->target.path, &st) < 0)
        || (pool->def->target.perms.uid != -1)) {

        uid_t uid = (pool->def->target.perms.uid == -1)
            ? getuid() : pool->def->target.perms.uid;
        gid_t gid = (pool->def->target.perms.gid == -1)
            ? getgid() : pool->def->target.perms.gid;

        if ((err = virDirCreate(pool->def->target.path,
                                pool->def->target.perms.mode,
                                uid, gid,
                                VIR_DIR_CREATE_FORCE_PERMS |
                                VIR_DIR_CREATE_ALLOW_EXIST |
                                (pool->def->type == VIR_STORAGE_POOL_NETFS
775 776
                                 ? VIR_DIR_CREATE_AS_UID : 0)) < 0)) {
            virReportSystemError(-err, _("cannot create path '%s'"),
777 778 779
                                 pool->def->target.path);
            goto error;
        }
780
    }
O
Osier Yang 已提交
781 782 783 784 785 786 787

    if (flags != 0) {
        ret = virStorageBackendMakeFileSystem(pool, flags);
    } else {
        ret = 0;
    }

788 789 790
error:
    VIR_FREE(parent);
    return ret;
791 792 793 794 795 796 797 798
}


/**
 * Iterate over the pool's directory and enumerate all disk images
 * within it. This is non-recursive.
 */
static int
799
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
800 801 802 803 804
                                   virStoragePoolObjPtr pool)
{
    DIR *dir;
    struct dirent *ent;
    struct statvfs sb;
805
    virStorageVolDefPtr vol = NULL;
806 807

    if (!(dir = opendir(pool->def->target.path))) {
808
        virReportSystemError(errno,
809 810
                             _("cannot open path '%s'"),
                             pool->def->target.path);
811 812 813 814 815
        goto cleanup;
    }

    while ((ent = readdir(dir)) != NULL) {
        int ret;
816
        char *backingStore;
817
        int backingStoreFormat;
818

819 820
        if (VIR_ALLOC(vol) < 0)
            goto no_memory;
821

822 823
        if ((vol->name = strdup(ent->d_name)) == NULL)
            goto no_memory;
824

825
        vol->type = VIR_STORAGE_VOL_FILE;
826
        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
827 828 829
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path,
                        vol->name) == -1)
830 831 832 833
            goto no_memory;

        if ((vol->key = strdup(vol->target.path)) == NULL)
            goto no_memory;
834

835
        if ((ret = virStorageBackendProbeTarget(&vol->target,
836
                                                &backingStore,
837
                                                &backingStoreFormat,
838
                                                &vol->allocation,
839
                                                &vol->capacity,
840
                                                &vol->target.encryption)) < 0) {
841
            if (ret == -2) {
842
                /* Silently ignore non-regular files,
843
                 * eg '.' '..', 'lost+found', dangling symbolic link */
844 845
                virStorageVolDefFree(vol);
                vol = NULL;
846
                continue;
847 848 849 850 851 852 853 854 855
            } 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;
856 857
        }

858 859 860 861
        /* directory based volume */
        if (vol->target.format == VIR_STORAGE_FILE_DIR)
            vol->type = VIR_STORAGE_VOL_DIR;

862
        if (backingStore != NULL) {
863 864 865 866
            vol->backingStore.path = backingStore;
            vol->backingStore.format = backingStoreFormat;

            if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
867 868
                                        NULL, NULL,
                                        VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) {
869 870 871 872 873 874 875 876 877
                /* The backing file is currently unavailable, the capacity,
                 * allocation, owner, group and mode are unknown. Just log the
                 * error an continue.
                 * Unfortunately virStorageBackendProbeTarget() might already
                 * have logged a similar message for the same problem, but only
                 * if AUTO format detection was used. */
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                      _("cannot probe backing volume info: %s"),
                                      vol->backingStore.path);
878 879 880 881
            }
        }


882 883 884 885 886
        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0)
            goto no_memory;
        pool->volumes.objs[pool->volumes.count++] = vol;
        vol = NULL;
887 888 889 890 891
    }
    closedir(dir);


    if (statvfs(pool->def->target.path, &sb) < 0) {
892
        virReportSystemError(errno,
893 894
                             _("cannot statvfs path '%s'"),
                             pool->def->target.path);
895 896 897 898 899 900 901 902 903 904
        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 *
                            (unsigned long long)sb.f_bsize);
    pool->def->allocation = pool->def->capacity - pool->def->available;

    return 0;

905
no_memory:
906
    virReportOOMError();
907 908
    /* fallthrough */

909
 cleanup:
910 911
    if (dir)
        closedir(dir);
912
    virStorageVolDefFree(vol);
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
    virStoragePoolObjClearVols(pool);
    return -1;
}


/**
 * @conn connection to report errors against
 * @pool storage pool to start
 *
 * Stops a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, unmounts the unlying source device on the pool
 *  - Releases all cached data about volumes
 */
#if WITH_STORAGE_FS
static int
929
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
930 931 932
                                virStoragePoolObjPtr pool)
{
    if (pool->def->type != VIR_STORAGE_POOL_DIR &&
933
        virStorageBackendFileSystemUnmount(pool) < 0)
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
        return -1;

    return 0;
}
#endif /* WITH_STORAGE_FS */


/**
 * @conn connection to report errors against
 * @pool storage pool to build
 *
 * Build a directory or FS based storage pool.
 *
 *  - If it is a FS based pool, mounts the unlying source device on the pool
 *
 * Returns 0 on success, -1 on error
 */
static int
952
virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
953
                                  virStoragePoolObjPtr pool,
E
Eric Blake 已提交
954
                                  unsigned int flags)
955
{
E
Eric Blake 已提交
956 957
    virCheckFlags(0, -1);

958 959
    /* XXX delete all vols first ? */

960
    if (rmdir(pool->def->target.path) < 0) {
961
        virReportSystemError(errno,
962
                             _("failed to remove pool '%s'"),
963
                             pool->def->target.path);
964 965 966 967 968 969 970 971
        return -1;
    }

    return 0;
}


/**
972 973 974 975
 * 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.
976 977
 */
static int
978
virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
979 980 981 982
                                     virStoragePoolObjPtr pool,
                                     virStorageVolDefPtr vol)
{

983 984
    vol->type = VIR_STORAGE_VOL_FILE;

R
Ryota Ozaki 已提交
985
    VIR_FREE(vol->target.path);
986 987 988
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->target.path,
                    vol->name) == -1) {
989
        virReportOOMError();
990 991
        return -1;
    }
992

R
Ryota Ozaki 已提交
993
    VIR_FREE(vol->key);
994 995
    vol->key = strdup(vol->target.path);
    if (vol->key == NULL) {
996
        virReportOOMError();
997 998 999
        return -1;
    }

1000 1001 1002
    return 0;
}

1003
static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
1004
                         virStoragePoolObjPtr pool,
1005
                         virStorageVolDefPtr vol,
1006
                         virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1007 1008
                         unsigned int flags)
{
1009 1010
    int err;

E
Eric Blake 已提交
1011 1012
    virCheckFlags(0, -1);

1013
    if (inputvol) {
1014
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
1015 1016 1017 1018 1019
                              "%s",
                              _("cannot copy from volume to a directory volume"));
        return -1;
    }

1020 1021 1022 1023 1024
    uid_t uid = (vol->target.perms.uid == -1)
        ? getuid() : vol->target.perms.uid;
    gid_t gid = (vol->target.perms.gid == -1)
        ? getgid() : vol->target.perms.gid;

1025
    if ((err = virDirCreate(vol->target.path, vol->target.perms.mode,
1026
                            uid, gid,
1027
                            VIR_DIR_CREATE_FORCE_PERMS |
1028
                            (pool->def->type == VIR_STORAGE_POOL_NETFS
1029 1030
                             ? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
        virReportSystemError(-err, _("cannot create path '%s'"),
1031 1032 1033
                             vol->target.path);
        return -1;
    }
1034

1035 1036
    return 0;
}
1037

1038
static int
1039
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
1040
                                     virStoragePoolObjPtr pool,
1041 1042
                                     virStorageVolDefPtr vol,
                                     virStorageVolDefPtr inputvol)
1043
{
1044
    virStorageBackendBuildVolFrom create_func;
1045
    int tool_type;
1046

1047
    if (inputvol) {
1048
        if (vol->target.encryption != NULL) {
O
Osier Yang 已提交
1049
            virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1050 1051 1052 1053 1054
                                  "%s", _("storage pool does not support "
                                          "building encrypted volumes from "
                                          "other volumes"));
            return -1;
        }
1055
        create_func = virStorageBackendGetBuildVolFromFunction(vol,
1056
                                                               inputvol);
1057 1058
        if (!create_func)
            return -1;
1059
    } else if (vol->target.format == VIR_STORAGE_FILE_RAW) {
1060
        create_func = virStorageBackendCreateRaw;
1061
    } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
1062
        create_func = createFileDir;
1063
    } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) {
1064
        create_func = virStorageBackendFSImageToolTypeToFunc(tool_type);
1065 1066

        if (!create_func)
1067
            return -1;
1068
    } else {
1069
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1070 1071
                              "%s", _("creation of non-raw images "
                                      "is not supported without qemu-img"));
1072 1073 1074
        return -1;
    }

1075
    if (create_func(conn, pool, vol, inputvol, 0) < 0)
1076
        return -1;
1077 1078 1079
    return 0;
}

1080 1081 1082 1083 1084 1085 1086
/**
 * 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,
1087
                                    virStoragePoolObjPtr pool,
1088
                                    virStorageVolDefPtr vol) {
1089
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL);
1090 1091 1092 1093 1094 1095 1096
}

/*
 * Create a storage vol using 'inputvol' as input
 */
static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
1097
                                        virStoragePoolObjPtr pool,
1098 1099
                                        virStorageVolDefPtr vol,
                                        virStorageVolDefPtr inputvol,
E
Eric Blake 已提交
1100 1101 1102 1103
                                        unsigned int flags)
{
    virCheckFlags(0, -1);

1104
    return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol);
1105
}
1106 1107 1108 1109 1110

/**
 * Remove a volume - just unlinks for now
 */
static int
1111
virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
1112 1113
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
E
Eric Blake 已提交
1114
                                     unsigned int flags)
1115
{
E
Eric Blake 已提交
1116 1117
    virCheckFlags(0, -1);

1118 1119 1120
    if (unlink(vol->target.path) < 0) {
        /* Silently ignore failures where the vol has already gone away */
        if (errno != ENOENT) {
1121
            virReportSystemError(errno,
1122 1123
                                 _("cannot unlink file '%s'"),
                                 vol->target.path);
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
            return -1;
        }
    }
    return 0;
}


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

1141
    /* Refresh allocation / permissions info in case its changed */
1142 1143
    ret = virStorageBackendUpdateVolInfoFlags(vol, 0,
                                              VIR_STORAGE_VOL_FS_OPEN_FLAGS);
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
    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);
1161
                virReportOOMError();
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
                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;
1176 1177 1178 1179 1180 1181
}

virStorageBackend virStorageBackendDirectory = {
    .type = VIR_STORAGE_POOL_DIR,

    .buildPool = virStorageBackendFileSystemBuild,
1182
    .checkPool = virStorageBackendFileSystemCheck,
1183 1184
    .refreshPool = virStorageBackendFileSystemRefresh,
    .deletePool = virStorageBackendFileSystemDelete,
1185
    .buildVol = virStorageBackendFileSystemVolBuild,
1186
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};

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

    .buildPool = virStorageBackendFileSystemBuild,
1197
    .checkPool = virStorageBackendFileSystemCheck,
1198 1199 1200 1201
    .startPool = virStorageBackendFileSystemStart,
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1202
    .buildVol = virStorageBackendFileSystemVolBuild,
1203
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1204 1205 1206 1207 1208 1209 1210 1211
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};
virStorageBackend virStorageBackendNetFileSystem = {
    .type = VIR_STORAGE_POOL_NETFS,

    .buildPool = virStorageBackendFileSystemBuild,
1212
    .checkPool = virStorageBackendFileSystemCheck,
1213
    .startPool = virStorageBackendFileSystemStart,
1214
    .findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
1215 1216 1217
    .refreshPool = virStorageBackendFileSystemRefresh,
    .stopPool = virStorageBackendFileSystemStop,
    .deletePool = virStorageBackendFileSystemDelete,
1218
    .buildVol = virStorageBackendFileSystemVolBuild,
1219
    .buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
1220 1221 1222 1223 1224
    .createVol = virStorageBackendFileSystemVolCreate,
    .refreshVol = virStorageBackendFileSystemVolRefresh,
    .deleteVol = virStorageBackendFileSystemVolDelete,
};
#endif /* WITH_STORAGE_FS */