watchdog: Fix kref imbalance seen if handle_boot_enabled=0
authorGuenter Roeck <linux@roeck-us.net>
Mon, 25 Sep 2017 16:17:02 +0000 (09:17 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Mar 2018 10:01:23 +0000 (11:01 +0100)
[ Upstream commit 914d65f3f013ba2556c7beec5d3baac7b3292504 ]

If handle_boot_enabled is set to 0, the watchdog driver module use
counter will not be increased and kref_get() will not be called when
registering the watchdog. Subsequently, on open, this does not happen
either because the code believes that it was already done because the
hardware watchdog is marked as running.

We could introduce a state variable to indicate this state, but let's
just increase the module use counter and call kref_get() unconditionally
if the hardware watchdog is running when a driver is registering itself
to keep the code simple.

Fixes: 2501b015313fe ("watchdog: core: add option to avoid early ...")
Cc: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/watchdog/watchdog_dev.c

index e6edf3737ea7b1a6ee00d8351a76a0d93d98ff3e..b30fb637ae947885e04eba1819e7d8cd145764d1 100644 (file)
@@ -966,14 +966,13 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
         * and schedule an immediate ping.
         */
        if (watchdog_hw_running(wdd)) {
-               if (handle_boot_enabled) {
-                       __module_get(wdd->ops->owner);
-                       kref_get(&wd_data->kref);
+               __module_get(wdd->ops->owner);
+               kref_get(&wd_data->kref);
+               if (handle_boot_enabled)
                        queue_delayed_work(watchdog_wq, &wd_data->work, 0);
-               } else {
+               else
                        pr_info("watchdog%d running and kernel based pre-userspace handler disabled\n",
-                                       wdd->id);
-               }
+                               wdd->id);
        }
 
        return 0;