#include <linux/jiffies.h> /* For timeout functions */
#include <linux/kernel.h> /* For printk/panic/... */
#include <linux/kref.h> /* For data references */
+#include <linux/kthread.h> /* For kthread_delayed_work */
#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/module.h> /* For module stuff/... */
#include <linux/mutex.h> /* For mutexes */
#include <linux/slab.h> /* For memory functions */
#include <linux/types.h> /* For standard types (like size_t) */
#include <linux/watchdog.h> /* For watchdog specific items */
-#include <linux/workqueue.h> /* For workqueue */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
+#include <uapi/linux/sched/types.h> /* For struct sched_param */
+
#include "watchdog_core.h"
#include "watchdog_pretimeout.h"
struct mutex lock;
unsigned long last_keepalive;
unsigned long last_hw_keepalive;
- struct delayed_work work;
+ struct kthread_delayed_work work;
unsigned long status; /* Internal status bits */
#define _WDOG_DEV_OPEN 0 /* Opened ? */
#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */
/* Reference to watchdog device behind /dev/watchdog */
static struct watchdog_core_data *old_wd_data;
-static struct workqueue_struct *watchdog_wq;
+static struct kthread_worker *watchdog_kworker;
static bool handle_boot_enabled =
IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED);
long t = watchdog_next_keepalive(wdd);
if (t > 0)
- mod_delayed_work(watchdog_wq, &wd_data->work, t);
+ kthread_mod_delayed_work(watchdog_kworker,
+ &wd_data->work, t);
} else {
- cancel_delayed_work(&wd_data->work);
+ kthread_cancel_delayed_work_sync(&wd_data->work);
}
}
int err;
if (time_is_after_jiffies(earliest_keepalive)) {
- mod_delayed_work(watchdog_wq, &wd_data->work,
- earliest_keepalive - jiffies);
+ kthread_mod_delayed_work(watchdog_kworker, &wd_data->work,
+ earliest_keepalive - jiffies);
return 0;
}
return wdd && (watchdog_active(wdd) || watchdog_hw_running(wdd));
}
-static void watchdog_ping_work(struct work_struct *work)
+static void watchdog_ping_work(struct kthread_work *work)
{
struct watchdog_core_data *wd_data;
- wd_data = container_of(to_delayed_work(work), struct watchdog_core_data,
- work);
+ wd_data = container_of(container_of(work, struct kthread_delayed_work,
+ work),
+ struct watchdog_core_data, work);
mutex_lock(&wd_data->lock);
if (watchdog_worker_should_ping(wd_data))
wd_data->wdd = wdd;
wdd->wd_data = wd_data;
- if (!watchdog_wq)
+ if (IS_ERR_OR_NULL(watchdog_kworker))
return -ENODEV;
- INIT_DELAYED_WORK(&wd_data->work, watchdog_ping_work);
+ kthread_init_delayed_work(&wd_data->work, watchdog_ping_work);
if (wdd->id == 0) {
old_wd_data = wd_data;
__module_get(wdd->ops->owner);
kref_get(&wd_data->kref);
if (handle_boot_enabled)
- queue_delayed_work(watchdog_wq, &wd_data->work, 0);
+ kthread_queue_delayed_work(watchdog_kworker,
+ &wd_data->work, 0);
else
pr_info("watchdog%d running and kernel based pre-userspace handler disabled\n",
wdd->id);
watchdog_stop(wdd);
}
- cancel_delayed_work_sync(&wd_data->work);
+ kthread_cancel_delayed_work_sync(&wd_data->work);
kref_put(&wd_data->kref, watchdog_core_data_release);
}
int __init watchdog_dev_init(void)
{
int err;
+ struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1,};
- watchdog_wq = alloc_workqueue("watchdogd",
- WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
- if (!watchdog_wq) {
- pr_err("Failed to create watchdog workqueue\n");
- return -ENOMEM;
+ watchdog_kworker = kthread_create_worker(0, "watchdogd");
+ if (IS_ERR(watchdog_kworker)) {
+ pr_err("Failed to create watchdog kworker\n");
+ return PTR_ERR(watchdog_kworker);
}
+ sched_setscheduler(watchdog_kworker->task, SCHED_FIFO, ¶m);
err = class_register(&watchdog_class);
if (err < 0) {
err_alloc:
class_unregister(&watchdog_class);
err_register:
- destroy_workqueue(watchdog_wq);
+ kthread_destroy_worker(watchdog_kworker);
return err;
}
{
unregister_chrdev_region(watchdog_devt, MAX_DOGS);
class_unregister(&watchdog_class);
- destroy_workqueue(watchdog_wq);
+ kthread_destroy_worker(watchdog_kworker);
}
module_param(handle_boot_enabled, bool, 0444);