[CRIU] [PATCH] mount: Move fstypes related code into separate files

Pavel Emelyanov xemul at virtuozzo.com
Thu Sep 22 01:56:33 PDT 2016


After this the mount.c is no longer the fattest .c in the tree:

  - before
    3947 criu/mount.c
    3179 criu/cr-restore.c
    2622 criu/proc_parse.c
    2095 criu/tty.c

  - after
    3179 criu/cr-restore.c
    3170 criu/mount.c
    2623 criu/proc_parse.c
    2095 criu/tty.c

One "not move" thing is -- since fstype array is static to the
filesystems.c and mount.c needs to access fstype[1] for auto 
mounts, the fstype_auto() call is added.

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
 criu/Makefile.crtools      |   1 +
 criu/cr-service.c          |   1 +
 criu/crtools.c             |   1 +
 criu/filesystems.c         | 794 +++++++++++++++++++++++++++++++++++++++++++++
 criu/fsnotify.c            |   1 +
 criu/include/filesystems.h |  30 ++
 criu/include/mount.h       |  22 +-
 criu/mount.c               | 783 +-------------------------------------------
 criu/proc_parse.c          |   1 +
 9 files changed, 833 insertions(+), 801 deletions(-)
 create mode 100644 criu/filesystems.c
 create mode 100644 criu/include/filesystems.h

diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
index 52c00ec..9955a2f 100644
--- a/criu/Makefile.crtools
+++ b/criu/Makefile.crtools
@@ -34,6 +34,7 @@ obj-y			+= log.o
 obj-y			+= lsm.o
 obj-y			+= mem.o
 obj-y			+= mount.o
+obj-y			+= filesystems.o
 obj-y			+= namespaces.o
 obj-y			+= netfilter.o
 obj-y			+= net.o
diff --git a/criu/cr-service.c b/criu/cr-service.c
index 2cb6f83..4f97397 100644
--- a/criu/cr-service.c
+++ b/criu/cr-service.c
@@ -27,6 +27,7 @@
 #include "page-xfer.h"
 #include "net.h"
 #include "mount.h"
+#include "filesystems.h"
 #include "cgroup.h"
 #include "cgroup-props.h"
 #include "action-scripts.h"
diff --git a/criu/crtools.c b/criu/crtools.c
index 40f4018..3eafed3 100644
--- a/criu/crtools.c
+++ b/criu/crtools.c
@@ -36,6 +36,7 @@
 #include "cr-service.h"
 #include "plugin.h"
 #include "mount.h"
+#include "filesystems.h"
 #include "namespaces.h"
 #include "cgroup.h"
 #include "cgroup-props.h"
