370 lines
10 KiB
Diff
370 lines
10 KiB
Diff
From af999d8da16a36ff541d27d84d40bcf97f62e581 Mon Sep 17 00:00:00 2001
|
|
From: tanyifeng <tanyifeng1@huawei.com>
|
|
Date: Tue, 15 Jan 2019 19:54:13 +0800
|
|
Subject: [PATCH 033/139] support mount squashfs in mount entry
|
|
|
|
Signed-off-by: LiFeng <lifeng68@huawei.com>
|
|
---
|
|
src/lxc/conf.c | 88 +++++++++++++++++++++++++++++++++++++++--
|
|
src/lxc/storage/loop.c | 36 ++++++++++++++---
|
|
src/lxc/storage/storage_utils.c | 36 ++++++++++++++++-
|
|
src/lxc/utils.c | 33 ++++++++++++++--
|
|
src/lxc/utils.h | 1 +
|
|
5 files changed, 181 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
|
|
index 54b967b..fea0f59 100644
|
|
--- a/src/lxc/conf.c
|
|
+++ b/src/lxc/conf.c
|
|
@@ -78,6 +78,7 @@
|
|
#include "storage/overlay.h"
|
|
#include "syscall_wrappers.h"
|
|
#include "terminal.h"
|
|
+#include "loop.h"
|
|
#include "path.h"
|
|
#include "utils.h"
|
|
|
|
@@ -2444,6 +2445,82 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
|
|
return 0;
|
|
}
|
|
|
|
+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/<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;
|
|
+}
|
|
+
|
|
/* 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,
|
|
@@ -2502,8 +2579,14 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
|
|
return -1;
|
|
}
|
|
|
|
- ret = mount_entry(mntent->mnt_fsname, dest, mntent->mnt_type, mntflags,
|
|
- pflags, mntdata, optional, dev, relative, rootfs_path);
|
|
+ // 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 {
|
|
+ ret = mount_entry(mntent->mnt_fsname, dest, mntent->mnt_type, mntflags,
|
|
+ pflags, mntdata, optional, dev, relative, rootfs_path);
|
|
+ }
|
|
|
|
free(mntdata);
|
|
free(rpath);
|
|
@@ -3897,7 +3980,6 @@ static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs)
|
|
return 0;
|
|
}
|
|
|
|
-
|
|
int lxc_setup(struct lxc_handler *handler)
|
|
{
|
|
int ret;
|
|
diff --git a/src/lxc/storage/loop.c b/src/lxc/storage/loop.c
|
|
index 35cb13e..760def8 100644
|
|
--- a/src/lxc/storage/loop.c
|
|
+++ b/src/lxc/storage/loop.c
|
|
@@ -41,6 +41,7 @@
|
|
#include "loop.h"
|
|
#include "storage.h"
|
|
#include "storage_utils.h"
|
|
+#include "lxclock.h"
|
|
#include "utils.h"
|
|
|
|
lxc_log_define(loop, lxc);
|
|
@@ -236,9 +237,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;
|
|
@@ -246,13 +249,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);
|
|
|
|
@@ -261,14 +280,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 b4dcb57..0a87778 100644
|
|
--- a/src/lxc/storage/storage_utils.c
|
|
+++ b/src/lxc/storage/storage_utils.c
|
|
@@ -339,10 +339,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;
|
|
@@ -371,15 +375,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;
|
|
}
|
|
|
|
@@ -399,6 +418,8 @@ int find_fstype_cb(char *buffer, void *data)
|
|
unsigned long mntflags, pflags;
|
|
char *mntdata;
|
|
char *fstype;
|
|
+ char mount_err[BUFSIZ] = {0};
|
|
+ int ret;
|
|
|
|
/* we don't try 'nodev' entries */
|
|
if (strstr(buffer, "nodev"))
|
|
@@ -419,6 +440,17 @@ int find_fstype_cb(char *buffer, void *data)
|
|
if (mount(cbarg->rootfs, cbarg->target, fstype, (mntflags & ~MS_RDONLY), mntdata)) {
|
|
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 d1a22f7..120a13d 100644
|
|
--- a/src/lxc/utils.c
|
|
+++ b/src/lxc/utils.c
|
|
@@ -1053,7 +1053,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;
|
|
@@ -1473,6 +1473,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) {
|
|
@@ -1489,10 +1492,34 @@ 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 (fd_tmp < 0) {
|
|
+ /* 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;
|
|
+ }
|
|
|
|
on_error:
|
|
close(fd_ctl);
|
|
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
|
|
index abc88ca..4313942 100644
|
|
--- a/src/lxc/utils.h
|
|
+++ b/src/lxc/utils.h
|
|
@@ -224,6 +224,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
|
|
|