From: Christian Brauner Date: Wed, 30 Dec 2015 14:06:36 +0000 (+0100) Subject: Split bdev into modules: lxcloop X-Git-Tag: lxc-2.1.1~723^2~3 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=304b4cf3ae6c23d8e2a604b5e78e850d767a9f6e;p=mirror_lxc.git Split bdev into modules: lxcloop The functions - loop_clonepaths(); - loop_create(); - loop_destroy(); - loop_detect(); - loop_mount(); - loop_umount(); move from bdev.c to lxcloop.{c,h}. All functions previously declared static become extern. The functions - do_loop_create(); - find_free_loopdev_no_control(); - find_free_loopdev(); move from bdev.c to lxcloop.c. They remain static. Adapt Makefile.am to include lxcloop.{c,h}. The structs - struct bdev; /* defined in bdev.h */ - struct bdev_specs; /* defined in lxccontainer.h */ - struct lxc_conf; /* defined conf.h */ are forward declared/put as incomplete types into lxcloop.h as the functions associated with loop need access to it. Signed-off-by: Christian Brauner --- diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index d74385127..697d3c39d 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -10,6 +10,7 @@ noinst_HEADERS = \ bdev/lxcaufs.h \ bdev/lxcbtrfs.h \ bdev/lxcdir.h \ + bdev/lxcloop.h \ bdev/lxclvm.h \ bdev/lxcoverlay.h \ bdev/lxcrsync.h \ @@ -70,6 +71,7 @@ liblxc_so_SOURCES = \ bdev/lxcaufs.c bdev/lxcaufs.h \ bdev/lxcbtrfs.c bdev/lxcbtrfs.h \ bdev/lxcdir.c bdev/lxcdir.h \ + bdev/lxcloop.c bdev/lxcloop.h \ bdev/lxclvm.c bdev/lxclvm.h \ bdev/lxcoverlay.c bdev/lxcoverlay.h \ bdev/lxcrsync.c bdev/lxcrsync.h \ diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c index 323241a50..700a3ece1 100644 --- a/src/lxc/bdev/bdev.c +++ b/src/lxc/bdev/bdev.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,7 @@ #include "lxcdir.h" #include "lxclock.h" #include "lxclvm.h" +#include "lxcloop.h" #include "lxcoverlay.h" #include "lxcrsync.h" #include "lxczfs.h" @@ -103,6 +103,7 @@ static const struct bdev_ops btrfs_ops = { .can_backup = true, }; +/* dir */ static const struct bdev_ops dir_ops = { .detect = &dir_detect, .mount = &dir_mount, @@ -114,6 +115,18 @@ static const struct bdev_ops dir_ops = { .can_backup = true, }; +/* loop */ +static const struct bdev_ops loop_ops = { + .detect = &loop_detect, + .mount = &loop_mount, + .umount = &loop_umount, + .clone_paths = &loop_clonepaths, + .destroy = &loop_destroy, + .create = &loop_create, + .can_snapshot = false, + .can_backup = true, +}; + /* lvm */ static const struct bdev_ops lvm_ops = { .detect = &lvm_detect, @@ -150,21 +163,6 @@ static const struct bdev_ops zfs_ops = { .can_backup = true, }; -/* functions associated with a loop bdev struct */ -static int do_loop_create(const char *path, uint64_t size, const char *fstype); -static int loop_create(struct bdev *bdev, const char *dest, const char *n, - struct bdev_specs *specs); -static int loop_destroy(struct bdev *orig); -static int loop_detect(const char *path); -static int loop_clonepaths(struct bdev *orig, struct bdev *new, - const char *oldname, const char *cname, - const char *oldpath, const char *lxcpath, int snap, - uint64_t newsize, struct lxc_conf *conf); -static int loop_mount(struct bdev *bdev); -static int loop_umount(struct bdev *bdev); -static int find_free_loopdev_no_control(int *retfd, char *namep); -static int find_free_loopdev(int *retfd, char *namep); - /* functions associated with an nbd bdev struct */ static bool attach_nbd(char *src, struct lxc_conf *conf); static bool clone_attach_nbd(const char *nbd, const char *path); @@ -674,299 +672,6 @@ static const struct bdev_ops rbd_ops = { .can_backup = false, }; -// -// loopback dev ops -// -static int loop_detect(const char *path) -{ - if (strncmp(path, "loop:", 5) == 0) - return 1; - return 0; -} - -static int find_free_loopdev_no_control(int *retfd, char *namep) -{ - struct dirent dirent, *direntp; - struct loop_info64 lo; - DIR *dir; - int fd = -1; - - dir = opendir("/dev"); - if (!dir) { - SYSERROR("Error opening /dev"); - return -1; - } - while (!readdir_r(dir, &dirent, &direntp)) { - - if (!direntp) - break; - if (strncmp(direntp->d_name, "loop", 4) != 0) - continue; - fd = openat(dirfd(dir), direntp->d_name, O_RDWR); - if (fd < 0) - continue; - if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) { - close(fd); - fd = -1; - continue; - } - // We can use this fd - snprintf(namep, 100, "/dev/%s", direntp->d_name); - break; - } - closedir(dir); - if (fd == -1) { - ERROR("No loop device found"); - return -1; - } - - *retfd = fd; - return 0; -} - -static int find_free_loopdev(int *retfd, char *namep) -{ - int rc, fd = -1; - int ctl = open("/dev/loop-control", O_RDWR); - if (ctl < 0) - return find_free_loopdev_no_control(retfd, namep); - rc = ioctl(ctl, LOOP_CTL_GET_FREE); - if (rc >= 0) { - snprintf(namep, 100, "/dev/loop%d", rc); - fd = open(namep, O_RDWR); - } - close(ctl); - if (fd == -1) { - ERROR("No loop device found"); - return -1; - } - *retfd = fd; - return 0; -} - -static int loop_mount(struct bdev *bdev) -{ - int lfd, ffd = -1, ret = -1; - struct loop_info64 lo; - char loname[100]; - - if (strcmp(bdev->type, "loop")) - return -22; - if (!bdev->src || !bdev->dest) - return -22; - if (find_free_loopdev(&lfd, loname) < 0) - return -22; - - ffd = open(bdev->src + 5, O_RDWR); - if (ffd < 0) { - SYSERROR("Error opening backing file %s", bdev->src); - goto out; - } - - if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) { - SYSERROR("Error attaching backing file to loop dev"); - goto out; - } - memset(&lo, 0, sizeof(lo)); - lo.lo_flags = LO_FLAGS_AUTOCLEAR; - if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) { - SYSERROR("Error setting autoclear on loop dev"); - goto out; - } - - ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts); - if (ret < 0) - ERROR("Error mounting %s", bdev->src); - else - bdev->lofd = lfd; - -out: - if (ffd > -1) - close(ffd); - if (ret < 0) { - close(lfd); - bdev->lofd = -1; - } - return ret; -} - -static int loop_umount(struct bdev *bdev) -{ - int ret; - - if (strcmp(bdev->type, "loop")) - return -22; - if (!bdev->src || !bdev->dest) - return -22; - ret = umount(bdev->dest); - if (bdev->lofd >= 0) { - close(bdev->lofd); - bdev->lofd = -1; - } - return ret; -} - -static int do_loop_create(const char *path, uint64_t size, const char *fstype) -{ - int fd, ret; - // create the new loopback file. - fd = creat(path, S_IRUSR|S_IWUSR); - if (fd < 0) - return -1; - if (lseek(fd, size, SEEK_SET) < 0) { - SYSERROR("Error seeking to set new loop file size"); - close(fd); - return -1; - } - if (write(fd, "1", 1) != 1) { - SYSERROR("Error creating new loop file"); - close(fd); - return -1; - } - ret = close(fd); - if (ret < 0) { - SYSERROR("Error closing new loop file"); - return -1; - } - - // create an fs in the loopback file - if (do_mkfs(path, fstype) < 0) { - ERROR("Error creating filesystem type %s on %s", fstype, - path); - return -1; - } - - return 0; -} - -/* - * No idea what the original blockdev will be called, but the copy will be - * called $lxcpath/$lxcname/rootdev - */ -static int loop_clonepaths(struct bdev *orig, struct bdev *new, - const char *oldname, const char *cname, - const char *oldpath, const char *lxcpath, int snap, - uint64_t newsize, struct lxc_conf *conf) -{ - char fstype[100]; - uint64_t size = newsize; - int len, ret; - char *srcdev; - - if (snap) { - ERROR("loop devices cannot be snapshotted."); - return -1; - } - - if (!orig->dest || !orig->src) - return -1; - - len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3; - srcdev = alloca(len); - ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname); - if (ret < 0 || ret >= len) - return -1; - - new->src = malloc(len + 5); - if (!new->src) - return -1; - ret = snprintf(new->src, len + 5, "loop:%s", srcdev); - if (ret < 0 || ret >= len + 5) - return -1; - - new->dest = malloc(len); - if (!new->dest) - return -1; - ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname); - if (ret < 0 || ret >= len) - return -1; - - // it's tempting to say: if orig->src == loopback and !newsize, then - // copy the loopback file. However, we'd have to make sure to - // correctly keep holes! So punt for now. - - if (is_blktype(orig)) { - if (!newsize && blk_getsize(orig, &size) < 0) { - ERROR("Error getting size of %s", orig->src); - return -1; - } - if (detect_fs(orig, fstype, 100) < 0) { - INFO("could not find fstype for %s, using %s", orig->src, - DEFAULT_FSTYPE); - return -1; - } - } else { - sprintf(fstype, "%s", DEFAULT_FSTYPE); - if (!newsize) - size = DEFAULT_FS_SIZE; - } - return do_loop_create(srcdev, size, fstype); -} - -static int loop_create(struct bdev *bdev, const char *dest, const char *n, - struct bdev_specs *specs) -{ - const char *fstype; - uint64_t sz; - int ret, len; - char *srcdev; - - if (!specs) - return -1; - - // dest is passed in as $lxcpath / $lxcname / rootfs - // srcdev will be: $lxcpath / $lxcname / rootdev - // src will be 'loop:$srcdev' - len = strlen(dest) + 2; - srcdev = alloca(len); - - ret = snprintf(srcdev, len, "%s", dest); - if (ret < 0 || ret >= len) - return -1; - sprintf(srcdev + len - 4, "dev"); - - bdev->src = malloc(len + 5); - if (!bdev->src) - return -1; - ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev); - if (ret < 0 || ret >= len + 5) - return -1; - - sz = specs->fssize; - if (!sz) - sz = DEFAULT_FS_SIZE; - - fstype = specs->fstype; - if (!fstype) - fstype = DEFAULT_FSTYPE; - - if (!(bdev->dest = strdup(dest))) - return -1; - - if (mkdir_p(bdev->dest, 0755) < 0) { - ERROR("Error creating %s", bdev->dest); - return -1; - } - - return do_loop_create(srcdev, sz, fstype); -} - -static int loop_destroy(struct bdev *orig) -{ - return unlink(orig->src + 5); -} - -static const struct bdev_ops loop_ops = { - .detect = &loop_detect, - .mount = &loop_mount, - .umount = &loop_umount, - .clone_paths = &loop_clonepaths, - .destroy = &loop_destroy, - .create = &loop_create, - .can_snapshot = false, - .can_backup = true, -}; - // // nbd dev ops // diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c new file mode 100644 index 000000000..9e977f011 --- /dev/null +++ b/src/lxc/bdev/lxcloop.c @@ -0,0 +1,320 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "bdev.h" +#include "log.h" +#include "lxcloop.h" +#include "utils.h" + +lxc_log_define(lxcloop, lxc); + +static int do_loop_create(const char *path, uint64_t size, const char *fstype); +static int find_free_loopdev_no_control(int *retfd, char *namep); +static int find_free_loopdev(int *retfd, char *namep); + +/* + * No idea what the original blockdev will be called, but the copy will be + * called $lxcpath/$lxcname/rootdev + */ +int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, + const char *cname, const char *oldpath, const char *lxcpath, + int snap, uint64_t newsize, struct lxc_conf *conf) +{ + char fstype[100]; + uint64_t size = newsize; + int len, ret; + char *srcdev; + + if (snap) { + ERROR("loop devices cannot be snapshotted."); + return -1; + } + + if (!orig->dest || !orig->src) + return -1; + + len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3; + srcdev = alloca(len); + ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname); + if (ret < 0 || ret >= len) + return -1; + + new->src = malloc(len + 5); + if (!new->src) + return -1; + ret = snprintf(new->src, len + 5, "loop:%s", srcdev); + if (ret < 0 || ret >= len + 5) + return -1; + + new->dest = malloc(len); + if (!new->dest) + return -1; + ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname); + if (ret < 0 || ret >= len) + return -1; + + // it's tempting to say: if orig->src == loopback and !newsize, then + // copy the loopback file. However, we'd have to make sure to + // correctly keep holes! So punt for now. + + if (is_blktype(orig)) { + if (!newsize && blk_getsize(orig, &size) < 0) { + ERROR("Error getting size of %s", orig->src); + return -1; + } + if (detect_fs(orig, fstype, 100) < 0) { + INFO("could not find fstype for %s, using %s", orig->src, + DEFAULT_FSTYPE); + return -1; + } + } else { + sprintf(fstype, "%s", DEFAULT_FSTYPE); + if (!newsize) + size = DEFAULT_FS_SIZE; + } + return do_loop_create(srcdev, size, fstype); +} + +int loop_create(struct bdev *bdev, const char *dest, const char *n, + struct bdev_specs *specs) +{ + const char *fstype; + uint64_t sz; + int ret, len; + char *srcdev; + + if (!specs) + return -1; + + // dest is passed in as $lxcpath / $lxcname / rootfs + // srcdev will be: $lxcpath / $lxcname / rootdev + // src will be 'loop:$srcdev' + len = strlen(dest) + 2; + srcdev = alloca(len); + + ret = snprintf(srcdev, len, "%s", dest); + if (ret < 0 || ret >= len) + return -1; + sprintf(srcdev + len - 4, "dev"); + + bdev->src = malloc(len + 5); + if (!bdev->src) + return -1; + ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev); + if (ret < 0 || ret >= len + 5) + return -1; + + sz = specs->fssize; + if (!sz) + sz = DEFAULT_FS_SIZE; + + fstype = specs->fstype; + if (!fstype) + fstype = DEFAULT_FSTYPE; + + if (!(bdev->dest = strdup(dest))) + return -1; + + if (mkdir_p(bdev->dest, 0755) < 0) { + ERROR("Error creating %s", bdev->dest); + return -1; + } + + return do_loop_create(srcdev, sz, fstype); +} + +int loop_destroy(struct bdev *orig) +{ + return unlink(orig->src + 5); +} + +int loop_detect(const char *path) +{ + if (strncmp(path, "loop:", 5) == 0) + return 1; + return 0; +} + +int loop_mount(struct bdev *bdev) +{ + int lfd, ffd = -1, ret = -1; + struct loop_info64 lo; + char loname[100]; + + if (strcmp(bdev->type, "loop")) + return -22; + if (!bdev->src || !bdev->dest) + return -22; + if (find_free_loopdev(&lfd, loname) < 0) + return -22; + + ffd = open(bdev->src + 5, O_RDWR); + if (ffd < 0) { + SYSERROR("Error opening backing file %s", bdev->src); + goto out; + } + + if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) { + SYSERROR("Error attaching backing file to loop dev"); + goto out; + } + memset(&lo, 0, sizeof(lo)); + lo.lo_flags = LO_FLAGS_AUTOCLEAR; + if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) { + SYSERROR("Error setting autoclear on loop dev"); + goto out; + } + + ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts); + if (ret < 0) + ERROR("Error mounting %s", bdev->src); + else + bdev->lofd = lfd; + +out: + if (ffd > -1) + close(ffd); + if (ret < 0) { + close(lfd); + bdev->lofd = -1; + } + return ret; +} + +int loop_umount(struct bdev *bdev) +{ + int ret; + + if (strcmp(bdev->type, "loop")) + return -22; + if (!bdev->src || !bdev->dest) + return -22; + ret = umount(bdev->dest); + if (bdev->lofd >= 0) { + close(bdev->lofd); + bdev->lofd = -1; + } + return ret; +} + +static int do_loop_create(const char *path, uint64_t size, const char *fstype) +{ + int fd, ret; + // create the new loopback file. + fd = creat(path, S_IRUSR|S_IWUSR); + if (fd < 0) + return -1; + if (lseek(fd, size, SEEK_SET) < 0) { + SYSERROR("Error seeking to set new loop file size"); + close(fd); + return -1; + } + if (write(fd, "1", 1) != 1) { + SYSERROR("Error creating new loop file"); + close(fd); + return -1; + } + ret = close(fd); + if (ret < 0) { + SYSERROR("Error closing new loop file"); + return -1; + } + + // create an fs in the loopback file + if (do_mkfs(path, fstype) < 0) { + ERROR("Error creating filesystem type %s on %s", fstype, + path); + return -1; + } + + return 0; +} + +static int find_free_loopdev_no_control(int *retfd, char *namep) +{ + struct dirent dirent, *direntp; + struct loop_info64 lo; + DIR *dir; + int fd = -1; + + dir = opendir("/dev"); + if (!dir) { + SYSERROR("Error opening /dev"); + return -1; + } + while (!readdir_r(dir, &dirent, &direntp)) { + + if (!direntp) + break; + if (strncmp(direntp->d_name, "loop", 4) != 0) + continue; + fd = openat(dirfd(dir), direntp->d_name, O_RDWR); + if (fd < 0) + continue; + if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) { + close(fd); + fd = -1; + continue; + } + // We can use this fd + snprintf(namep, 100, "/dev/%s", direntp->d_name); + break; + } + closedir(dir); + if (fd == -1) { + ERROR("No loop device found"); + return -1; + } + + *retfd = fd; + return 0; +} + +static int find_free_loopdev(int *retfd, char *namep) +{ + int rc, fd = -1; + int ctl = open("/dev/loop-control", O_RDWR); + if (ctl < 0) + return find_free_loopdev_no_control(retfd, namep); + rc = ioctl(ctl, LOOP_CTL_GET_FREE); + if (rc >= 0) { + snprintf(namep, 100, "/dev/loop%d", rc); + fd = open(namep, O_RDWR); + } + close(ctl); + if (fd == -1) { + ERROR("No loop device found"); + return -1; + } + *retfd = fd; + return 0; +} diff --git a/src/lxc/bdev/lxcloop.h b/src/lxc/bdev/lxcloop.h new file mode 100644 index 000000000..5d33182a3 --- /dev/null +++ b/src/lxc/bdev/lxcloop.h @@ -0,0 +1,52 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LXC_LOOP_H +#define __LXC_LOOP_H + +#define _GNU_SOURCE +#include + +/* defined in bdev.h */ +struct bdev; + +/* defined in lxccontainer.h */ +struct bdev_specs; + +/* defined conf.h */ +struct lxc_conf; + +/* + * functions associated with a loop bdev struct + */ +int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, + const char *cname, const char *oldpath, const char *lxcpath, + int snap, uint64_t newsize, struct lxc_conf *conf); +int loop_create(struct bdev *bdev, const char *dest, const char *n, + struct bdev_specs *specs); +int loop_destroy(struct bdev *orig); +int loop_detect(const char *path); +int loop_mount(struct bdev *bdev); +int loop_umount(struct bdev *bdev); + +#endif /* __LXC_LOOP_H */