C/R tsk->files and opened files! fd should have struct file::checkpoint ;-) Signed-off-by: Alexey Dobriyan <adobriyan@xxxxxxxxx> --- include/linux/cr.h | 16 +++ kernel/cr/cpt-sys.c | 6 + kernel/cr/cr-file.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/cr/cr-task.c | 5 + kernel/cr/cr.h | 4 5 files changed, 280 insertions(+) --- a/include/linux/cr.h +++ b/include/linux/cr.h @@ -39,6 +39,8 @@ struct cr_object_header { #define CR_OBJ_UTS_NS 8 #define CR_OBJ_PID_NS 9 #define CR_OBJ_PID 10 +#define CR_OBJ_FILES_STRUCT 11 +#define CR_OBJ_FD 12 __u32 cr_type; /* object type */ __u32 cr_len; /* object length in bytes including header */ } __packed; @@ -59,6 +61,7 @@ struct cr_image_task_struct { cr_pos_t cr_pos_real_parent; cr_pos_t cr_pos_mm; cr_pos_t cr_pos_pids[3]; + cr_pos_t cr_pos_files; cr_pos_t cr_pos_nsproxy; __u8 cr_comm[16]; @@ -228,6 +231,10 @@ struct cr_image_vma_content { /* __u8 cr_data[cr_nr_pages * cr_page_size]; */ } __packed; +struct cr_image_files_struct { + struct cr_object_header cr_hdr; +} __packed; + struct cr_image_file { struct cr_object_header cr_hdr; @@ -245,6 +252,15 @@ struct cr_image_file { /* __u8 cr_name[cr_name_len] */ } __packed; +struct cr_image_fd { + struct cr_object_header cr_hdr; + + cr_pos_t cr_pos_file; + __u32 cr_fd; +#define CR_FD_FLAGS_CLOEXEC (1 << 0) + __u32 cr_fd_flags; +} __packed; + struct cr_image_pid { struct cr_object_header cr_hdr; --- a/kernel/cr/cpt-sys.c +++ b/kernel/cr/cpt-sys.c @@ -77,6 +77,9 @@ static int cr_collect(struct cr_context *ctx) rv = cr_collect_all_mm_struct(ctx); if (rv < 0) return rv; + rv = cr_collect_all_files_struct(ctx); + if (rv < 0) + return rv; rv = cr_collect_all_file(ctx); if (rv < 0) return rv; @@ -125,6 +128,9 @@ static int cr_dump(struct cr_context *ctx) rv = cr_dump_all_file(ctx); if (rv < 0) return rv; + rv = cr_dump_all_files_struct(ctx); + if (rv < 0) + return rv; rv = cr_dump_all_uts_ns(ctx); if (rv < 0) return rv; --- a/kernel/cr/cr-file.c +++ b/kernel/cr/cr-file.c @@ -64,6 +64,20 @@ int cr_collect_all_file(struct cr_context *ctx) struct cr_object *obj; int rv; + for_each_cr_object(ctx, obj, CR_CTX_FILES_STRUCT) { + struct files_struct *files = obj->o_obj; + struct file *file; + int fd; + + for (fd = 0; fd < files->fdt->max_fds; fd++) { + file = fcheck_files(files, fd); + if (!file) + continue; + rv = cr_collect_file(ctx, file); + if (rv < 0) + return rv; + } + } for_each_cr_object(ctx, obj, CR_CTX_MM_STRUCT) { struct mm_struct *mm = obj->o_obj; struct vm_area_struct *vma; @@ -229,3 +243,238 @@ int cr_restore_file(struct cr_context *ctx, loff_t pos) kfree(i); return 0; } + +static int cr_restore_fd(struct cr_context *ctx, loff_t pos) +{ + struct cr_image_fd *i; + struct file *file; + int fd; + unsigned int flags; + struct cr_object *tmp; + int rv; + + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return -ENOMEM; + rv = cr_pread(ctx, i, sizeof(*i), pos); + if (rv < 0) { + kfree(i); + return rv; + } + if (i->cr_hdr.cr_type != CR_OBJ_FD) { + kfree(i); + return -EINVAL; + } + + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_file, CR_CTX_FILE); + if (!tmp) { + rv = cr_restore_file(ctx, i->cr_pos_file); + if (rv < 0) { + kfree(i); + return rv; + } + tmp = cr_find_obj_by_pos(ctx, i->cr_pos_file, CR_CTX_FILE); + } + file = tmp->o_obj; + + flags = 0; + if (i->cr_fd_flags & CR_FD_FLAGS_CLOEXEC) + flags |= O_CLOEXEC; + fd = alloc_fd(i->cr_fd, flags); + if (fd != i->cr_fd) + rv = (fd < 0) ? fd : -EINVAL; + else + rv = 0; + kfree(i); + if (rv < 0) + return rv; + + get_file(file); + fd_install(fd, file); + return 0; +} + +static int cr_restore_all_fd(struct cr_context *ctx, loff_t pos) +{ + struct cr_object_header cr_hdr; + int rv; + + while (1) { + rv = cr_pread(ctx, &cr_hdr, sizeof(cr_hdr), pos); + if (rv < 0) + return rv; + if (cr_hdr.cr_type == CR_OBJ_FD) { + rv = cr_restore_fd(ctx, pos); + if (rv < 0) + return rv; + } else + return 0; + pos += cr_hdr.cr_len; + } +} + +static int cr_collect_files_struct(struct cr_context *ctx, struct files_struct *files) +{ + int rv; + + rv = cr_collect_object(ctx, files, CR_CTX_FILES_STRUCT); + printk("collect files_struct %p: rv %d\n", files, rv); + return rv; +} + +int cr_collect_all_files_struct(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_TASK_STRUCT) { + struct task_struct *tsk = obj->o_obj; + + rv = cr_collect_files_struct(ctx, tsk->files); + if (rv < 0) + return rv; + } + for_each_cr_object(ctx, obj, CR_CTX_FILES_STRUCT) { + struct files_struct *files = obj->o_obj; + unsigned int cnt = atomic_read(&files->count); + + if (obj->o_count != cnt) { + printk("%s: files_struct %p has external references %lu:%u\n", __func__, files, obj->o_count, cnt); + return -EINVAL; + } + } + return 0; +} + +static int cr_dump_fd(struct cr_context *ctx, struct files_struct *files, int fd, struct file *file) +{ + struct cr_image_fd *i; + struct cr_object *tmp; + int rv; + + printk("dump fd %d, files_struct = %p, file = %p\n", fd, files, file); + + i = cr_prepare_image(CR_OBJ_FD, sizeof(*i)); + if (!i) + return -ENOMEM; + + tmp = cr_find_obj_by_ptr(ctx, file, CR_CTX_FILE); + i->cr_pos_file = tmp->o_pos; + i->cr_fd = fd; + i->cr_fd_flags = 0; + if (FD_ISSET(fd, files->fdt->close_on_exec)) + i->cr_fd_flags |= CR_FD_FLAGS_CLOEXEC; + + rv = cr_write(ctx, i, sizeof(*i)); + kfree(i); + return rv; +} + +static int cr_dump_files_struct(struct cr_context *ctx, struct cr_object *obj) +{ + struct files_struct *files = obj->o_obj; + struct cr_image_files_struct *i; + int fd; + int rv; + + printk("dump files_struct %p\n", files); + + i = cr_prepare_image(CR_OBJ_FILES_STRUCT, sizeof(*i)); + if (!i) + return -ENOMEM; + + obj->o_pos = ctx->cr_dump_file->f_pos; + rv = cr_write(ctx, i, sizeof(*i)); + kfree(i); + if (rv < 0) + return rv; + + for (fd = 0; fd < files->fdt->max_fds; fd++) { + struct file *file; + + file = fcheck_files(files, fd); + if (file) { + rv = cr_dump_fd(ctx, files, fd, file); + if (rv < 0) + return rv; + } + } + return 0; +} + +int cr_dump_all_files_struct(struct cr_context *ctx) +{ + struct cr_object *obj; + int rv; + + for_each_cr_object(ctx, obj, CR_CTX_FILES_STRUCT) { + rv = cr_dump_files_struct(ctx, obj); + if (rv < 0) + return rv; + } + return 0; +} + +static int __cr_restore_files_struct(struct cr_context *ctx, loff_t pos) +{ + struct cr_image_files_struct *i; + struct files_struct *files; + struct cr_object *obj; + int rv; + + i = kzalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return -ENOMEM; + rv = cr_pread(ctx, i, sizeof(*i), pos); + if (rv < 0) { + kfree(i); + return rv; + } + if (i->cr_hdr.cr_type != CR_OBJ_FILES_STRUCT) { + kfree(i); + return -EINVAL; + } + + files = kmem_cache_zalloc(files_cachep, GFP_KERNEL); + if (!files) { + kfree(i); + return -ENOMEM; + } + atomic_set(&files->count, 1); + files->fdt = &files->fdtab; + files->fdt->max_fds = NR_OPEN_DEFAULT; + files->fdt->fd = files->fd_array; + files->fdt->close_on_exec = (fd_set *)&files->close_on_exec_init; + files->fdt->open_fds = (fd_set *)&files->open_fds_init; + spin_lock_init(&files->file_lock); + kfree(i); + + obj = cr_object_create(files); + if (!obj) { + kmem_cache_free(files_cachep, files); + return -ENOMEM; + } + obj->o_pos = pos; + list_add(&obj->o_list, &ctx->cr_obj[CR_CTX_FILES_STRUCT]); + printk("restore files_struct %p, pos %lld\n", files, (long long)pos); + return 0; +} + +int cr_restore_files_struct(struct cr_context *ctx, loff_t pos) +{ + struct files_struct *files; + struct cr_object *tmp; + int rv; + + tmp = cr_find_obj_by_pos(ctx, pos, CR_CTX_FILES_STRUCT); + if (!tmp) { + rv = __cr_restore_files_struct(ctx, pos); + if (rv < 0) + return rv; + tmp = cr_find_obj_by_pos(ctx, pos, CR_CTX_FILES_STRUCT); + } + files = tmp->o_obj; + atomic_inc(&files->count); + reset_files_struct(files); + return cr_restore_all_fd(ctx, pos + sizeof(struct cr_image_files_struct)); +} --- a/kernel/cr/cr-task.c +++ b/kernel/cr/cr-task.c @@ -127,6 +127,8 @@ static int cr_dump_task_struct(struct cr_context *ctx, struct cr_object *obj) i->cr_pos_pids[2] = tmp->o_pos; else i->cr_pos_pids[2] = CR_POS_UNDEF; + tmp = cr_find_obj_by_ptr(ctx, tsk->files, CR_CTX_FILES_STRUCT); + i->cr_pos_files = tmp->o_pos; BUILD_BUG_ON(TASK_COMM_LEN != 16); strlcpy((char *)i->cr_comm, (const char *)tsk->comm, sizeof(i->cr_comm)); @@ -186,6 +188,9 @@ static int task_struct_restorer(void *_tsk_ctx) rv = cr_restore_nsproxy(ctx, i->cr_pos_nsproxy); if (rv < 0) goto out; + rv = cr_restore_files_struct(ctx, i->cr_pos_files); + if (rv < 0) + return rv; rv = cr_restore_pid(ctx, i); if (rv < 0) goto out; --- a/kernel/cr/cr.h +++ b/kernel/cr/cr.h @@ -23,6 +23,7 @@ struct cr_object { /* Not visible to userspace! */ enum cr_context_obj_type { CR_CTX_FILE, + CR_CTX_FILES_STRUCT, CR_CTX_MM_STRUCT, CR_CTX_NSPROXY, CR_CTX_PID, @@ -70,6 +71,7 @@ static inline void __user *cr_restore_ptr(__u64 ptr) return (void __user *)(unsigned long)ptr; } +int cr_collect_all_files_struct(struct cr_context *ctx); int cr_collect_all_file(struct cr_context *ctx); int cr_collect_all_mm_struct(struct cr_context *ctx); int cr_collect_all_nsproxy(struct cr_context *ctx); @@ -78,6 +80,7 @@ int cr_collect_all_pid(struct cr_context *ctx); int cr_collect_all_task_struct(struct cr_context *ctx); int cr_collect_all_uts_ns(struct cr_context *ctx); +int cr_dump_all_files_struct(struct cr_context *ctx); int cr_dump_all_file(struct cr_context *ctx); int cr_dump_all_mm_struct(struct cr_context *ctx); int cr_dump_all_nsproxy(struct cr_context *ctx); @@ -86,6 +89,7 @@ int cr_dump_all_pid(struct cr_context *ctx); int cr_dump_all_task_struct(struct cr_context *ctx); int cr_dump_all_uts_ns(struct cr_context *ctx); +int cr_restore_files_struct(struct cr_context *ctx, loff_t pos); int cr_restore_file(struct cr_context *ctx, loff_t pos); int cr_restore_mm_struct(struct cr_context *ctx, loff_t pos); int cr_restore_nsproxy(struct cr_context *ctx, loff_t pos); _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers