diff --git a/image.c b/image.c index a7280e704..456cbce5f 100644 --- a/image.c +++ b/image.c @@ -127,6 +127,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { FD_ENTRY(NETDEV, "netdev-%d", show_netdevices), FD_ENTRY(IFADDR, "ifaddr-%d", show_raw_image), FD_ENTRY(ROUTE, "route-%d", show_raw_image), + FD_ENTRY(TMPFS, "tmpfs-%d.tar.gz", show_raw_image), }; static struct cr_fdset *alloc_cr_fdset(int nr) diff --git a/include/crtools.h b/include/crtools.h index b45d4152c..702196b2a 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -75,6 +75,8 @@ enum { CR_FD_INOTIFY_WD, _CR_FD_GLOB_TO, + CR_FD_TMPFS, + CR_FD_MAX }; diff --git a/include/image.h b/include/image.h index 97201219c..983d3596d 100644 --- a/include/image.h +++ b/include/image.h @@ -62,6 +62,7 @@ #define IFADDR_MAGIC RAW_IMAGE_MAGIC #define ROUTE_MAGIC RAW_IMAGE_MAGIC +#define TMPFS_MAGIC RAW_IMAGE_MAGIC #define PAGE_IMAGE_SIZE 4096 #define PAGE_RSS 1 diff --git a/mount.c b/mount.c index 68a5f367a..90f82d924 100644 --- a/mount.c +++ b/mount.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "crtools.h" #include "types.h" @@ -231,6 +233,137 @@ static int close_mountpoint(DIR *dfd) return 0; } +static int tmpfs_dump(struct mount_info *pm) +{ + int ret, status; + pid_t pid; + + pid = fork(); + if (pid == -1) { + pr_perror("fork() failed\n"); + return -1; + } else if (pid == 0) { + char tmpfs_path[PATH_MAX]; + int fd, fd_img; + DIR *fdir; + + fdir = open_mountpoint(pm); + if (fdir == NULL) + exit(1); + + fd = dirfd(fdir); + if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC) == -1) { + pr_perror("Can not drop FD_CLOEXEC"); + exit(1); + } + + fd_img = open_image(CR_FD_TMPFS, O_DUMP, pm->mnt_id); + if (fd_img < 0) + exit(1); + + ret = dup2(fd_img, STDOUT_FILENO); + if (ret < 0) { + pr_perror("dup2() failed"); + exit(1); + } + ret = dup2(log_get_fd(), STDERR_FILENO); + if (ret < 0) { + pr_perror("dup2() failed"); + exit(1); + } + close(fd_img); + + /* tmpfs is in another mount namespace, + * a direct path is inaccessible */ + snprintf(tmpfs_path, sizeof(tmpfs_path), + "/proc/self/fd/%d", fd); + + execlp("tar", "tar", "-czlp", + "--sparse", + "--numeric-owner", + "-C", tmpfs_path, ".", NULL); + pr_perror("exec failed"); + exit(1); + } + + ret = waitpid(pid, &status, 0); + if (ret == -1) { + pr_perror("waitpid() failed"); + return -1; + } + + if (status) { + pr_err("Can't dump tmpfs content\n"); + return -1; + } + + return 0; +} + +static int tmpfs_restore(struct mount_info *pm) +{ + int ret, status = -1; + sigset_t mask, oldmask; + pid_t pid; + + ret = sigprocmask(SIG_SETMASK, NULL, &oldmask); + if (ret == -1) { + pr_perror("Can not get mask of blocked signals"); + return -1; + } + mask = oldmask; + sigaddset(&mask, SIGCHLD); + ret = sigprocmask(SIG_SETMASK, &mask, NULL); + if (ret == -1) { + pr_perror("Can not set mask of blocked signals"); + return -1; + } + + pid = fork(); + if (pid == -1) { + pr_perror("fork() failed\n"); + goto out_unlock; + } else if (pid == 0) { + int fd_img; + + fd_img = open_image_ro(CR_FD_TMPFS, pm->mnt_id); + if (fd_img < 0) + exit(1); + + ret = dup2(fd_img, STDIN_FILENO); + if (ret < 0) { + pr_perror("dup2() failed"); + exit(1); + } + close(fd_img); + + execlp("tar", "tar", "-xz", "-C", pm->mountpoint, NULL); + pr_perror("exec failed"); + exit(1); + } + + ret = waitpid(pid, &status, 0); + if (ret == -1) { + pr_perror("waitpid() failed"); + goto out_unlock; + } + + if (status) { + pr_err("Can't restore tmpfs content\n"); + status = -1; + goto out_unlock; + } + +out_unlock: + ret = sigprocmask(SIG_SETMASK, &oldmask, NULL); + if (ret == -1) { + pr_perror("Can not set mask of blocked signals"); + BUG_ON(1); + } + + return status; +} + static int binfmt_misc_dump(struct mount_info *pm) { int ret = -1; @@ -267,6 +400,7 @@ static struct fstype fstypes[] = { { "sysfs" }, { "devtmpfs" }, { "binfmt_misc", binfmt_misc_dump }, + { "tmpfs", tmpfs_dump, tmpfs_restore }, }; struct fstype *find_fstype_by_name(char *fst) diff --git a/test/zdtm/live/static/mountpoints.c b/test/zdtm/live/static/mountpoints.c index 303500ce1..090b02319 100644 --- a/test/zdtm/live/static/mountpoints.c +++ b/test/zdtm/live/static/mountpoints.c @@ -16,7 +16,7 @@ static char buf[1024]; static int test_fn(int argc, char **argv) { FILE *f; - int fd; + int fd, tmpfs_fd; unsigned fs_cnt, fs_cnt_last = 0; again: @@ -74,6 +74,16 @@ done: return 1; } + if (mount("none", MPTS_ROOT"/dev", "tmpfs", 0, "") < 0) { + fail("Can't mount tmpfs"); + return 1; + } + tmpfs_fd = open(MPTS_ROOT"/dev/test", O_WRONLY | O_CREAT); + if (write(tmpfs_fd, "hello", 5) <= 0) { + err("write() failed"); + return 1; + } + if (mount("none", MPTS_ROOT"/kernel", "proc", 0, "") < 0) { fail("Can't mount proc"); return 1;