Skip to content

Commit 5442e9f

Browse files
Cyrill GorcunovKAGA-KOKO
authored andcommitted
timerfd: Implement timerfd_ioctl method to restore timerfd_ctx::ticks, v3
The read() of timerfd files allows to fetch the number of timer ticks while there is no way to set it back from userspace. To restore the timer's state as it was at checkpoint moment we need a path to bring @ticks back. Initially I thought about writing ticks back via write() interface but it seems such API is somehow obscure. Instead implement timerfd_ioctl() method with TFD_IOC_SET_TICKS command which allows to adjust @ticks into non-zero value waking up the waiters. I wrapped code with CONFIG_CHECKPOINT_RESTORE which can be dropped off if there users except c/r camp appear. v2 (by akpm@): - Use define timerfd_ioctl NULL for non c/r config v3: - Use copy_from_user for @ticks fetching since not all arch support get_user for 8 byte argument Signed-off-by: Cyrill Gorcunov <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Andrey Vagin <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Christopher Covington <[email protected]> Cc: Pavel Emelyanov <[email protected]> Cc: Vladimir Davydov <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 854d06d commit 5442e9f

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

fs/timerfd.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,49 @@ static int timerfd_show(struct seq_file *m, struct file *file)
315315
#define timerfd_show NULL
316316
#endif
317317

318+
#ifdef CONFIG_CHECKPOINT_RESTORE
319+
static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
320+
{
321+
struct timerfd_ctx *ctx = file->private_data;
322+
int ret = 0;
323+
324+
switch (cmd) {
325+
case TFD_IOC_SET_TICKS: {
326+
u64 ticks;
327+
328+
if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
329+
return -EFAULT;
330+
if (!ticks)
331+
return -EINVAL;
332+
333+
spin_lock_irq(&ctx->wqh.lock);
334+
if (!timerfd_canceled(ctx)) {
335+
ctx->ticks = ticks;
336+
if (ticks)
337+
wake_up_locked(&ctx->wqh);
338+
} else
339+
ret = -ECANCELED;
340+
spin_unlock_irq(&ctx->wqh.lock);
341+
break;
342+
}
343+
default:
344+
ret = -ENOTTY;
345+
break;
346+
}
347+
348+
return ret;
349+
}
350+
#else
351+
#define timerfd_ioctl NULL
352+
#endif
353+
318354
static const struct file_operations timerfd_fops = {
319355
.release = timerfd_release,
320356
.poll = timerfd_poll,
321357
.read = timerfd_read,
322358
.llseek = noop_llseek,
323359
.show_fdinfo = timerfd_show,
360+
.unlocked_ioctl = timerfd_ioctl,
324361
};
325362

326363
static int timerfd_fget(int fd, struct fd *p)

include/linux/timerfd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
/* For O_CLOEXEC and O_NONBLOCK */
1212
#include <linux/fcntl.h>
1313

14+
/* For _IO helpers */
15+
#include <linux/ioctl.h>
16+
1417
/*
1518
* CAREFUL: Check include/asm-generic/fcntl.h when defining
1619
* new flags, since they might collide with O_* ones. We want
@@ -29,4 +32,6 @@
2932
/* Flags for timerfd_settime. */
3033
#define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)
3134

35+
#define TFD_IOC_SET_TICKS _IOW('T', 0, u64)
36+
3237
#endif /* _LINUX_TIMERFD_H */

0 commit comments

Comments
 (0)