Skip to content

Commit

Permalink
memfd: add memory mapping support
Browse files Browse the repository at this point in the history
* During checkpoint, we add a vma flags: VMA_AREA_MEMFD to denote memfd
  regions.
* Even though memfd is backed by the shmem device, we use the file
  semantics of memfd (via /proc/map_files/<vma>) which we already have
  support for.

Signed-off-by: Nicolas Viennot <[email protected]>
  • Loading branch information
nviennot authored and avagin committed Mar 27, 2020
1 parent b25684e commit 29a1a88
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 4 deletions.
6 changes: 5 additions & 1 deletion criu/cr-dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
#include "fault-injection.h"
#include "dump.h"
#include "eventpoll.h"
#include "memfd.h"

/*
* Architectures can overwrite this function to restore register sets that
Expand Down Expand Up @@ -414,7 +415,10 @@ static int dump_filemap(struct vma_area *vma_area, int fd)

/* Flags will be set during restore in open_filmap() */

ret = dump_one_reg_file_cond(fd, &id, &p);
if (vma->status & VMA_AREA_MEMFD)
ret = dump_one_memfd_cond(fd, &id, &p);
else
ret = dump_one_reg_file_cond(fd, &id, &p);

vma->shmid = id;
return ret;
Expand Down
11 changes: 9 additions & 2 deletions criu/files-reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "pstree.h"
#include "fault-injection.h"
#include "external.h"
#include "memfd.h"

#include "protobuf.h"
#include "util.h"
Expand Down Expand Up @@ -1879,7 +1880,10 @@ static int open_filemap(int pid, struct vma_area *vma)
flags = vma->e->fdflags;

if (ctx.flags != flags || ctx.desc != vma->vmfd) {
ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags);
if (vma->e->status & VMA_AREA_MEMFD)
ret = memfd_open(vma->vmfd, &flags);
else
ret = open_path(vma->vmfd, do_open_reg_noseek_flags, &flags);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -1909,7 +1913,10 @@ int collect_filemap(struct vma_area *vma)
vma->e->fdflags = O_RDONLY;
}

fd = collect_special_file(vma->e->shmid);
if (vma->e->status & VMA_AREA_MEMFD)
fd = collect_memfd(vma->e->shmid);
else
fd = collect_special_file(vma->e->shmid);
if (!fd)
return -1;

Expand Down
1 change: 1 addition & 0 deletions criu/include/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
#define VMA_AREA_SOCKET (1 << 11)
#define VMA_AREA_VVAR (1 << 12)
#define VMA_AREA_AIORING (1 << 13)
#define VMA_AREA_MEMFD (1 << 14)

#define VMA_CLOSE (1 << 28)
#define VMA_NO_PROT_WRITE (1 << 29)
Expand Down
6 changes: 6 additions & 0 deletions criu/include/memfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
#include "int.h"
#include "common/config.h"

struct fd_parms;
struct file_desc;

extern int is_memfd(dev_t dev, const char *path);
extern int dump_one_memfd_cond(int lfd, u32 *id, struct fd_parms *parms);
extern const struct fdtype_ops memfd_dump_ops;

extern int memfd_open(struct file_desc *d, u32 *fdflags);
extern struct collect_image_info memfd_cinfo;
extern struct file_desc *collect_memfd(u32 id);

#ifdef CONFIG_HAS_MEMFD_CREATE
# include <sys/mman.h>
Expand Down
19 changes: 18 additions & 1 deletion criu/memfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ static int dump_one_memfd(int lfd, u32 id, const struct fd_parms *p)
return pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE);
}

int dump_one_memfd_cond(int lfd, u32 *id, struct fd_parms *parms)
{
if (fd_id_generate_special(parms, id))
return dump_one_memfd(lfd, *id, parms);
return 0;
}

const struct fdtype_ops memfd_dump_ops = {
.type = FD_TYPES__MEMFD,
.dump = dump_one_memfd,
Expand Down Expand Up @@ -265,7 +272,7 @@ static int memfd_open_inode(struct memfd_inode *inode)
return fd;
}

static int memfd_open(struct file_desc *d, u32 *fdflags)
int memfd_open(struct file_desc *d, u32 *fdflags)
{
char lpath[PSFDS];
struct memfd_info *mfi;
Expand Down Expand Up @@ -384,3 +391,13 @@ struct collect_image_info memfd_cinfo = {
.priv_size = sizeof(struct memfd_info),
.collect = collect_one_memfd,
};

struct file_desc *collect_memfd(u32 id) {
struct file_desc *fdesc;

fdesc = find_file_desc_raw(FD_TYPES__MEMFD, id);
if (fdesc == NULL)
pr_err("No entry for memfd %#x\n", id);

return fdesc;
}
35 changes: 35 additions & 0 deletions criu/proc_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "timerfd.h"
#include "path.h"
#include "fault-injection.h"
#include "memfd.h"

#include "protobuf.h"
#include "images/fdinfo.pb-c.h"
Expand Down Expand Up @@ -303,6 +304,26 @@ static int vma_get_mapfile_user(const char *fname, struct vma_area *vma,
}

vfi_dev = makedev(vfi->dev_maj, vfi->dev_min);

if (is_memfd(vfi_dev, fname)) {
struct fd_link link;
link.len = strlen(fname);
strlcpy(link.name, fname, sizeof(link.name));
strip_deleted(&link);

/*
* The error EPERM will be shown in the following pr_perror().
* It comes from the previous open() call.
*/
pr_perror("Can't open mapped [%s]", link.name);

/*
* TODO Perhaps we could do better than failing and dump the
* memory like what is being done in shmem.c
*/
return -1;
}

if (is_anon_shmem_map(vfi_dev)) {
if (!(vma->e->flags & MAP_SHARED))
return -1;
Expand Down Expand Up @@ -578,7 +599,20 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area,
/*
* /dev/zero stands for anon-shared mapping
* otherwise it's some file mapping.
*
* We treat memfd mappings as regular file mappings because
* their backing can be seen as files, which is easy to
* support. So even though memfd is an anonymous shmem, we
* treat it differently.
* Note: maybe we should revisit this as /proc/map_files/<vma>
* may not always be accessible.
*/

if (is_memfd(st_buf->st_dev, file_path)) {
vma_area->e->status |= VMA_AREA_MEMFD;
goto normal_file;
}

if (is_anon_shmem_map(st_buf->st_dev)) {
if (!(vma_area->e->flags & MAP_SHARED))
goto err_bogus_mapping;
Expand All @@ -594,6 +628,7 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area,
vma_area->e->shmid += FI_HUGE_ANON_SHMEM_ID_BASE;
}
} else {
normal_file:
if (vma_area->e->flags & MAP_PRIVATE)
vma_area->e->status |= VMA_FILE_PRIVATE;
else
Expand Down

0 comments on commit 29a1a88

Please sign in to comment.