aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@gmail.com>2017-07-12 17:34:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-12 19:26:01 -0400
commit0791e3644e5ef21646fe565b9061788d05ec71d4 (patch)
treef16169f6551fe0b2fea513080fcecbe0d4a5cccc /kernel
parent77493f04b74cdff3a61fb3fb14b1f5a71d88fd5f (diff)
kcmp: add KCMP_EPOLL_TFD mode to compare epoll target files
With current epoll architecture target files are addressed with file_struct and file descriptor number, where the last is not unique. Moreover files can be transferred from another process via unix socket, added into queue and closed then so we won't find this descriptor in the task fdinfo list. Thus to checkpoint and restore such processes CRIU needs to find out where exactly the target file is present to add it into epoll queue. For this sake one can use kcmp call where some particular target file from the queue is compared with arbitrary file passed as an argument. Because epoll target files can have same file descriptor number but different file_struct a caller should explicitly specify the offset within. To test if some particular file is matching entry inside epoll one have to - fill kcmp_epoll_slot structure with epoll file descriptor, target file number and target file offset (in case if only one target is present then it should be 0) - call kcmp as kcmp(pid1, pid2, KCMP_EPOLL_TFD, fd, &kcmp_epoll_slot) - the kernel fetch file pointer matching file descriptor @fd of pid1 - lookups for file struct in epoll queue of pid2 and returns traditional 0,1,2 result for sorting purpose Link: http://lkml.kernel.org/r/20170424154423.511592110@gmail.com Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Acked-by: Andrey Vagin <avagin@openvz.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Pavel Emelyanov <xemul@virtuozzo.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Jason Baron <jbaron@akamai.com> Cc: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kcmp.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/kernel/kcmp.c b/kernel/kcmp.c
index 3a47fa998fe0..ea34ed8bb952 100644
--- a/kernel/kcmp.c
+++ b/kernel/kcmp.c
@@ -11,6 +11,10 @@
11#include <linux/bug.h> 11#include <linux/bug.h>
12#include <linux/err.h> 12#include <linux/err.h>
13#include <linux/kcmp.h> 13#include <linux/kcmp.h>
14#include <linux/capability.h>
15#include <linux/list.h>
16#include <linux/eventpoll.h>
17#include <linux/file.h>
14 18
15#include <asm/unistd.h> 19#include <asm/unistd.h>
16 20
@@ -94,6 +98,56 @@ static int kcmp_lock(struct mutex *m1, struct mutex *m2)
94 return err; 98 return err;
95} 99}
96 100
101#ifdef CONFIG_EPOLL
102static int kcmp_epoll_target(struct task_struct *task1,
103 struct task_struct *task2,
104 unsigned long idx1,
105 struct kcmp_epoll_slot __user *uslot)
106{
107 struct file *filp, *filp_epoll, *filp_tgt;
108 struct kcmp_epoll_slot slot;
109 struct files_struct *files;
110
111 if (copy_from_user(&slot, uslot, sizeof(slot)))
112 return -EFAULT;
113
114 filp = get_file_raw_ptr(task1, idx1);
115 if (!filp)
116 return -EBADF;
117
118 files = get_files_struct(task2);
119 if (!files)
120 return -EBADF;
121
122 spin_lock(&files->file_lock);
123 filp_epoll = fcheck_files(files, slot.efd);
124 if (filp_epoll)
125 get_file(filp_epoll);
126 else
127 filp_tgt = ERR_PTR(-EBADF);
128 spin_unlock(&files->file_lock);
129 put_files_struct(files);
130
131 if (filp_epoll) {
132 filp_tgt = get_epoll_tfile_raw_ptr(filp_epoll, slot.tfd, slot.toff);
133 fput(filp_epoll);
134 } else
135
136 if (IS_ERR(filp_tgt))
137 return PTR_ERR(filp_tgt);
138
139 return kcmp_ptr(filp, filp_tgt, KCMP_FILE);
140}
141#else
142static int kcmp_epoll_target(struct task_struct *task1,
143 struct task_struct *task2,
144 unsigned long idx1,
145 struct kcmp_epoll_slot __user *uslot)
146{
147 return -EOPNOTSUPP;
148}
149#endif
150
97SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type, 151SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,
98 unsigned long, idx1, unsigned long, idx2) 152 unsigned long, idx1, unsigned long, idx2)
99{ 153{
@@ -165,6 +219,9 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,
165 ret = -EOPNOTSUPP; 219 ret = -EOPNOTSUPP;
166#endif 220#endif
167 break; 221 break;
222 case KCMP_EPOLL_TFD:
223 ret = kcmp_epoll_target(task1, task2, idx1, (void *)idx2);
224 break;
168 default: 225 default:
169 ret = -EINVAL; 226 ret = -EINVAL;
170 break; 227 break;