|
@@ -40,6 +40,7 @@ struct timerfd_ctx {
|
|
|
short unsigned settime_flags; /* to show in fdinfo */
|
|
|
struct rcu_head rcu;
|
|
|
struct list_head clist;
|
|
|
+ spinlock_t cancel_lock;
|
|
|
bool might_cancel;
|
|
|
};
|
|
|
|
|
@@ -112,7 +113,7 @@ void timerfd_clock_was_set(void)
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
-static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
|
|
|
+static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
|
|
|
{
|
|
|
if (ctx->might_cancel) {
|
|
|
ctx->might_cancel = false;
|
|
@@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
|
|
|
+{
|
|
|
+ spin_lock(&ctx->cancel_lock);
|
|
|
+ __timerfd_remove_cancel(ctx);
|
|
|
+ spin_unlock(&ctx->cancel_lock);
|
|
|
+}
|
|
|
+
|
|
|
static bool timerfd_canceled(struct timerfd_ctx *ctx)
|
|
|
{
|
|
|
if (!ctx->might_cancel || ctx->moffs != KTIME_MAX)
|
|
@@ -132,6 +140,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)
|
|
|
|
|
|
static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
|
|
|
{
|
|
|
+ spin_lock(&ctx->cancel_lock);
|
|
|
if ((ctx->clockid == CLOCK_REALTIME ||
|
|
|
ctx->clockid == CLOCK_REALTIME_ALARM) &&
|
|
|
(flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
|
@@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
|
|
|
list_add_rcu(&ctx->clist, &cancel_list);
|
|
|
spin_unlock(&cancel_lock);
|
|
|
}
|
|
|
- } else if (ctx->might_cancel) {
|
|
|
- timerfd_remove_cancel(ctx);
|
|
|
+ } else {
|
|
|
+ __timerfd_remove_cancel(ctx);
|
|
|
}
|
|
|
+ spin_unlock(&ctx->cancel_lock);
|
|
|
}
|
|
|
|
|
|
static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
|
|
@@ -400,6 +410,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
init_waitqueue_head(&ctx->wqh);
|
|
|
+ spin_lock_init(&ctx->cancel_lock);
|
|
|
ctx->clockid = clockid;
|
|
|
|
|
|
if (isalarm(ctx))
|