diff --git a/criu/filesystems.c b/criu/filesystems.c
new file mode 100644
index 0000000..d66a6c6
--- /dev/null
+++ b/criu/filesystems.c
@@ -0,0 +1,794 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+
+#include "asm/types.h"
+#include "compiler.h"
+#include "xmalloc.h"
+#include "cr_options.h"
+#include "filesystems.h"
+#include "namespaces.h"
+#include "mount.h"
+#include "pstree.h"
+#include "kerndat.h"
+#include "protobuf.h"
+#include "autofs.h"
+#include "util.h"
+#include "fs-magic.h"
+
+#include "images/mnt.pb-c.h"
+#include "images/binfmt-misc.pb-c.h"
+
+static int attach_option(struct mount_info *pm, char *opt)
+{
+	if (pm->options[0] == '\0')
+		pm->options = xstrcat(pm->options, "%s", opt);
+	else
+		pm->options = xstrcat(pm->options, ",%s", opt);
+	return pm->options ? 0 : -1;
+}
+
+struct binfmt_misc_info {
+	BinfmtMiscEntry *bme;
+	struct list_head list;
+};
+
+LIST_HEAD(binfmt_misc_list);
+
+static int binfmt_misc_parse(struct mount_info *pm)
+{
+	if (pm->nsid->type == NS_ROOT)
+		opts.has_binfmt_misc = true;
+	return 0;
+
+}
+
+static int binfmt_misc_virtual(struct mount_info *pm)
+{
+	return kerndat_fs_virtualized(KERNDAT_FS_STAT_BINFMT_MISC, pm->s_dev);
+}
+
+static int parse_binfmt_misc_entry(struct bfd *f, BinfmtMiscEntry *bme)
+{
+	while (1) {
+		char *str;
+
+		str = breadline(f);
+                if (IS_ERR(str))
+			return -1;
+		if (!str)
+			break;
+
+		if (!strncmp(str, "enabled", 7)) {
+			bme->enabled = true;
+			continue;
+		}
+
+		if (!strncmp(str, "disabled", 8))
+			continue;
+
+		if (!strncmp(str, "offset ", 7)) {
+			if (sscanf(str + 7, "%i", &bme->offset) != 1)
+				return -1;
+			bme->has_offset = true;
+			continue;
+		}
+
+#define DUP_EQUAL_AS(key, member)					\
+		if (!strncmp(str, key, strlen(key))) {			\
+			bme->member = xstrdup(str + strlen(key));	\
+			if (!bme->member)				\
+				return -1;				\
+			continue;					\
+		}
+		DUP_EQUAL_AS("interpreter ", interpreter)
+		DUP_EQUAL_AS("flags: ", flags)
+		DUP_EQUAL_AS("extension .", extension)
+		DUP_EQUAL_AS("magic ", magic)
+		DUP_EQUAL_AS("mask ", mask)
+#undef DUP_EQUAL_AS
+
+		pr_perror("binfmt_misc: unsupported feature %s", str);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int dump_binfmt_misc_entry(int dfd, char *name, struct cr_img *img)
+{
+	BinfmtMiscEntry bme = BINFMT_MISC_ENTRY__INIT;
+	struct bfd f;
+	int ret = -1;
+
+	f.fd = openat(dfd, name, O_RDONLY);
+	if (f.fd < 0) {
+		pr_perror("binfmt_misc: can't open %s", name);
+		return -1;
+	}
+
+	if (bfdopenr(&f))
+		return -1;
+
+	if (parse_binfmt_misc_entry(&f, &bme))
+		goto err;
+
+	bme.name = name;
+
+	if (pb_write_one(img, &bme, PB_BINFMT_MISC))
+		goto err;
+	ret = 0;
+err:
+	free(bme.interpreter);
+	free(bme.flags);
+	free(bme.extension);
+	free(bme.magic);
+	free(bme.mask);
+	bclose(&f);
+	return ret;
+
+}
+
+static int binfmt_misc_dump(struct mount_info *pm)
+{
+	static bool dumped = false;
+	struct cr_img *img = NULL;
+	struct dirent *de;
+	DIR *fdir = NULL;
+	int fd, ret;
+
+	ret = binfmt_misc_virtual(pm);
+	if (ret <= 0)
+		return ret;
+
+	if (dumped) {
+		pr_err("Second binfmt_misc superblock\n");
+		return -1;
+	}
+	dumped = true;
+
+	fd = open_mountpoint(pm);
+	if (fd < 0)
+		return fd;
+
+	fdir = fdopendir(fd);
+	if (fdir == NULL) {
+		close(fd);
+		return -1;
+	}
+
+	ret = -1;
+	while ((de = readdir(fdir))) {
+		if (dir_dots(de))
+			continue;
+		if (!strcmp(de->d_name, "register"))
+			continue;
+		if (!strcmp(de->d_name, "status"))
+			continue;
+
+		if (!img) {
+			/* Create image only if an extry exists, i.e. here */
+			img = open_image(CR_FD_BINFMT_MISC, O_DUMP);
+			if (!img)
+				goto out;
+		}
+
+		if (dump_binfmt_misc_entry(fd, de->d_name, img))
+			goto out;
+	}
+
+	ret = 0;
+out:
+	if (img)
+		close_image(img);
+	closedir(fdir);
+	return ret;
+}
+
+static int write_binfmt_misc_entry(char *mp, char *buf, BinfmtMiscEntry *bme)
+{
+	int fd, len, ret = -1;
+	char path[PATH_MAX+1];
+
+	snprintf(path, PATH_MAX, "%s/register", mp);
+
+	fd = open(path, O_WRONLY);
+	if (fd < 0) {
+		pr_perror("binfmt_misc: can't open %s", path);
+		return -1;
+	}
+
+	len = strlen(buf);
+
+	if (write(fd, buf, len) != len) {
+		pr_perror("binfmt_misc: can't write to %s", path);
+		goto close;
+	}
+
+	if (!bme->enabled) {
+		close(fd);
+		snprintf(path, PATH_MAX, "%s/%s", mp, bme->name);
+
+		fd = open(path, O_WRONLY);
+		if (!fd) {
+			pr_perror("binfmt_misc: can't open %s", path);
+			goto out;
+		}
+		if (write(fd, "0", 1) != 1) {
+			pr_perror("binfmt_misc: can't write to %s", path);
+			goto close;
+		}
+	}
+
+	ret = 0;
+close:
+	close(fd);
+out:
+	return ret;
+}
+
+#define BINFMT_MISC_STR (1920 + 1)
+static int make_bfmtm_magic_str(char *buf, BinfmtMiscEntry *bme)
+{
+	int i, len;
+
+	/*
+	 * Format is ":name:type(M):offset:magic:mask:interpreter:flags".
+	 * Magic and mask are special fields. Kernel outputs them as
+	 * a sequence of hexadecimal numbers (abc -> 616263), and we
+	 * dump them without changes. But for registering a new entry
+	 * it expects every byte is prepended with \x, i.e. \x61\x62\x63.
+	 */
+	len = strlen(bme->name) + 3 /* offset < 128 */ + 2 * strlen(bme->magic)
+	    + (bme->mask ? 2 * strlen(bme->mask) : 0) + strlen(bme->interpreter)
+	    + (bme->flags ? strlen(bme->flags) : 0) + strlen(":::::::");
+
+	if ((len > BINFMT_MISC_STR - 1) || bme->offset > 128)
+		return -1;
+
+	buf += sprintf(buf, ":%s:M:%d:", bme->name, bme->offset);
+
+	len = strlen(bme->magic);
+	for (i = 0; i < len; i += 2)
+		buf += sprintf(buf, "\\x%c%c", bme->magic[i], bme->magic[i + 1]);
+
+	buf += sprintf(buf, ":");
+
+	if (bme->mask) {
+		len = strlen(bme->mask);
+		for (i = 0; i < len; i += 2)
+			buf += sprintf(buf, "\\x%c%c", bme->mask[i], bme->mask[i + 1]);
+	}
+
+	sprintf(buf, ":%s:%s", bme->interpreter, bme->flags ? : "\0");
+
+	return 1;
+}
+
+static int binfmt_misc_restore_bme(struct mount_info *mi, BinfmtMiscEntry *bme, char *buf)
+{
+	int ret;
+
+	/* :name:type:offset:magic/extension:mask:interpreter:flags */
+	if ((!bme->magic && !bme->extension) || !bme->interpreter) {
+		pr_perror("binfmt_misc: bad dump");
+		ret = -1;
+	} else if (bme->magic) {
+		ret = make_bfmtm_magic_str(buf, bme);
+	} else if (bme->extension) {
+		/* :name:E::extension::interpreter:flags */
+		ret = snprintf(buf, BINFMT_MISC_STR, ":%s:E::%s::%s:%s",
+			       bme->name, bme->extension, bme->interpreter,
+			       bme->flags ? : "\0");
+	}
+
+	if (ret > 0) {
+		pr_debug("binfmt_misc_pattern=%s\n", buf);
+		ret = write_binfmt_misc_entry(mi->mountpoint, buf, bme);
+	}
+
+	return ret;
+}
+
+static int binfmt_misc_restore(struct mount_info *mi)
+{
+	struct cr_img *img;
+	char *buf;
+	int ret = -1;
+
+	buf = xmalloc(BINFMT_MISC_STR);
+	if (!buf)
+		return -1;
+
+	if (!list_empty(&binfmt_misc_list)) {
+		struct binfmt_misc_info *bmi;
+
+		list_for_each_entry(bmi, &binfmt_misc_list, list) {
+			ret = binfmt_misc_restore_bme(mi, bmi->bme, buf);
+			if (ret)
+				break;
+		}
+		goto free_buf;
+	}
+
+	img = open_image(CR_FD_BINFMT_MISC_OLD, O_RSTR, mi->s_dev);
+	if (!img) {
+		pr_err("Can't open binfmt_misc_old image\n");
+		goto free_buf;
+	} else if (empty_image(img)) {
+		close_image(img);
+		ret = 0;
+		goto free_buf;
+	}
+
+	ret = 0;
+	while (ret == 0) {
+		BinfmtMiscEntry *bme;
+
+		ret = pb_read_one_eof(img, &bme, PB_BINFMT_MISC);
+		if (ret <= 0)
+			break;
+
+		ret = binfmt_misc_restore_bme(mi, bme, buf);
+
+		binfmt_misc_entry__free_unpacked(bme, NULL);
+	}
+
+	close_image(img);
+free_buf:
+	free(buf);
+	return ret;
+}
+
+static int collect_one_binfmt_misc_entry(void *o, ProtobufCMessage *msg, struct cr_img *img)
+{
+	struct binfmt_misc_info *bmi = o;
+
+	bmi->bme = pb_msg(msg, BinfmtMiscEntry);
+	list_add_tail(&bmi->list, &binfmt_misc_list);
+
+	return 0;
+}
+
+struct collect_image_info binfmt_misc_cinfo = {
+	.fd_type = CR_FD_BINFMT_MISC,
+	.pb_type = PB_BINFMT_MISC,
+	.priv_size = sizeof(struct binfmt_misc_info),
+	.collect = collect_one_binfmt_misc_entry,
+};
+
+int collect_binfmt_misc(void)
+{
+	return collect_image(&binfmt_misc_cinfo);
+}
+
+static int tmpfs_dump(struct mount_info *pm)
+{
+	int ret = -1, fd = -1, userns_pid = -1;
+	char tmpfs_path[PSFDS];
+	struct cr_img *img;
+
+	fd = open_mountpoint(pm);
+	if (fd < 0)
+		return fd;
+
+	/* if fd happens to be 0 here, we need to move it to something
+	 * non-zero, because cr_system_userns closes STDIN_FILENO as we are not
+	 * interested in passing stdin to tar.
+	 */
+	if (move_fd_from(&fd, STDIN_FILENO) < 0)
+		goto out;
+
+	if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC) == -1) {
+		pr_perror("Can not drop FD_CLOEXEC");
+		goto out;
+	}
+
+	img = open_image(CR_FD_TMPFS_DEV, O_DUMP, pm->s_dev);
+	if (!img)
+		goto out;
+
+	sprintf(tmpfs_path, "/proc/self/fd/%d", fd);
+
+	if (root_ns_mask & CLONE_NEWUSER)
+		userns_pid = root_item->pid.real;
+
+	ret = cr_system_userns(-1, img_raw_fd(img), -1, "tar", (char *[])
+			{ "tar", "--create",
+			"--gzip",
+			"--no-unquote",
+			"--no-wildcards",
+			"--one-file-system",
+			"--check-links",
+			"--preserve-permissions",
+			"--sparse",
+			"--numeric-owner",
+			"--directory", tmpfs_path, ".", NULL }, 0, userns_pid);
+
+	if (ret)
+		pr_err("Can't dump tmpfs content\n");
+
+	close_image(img);
+out:
+	close_safe(&fd);
+	return ret;
+}
+
+static int tmpfs_restore(struct mount_info *pm)
+{
+	int ret;
+	struct cr_img *img;
+
+	img = open_image(CR_FD_TMPFS_DEV, O_RSTR, pm->s_dev);
+	if (empty_image(img)) {
+		close_image(img);
+		img = open_image(CR_FD_TMPFS_IMG, O_RSTR, pm->mnt_id);
+	}
+	if (!img)
+		return -1;
+	if (empty_image(img)) {
+		close_image(img);
+		return -1;
+	}
+
+	ret = cr_system(img_raw_fd(img), -1, -1, "tar",
+			(char *[]) {"tar", "--extract", "--gzip",
+				"--no-unquote", "--no-wildcards",
+				"--directory", pm->mountpoint, NULL}, 0);
+	close_image(img);
+
+	if (ret) {
+		pr_err("Can't restore tmpfs content\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Virtualized devtmpfs on any side (dump or restore)
+ * means, that we should try to handle it as a plain
+ * tmpfs.
+ *
+ * Interesting case -- shared on dump and virtual on
+ * restore -- will fail, since no tarball with the fs
+ * contents will be found.
+ */
+
+static int devtmpfs_virtual(struct mount_info *pm)
+{
+	return kerndat_fs_virtualized(KERNDAT_FS_STAT_DEVTMPFS, pm->s_dev);
+}
+
+static int devtmpfs_dump(struct mount_info *pm)
+{
+	int ret;
+
+	ret = devtmpfs_virtual(pm);
+	if (ret == 1)
+		ret = tmpfs_dump(pm);
+
+	return ret;
+}
+
+static int devtmpfs_restore(struct mount_info *pm)
+{
+	int ret;
+
+	ret = devtmpfs_virtual(pm);
+	if (ret == 1)
+		ret = tmpfs_restore(pm);
+
+	return ret;
+}
+
+/* Is it mounted w or w/o the newinstance option */
+static int devpts_parse(struct mount_info *pm)
+{
+	int ret;
+
+	ret = kerndat_fs_virtualized(KERNDAT_FS_STAT_DEVPTS, pm->s_dev);
+	if (ret <= 0)
+		return ret;
+
+	/*
+	 * Kernel hides this option, but if the fs instance
+	 * is new (virtualized) we know that it was created
+	 * with -o newinstance.
+	 */
+	return attach_option(pm, "newinstance");
+}
+
+static int fusectl_dump(struct mount_info *pm)
+{
+	int fd, ret = -1;
+	struct dirent *de;
+	DIR *fdir = NULL;
+
+	fd = open_mountpoint(pm);
+	if (fd < 0)
+		return fd;
+
+	fdir = fdopendir(fd);
+	if (fdir == NULL) {
+		close(fd);
+		return -1;
+	}
+
+	while ((de = readdir(fdir))) {
+		int id;
+		struct mount_info *it;
+
+		if (dir_dots(de))
+			continue;
+
+		if (sscanf(de->d_name, "%d", &id) != 1) {
+			pr_err("wrong number of items scanned in fusectl dump\n");
+			goto out;
+		}
+
+		for (it = mntinfo; it; it = it->next) {
+			if (it->fstype->code == FSTYPE__FUSE &&
+					id == kdev_minor(it->s_dev) && !it->external) {
+				pr_err("%s is a fuse mount but not external\n", it->mountpoint);
+				goto out;
+			}
+		}
+	}
+
+	ret = 0;
+out:
+	closedir(fdir);
+	return ret;
+}
+
+static int debugfs_parse(struct mount_info *pm)
+{
+	/* tracefs is automounted underneath debugfs sometimes, and the
+	 * kernel's overmounting protection prevents us from mounting debugfs
+	 * first without tracefs, so let's always mount debugfs MS_REC.
+	 */
+	pm->flags |= MS_REC;
+
+	return 0;
+}
+
+static int tracefs_parse(struct mount_info *pm)
+{
+	return 1;
+}
+
+static int cgroup_parse(struct mount_info *pm)
+{
+	if (!(root_ns_mask & CLONE_NEWCGROUP))
+		return 0;
+
+	/* cgroup namespaced mounts don't look rooted to CRIU, so let's fake it
+	 * here.
+	 */
+	pm->private = pm->root;
+	pm->root = xstrdup("/");
+	if (!pm->root)
+		return -1;
+
+	return 0;
+}
+
+static int dump_empty_fs(struct mount_info *pm)
+{
+	int fd, ret = -1;
+
+	fd = open_mountpoint(pm);
+	if (fd < 0)
+		return fd;
+
+	ret = is_empty_dir(fd);
+	close(fd);
+	if (ret < 0) {
+		pr_err("%s isn't empty\n", pm->fstype->name);
+		return -1;
+	}
+
+	return ret ? 0 : -1;
+}
+
+/*
+ * Some fses (fuse) cannot be dumped, so we should always fail on dump/restore
+ * of these fses.
+ */
+static int always_fail(struct mount_info *pm)
+{
+	pr_err("failed to dump fs %s (%s): always fail\n", pm->mountpoint,
+							   pm->fstype->name);
+	return -1;
+}
+
+static struct fstype fstypes[] = {
+	{
+		.name = "unsupported",
+		.code = FSTYPE__UNSUPPORTED,
+	}, {
+		.name = "auto_cr",
+		.code = FSTYPE__AUTO,
+	}, {
+		.name = "proc",
+		.code = FSTYPE__PROC,
+	}, {
+		.name = "sysfs",
+		.code = FSTYPE__SYSFS,
+	}, {
+		.name = "devtmpfs",
+		.code = FSTYPE__DEVTMPFS,
+		.dump = devtmpfs_dump,
+		.restore = devtmpfs_restore,
+	}, {
+		.name = "binfmt_misc",
+		.parse = binfmt_misc_parse,
+		.code = FSTYPE__BINFMT_MISC,
+		.dump = binfmt_misc_dump,
+		.restore = binfmt_misc_restore,
+	}, {
+		.name = "tmpfs",
+		.code = FSTYPE__TMPFS,
+		.dump = tmpfs_dump,
+		.restore = tmpfs_restore,
+	}, {
+		.name = "devpts",
+		.parse = devpts_parse,
+		.code = FSTYPE__DEVPTS,
+	}, {
+		.name = "simfs",
+		.code = FSTYPE__SIMFS,
+	}, {
+		.name = "btrfs",
+		.code = FSTYPE__UNSUPPORTED,
+	}, {
+		.name = "pstore",
+		.dump = dump_empty_fs,
+		.code = FSTYPE__PSTORE,
+	}, {
+		.name = "mqueue",
+		.dump = dump_empty_fs,
+		.code = FSTYPE__MQUEUE,
+	}, {
+		.name = "securityfs",
+		.code = FSTYPE__SECURITYFS,
+	}, {
+		.name = "fusectl",
+		.dump = fusectl_dump,
+		.code = FSTYPE__FUSECTL,
+	}, {
+		.name = "debugfs",
+		.code = FSTYPE__DEBUGFS,
+		.parse = debugfs_parse,
+	}, {
+		.name = "tracefs",
+		.code = FSTYPE__TRACEFS,
+		.parse = tracefs_parse,
+	}, {
+		.name = "cgroup",
+		.code = FSTYPE__CGROUP,
+		.parse = cgroup_parse,
+	}, {
+		.name = "aufs",
+		.code = FSTYPE__AUFS,
+		.parse = aufs_parse,
+	}, {
+		.name = "fuse",
+		.code = FSTYPE__FUSE,
+		.dump = always_fail,
+		.restore = always_fail,
+	}, {
+		.name = "overlay",
+		.code = FSTYPE__OVERLAYFS,
+		.parse = overlayfs_parse,
+	}, {
+		.name = "autofs",
+		.code = FSTYPE__AUTOFS,
+		.parse = autofs_parse,
+		.dump = autofs_dump,
+		.mount = autofs_mount,
+	},
+};
+
+struct fstype *fstype_auto(void) { return &fstypes[1]; }
+
+static char fsauto_all[] = "all";
+static char *fsauto_names;
+
+static bool css_contains(const char *css, const char *str)
+{
+	int len = strlen(str);
+	const char *cur;
+
+	if (!len)
+		return false;
+
+	for (cur = css; (cur = strstr(cur, str)); cur += len) {
+		if (cur > css && cur[-1] != ',')
+			continue;
+		if (cur[len] && cur[len] != ',')
+			continue;
+		return true;
+	}
+
+	return false;
+}
+
+static bool fsname_is_auto(const char *name)
+{
+	if (!fsauto_names)
+		return false;
+
+	if (fsauto_names == fsauto_all)
+		return true;
+
+	return css_contains(fsauto_names, name);
+}
+
+bool add_fsname_auto(const char *names)
+{
+	char *old = fsauto_names;
+
+	if (old == fsauto_all)
+		return true;
+
+	if (css_contains(names, fsauto_all))
+		fsauto_names = fsauto_all;
+	else if (!old)
+		fsauto_names = xstrdup(names);
+	else {
+		if (asprintf(&fsauto_names, "%s,%s", old, names) < 0)
+			fsauto_names = NULL;
+	}
+
+	xfree(old);
+	return fsauto_names != NULL;
+}
+
+struct fstype *find_fstype_by_name(char *fst)
+{
+	int i;
+
+	/*
+	 * This fn is required for two things.
+	 * 1st -- to check supported filesystems (as just mounting
+	 * anything is wrong, almost every fs has its own features)
+	 * 2nd -- save some space in the image (since we scan all
+	 * names anyway)
+	 */
+	for (i = 1; i < ARRAY_SIZE(fstypes); i++) {
+		struct fstype *fstype = fstypes + i;
+
+		if (!strcmp(fstype->name, fst))
+			return fstype;
+	}
+
+	if (fsname_is_auto(fst))
+		return &fstypes[1];
+
+	return &fstypes[0];
+}
+
+struct fstype *decode_fstype(u32 fst)
+{
+	int i;
+
+	if (fst == FSTYPE__UNSUPPORTED)
+		goto uns;
+
+	for (i = 1; i < ARRAY_SIZE(fstypes); i++) {
+		struct fstype *fstype = fstypes + i;
+
+		if (!fstype->name)
+			break;
+
+		if (fstype->code == fst)
+			return fstype;
+	}
+uns:
+	return &fstypes[0];
+}
+
diff --git a/criu/fsnotify.c b/criu/fsnotify.c
index f1e66d0..dd3b78a 100644
--- a/criu/fsnotify.c
+++ b/criu/fsnotify.c
@@ -28,6 +28,7 @@
 #include "fsnotify.h"
 #include "fdinfo.h"
 #include "mount.h"
+#include "filesystems.h"
 #include "image.h"
 #include "util.h"
 #include "files.h"
diff --git a/criu/include/filesystems.h b/criu/include/filesystems.h
new file mode 100644
index 0000000..1e8d2aa
--- /dev/null
+++ b/criu/include/filesystems.h
@@ -0,0 +1,30 @@
+#ifndef __CR_FILESYSTEMS_H__
+#define __CR_FILESYSTEMS_H__
+extern struct fstype *find_fstype_by_name(char *fst);
+extern struct fstype *decode_fstype(u32 fst);
+extern bool add_fsname_auto(const char *names);
+
+struct mount_info;
+typedef int (*mount_fn_t)(struct mount_info *mi, const char *src, const
+			  char *fstype, unsigned long mountflags);
+
+struct fstype {
+	char *name;
+	int code;
+	int (*dump)(struct mount_info *pm);
+	int (*restore)(struct mount_info *pm);
+	int (*parse)(struct mount_info *pm);
+	mount_fn_t mount;
+};
+
+extern struct fstype *fstype_auto(void);
+
+/* callback for AUFS support */
+extern int aufs_parse(struct mount_info *mi);
+
+/* callback for OverlayFS support */
+extern int overlayfs_parse(struct mount_info *mi);
+
+/* FIXME -- remove */
+extern struct list_head binfmt_misc_list;
+#endif
diff --git a/criu/include/mount.h b/criu/include/mount.h
index 8d5dfbb..2eb3b0c 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -102,8 +102,7 @@ extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id);
 
 extern int open_mount(unsigned int s_dev);
 extern int __open_mountpoint(struct mount_info *pm, int mnt_fd);
-extern struct fstype *find_fstype_by_name(char *fst);
-extern bool add_fsname_auto(const char *names);
+extern int open_mountpoint(struct mount_info *pm);
 
 extern struct mount_info *collect_mntinfo(struct ns_id *ns, bool for_dump);
 extern int prepare_mnt_ns(void);
@@ -130,29 +129,10 @@ extern int read_mnt_ns_img(void);
 extern void cleanup_mnt_ns(void);
 extern void clean_cr_time_mounts(void);
 
-struct mount_info;
-typedef int (*mount_fn_t)(struct mount_info *mi, const char *src, const
-			  char *fstype, unsigned long mountflags);
-
-struct fstype {
-	char *name;
-	int code;
-	int (*dump)(struct mount_info *pm);
-	int (*restore)(struct mount_info *pm);
-	int (*parse)(struct mount_info *pm);
-	mount_fn_t mount;
-};
-
 extern bool add_skip_mount(const char *mountpoint);
 struct ns_id;
 extern struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump);
 
-/* callback for AUFS support */
-extern int aufs_parse(struct mount_info *mi);
-
-/* callback for OverlayFS support */
-extern int overlayfs_parse(struct mount_info *mi);
-
 extern int check_mnt_id(void);
 
 #endif /* __CR_MOUNT_H__ */
diff --git a/criu/mount.c b/criu/mount.c
index f402f6f..e69d08d 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -1,7 +1,5 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <errno.h>
@@ -19,20 +17,17 @@
 #include "util-pie.h"
 #include "log.h"
 #include "plugin.h"
+#include "filesystems.h"
 #include "mount.h"
 #include "pstree.h"
 #include "image.h"
 #include "namespaces.h"
 #include "protobuf.h"
-#include "kerndat.h"
 #include "fs-magic.h"
-#include "sysfs_parse.h"
 #include "path.h"
-#include "autofs.h"
 #include "files-reg.h"
 
 #include "images/mnt.pb-c.h"
-#include "images/binfmt-misc.pb-c.h"
 
 #define AUTODETECTED_MOUNT "CRIU:AUTOGENERATED"
 #define MS_PROPAGATE (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE | MS_SLAVE)
@@ -43,14 +38,6 @@
 #define BINFMT_MISC_HOME "/proc/sys/fs/binfmt_misc"
 #define CRTIME_MNT_ID 0
 
-struct binfmt_misc_info {
-	BinfmtMiscEntry *bme;
-	struct list_head list;
-};
-
-static LIST_HEAD(binfmt_misc_list);
-static struct fstype fstypes[];
-
 int ext_mount_add(char *key, char *val)
 {
 	struct ext_mount *em;
@@ -97,8 +84,6 @@ static void mntinfo_add_list(struct mount_info *new)
 	}
 }
 
