From 653eefea0c715d737b5d478bf64bdc205fbd2189 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 28 Sep 2021 09:38:13 -0400 Subject: [PATCH] criu/plugin: Do not reopen vma fd for plugins Some device drivers (e.g DRM) only allow the file descriptor that was used to create the vma to be used when calling mmap. In this case, instead of opening a new FD, the plugin will return a valid FD that can be used for mmap later. The plugin needs to close the returned FD later. Copies of the returned FD that are created using dup or fnctl(..,F_DUPFD,..) are references to the same struct file inside kernel so they are also allowed to mmap. The plugin does not need to update the path anymore as the plugin can return a FD for the correct path. Signed-off-by: David Yat Sin --- criu/files-reg.c | 26 ++++++++++++++++++-------- criu/include/criu-plugin.h | 8 ++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/criu/files-reg.c b/criu/files-reg.c index 6759e00e5..c339876b4 100644 --- a/criu/files-reg.c +++ b/criu/files-reg.c @@ -2322,6 +2322,7 @@ static int open_filemap(int pid, struct vma_area *vma) { u32 flags; int ret; + int plugin_fd = -1; /* * The vma->fd should have been assigned in collect_filemap @@ -2335,25 +2336,34 @@ static int open_filemap(int pid, struct vma_area *vma) /* update the new device file page offsets and file paths set during restore */ if (vma->e->status & VMA_UNSUPP) { uint64_t new_pgoff; - char new_path[PATH_MAX]; int ret; struct reg_file_info *rfi = container_of(vma->vmfd, struct reg_file_info, d); - ret = run_plugins(UPDATE_VMA_MAP, rfi->rfe->name, new_path, vma->e->start, vma->e->pgoff, &new_pgoff); + ret = run_plugins(UPDATE_VMA_MAP, rfi->rfe->name, vma->e->start, vma->e->pgoff, &new_pgoff, &plugin_fd); if (ret == 1) { - pr_info("New mmap %#016" PRIx64 "->%#016" PRIx64 " path %s\n", vma->e->pgoff, new_pgoff, - new_path); + pr_info("New mmap %#016" PRIx64 ":%#016" PRIx64 "->%#016" PRIx64 " fd %d\n", vma->e->start, + vma->e->pgoff, new_pgoff, plugin_fd); vma->e->pgoff = new_pgoff; - rfi->path = xstrdup(new_path); - pr_debug("Updated rfi->path %s\n", rfi->path); } + /* Device plugin will restore vma contents, so no need for write permission */ + vma->e->status |= VMA_NO_PROT_WRITE; } if (ctx.flags != flags || ctx.desc != vma->vmfd) { - if (vma->e->status & VMA_AREA_MEMFD) + if (plugin_fd >= 0) { + /* + * Vma handled by device plugin. + * Some device drivers (e.g DRM) only allow the file descriptor that was used to create vma to + * be used when calling mmap. In this case, use the FD returned by plugin. FD can be copied + * using dup because dup returns a reference to the same struct file inside kernel, but we + * cannot open a new FD. + */ + ret = dup(plugin_fd); + } else if (vma->e->status & VMA_AREA_MEMFD) { ret = memfd_open(vma->vmfd, &flags); - else + } else { ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags); + } if (ret < 0) return ret; diff --git a/criu/include/criu-plugin.h b/criu/include/criu-plugin.h index 0bc7a4255..886832eaa 100644 --- a/criu/include/criu-plugin.h +++ b/criu/include/criu-plugin.h @@ -69,8 +69,8 @@ DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_EXT_MOUNT, char *mountpoint, int i DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__RESTORE_EXT_MOUNT, int id, char *mountpoint, char *old_root, int *is_file); DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__DUMP_EXT_LINK, int index, int type, char *kind); DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__HANDLE_DEVICE_VMA, int fd, const struct stat *stat); -DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__UPDATE_VMA_MAP, const char *old_path, char *new_path, const uint64_t addr, - const uint64_t old_pgoff, uint64_t *new_pgoff); +DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__UPDATE_VMA_MAP, const char *path, const uint64_t addr, + const uint64_t old_pgoff, uint64_t *new_pgoff, int *plugin_fd); DECLARE_PLUGIN_HOOK_ARGS(CR_PLUGIN_HOOK__RESUME_DEVICES_LATE, int pid); enum { @@ -143,8 +143,8 @@ typedef int(cr_plugin_dump_ext_mount_t)(char *mountpoint, int id); typedef int(cr_plugin_restore_ext_mount_t)(int id, char *mountpoint, char *old_root, int *is_file); typedef int(cr_plugin_dump_ext_link_t)(int index, int type, char *kind); typedef int(cr_plugin_handle_device_vma_t)(int fd, const struct stat *stat); -typedef int(cr_plugin_update_vma_map_t)(const char *old_path, char *new_path, const uint64_t addr, - const uint64_t old_pgoff, uint64_t *new_pgoff); +typedef int(cr_plugin_update_vma_map_t)(const char *path, const uint64_t addr, const uint64_t old_pgoff, + uint64_t *new_pgoff, int *plugin_fd); typedef int(cr_plugin_resume_devices_late_t)(int pid); #endif /* __CRIU_PLUGIN_H__ */