From 6124835dde5abfeeb8ac796813f2f18803b96117 Mon Sep 17 00:00:00 2001 From: tanyifeng Date: Tue, 15 Jan 2019 19:54:13 +0800 Subject: [PATCH 09/49] support mount squashfs in mount entry Signed-off-by: LiFeng Signed-off-by: WangFengTu --- src/lxc/conf.c | 95 +++++++++++++++++++++++++++++++++++++++-- src/lxc/storage/loop.c | 36 +++++++++++++--- src/lxc/storage/storage_utils.c | 36 +++++++++++++++- src/lxc/utils.c | 35 ++++++++++++++- src/lxc/utils.h | 1 + 5 files changed, 191 insertions(+), 12 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 35488e0..1f779b9 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -58,6 +58,7 @@ #include "storage/overlay.h" #include "syscall_wrappers.h" #include "terminal.h" +#include "loop.h" #include "utils.h" #include "uuid.h" @@ -2013,6 +2014,84 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, return 0; } +#ifdef HAVE_ISULAD +static int mount_entry_with_loop_dev(const char *src, const char *dest, const char *fstype, + char *mnt_opts, const char *rootfs) +{ + int srcfd = -1, destfd, ret, saved_errno; + char srcbuf[50], destbuf[50]; // only needs enough for /proc/self/fd/ + const char *mntsrc = src; + int max_retry = 5; + struct lxc_storage loop; + + if (!rootfs) + rootfs = ""; + + /* todo - allow symlinks for relative paths if 'allowsymlinks' option is passed */ + if (src && src[0] != '/') { + INFO("this is a relative mount"); + srcfd = open_without_symlink(src, NULL); + if (srcfd < 0) + return srcfd; + ret = snprintf(srcbuf, sizeof(srcbuf), "/proc/self/fd/%d", srcfd); + if (ret < 0 || ret > sizeof(srcbuf)) { + close(srcfd); + ERROR("Failed to print string"); + return -EINVAL; + } + mntsrc = srcbuf; + } + + destfd = open_without_symlink(dest, rootfs); + if (destfd < 0) { + if (srcfd != -1) { + saved_errno = errno; + close(srcfd); + errno = saved_errno; + } + return destfd; + } + + ret = snprintf(destbuf, sizeof(destbuf), "/proc/self/fd/%d", destfd); + if (ret < 0 || ret > sizeof(destbuf)) { + if (srcfd != -1) + close(srcfd); + close(destfd); + ERROR("Out of memory"); + return -EINVAL; + } + +retry: + loop.src = (char *)mntsrc; + loop.dest = destbuf; + loop.mntopts = mnt_opts; + loop.type = "loop"; + loop.lofd = -1; + ret = loop_mount(&loop); + if (ret < 0) { + /* If loop is used by other program, mount may fail. So + * we do retry to ensure mount ok */ + if (max_retry > 0) { + max_retry--; + DEBUG("mount entry with loop dev failed, retry mount." + "retry count left %d", max_retry); + goto retry; + } + } + if (loop.lofd != -1) + close(loop.lofd); + if (srcfd != -1) + close(srcfd); + close(destfd); + if (ret < 0) { + SYSERROR("Failed to mount %s onto %s", src, dest); + return ret; + } + + return 0; +} +#endif + /* rootfs, lxc_name, and lxc_path can be NULL when the container is created * without a rootfs. */ static inline int mount_entry_on_generic(struct mntent *mntent, @@ -2026,6 +2105,7 @@ static inline int mount_entry_on_generic(struct mntent *mntent, char *rootfs_path = NULL; int ret; bool dev, optional, relative; + const char *dest = path; optional = hasmntopt(mntent, "optional") != NULL; dev = hasmntopt(mntent, "dev") != NULL; @@ -2052,9 +2132,18 @@ static inline int mount_entry_on_generic(struct mntent *mntent, if (ret < 0) return ret; - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, - pflags, mntdata, optional, dev, relative, rootfs_path); - +#ifdef HAVE_ISULAD + // isulad: support squashfs + if (strcmp(mntent->mnt_type, "squashfs") == 0) { + ret = mount_entry_with_loop_dev(mntent->mnt_fsname, dest, mntent->mnt_type, + mntent->mnt_opts, rootfs_path); + } else { +#endif + ret = mount_entry(mntent->mnt_fsname, dest, mntent->mnt_type, mntflags, + pflags, mntdata, optional, dev, relative, rootfs_path); +#ifdef HAVE_ISULAD + } +#endif return ret; } diff --git a/src/lxc/storage/loop.c b/src/lxc/storage/loop.c index eebc1b6..345be50 100644 --- a/src/lxc/storage/loop.c +++ b/src/lxc/storage/loop.c @@ -21,6 +21,7 @@ #include "memory_utils.h" #include "storage.h" #include "storage_utils.h" +#include "lxclock.h" #include "utils.h" lxc_log_define(loop, lxc); @@ -216,9 +217,11 @@ bool loop_detect(const char *path) int loop_mount(struct lxc_storage *bdev) { - int ret, loopfd; + int ret = 0; + int loopfd, lret; char loname[PATH_MAX]; const char *src; + struct lxc_lock *l = NULL; if (strcmp(bdev->type, "loop")) return -22; @@ -226,13 +229,29 @@ int loop_mount(struct lxc_storage *bdev) if (!bdev->src || !bdev->dest) return -22; + /* isulad: do lock before mount, so we can avoid use loop which is used by + * other starting contianers */ + l = lxc_newlock("mount_lock", "mount_lock"); + if (!l) { + SYSERROR("create file lock error when mount fs"); + return -1; + } + + lret = lxclock(l, 0); + if (lret) { + SYSERROR("try to lock failed when mount fs"); + ret = -1; + goto out; + } + /* skip prefix */ src = lxc_storage_get_path(bdev->src, bdev->type); loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR); if (loopfd < 0) { ERROR("Failed to prepare loop device for loop file \"%s\"", src); - return -1; + ret = -1; + goto out; } DEBUG("Prepared loop device \"%s\"", loname); @@ -241,14 +260,21 @@ int loop_mount(struct lxc_storage *bdev) ERROR("Failed to mount rootfs \"%s\" on \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname); close(loopfd); - return -1; + ret = -1; + goto out; } bdev->lofd = loopfd; DEBUG("Mounted rootfs \"%s\" on \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname); - - return 0; +out: + lret = lxcunlock(l); + if (lret) { + SYSERROR("try to unlock failed when mount fs"); + ret = -1; + } + lxc_putlock(l); + return ret; } int loop_umount(struct lxc_storage *bdev) diff --git a/src/lxc/storage/storage_utils.c b/src/lxc/storage/storage_utils.c index bfbb782..07eee22 100644 --- a/src/lxc/storage/storage_utils.c +++ b/src/lxc/storage/storage_utils.c @@ -259,10 +259,14 @@ int is_blktype(struct lxc_storage *b) return 0; } +// isulad: recored error +static char **mount_errors = NULL; + int mount_unknown_fs(const char *rootfs, const char *target, const char *options) { size_t i; + char *errs = NULL; int ret; struct cbarg { const char *rootfs; @@ -291,15 +295,30 @@ int mount_unknown_fs(const char *rootfs, const char *target, ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg); if (ret < 0) { ERROR("Failed to parse \"%s\"", fsfile[i]); + lxc_free_array((void**)mount_errors, free); + mount_errors = NULL; return -1; } - if (ret) + if (ret) { + lxc_free_array((void**)mount_errors, free); + mount_errors = NULL; return 0; + } + } + + if (mount_errors != NULL) { + errs = lxc_string_join("\n", (const char **)mount_errors, false); + if (errs == NULL) { + ERROR("failed to join mount errors"); + } } - ERROR("Failed to determine FSType for \"%s\"", rootfs); + ERROR("Failed to determine FSType for \"%s\": %s", rootfs, errs ? errs : "unknown reason"); + free(errs); + lxc_free_array((void**)mount_errors, free); + mount_errors = NULL; return -1; } @@ -318,6 +337,8 @@ int find_fstype_cb(char *buffer, void *data) unsigned long mntflags = 0; char *mntdata = NULL; char *fstype; + char mount_err[BUFSIZ] = {0}; + int ret; /* we don't try 'nodev' entries */ if (strstr(buffer, "nodev")) @@ -342,6 +363,17 @@ int find_fstype_cb(char *buffer, void *data) #endif SYSDEBUG("Failed to mount"); free(mntdata); + // isulad: recored error + ret = snprintf(mount_err, BUFSIZ, "\t\tmount %s onto %s with FSType %s failed: %s", + cbarg->rootfs, cbarg->target, fstype, strerror(errno)); + if (ret < 0 || (size_t)ret >= BUFSIZ) { + ERROR("failed to format output mount error"); + return 0; + } + + if (lxc_append_string(&mount_errors, mount_err) < 0) { + ERROR("failed to append mount error"); + } return 0; } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index ebcdae0..90113e0 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "config.h" #include "log.h" @@ -1008,7 +1009,7 @@ static int open_if_safe(int dirfd, const char *nextpath) * * Return an open fd for the path, or <0 on error. */ -static int open_without_symlink(const char *target, const char *prefix_skip) +int open_without_symlink(const char *target, const char *prefix_skip) { int curlen = 0, dirfd, fulllen, i; char *dup; @@ -1425,6 +1426,9 @@ static int lxc_get_unused_loop_dev(char *name_loop) { int loop_nr, ret; int fd_ctl = -1, fd_tmp = -1; + // isulad: retry and try mknod + int max_retry = 200; + bool try_mknod = true; fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC); if (fd_ctl < 0) { @@ -1441,9 +1445,35 @@ static int lxc_get_unused_loop_dev(char *name_loop) ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/loop%d", loop_nr); if (ret < 0 || ret >= LO_NAME_SIZE) goto on_error; - +retry: fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC); if (fd_tmp < 0) { +#if HAVE_ISULAD + /* Success of LOOP_CTL_GET_FREE doesn't mean /dev/loop$i is ready, + * we try to make node by ourself to avoid wait. */ + if (try_mknod) { + /* Do not check result of mknod because LOOP_CTL_GET_FREE + * alse do mknod, so this mknod may fail as node already + * exist. If we can open the node without error, we can + * say that it's be created successfully. + * + * note: 7 is the major device number of loopback devices + * in kernel. + */ + mknod(name_loop, S_IFBLK | 0640, makedev(7, loop_nr)); + try_mknod = false; + goto retry; + } + /* we need to wait some time to make sure it's ready for open if + * it can't open even if we have already try to make node by ourself. */ + if (max_retry > 0) { + max_retry--; + usleep(5000); /* 5 millisecond */ + goto retry; + } + SYSERROR("Failed to open loop \"%s\"", name_loop); + goto on_error; +#else /* on Android loop devices are moved under /dev/block, give it a shot */ ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/block/loop%d", loop_nr); if (ret < 0 || ret >= LO_NAME_SIZE) @@ -1452,6 +1482,7 @@ static int lxc_get_unused_loop_dev(char *name_loop) fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC); if (fd_tmp < 0) SYSERROR("Failed to open loop \"%s\"", name_loop); +#endif } on_error: diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 11d6548..fbb0d55 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -215,6 +215,7 @@ extern bool cgns_supported(void); extern char *choose_init(const char *rootfs); extern bool switch_to_ns(pid_t pid, const char *ns); extern char *get_template_path(const char *t); +extern int open_without_symlink(const char *target, const char *prefix_skip); extern int safe_mount(const char *src, const char *dest, const char *fstype, unsigned long flags, const void *data, const char *rootfs); -- 1.8.3.1