-static int open_mountpoint(struct mount_info *pm);
-
 static struct mount_info *mnt_build_tree(struct mount_info *list, struct mount_info *roots_mp);
 static int validate_mounts(struct mount_info *info, bool for_dump);
 
@@ -503,7 +488,7 @@ static int try_resolve_ext_mount(struct mount_info *info)
 				return -1;
 
 			snprintf(source, len, "dev[%s]", val);
-			info->fstype = &fstypes[1];
+			info->fstype = fstype_auto();
 			BUG_ON(info->fstype->code != FSTYPE__AUTO);
 			xfree(info->source);
 			info->source = source;
@@ -1067,7 +1052,7 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_
 }
 
 #define MNT_UNREACHABLE INT_MIN
-static int open_mountpoint(struct mount_info *pm)
+int open_mountpoint(struct mount_info *pm)
 {
 	struct mount_info *c;
 	int fd = -1, ns_old = -1;
@@ -1140,15 +1125,6 @@ out:
 	return -1;
 }
 
-static int attach_option(struct mount_info *pm, char *opt)
-{
-	if (pm->options[0] == '\0')
-		pm->options = xstrcat(pm->options, "%s", opt);
-	else
-		pm->options = xstrcat(pm->options, ",%s", opt);
-	return pm->options ? 0 : -1;
-}
-
 static int add_cr_time_mount(struct mount_info *root, char *fsname, const char *path, unsigned int s_dev)
 {
 	struct mount_info *mi, *t, *parent;
@@ -1196,152 +1172,6 @@ static int add_cr_time_mount(struct mount_info *root, char *fsname, const char *
 	return 0;
 }
 
-
-/* Is it mounted w or w/o the newinstance option */
-static int devpts_parse(struct mount_info *pm)
-{
-	int ret;
-
-	ret = kerndat_fs_virtualized(KERNDAT_FS_STAT_DEVPTS, pm->s_dev);
-	if (ret <= 0)
-		return ret;
-
-	/*
-	 * Kernel hides this option, but if the fs instance
-	 * is new (virtualized) we know that it was created
-	 * with -o newinstance.
-	 */
-	return attach_option(pm, "newinstance");
-}
-
-static int tmpfs_dump(struct mount_info *pm)
-{
-	int ret = -1, fd = -1, userns_pid = -1;
-	char tmpfs_path[PSFDS];
-	struct cr_img *img;
-
-	fd = open_mountpoint(pm);
-	if (fd < 0)
-		return fd;
-
-	/* if fd happens to be 0 here, we need to move it to something
-	 * non-zero, because cr_system_userns closes STDIN_FILENO as we are not
-	 * interested in passing stdin to tar.
-	 */
-	if (move_fd_from(&fd, STDIN_FILENO) < 0)
-		goto out;
-
-	if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC) == -1) {
-		pr_perror("Can not drop FD_CLOEXEC");
-		goto out;
-	}
-
-	img = open_image(CR_FD_TMPFS_DEV, O_DUMP, pm->s_dev);
-	if (!img)
-		goto out;
-
-	sprintf(tmpfs_path, "/proc/self/fd/%d", fd);
-
-	if (root_ns_mask & CLONE_NEWUSER)
-		userns_pid = root_item->pid.real;
-
-	ret = cr_system_userns(-1, img_raw_fd(img), -1, "tar", (char *[])
-			{ "tar", "--create",
-			"--gzip",
-			"--no-unquote",
-			"--no-wildcards",
-			"--one-file-system",
-			"--check-links",
-			"--preserve-permissions",
-			"--sparse",
-			"--numeric-owner",
-			"--directory", tmpfs_path, ".", NULL }, 0, userns_pid);
-
-	if (ret)
-		pr_err("Can't dump tmpfs content\n");
-
-	close_image(img);
-out:
-	close_safe(&fd);
-	return ret;
-}
-
-/*
- * Virtualized devtmpfs on any side (dump or restore)
- * means, that we should try to handle it as a plain
- * tmpfs.
- *
- * Interesting case -- shared on dump and virtual on
- * restore -- will fail, since no tarball with the fs
- * contents will be found.
- */
-
-static int devtmpfs_virtual(struct mount_info *pm)
-{
-	return kerndat_fs_virtualized(KERNDAT_FS_STAT_DEVTMPFS, pm->s_dev);
-}
-
-static int devtmpfs_dump(struct mount_info *pm)
-{
-	int ret;
-
-	ret = devtmpfs_virtual(pm);
-	if (ret == 1)
-		ret = tmpfs_dump(pm);
-
-	return ret;
-}
-
-static int tmpfs_restore(struct mount_info *pm)
-{
-	int ret;
-	struct cr_img *img;
-
-	img = open_image(CR_FD_TMPFS_DEV, O_RSTR, pm->s_dev);
-	if (empty_image(img)) {
-		close_image(img);
-		img = open_image(CR_FD_TMPFS_IMG, O_RSTR, pm->mnt_id);
-	}
-	if (!img)
-		return -1;
-	if (empty_image(img)) {
-		close_image(img);
-		return -1;
-	}
-
-	ret = cr_system(img_raw_fd(img), -1, -1, "tar",
-			(char *[]) {"tar", "--extract", "--gzip",
-				"--no-unquote", "--no-wildcards",
-				"--directory", pm->mountpoint, NULL}, 0);
-	close_image(img);
-
-	if (ret) {
-		pr_err("Can't restore tmpfs content\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int devtmpfs_restore(struct mount_info *pm)
-{
-	int ret;
-
-	ret = devtmpfs_virtual(pm);
-	if (ret == 1)
-		ret = tmpfs_restore(pm);
-
-	return ret;
-}
-
-static int binfmt_misc_parse(struct mount_info *pm)
-{
-	if (pm->nsid->type == NS_ROOT)
-		opts.has_binfmt_misc = true;
-	return 0;
-
-}
-
 /* Returns 1 in case of success, -errno in case of mount fail, and 0 on other errors */
 static int mount_cr_time_mount(struct ns_id *ns, unsigned int *s_dev, const char *source,
 			       const char *target, const char *type)
@@ -1375,614 +1205,7 @@ out:
 	return ret < 0 ? 0 : exit_code;
 }
 
-static int binfmt_misc_virtual(struct mount_info *pm)
-{
-	return kerndat_fs_virtualized(KERNDAT_FS_STAT_BINFMT_MISC, pm->s_dev);
-}
-
-static int parse_binfmt_misc_entry(struct bfd *f, BinfmtMiscEntry *bme)
-{
-	while (1) {
-		char *str;
-
-		str = breadline(f);
-                if (IS_ERR(str))
-			return -1;
-		if (!str)
-			break;
-
-		if (!strncmp(str, "enabled", 7)) {
-			bme->enabled = true;
-			continue;
-		}
-
-		if (!strncmp(str, "disabled", 8))
-			continue;
-
-		if (!strncmp(str, "offset ", 7)) {
-			if (sscanf(str + 7, "%i", &bme->offset) != 1)
-				return -1;
-			bme->has_offset = true;
-			continue;
-		}
-
-#define DUP_EQUAL_AS(key, member)					\
-		if (!strncmp(str, key, strlen(key))) {			\
-			bme->member = xstrdup(str + strlen(key));	\
-			if (!bme->member)				\
-				return -1;				\
-			continue;					\
-		}
-		DUP_EQUAL_AS("interpreter ", interpreter)
-		DUP_EQUAL_AS("flags: ", flags)
-		DUP_EQUAL_AS("extension .", extension)
-		DUP_EQUAL_AS("magic ", magic)
-		DUP_EQUAL_AS("mask ", mask)
-#undef DUP_EQUAL_AS
-
-		pr_perror("binfmt_misc: unsupported feature %s", str);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int dump_binfmt_misc_entry(int dfd, char *name, struct cr_img *img)
-{
-	BinfmtMiscEntry bme = BINFMT_MISC_ENTRY__INIT;
-	struct bfd f;
-	int ret = -1;
-
-	f.fd = openat(dfd, name, O_RDONLY);
-	if (f.fd < 0) {
-		pr_perror("binfmt_misc: can't open %s", name);
-		return -1;
-	}
-
-	if (bfdopenr(&f))
-		return -1;
-
-	if (parse_binfmt_misc_entry(&f, &bme))
-		goto err;
-
-	bme.name = name;
-
-	if (pb_write_one(img, &bme, PB_BINFMT_MISC))
-		goto err;
-	ret = 0;
-err:
-	free(bme.interpreter);
-	free(bme.flags);
-	free(bme.extension);
-	free(bme.magic);
-	free(bme.mask);
-	bclose(&f);
-	return ret;
-
-}
-
-static int binfmt_misc_dump(struct mount_info *pm)
-{
-	static bool dumped = false;
-	struct cr_img *img = NULL;
-	struct dirent *de;
-	DIR *fdir = NULL;
-	int fd, ret;
-
-	ret = binfmt_misc_virtual(pm);
-	if (ret <= 0)
-		return ret;
-
-	if (dumped) {
-		pr_err("Second binfmt_misc superblock\n");
-		return -1;
-	}
-	dumped = true;
-
-	fd = open_mountpoint(pm);
-	if (fd < 0)
-		return fd;
-
-	fdir = fdopendir(fd);
-	if (fdir == NULL) {
-		close(fd);
-		return -1;
-	}
-
-	ret = -1;
-	while ((de = readdir(fdir))) {
-		if (dir_dots(de))
-			continue;
-		if (!strcmp(de->d_name, "register"))
-			continue;
-		if (!strcmp(de->d_name, "status"))
-			continue;
-
-		if (!img) {
-			/* Create image only if an extry exists, i.e. here */
-			img = open_image(CR_FD_BINFMT_MISC, O_DUMP);
-			if (!img)
-				goto out;
-		}
-
-		if (dump_binfmt_misc_entry(fd, de->d_name, img))
-			goto out;
-	}
-
-	ret = 0;
-out:
-	if (img)
-		close_image(img);
-	closedir(fdir);
-	return ret;
-}
-
-static int write_binfmt_misc_entry(char *mp, char *buf, BinfmtMiscEntry *bme)
-{
-	int fd, len, ret = -1;
-	char path[PATH_MAX+1];
-
-	snprintf(path, PATH_MAX, "%s/register", mp);
-
-	fd = open(path, O_WRONLY);
-	if (fd < 0) {
-		pr_perror("binfmt_misc: can't open %s", path);
-		return -1;
-	}
-
-	len = strlen(buf);
-
-	if (write(fd, buf, len) != len) {
-		pr_perror("binfmt_misc: can't write to %s", path);
-		goto close;
-	}
-
-	if (!bme->enabled) {
-		close(fd);
-		snprintf(path, PATH_MAX, "%s/%s", mp, bme->name);
-
-		fd = open(path, O_WRONLY);
-		if (!fd) {
-			pr_perror("binfmt_misc: can't open %s", path);
-			goto out;
-		}
-		if (write(fd, "0", 1) != 1) {
-			pr_perror("binfmt_misc: can't write to %s", path);
-			goto close;
-		}
-	}
-
-	ret = 0;
-close:
-	close(fd);
-out:
-	return ret;
-}
-
-#define BINFMT_MISC_STR (1920 + 1)
-static int make_bfmtm_magic_str(char *buf, BinfmtMiscEntry *bme)
-{
-	int i, len;
-
-	/*
-	 * Format is ":name:type(M):offset:magic:mask:interpreter:flags".
-	 * Magic and mask are special fields. Kernel outputs them as
-	 * a sequence of hexadecimal numbers (abc -> 616263), and we
-	 * dump them without changes. But for registering a new entry
-	 * it expects every byte is prepended with \x, i.e. \x61\x62\x63.
-	 */
-	len = strlen(bme->name) + 3 /* offset < 128 */ + 2 * strlen(bme->magic)
-	    + (bme->mask ? 2 * strlen(bme->mask) : 0) + strlen(bme->interpreter)
-	    + (bme->flags ? strlen(bme->flags) : 0) + strlen(":::::::");
-
-	if ((len > BINFMT_MISC_STR - 1) || bme->offset > 128)
-		return -1;
-
-	buf += sprintf(buf, ":%s:M:%d:", bme->name, bme->offset);
-
-	len = strlen(bme->magic);
-	for (i = 0; i < len; i += 2)
-		buf += sprintf(buf, "\\x%c%c", bme->magic[i], bme->magic[i + 1]);
-
-	buf += sprintf(buf, ":");
-
-	if (bme->mask) {
-		len = strlen(bme->mask);
-		for (i = 0; i < len; i += 2)
-			buf += sprintf(buf, "\\x%c%c", bme->mask[i], bme->mask[i + 1]);
-	}
-
-	sprintf(buf, ":%s:%s", bme->interpreter, bme->flags ? : "\0");
-
-	return 1;
-}
-
-static int binfmt_misc_restore_bme(struct mount_info *mi, BinfmtMiscEntry *bme, char *buf)
-{
-	int ret;
-
-	/* :name:type:offset:magic/extension:mask:interpreter:flags */
-	if ((!bme->magic && !bme->extension) || !bme->interpreter) {
-		pr_perror("binfmt_misc: bad dump");
-		ret = -1;
-	} else if (bme->magic) {
-		ret = make_bfmtm_magic_str(buf, bme);
-	} else if (bme->extension) {
-		/* :name:E::extension::interpreter:flags */
-		ret = snprintf(buf, BINFMT_MISC_STR, ":%s:E::%s::%s:%s",
-			       bme->name, bme->extension, bme->interpreter,
-			       bme->flags ? : "\0");
-	}
-
-	if (ret > 0) {
-		pr_debug("binfmt_misc_pattern=%s\n", buf);
-		ret = write_binfmt_misc_entry(mi->mountpoint, buf, bme);
-	}
-
-	return ret;
-}
-
-static int binfmt_misc_restore(struct mount_info *mi)
-{
-	struct cr_img *img;
-	char *buf;
-	int ret = -1;
-
-	buf = xmalloc(BINFMT_MISC_STR);
-	if (!buf)
-		return -1;
-
-	if (!list_empty(&binfmt_misc_list)) {
-		struct binfmt_misc_info *bmi;
-
-		list_for_each_entry(bmi, &binfmt_misc_list, list) {
-			ret = binfmt_misc_restore_bme(mi, bmi->bme, buf);
-			if (ret)
-				break;
-		}
-		goto free_buf;
-	}
-
-	img = open_image(CR_FD_BINFMT_MISC_OLD, O_RSTR, mi->s_dev);
-	if (!img) {
-		pr_err("Can't open binfmt_misc_old image\n");
-		goto free_buf;
-	} else if (empty_image(img)) {
-		close_image(img);
-		ret = 0;
-		goto free_buf;
-	}
-
-	ret = 0;
-	while (ret == 0) {
-		BinfmtMiscEntry *bme;
-
-		ret = pb_read_one_eof(img, &bme, PB_BINFMT_MISC);
-		if (ret <= 0)
-			break;
-
-		ret = binfmt_misc_restore_bme(mi, bme, buf);
-
-		binfmt_misc_entry__free_unpacked(bme, NULL);
-	}
-
-	close_image(img);
-free_buf:
-	free(buf);
-	return ret;
-}
-
-static int collect_one_binfmt_misc_entry(void *o, ProtobufCMessage *msg, struct cr_img *img)
-{
-	struct binfmt_misc_info *bmi = o;
-
-	bmi->bme = pb_msg(msg, BinfmtMiscEntry);
-	list_add_tail(&bmi->list, &binfmt_misc_list);
-
-	return 0;
-}
-
-struct collect_image_info binfmt_misc_cinfo = {
-	.fd_type = CR_FD_BINFMT_MISC,
-	.pb_type = PB_BINFMT_MISC,
-	.priv_size = sizeof(struct binfmt_misc_info),
-	.collect = collect_one_binfmt_misc_entry,
-};
-
-int collect_binfmt_misc(void)
-{
-	return collect_image(&binfmt_misc_cinfo);
-}
-
-
-static int fusectl_dump(struct mount_info *pm)
-{
-	int fd, ret = -1;
-	struct dirent *de;
-	DIR *fdir = NULL;
-
-	fd = open_mountpoint(pm);
-	if (fd < 0)
-		return fd;
-
-	fdir = fdopendir(fd);
-	if (fdir == NULL) {
-		close(fd);
-		return -1;
-	}
-
-	while ((de = readdir(fdir))) {
-		int id;
-		struct mount_info *it;
-
-		if (dir_dots(de))
-			continue;
-
-		if (sscanf(de->d_name, "%d", &id) != 1) {
-			pr_err("wrong number of items scanned in fusectl dump\n");
-			goto out;
-		}
-
-		for (it = mntinfo; it; it = it->next) {
-			if (it->fstype->code == FSTYPE__FUSE &&
-					id == kdev_minor(it->s_dev) && !it->external) {
-				pr_err("%s is a fuse mount but not external\n", it->mountpoint);
-				goto out;
-			}
-		}
-	}
-
-	ret = 0;
-out:
-	closedir(fdir);
-	return ret;
-}
-
-static int debugfs_parse(struct mount_info *pm)
-{
-	/* tracefs is automounted underneath debugfs sometimes, and the
-	 * kernel's overmounting protection prevents us from mounting debugfs
-	 * first without tracefs, so let's always mount debugfs MS_REC.
-	 */
-	pm->flags |= MS_REC;
-
-	return 0;
-}
-
-static int tracefs_parse(struct mount_info *pm)
-{
-	return 1;
-}
-
-static int cgroup_parse(struct mount_info *pm)
-{
-	if (!(root_ns_mask & CLONE_NEWCGROUP))
-		return 0;
-
-	/* cgroup namespaced mounts don't look rooted to CRIU, so let's fake it
-	 * here.
-	 */
-	pm->private = pm->root;
-	pm->root = xstrdup("/");
-	if (!pm->root)
-		return -1;
-
-	return 0;
-}
-
-static int dump_empty_fs(struct mount_info *pm)
-{
-	int fd, ret = -1;
-
-	fd = open_mountpoint(pm);
-	if (fd < 0)
-		return fd;
-
-	ret = is_empty_dir(fd);
-	close(fd);
-	if (ret < 0) {
-		pr_err("%s isn't empty\n", pm->fstype->name);
-		return -1;
-	}
-
-	return ret ? 0 : -1;
-}
-
-/*
- * Some fses (fuse) cannot be dumped, so we should always fail on dump/restore
- * of these fses.
- */
-static int always_fail(struct mount_info *pm)
-{
-	pr_err("failed to dump fs %s (%s): always fail\n", pm->mountpoint,
-							   pm->fstype->name);
-	return -1;
-}
-
-static struct fstype fstypes[] = {
-	{
-		.name = "unsupported",
-		.code = FSTYPE__UNSUPPORTED,
-	}, {
-		.name = "auto_cr",
-		.code = FSTYPE__AUTO,
-	}, {
-		.name = "proc",
-		.code = FSTYPE__PROC,
-	}, {
-		.name = "sysfs",
-		.code = FSTYPE__SYSFS,
-	}, {
-		.name = "devtmpfs",
-		.code = FSTYPE__DEVTMPFS,
-		.dump = devtmpfs_dump,
-		.restore = devtmpfs_restore,
-	}, {
-		.name = "binfmt_misc",
-		.parse = binfmt_misc_parse,
-		.code = FSTYPE__BINFMT_MISC,
-		.dump = binfmt_misc_dump,
-		.restore = binfmt_misc_restore,
-	}, {
-		.name = "tmpfs",
-		.code = FSTYPE__TMPFS,
-		.dump = tmpfs_dump,
-		.restore = tmpfs_restore,
-	}, {
-		.name = "devpts",
-		.parse = devpts_parse,
-		.code = FSTYPE__DEVPTS,
-	}, {
-		.name = "simfs",
-		.code = FSTYPE__SIMFS,
-	}, {
-		.name = "btrfs",
-		.code = FSTYPE__UNSUPPORTED,
-	}, {
-		.name = "pstore",
-		.dump = dump_empty_fs,
-		.code = FSTYPE__PSTORE,
-	}, {
-		.name = "mqueue",
-		.dump = dump_empty_fs,
-		.code = FSTYPE__MQUEUE,
-	}, {
-		.name = "securityfs",
-		.code = FSTYPE__SECURITYFS,
-	}, {
-		.name = "fusectl",
-		.dump = fusectl_dump,
-		.code = FSTYPE__FUSECTL,
-	}, {
-		.name = "debugfs",
-		.code = FSTYPE__DEBUGFS,
-		.parse = debugfs_parse,
-	}, {
-		.name = "tracefs",
-		.code = FSTYPE__TRACEFS,
-		.parse = tracefs_parse,
-	}, {
-		.name = "cgroup",
-		.code = FSTYPE__CGROUP,
-		.parse = cgroup_parse,
-	}, {
-		.name = "aufs",
-		.code = FSTYPE__AUFS,
-		.parse = aufs_parse,
-	}, {
-		.name = "fuse",
-		.code = FSTYPE__FUSE,
-		.dump = always_fail,
-		.restore = always_fail,
-	}, {
-		.name = "overlay",
-		.code = FSTYPE__OVERLAYFS,
-		.parse = overlayfs_parse,
-	}, {
-		.name = "autofs",
-		.code = FSTYPE__AUTOFS,
-		.parse = autofs_parse,
-		.dump = autofs_dump,
-		.mount = autofs_mount,
-	},
-};
-
-static char fsauto_all[] = "all";
-static char *fsauto_names;
-
-static bool css_contains(const char *css, const char *str)
-{
-	int len = strlen(str);
-	const char *cur;
 
-	if (!len)
-		return false;
-
-	for (cur = css; (cur = strstr(cur, str)); cur += len) {
-		if (cur > css && cur[-1] != ',')
-			continue;
-		if (cur[len] && cur[len] != ',')
-			continue;
-		return true;
-	}
-
-	return false;
-}
-
-static bool fsname_is_auto(const char *name)
-{
-	if (!fsauto_names)
-		return false;
-
-	if (fsauto_names == fsauto_all)
-		return true;
-
-	return css_contains(fsauto_names, name);
-}
-
-bool add_fsname_auto(const char *names)
-{
-	char *old = fsauto_names;
-
-	if (old == fsauto_all)
-		return true;
-
-	if (css_contains(names, fsauto_all))
-		fsauto_names = fsauto_all;
-	else if (!old)
-		fsauto_names = xstrdup(names);
-	else {
-		if (asprintf(&fsauto_names, "%s,%s", old, names) < 0)
-			fsauto_names = NULL;
-	}
-
-	xfree(old);
-	return fsauto_names != NULL;
-}
-
-struct fstype *find_fstype_by_name(char *fst)
-{
-	int i;
-
-	/*
-	 * This fn is required for two things.
-	 * 1st -- to check supported filesystems (as just mounting
-	 * anything is wrong, almost every fs has its own features)
-	 * 2nd -- save some space in the image (since we scan all
-	 * names anyway)
-	 */
-	for (i = 1; i < ARRAY_SIZE(fstypes); i++) {
-		struct fstype *fstype = fstypes + i;
-
-		if (!strcmp(fstype->name, fst))
-			return fstype;
-	}
-
-	if (fsname_is_auto(fst))
-		return &fstypes[1];
-
-	return &fstypes[0];
-}
-
-static struct fstype *decode_fstype(u32 fst)
-{
-	int i;
-
-	if (fst == FSTYPE__UNSUPPORTED)
-		goto uns;
-
-	for (i = 1; i < ARRAY_SIZE(fstypes); i++) {
-		struct fstype *fstype = fstypes + i;
-
-		if (!fstype->name)
-			break;
-
-		if (fstype->code == fst)
-			return fstype;
-	}
-uns:
-	return &fstypes[0];
-}
 
 static int dump_one_fs(struct mount_info *mi)
 {
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index 49d6c1a..204c31e 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -14,6 +14,7 @@
 #include "list.h"
 #include "util.h"
 #include "mount.h"
+#include "filesystems.h"
 #include "mman.h"
 #include "cpu.h"
 #include "file-lock.h"
-- 
2.5.0


More information about the CRIU mailing list