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 <david.yatsin@amd.com>
This commit is contained in:
David Yat Sin 2021-09-28 09:38:13 -04:00 committed by Andrei Vagin
parent 5b0a639a55
commit 653eefea0c
2 changed files with 22 additions and 12 deletions

View file

@ -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;

View file

@ -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__ */