FAILED: patch "[PATCH] kthread_worker: split code for canceling the delayed work" failed to apply to 4.14-stable tree
[email protected]
maintainerThe patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 34b3d5344719d14fd2185b2d9459b3abcb8cf9d8 Mon Sep 17 00:00:00 2001
From: Petr Mladek <[email protected]>
Date: Thu, 24 Jun 2021 18:39:45 -0700
Subject: [PATCH] kthread_worker: split code for canceling the delayed work
timer
Patch series "kthread_worker: Fix race between kthread_mod_delayed_work() and kthread_cancel_delayed_work_sync()".
This patchset fixes the race between kthread_mod_delayed_work() and kthread_cancel_delayed_work_sync() including proper return value handling.
This patch (of 2):
Simple code refactoring as a preparation step for fixing a race between kthread_mod_delayed_work() and kthread_cancel_delayed_work_sync().
It does not modify the existing behavior.
kernel/kthread.c +29 -17
@@ -1092,6 +1092,33 @@ void kthread_flush_work(struct kthread_work *work) }EXPORT_SYMBOL_GPL (kthread_flush_work); +/* +* Make sure that the timer is neither set nor running and could +* not manipulate the work list_head any longer. +* +* The function is called under worker->lock. The lock is temporary +* released but the timer can't be set again in the meantime. +*/ +static void kthread_cancel_delayed_work_timer (struct kthread_work *work, +unsigned long *flags) +{ +struct kthread_delayed_work *dwork = + container_of(work, struct kthread_delayed_work, work); +struct kthread_worker *worker = work->worker; + +/* +* del_timer_sync() must be called to make sure that the timer +* callback is not running. The lock must be temporary released +* to avoid a deadlock with the callback. In the meantime, +* any queuing is blocked by setting the canceling counter. +*/ + work->canceling++; +raw_spin_unlock_irqrestore (&worker->lock, *flags); +del_timer_sync (&dwork->timer); +raw_spin_lock_irqsave (&worker->lock, *flags); + work->canceling--; +} +/* * This function removes the work from the worker queue. Also it makes sure * that it won't get queued later via the delayed work's timer.
@@ -1106,23 +1133,8 @@ static bool __kthread_cancel_work(struct kthread_work *work, bool is_dwork, unsigned long *flags) {/* Try to cancel the timer if exists. */ -if (is_dwork) { -struct kthread_delayed_work *dwork = - container_of(work, struct kthread_delayed_work, work); -struct kthread_worker *worker = work->worker; - -/* -* del_timer_sync() must be called to make sure that the timer -* callback is not running. The lock must be temporary released -* to avoid a deadlock with the callback. In the meantime, -* any queuing is blocked by setting the canceling counter. -*/ - work->canceling++; -raw_spin_unlock_irqrestore (&worker->lock, *flags); -del_timer_sync (&dwork->timer); -raw_spin_lock_irqsave (&worker->lock, *flags); - work->canceling--; - } +if (is_dwork) +kthread_cancel_delayed_work_timer (work, flags);/* * Try to remove the work from a worker list. It might either