mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-28 12:57:57 +00:00
timerfd: Implement c/r procedure
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
5c93ba3b7b
commit
ecd432fe27
@ -57,6 +57,7 @@ obj-y += pagemap-cache.o
|
|||||||
obj-y += kerndat.o
|
obj-y += kerndat.o
|
||||||
obj-y += stats.o
|
obj-y += stats.o
|
||||||
obj-y += cgroup.o
|
obj-y += cgroup.o
|
||||||
|
obj-y += timerfd.o
|
||||||
obj-y += string.o
|
obj-y += string.o
|
||||||
obj-y += sigframe.o
|
obj-y += sigframe.o
|
||||||
ifeq ($(VDSO),y)
|
ifeq ($(VDSO),y)
|
||||||
|
18
cr-restore.c
18
cr-restore.c
@ -69,6 +69,7 @@
|
|||||||
#include "rst-malloc.h"
|
#include "rst-malloc.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
|
#include "timerfd.h"
|
||||||
|
|
||||||
#include "parasite-syscall.h"
|
#include "parasite-syscall.h"
|
||||||
|
|
||||||
@ -153,6 +154,7 @@ static struct collect_image_info *cinfos[] = {
|
|||||||
&tty_cinfo,
|
&tty_cinfo,
|
||||||
&tunfile_cinfo,
|
&tunfile_cinfo,
|
||||||
&ext_file_cinfo,
|
&ext_file_cinfo,
|
||||||
|
&timerfd_cinfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int root_prepare_shared(void)
|
static int root_prepare_shared(void)
|
||||||
@ -2358,6 +2360,9 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
|
|||||||
void *tcp_socks_mem;
|
void *tcp_socks_mem;
|
||||||
unsigned long tcp_socks;
|
unsigned long tcp_socks;
|
||||||
|
|
||||||
|
void *timerfd_mem;
|
||||||
|
unsigned long timerfd_mem_cpos;
|
||||||
|
|
||||||
#ifdef CONFIG_VDSO
|
#ifdef CONFIG_VDSO
|
||||||
unsigned long vdso_rt_size = 0;
|
unsigned long vdso_rt_size = 0;
|
||||||
unsigned long vdso_rt_delta = 0;
|
unsigned long vdso_rt_delta = 0;
|
||||||
@ -2410,6 +2415,16 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
|
|||||||
|
|
||||||
memcpy(tcp_socks_mem, rst_tcp_socks, rst_tcp_socks_len());
|
memcpy(tcp_socks_mem, rst_tcp_socks, rst_tcp_socks_len());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy timerfd params for restorer args, we need to proceed
|
||||||
|
* timer setting at the very late.
|
||||||
|
*/
|
||||||
|
timerfd_mem_cpos = rst_mem_cpos(RM_PRIVATE);
|
||||||
|
timerfd_mem = rst_mem_alloc(rst_timerfd_len(), RM_PRIVATE);
|
||||||
|
if (!timerfd_mem)
|
||||||
|
goto err_nv;
|
||||||
|
memcpy(timerfd_mem, rst_timerfd, rst_timerfd_len());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're about to search for free VM area and inject the restorer blob
|
* We're about to search for free VM area and inject the restorer blob
|
||||||
* into it. No irrelevent mmaps/mremaps beyond this point, otherwise
|
* into it. No irrelevent mmaps/mremaps beyond this point, otherwise
|
||||||
@ -2533,6 +2548,9 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
|
|||||||
task_args->timer_n = posix_timers_nr;
|
task_args->timer_n = posix_timers_nr;
|
||||||
task_args->posix_timers = rst_mem_remap_ptr(posix_timers_cpos, RM_PRIVATE);
|
task_args->posix_timers = rst_mem_remap_ptr(posix_timers_cpos, RM_PRIVATE);
|
||||||
|
|
||||||
|
task_args->timerfd_n = rst_timerfd_nr;
|
||||||
|
task_args->timerfd = rst_mem_remap_ptr(timerfd_mem_cpos, RM_PRIVATE);
|
||||||
|
|
||||||
task_args->siginfo_nr = siginfo_nr;
|
task_args->siginfo_nr = siginfo_nr;
|
||||||
task_args->siginfo = rst_mem_remap_ptr(siginfo_cpos, RM_PRIVATE);
|
task_args->siginfo = rst_mem_remap_ptr(siginfo_cpos, RM_PRIVATE);
|
||||||
|
|
||||||
|
3
files.c
3
files.c
@ -32,6 +32,7 @@
|
|||||||
#include "signalfd.h"
|
#include "signalfd.h"
|
||||||
#include "namespaces.h"
|
#include "namespaces.h"
|
||||||
#include "tun.h"
|
#include "tun.h"
|
||||||
|
#include "timerfd.h"
|
||||||
#include "fdset.h"
|
#include "fdset.h"
|
||||||
#include "fs-magic.h"
|
#include "fs-magic.h"
|
||||||
#include "proc_parse.h"
|
#include "proc_parse.h"
|
||||||
@ -325,6 +326,8 @@ static int dump_one_file(struct parasite_ctl *ctl, int fd, int lfd, struct fd_op
|
|||||||
ops = &fanotify_dump_ops;
|
ops = &fanotify_dump_ops;
|
||||||
else if (is_signalfd_link(link))
|
else if (is_signalfd_link(link))
|
||||||
ops = &signalfd_dump_ops;
|
ops = &signalfd_dump_ops;
|
||||||
|
else if (is_timerfd_link(link))
|
||||||
|
ops = &timerfd_dump_ops;
|
||||||
else
|
else
|
||||||
return dump_unsupp_fd(&p, lfd, fdinfo, "anon", link);
|
return dump_unsupp_fd(&p, lfd, fdinfo, "anon", link);
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "protobuf/eventpoll.pb-c.h"
|
#include "protobuf/eventpoll.pb-c.h"
|
||||||
#include "protobuf/signalfd.pb-c.h"
|
#include "protobuf/signalfd.pb-c.h"
|
||||||
#include "protobuf/fsnotify.pb-c.h"
|
#include "protobuf/fsnotify.pb-c.h"
|
||||||
|
#include "protobuf/timerfd.pb-c.h"
|
||||||
|
|
||||||
#define PROC_TASK_COMM_LEN 32
|
#define PROC_TASK_COMM_LEN 32
|
||||||
#define PROC_TASK_COMM_LEN_FMT "(%31s"
|
#define PROC_TASK_COMM_LEN_FMT "(%31s"
|
||||||
@ -171,6 +172,7 @@ union fdinfo_entries {
|
|||||||
SignalfdEntry sfd;
|
SignalfdEntry sfd;
|
||||||
InotifyWdEntry ify;
|
InotifyWdEntry ify;
|
||||||
FanotifyMarkEntry ffy;
|
FanotifyMarkEntry ffy;
|
||||||
|
TimerfdEntry tfy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fdinfo_common {
|
struct fdinfo_common {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "posix-timer.h"
|
#include "posix-timer.h"
|
||||||
|
#include "timerfd.h"
|
||||||
#include "shmem.h"
|
#include "shmem.h"
|
||||||
#include "sigframe.h"
|
#include "sigframe.h"
|
||||||
#include "vdso.h"
|
#include "vdso.h"
|
||||||
@ -126,6 +127,9 @@ struct task_restore_args {
|
|||||||
int timer_n;
|
int timer_n;
|
||||||
struct restore_posix_timer *posix_timers;
|
struct restore_posix_timer *posix_timers;
|
||||||
|
|
||||||
|
int timerfd_n;
|
||||||
|
struct restore_timerfd *timerfd;
|
||||||
|
|
||||||
CredsEntry creds;
|
CredsEntry creds;
|
||||||
u32 cap_inh[CR_CAP_SIZE];
|
u32 cap_inh[CR_CAP_SIZE];
|
||||||
u32 cap_prm[CR_CAP_SIZE];
|
u32 cap_prm[CR_CAP_SIZE];
|
||||||
|
39
include/timerfd.h
Normal file
39
include/timerfd.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef __CR_TIMERFD_H__
|
||||||
|
#define __CR_TIMERFD_H__
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
|
struct pstree_item;
|
||||||
|
|
||||||
|
struct restore_timerfd {
|
||||||
|
int id;
|
||||||
|
int fd;
|
||||||
|
int clockid;
|
||||||
|
int settime_flags;
|
||||||
|
unsigned long ticks;
|
||||||
|
struct itimerspec val;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct fdtype_ops timerfd_dump_ops;
|
||||||
|
extern struct collect_image_info timerfd_cinfo;
|
||||||
|
extern struct restore_timerfd *rst_timerfd;
|
||||||
|
extern unsigned int rst_timerfd_nr;
|
||||||
|
|
||||||
|
static inline unsigned long rst_timerfd_len(void)
|
||||||
|
{
|
||||||
|
return sizeof(*rst_timerfd) * rst_timerfd_nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int is_timerfd_link(char *link);
|
||||||
|
|
||||||
|
#ifndef TFD_TIMER_ABSTIME
|
||||||
|
# define TFD_TIMER_ABSTIME (1 << 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TFD_IOC_SET_TICKS
|
||||||
|
# define TFD_IOC_SET_TICKS 0x40085400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CR_TIMERFD_H__ */
|
@ -534,6 +534,49 @@ static int vma_remap(unsigned long src, unsigned long dst, unsigned long len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int timerfd_arm(struct task_restore_args *args)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < args->timerfd_n; i++) {
|
||||||
|
struct restore_timerfd *t = &args->timerfd[i];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pr_debug("timerfd: arm for fd %d (%d)\n", t->fd, i);
|
||||||
|
|
||||||
|
if (t->settime_flags & TFD_TIMER_ABSTIME) {
|
||||||
|
struct timespec ts = { };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We might need to adjust value because the checkpoint
|
||||||
|
* and restore procedure takes some time itself. Note
|
||||||
|
* we don't adjust nanoseconds, since the result may
|
||||||
|
* overflow the limit NSEC_PER_SEC FIXME
|
||||||
|
*/
|
||||||
|
if (sys_clock_gettime(t->clockid, &ts)) {
|
||||||
|
pr_err("Can't get current time");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->val.it_value.tv_sec += (time_t)ts.tv_sec;
|
||||||
|
|
||||||
|
pr_debug("Ajust id %#x it_value(%llu, %llu) -> it_value(%llu, %llu)\n",
|
||||||
|
t->id, (unsigned long long)ts.tv_sec,
|
||||||
|
(unsigned long long)ts.tv_nsec,
|
||||||
|
(unsigned long long)t->val.it_value.tv_sec,
|
||||||
|
(unsigned long long)t->val.it_value.tv_nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sys_timerfd_settime(t->fd, t->settime_flags, &t->val, NULL);
|
||||||
|
ret |= sys_ioctl(t->fd, TFD_IOC_SET_TICKS, (unsigned long)&t->ticks);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Can't restore ticks/time for timerfd - %d\n", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int create_posix_timers(struct task_restore_args *args)
|
static int create_posix_timers(struct task_restore_args *args)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
@ -962,6 +1005,12 @@ long __export_restore_task(struct task_restore_args *args)
|
|||||||
goto core_restore_end;
|
goto core_restore_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = timerfd_arm(args);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Can't restore timerfd %ld\n", ret);
|
||||||
|
goto core_restore_end;
|
||||||
|
}
|
||||||
|
|
||||||
pr_info("%ld: Restored\n", sys_getpid());
|
pr_info("%ld: Restored\n", sys_getpid());
|
||||||
|
|
||||||
futex_set(&zombies_inprogress, args->nr_zombies);
|
futex_set(&zombies_inprogress, args->nr_zombies);
|
||||||
|
60
proc_parse.c
60
proc_parse.c
@ -1043,6 +1043,51 @@ static void parse_fhandle_encoded(char *tok, FhEntry *fh)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_timerfd(FILE *f, char *buf, size_t size, TimerfdEntry *tfy)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Format is
|
||||||
|
* clockid: 0
|
||||||
|
* ticks: 0
|
||||||
|
* settime flags: 01
|
||||||
|
* it_value: (0, 49406829)
|
||||||
|
* it_interval: (1, 0)
|
||||||
|
*/
|
||||||
|
if (sscanf(buf, "clockid: %d", &tfy->clockid) != 1)
|
||||||
|
goto parse_err;
|
||||||
|
|
||||||
|
if (!fgets(buf, size, f))
|
||||||
|
goto nodata;
|
||||||
|
if (sscanf(buf, "ticks: %llu", (unsigned long long *)&tfy->ticks) != 1)
|
||||||
|
goto parse_err;
|
||||||
|
|
||||||
|
if (!fgets(buf, size, f))
|
||||||
|
goto nodata;
|
||||||
|
if (sscanf(buf, "settime flags: 0%o", &tfy->settime_flags) != 1)
|
||||||
|
goto parse_err;
|
||||||
|
|
||||||
|
if (!fgets(buf, size, f))
|
||||||
|
goto nodata;
|
||||||
|
if (sscanf(buf, "it_value: (%llu, %llu)",
|
||||||
|
(unsigned long long *)&tfy->vsec,
|
||||||
|
(unsigned long long *)&tfy->vnsec) != 2)
|
||||||
|
goto parse_err;
|
||||||
|
|
||||||
|
if (!fgets(buf, size, f))
|
||||||
|
goto nodata;
|
||||||
|
if (sscanf(buf, "it_interval: (%llu, %llu)",
|
||||||
|
(unsigned long long *)&tfy->isec,
|
||||||
|
(unsigned long long *)&tfy->insec) != 2)
|
||||||
|
goto parse_err;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
parse_err:
|
||||||
|
return -1;
|
||||||
|
nodata:
|
||||||
|
pr_err("No data left in proc file while parsing timerfd\n");
|
||||||
|
goto parse_err;
|
||||||
|
}
|
||||||
|
|
||||||
#define fdinfo_field(str, field) !strncmp(str, field":", sizeof(field))
|
#define fdinfo_field(str, field) !strncmp(str, field":", sizeof(field))
|
||||||
|
|
||||||
static int parse_fdinfo_pid_s(char *pid, int fd, int type,
|
static int parse_fdinfo_pid_s(char *pid, int fd, int type,
|
||||||
@ -1105,6 +1150,21 @@ static int parse_fdinfo_pid_s(char *pid, int fd, int type,
|
|||||||
entry_met = true;
|
entry_met = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (fdinfo_field(str, "clockid")) {
|
||||||
|
timerfd_entry__init(&entry.tfy);
|
||||||
|
|
||||||
|
if (type != FD_TYPES__TIMERFD)
|
||||||
|
goto parse_err;
|
||||||
|
ret = parse_timerfd(f, str, sizeof(str), &entry.tfy);
|
||||||
|
if (ret)
|
||||||
|
goto parse_err;
|
||||||
|
ret = cb(&entry, arg);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
entry_met = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (fdinfo_field(str, "tfd")) {
|
if (fdinfo_field(str, "tfd")) {
|
||||||
eventpoll_tfd_entry__init(&entry.epl);
|
eventpoll_tfd_entry__init(&entry.epl);
|
||||||
|
|
||||||
|
170
timerfd.c
Normal file
170
timerfd.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "protobuf.h"
|
||||||
|
#include "protobuf/timerfd.pb-c.h"
|
||||||
|
|
||||||
|
#include "proc_parse.h"
|
||||||
|
#include "rst-malloc.h"
|
||||||
|
#include "restorer.h"
|
||||||
|
#include "timerfd.h"
|
||||||
|
#include "pstree.h"
|
||||||
|
#include "files.h"
|
||||||
|
#include "fdset.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "bug.h"
|
||||||
|
|
||||||
|
#undef LOG_PREFIX
|
||||||
|
#define LOG_PREFIX "timerfd: "
|
||||||
|
|
||||||
|
struct timerfd_dump_arg {
|
||||||
|
u32 id;
|
||||||
|
const struct fd_parms *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timerfd_info {
|
||||||
|
TimerfdEntry *tfe;
|
||||||
|
struct file_desc d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct restore_timerfd *rst_timerfd;
|
||||||
|
unsigned int rst_timerfd_nr;
|
||||||
|
|
||||||
|
int is_timerfd_link(char *link)
|
||||||
|
{
|
||||||
|
return is_anon_link_type(link, "[timerfd]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_timerfd_entry(union fdinfo_entries *e, void *arg)
|
||||||
|
{
|
||||||
|
struct timerfd_dump_arg *da = arg;
|
||||||
|
TimerfdEntry *tfy = &e->tfy;
|
||||||
|
|
||||||
|
tfy->id = da->id;
|
||||||
|
tfy->flags = da->p->flags;
|
||||||
|
tfy->fown = (FownEntry *)&da->p->fown;
|
||||||
|
|
||||||
|
pr_info("Dumping id %#x clockid %d it_value(%llu, %llu) it_interval(%llu, %llu)\n",
|
||||||
|
tfy->id, tfy->clockid, (unsigned long long)tfy->vsec, (unsigned long long)tfy->vnsec,
|
||||||
|
(unsigned long long)tfy->isec, (unsigned long long)tfy->insec);
|
||||||
|
|
||||||
|
return pb_write_one(fdset_fd(glob_fdset, CR_FD_TIMERFD), &e->tfy, PB_TIMERFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_one_timerfd(int lfd, u32 id, const struct fd_parms *p)
|
||||||
|
{
|
||||||
|
struct timerfd_dump_arg da = { .id = id, .p = p, };
|
||||||
|
return parse_fdinfo(lfd, FD_TYPES__TIMERFD, dump_timerfd_entry, &da);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct fdtype_ops timerfd_dump_ops = {
|
||||||
|
.type = FD_TYPES__TIMERFD,
|
||||||
|
.dump = dump_one_timerfd,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to restore timers at the very late stage in restorer
|
||||||
|
* to eliminate the case when timer is expired but we have not
|
||||||
|
* yet finished restore procedure and signal handlers are not
|
||||||
|
* set up properly. We need to copy timers settings into restorer
|
||||||
|
* area that's why post-open is used for.
|
||||||
|
*/
|
||||||
|
static int timerfd_post_open(struct file_desc *d, int fd)
|
||||||
|
{
|
||||||
|
struct timerfd_info *info = container_of(d, struct timerfd_info, d);
|
||||||
|
TimerfdEntry *tfe = info->tfe;
|
||||||
|
struct restore_timerfd *t;
|
||||||
|
|
||||||
|
rst_timerfd_nr++;
|
||||||
|
rst_timerfd = xrealloc(rst_timerfd, rst_timerfd_len());
|
||||||
|
if (!rst_timerfd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
t = &rst_timerfd[rst_timerfd_nr - 1];
|
||||||
|
t->id = tfe->id;
|
||||||
|
t->fd = fd;
|
||||||
|
t->clockid = tfe->clockid;
|
||||||
|
t->ticks = (unsigned long)tfe->ticks;
|
||||||
|
t->settime_flags = tfe->settime_flags;
|
||||||
|
t->val.it_interval.tv_sec = (time_t)tfe->isec;
|
||||||
|
t->val.it_interval.tv_nsec = (long)tfe->insec;
|
||||||
|
t->val.it_value.tv_sec = (time_t)tfe->vsec;
|
||||||
|
t->val.it_value.tv_nsec = (long)tfe->vnsec;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int timerfd_open(struct file_desc *d)
|
||||||
|
{
|
||||||
|
struct timerfd_info *info;
|
||||||
|
TimerfdEntry *tfe;
|
||||||
|
int tmp = -1;
|
||||||
|
|
||||||
|
info = container_of(d, struct timerfd_info, d);
|
||||||
|
tfe = info->tfe;
|
||||||
|
pr_info("Creating timerfd id %#x clockid %d settime_flags %x ticks %llu "
|
||||||
|
"it_value(%llu, %llu) it_interval(%llu, %llu)\n",
|
||||||
|
tfe->id, tfe->clockid, tfe->settime_flags, (unsigned long long)tfe->ticks,
|
||||||
|
(unsigned long long)tfe->vsec, (unsigned long long)tfe->vnsec,
|
||||||
|
(unsigned long long)tfe->isec, (unsigned long long)tfe->insec);
|
||||||
|
|
||||||
|
tmp = timerfd_create(tfe->clockid, 0);
|
||||||
|
if (tmp < 0) {
|
||||||
|
pr_perror("Can't create for %#x\n", tfe->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rst_file_params(tmp, tfe->fown, tfe->flags)) {
|
||||||
|
pr_perror("Can't restore params for %#x", tfe->id);
|
||||||
|
goto err_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
err_close:
|
||||||
|
close_safe(&tmp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_desc_ops timerfd_desc_ops = {
|
||||||
|
.type = FD_TYPES__TIMERFD,
|
||||||
|
.open = timerfd_open,
|
||||||
|
.post_open = timerfd_post_open,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int verify_timerfd(TimerfdEntry *tfe)
|
||||||
|
{
|
||||||
|
if (tfe->clockid != CLOCK_REALTIME &&
|
||||||
|
tfe->clockid != CLOCK_MONOTONIC) {
|
||||||
|
pr_err("Unknown clock type %d for %#x\n", tfe->clockid, tfe->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_one_timerfd(void *o, ProtobufCMessage *msg)
|
||||||
|
{
|
||||||
|
struct timerfd_info *info = o;
|
||||||
|
|
||||||
|
info->tfe = pb_msg(msg, TimerfdEntry);
|
||||||
|
if (verify_timerfd(info->tfe)) {
|
||||||
|
pr_err("Verification failed for %#x\n", info->tfe->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_desc_add(&info->d, info->tfe->id, &timerfd_desc_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct collect_image_info timerfd_cinfo = {
|
||||||
|
.fd_type = CR_FD_TIMERFD,
|
||||||
|
.pb_type = PB_TIMERFD,
|
||||||
|
.priv_size = sizeof(struct timerfd_info),
|
||||||
|
.collect = collect_one_timerfd,
|
||||||
|
.flags = COLLECT_OPTIONAL,
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user