From 6bbdec26f31c9fd19ba26ad30b20a0fd3985f373 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Fri, 20 Dec 2013 16:05:17 +0400 Subject: [PATCH] files: add ability to set callbacks for files (v7) Here is nothing interecting. If a file can't be dumped by criu, plugins are called. If one of plugins knows how to dump the file, the file entry is marked as need_callback. On restore if we see this mark, we execute plugins for restoring the file. v2: Callbacks are called for all files, which are not supported by CRIU. v3: Call plugins for a file instead of file descriptor. A few file descriptors can be associated with one file. v4: A file descriptor is opened in a callback. It's required for restoring anon vmas. v5: Add a separate type for unsupported files v6: define FD_TYPES__UNSUPP v7: s/unsupp/ext (external) Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- Makefile.crtools | 1 + cr-restore.c | 1 + cr-show.c | 1 + files-ext.c | 93 +++++++++++++++++++++++++++++++++++++++++ files-reg.c | 1 + files.c | 14 +++---- image-desc.c | 1 + include/criu-plugin.h | 4 ++ include/files.h | 4 ++ include/image-desc.h | 1 + include/magic.h | 1 + include/plugin.h | 3 ++ include/protobuf-desc.h | 1 + plugin.c | 20 +++++++++ protobuf-desc.c | 1 + protobuf/Makefile | 1 + protobuf/ext-file.proto | 6 +++ protobuf/fdinfo.proto | 1 + 18 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 files-ext.c create mode 100644 protobuf/ext-file.proto diff --git a/Makefile.crtools b/Makefile.crtools index aecab0f94..742d70ed5 100644 --- a/Makefile.crtools +++ b/Makefile.crtools @@ -29,6 +29,7 @@ obj-y += sk-netlink.o obj-y += sk-queue.o obj-y += files.o obj-y += files-reg.o +obj-y += files-ext.o obj-y += pipes.o obj-y += fifo.o obj-y += file-ids.o diff --git a/cr-restore.c b/cr-restore.c index e42f58296..274d76048 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -141,6 +141,7 @@ static struct collect_image_info *cinfos[] = { &tty_info_cinfo, &tty_cinfo, &tunfile_cinfo, + &ext_file_cinfo, }; static int root_prepare_shared(void) diff --git a/cr-show.c b/cr-show.c index df564a58e..c1314d0dd 100644 --- a/cr-show.c +++ b/cr-show.c @@ -319,6 +319,7 @@ static struct show_image_info show_infos[] = { SHOW_PLAINS(FILE_LOCK), SHOW_PLAIN(RLIMIT), SHOW_PLAIN(TUNFILE), + SHOW_PLAINS(EXT_FILE), { TCP_STREAM_MAGIC, PB_TCP_STREAM, true, show_tcp_stream, "1:%u 2:%u 3:%u 4:%u 12:%u", }, { STATS_MAGIC, PB_STATS, true, NULL, "1.1:%u 1.2:%u 1.3:%u 1.4:%u 1.5:%Lu 1.6:%Lu 1.7:%Lu", }, diff --git a/files-ext.c b/files-ext.c new file mode 100644 index 000000000..cd434ee37 --- /dev/null +++ b/files-ext.c @@ -0,0 +1,93 @@ +/* An external file is a file, which is dumped with help a plugin */ + +#include + +#include "fdset.h" +#include "files.h" +#include "plugin.h" + +#include "protobuf.h" +#include "protobuf/ext-file.pb-c.h" + +int dump_one_ext_file(int lfd, u32 id, const struct fd_parms *p) +{ + int rfd, ret; + + ExtFileEntry xfe = EXT_FILE_ENTRY__INIT; + + ret = cr_plugin_dump_file(lfd, id); + if (ret < 0) + return ret; + + xfe.id = id; + xfe.fown = (FownEntry *)&p->fown; + + rfd = fdset_fd(glob_fdset, CR_FD_EXT_FILES); + + return pb_write_one(rfd, &xfe, PB_EXT_FILE); +} + +const struct fdtype_ops ext_dump_ops = { + .type = FD_TYPES__EXT, + .dump = dump_one_ext_file, +}; + +struct ext_file_info { + struct file_desc d; + ExtFileEntry *xfe; +}; + +static int open_fd(struct file_desc *d) +{ + struct ext_file_info *xfi; + int fd; + + xfi = container_of(d, struct ext_file_info, d); + + fd = cr_plugin_restore_file(xfi->xfe->id); + if (fd < 0) { + pr_err("Unable to restore %#x\n", xfi->xfe->id); + return -1; + } + + if (restore_fown(fd, xfi->xfe->fown)) + return -1; + + return fd; +} + +static struct file_desc_ops ext_desc_ops = { + .type = FD_TYPES__EXT, + .open = open_fd, +}; + +static int collect_one_ext(void *o, ProtobufCMessage *base) +{ + struct ext_file_info *xfi = o; + + xfi->xfe = pb_msg(base, ExtFileEntry); + + pr_info("Collected external file with ID %#x\n", xfi->xfe->id); + return file_desc_add(&xfi->d, xfi->xfe->id, &ext_desc_ops); +} + +struct collect_image_info ext_file_cinfo = { + .fd_type = CR_FD_EXT_FILES, + .pb_type = PB_EXT_FILE, + .priv_size = sizeof(struct ext_file_info), + .collect = collect_one_ext, +}; + +int dump_unsupp_fd(struct fd_parms *p, int lfd, + const int fdinfo, char *more, char *info) +{ + int ret; + + ret = do_dump_gen_file(p, lfd, &ext_dump_ops, fdinfo); + if (ret == 0) + return 0; + if (ret == -ENOTSUP) + pr_err("Can't dump file %d of that type [%o] (%s %s)\n", + p->fd, p->stat.st_mode, more, info); + return -1; +} diff --git a/files-reg.c b/files-reg.c index 181f1f202..2b466bd92 100644 --- a/files-reg.c +++ b/files-reg.c @@ -20,6 +20,7 @@ #include "protobuf/remap-file-path.pb-c.h" #include "files-reg.h" +#include "plugin.h" /* * Ghost files are those not visible from the FS. Dumping them is diff --git a/files.c b/files.c index a0a7ac663..2d32fa8c1 100644 --- a/files.c +++ b/files.c @@ -32,12 +32,16 @@ #include "signalfd.h" #include "namespaces.h" #include "tun.h" +#include "fdset.h" #include "parasite.h" #include "parasite-syscall.h" #include "protobuf.h" #include "protobuf/fs.pb-c.h" +#include "protobuf/ext-file.pb-c.h" + +#include "plugin.h" #define FDESC_HASH_SIZE 64 static struct hlist_head file_desc_hash[FDESC_HASH_SIZE]; @@ -170,7 +174,7 @@ int do_dump_gen_file(struct fd_parms *p, int lfd, ret = ops->dump(lfd, e.id, p); if (ret < 0) - return -1; + return ret; pr_info("fdinfo: type: 0x%2x flags: %#o/%#o pos: 0x%8"PRIx64" fd: %d\n", ops->type, p->flags, (int)p->fd_flags, p->pos, p->fd); @@ -239,14 +243,6 @@ static int fill_fd_params(struct parasite_ctl *ctl, int fd, int lfd, return 0; } -static int dump_unsupp_fd(const struct fd_parms *p, int lfd, - const int fdinfo, char *more, char *info) -{ - pr_err("Can't dump file %d of that type [%o] (%s %s)\n", - p->fd, p->stat.st_mode, more, info); - return -1; -} - static const struct fdtype_ops *get_misc_dev_ops(int minor) { switch (minor) { diff --git a/image-desc.c b/image-desc.c index 2361fe436..1a02e4261 100644 --- a/image-desc.c +++ b/image-desc.c @@ -23,6 +23,7 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = { FD_ENTRY(PAGEMAP, "pagemap-%ld"), FD_ENTRY(SHMEM_PAGEMAP, "pagemap-shmem-%ld"), FD_ENTRY(REG_FILES, "reg-files"), + FD_ENTRY(EXT_FILES, "ext-files"), FD_ENTRY(NS_FILES, "ns-files"), FD_ENTRY(EVENTFD_FILE, "eventfd"), FD_ENTRY(EVENTPOLL_FILE,"eventpoll"), diff --git a/include/criu-plugin.h b/include/criu-plugin.h index b205c10bb..cf6a2c535 100644 --- a/include/criu-plugin.h +++ b/include/criu-plugin.h @@ -21,6 +21,7 @@ #define __CRIU_PLUGIN_H__ #include +#include typedef int (cr_plugin_init_t)(void); typedef void (cr_plugin_fini_t)(void); @@ -28,6 +29,9 @@ typedef void (cr_plugin_fini_t)(void); typedef int (cr_plugin_dump_unix_sk_t)(int fd, int id); typedef int (cr_plugin_restore_unix_sk_t)(int id); +typedef int (cr_plugin_dump_file_t)(int fd, int id); +typedef int (cr_plugin_restore_file_t)(int id); + /* Public API */ extern int criu_get_image_dir(void); diff --git a/include/files.h b/include/files.h index d491cf1c5..7556319de 100644 --- a/include/files.h +++ b/include/files.h @@ -147,4 +147,8 @@ extern int close_old_fds(struct pstree_item *me); extern int shared_fdt_prepare(struct pstree_item *item); +extern struct collect_image_info ext_file_cinfo; +extern int dump_unsupp_fd(struct fd_parms *p, int lfd, + const int fdinfo, char *more, char *info); + #endif /* __CR_FILES_H__ */ diff --git a/include/image-desc.h b/include/image-desc.h index a38368b63..3899fc6a4 100644 --- a/include/image-desc.h +++ b/include/image-desc.h @@ -56,6 +56,7 @@ enum { _CR_FD_GLOB_FROM, CR_FD_SK_QUEUES, CR_FD_REG_FILES, + CR_FD_EXT_FILES, CR_FD_NS_FILES, CR_FD_INETSK, CR_FD_UNIXSK, diff --git a/include/magic.h b/include/magic.h index f17a19173..c9a562285 100644 --- a/include/magic.h +++ b/include/magic.h @@ -47,6 +47,7 @@ #define IPCNS_MSG_MAGIC 0x55453737 /* Moscow */ #define IPCNS_SEM_MAGIC 0x59573019 /* St. Petersburg */ #define REG_FILES_MAGIC 0x50363636 /* Belgorod */ +#define EXT_FILES_MAGIC 0x59255641 /* Usolye */ #define FS_MAGIC 0x51403912 /* Voronezh */ #define MM_MAGIC 0x57492820 /* Pskov */ #define REMAP_FPATH_MAGIC 0x59133954 /* Vologda */ diff --git a/include/plugin.h b/include/plugin.h index a70dde3fe..6c8ab829d 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -11,4 +11,7 @@ int cr_plugin_init(void); int cr_plugin_dump_unix_sk(int fd, int id); int cr_plugin_restore_unix_sk(int id); +int cr_plugin_dump_file(int fd, int id); +int cr_plugin_restore_file(int id); + #endif diff --git a/include/protobuf-desc.h b/include/protobuf-desc.h index fd9ee4370..5daeb13ef 100644 --- a/include/protobuf-desc.h +++ b/include/protobuf-desc.h @@ -25,6 +25,7 @@ enum { PB_GHOST_FILE, PB_TCP_STREAM, PB_REG_FILE, + PB_EXT_FILE, PB_NS_FILE, PB_INET_SK, PB_UNIX_SK, diff --git a/plugin.c b/plugin.c index e65cd3f21..222a2f598 100644 --- a/plugin.c +++ b/plugin.c @@ -17,6 +17,8 @@ struct cr_plugin_entry { cr_plugin_dump_unix_sk_t *cr_plugin_dump_unix_sk; cr_plugin_restore_unix_sk_t *cr_plugin_restore_unix_sk; + cr_plugin_dump_file_t *cr_plugin_dump_file; + cr_plugin_restore_file_t *cr_plugin_restore_file; }; struct cr_plugin_entry *next; @@ -27,6 +29,8 @@ struct cr_plugins { struct cr_plugin_entry *cr_plugin_dump_unix_sk; struct cr_plugin_entry *cr_plugin_restore_unix_sk; + struct cr_plugin_entry *cr_plugin_dump_file; + struct cr_plugin_entry *cr_plugin_restore_file; }; struct cr_plugins cr_plugins; @@ -73,6 +77,16 @@ int cr_plugin_restore_unix_sk(int id) return run_plugin_funcs(cr_plugin_restore_unix_sk, id); } +int cr_plugin_dump_file(int fd, int id) +{ + return run_plugin_funcs(cr_plugin_dump_file, fd, id); +} + +int cr_plugin_restore_file(int id) +{ + return run_plugin_funcs(cr_plugin_restore_file, id); +} + static int cr_lib_load(char *path) { struct cr_plugin_entry *ce; @@ -89,6 +103,9 @@ static int cr_lib_load(char *path) add_plugin_func(cr_plugin_dump_unix_sk); add_plugin_func(cr_plugin_restore_unix_sk); + add_plugin_func(cr_plugin_dump_file); + add_plugin_func(cr_plugin_restore_file); + ce = NULL; f_fini = dlsym(h, "cr_plugin_fini"); if (f_fini) { @@ -127,6 +144,9 @@ void cr_plugin_fini(void) cr_plugin_free(cr_plugin_dump_unix_sk); cr_plugin_free(cr_plugin_restore_unix_sk); + cr_plugin_free(cr_plugin_dump_file); + cr_plugin_free(cr_plugin_restore_file); + while (cr_plugins.cr_fini) { ce = cr_plugins.cr_fini; cr_plugins.cr_fini = cr_plugins.cr_fini->next; diff --git a/protobuf-desc.c b/protobuf-desc.c index 1d0f7cd37..a86ec388e 100644 --- a/protobuf-desc.c +++ b/protobuf-desc.c @@ -18,6 +18,7 @@ #include "protobuf/inventory.pb-c.h" #include "protobuf/stats.pb-c.h" #include "protobuf/regfile.pb-c.h" +#include "protobuf/ext-file.pb-c.h" #include "protobuf/ns.pb-c.h" #include "protobuf/eventfd.pb-c.h" #include "protobuf/eventpoll.pb-c.h" diff --git a/protobuf/Makefile b/protobuf/Makefile index 7ebe77a2d..2bfd696b8 100644 --- a/protobuf/Makefile +++ b/protobuf/Makefile @@ -57,6 +57,7 @@ proto-obj-y += rlimit.o proto-obj-y += pagemap.o proto-obj-y += siginfo.o proto-obj-y += rpc.o +proto-obj-y += ext-file.o proto := $(proto-obj-y:.o=) proto-c := $(proto-obj-y:.o=.pb-c.c) diff --git a/protobuf/ext-file.proto b/protobuf/ext-file.proto new file mode 100644 index 000000000..82b1b689e --- /dev/null +++ b/protobuf/ext-file.proto @@ -0,0 +1,6 @@ +import "fown.proto"; + +message ext_file_entry { + required uint32 id = 1; + required fown_entry fown = 5; +} diff --git a/protobuf/fdinfo.proto b/protobuf/fdinfo.proto index 5850bd738..2eb7986ea 100644 --- a/protobuf/fdinfo.proto +++ b/protobuf/fdinfo.proto @@ -15,6 +15,7 @@ enum fd_types { NETLINKSK = 13; NS = 14; TUN = 15; + EXT = 16; } message fdinfo_entry {