Re: [1/2] watchdog: xen_wdt: use the watchdog subsystem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 03, 2017 at 03:31:52PM +0000, Radu Rendec wrote:
> Change the xen_wdt driver to use the watchdog subsystem instead of
> registering and manipulating the char device directly through the misc
> API. This is mainly getting rid of the "write" and "ioctl" methods and
> part of the watchdog control logic (which are all implemented by the
> watchdog subsystem).
> 
> Even though the watchdog subsystem supports registering and handling
> multiple watchdog devices at the same time, the xen_wdt driver has an
> inherent limitation of only one device due to the way the Xen hypervisor
> exposes watchdog functionality. However, the driver can now coexist with
> other watchdog devices (supported by different drivers).
> 
> Signed-off-by: Radu Rendec <rrendec@xxxxxxxxxx>

Can you rebase the patch on top of Arnd's patch ("watchdog: xen: use time64_t
for timeouts") ?

> ---
>  drivers/watchdog/xen_wdt.c | 204 +++++++++------------------------------------
>  1 file changed, 38 insertions(+), 166 deletions(-)
> 
> diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
> index cf0e650c2015..8bea946dfdc7 100644
> --- a/drivers/watchdog/xen_wdt.c
> +++ b/drivers/watchdog/xen_wdt.c
> @@ -33,13 +33,11 @@
>  #include <xen/interface/sched.h>
>  
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>

should now be unnecessary.

>  static struct platform_device *platform_device;
> -static DEFINE_SPINLOCK(wdt_lock);
>  static struct sched_watchdog wdt;
>  static __kernel_time_t wdt_expires;
> -static bool is_active, expect_release;
>  
>  #define WATCHDOG_TIMEOUT 60 /* in seconds */
> -static unsigned int timeout = WATCHDOG_TIMEOUT;
> +static unsigned int timeout;
>  module_param(timeout, uint, S_IRUGO);
>  MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
>  	"(default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
> @@ -49,20 +47,18 @@ module_param(nowayout, bool, S_IRUGO);
>  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
>  	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
>  
> -static inline __kernel_time_t set_timeout(void)
> +static inline __kernel_time_t set_timeout(struct watchdog_device *wdd)
>  {
> -	wdt.timeout = timeout;
> -	return ktime_to_timespec(ktime_get()).tv_sec + timeout;
> +	wdt.timeout = wdd->timeout;
> +	return ktime_to_timespec(ktime_get()).tv_sec + wdd->timeout;
>  }
>  
> -static int xen_wdt_start(void)
> +static int xen_wdt_start(struct watchdog_device *wdd)
>  {
>  	__kernel_time_t expires;
>  	int err;
>  
> -	spin_lock(&wdt_lock);
> -
> -	expires = set_timeout();
> +	expires = set_timeout(wdd);
>  	if (!wdt.id)
>  		err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
>  	else
> @@ -74,36 +70,28 @@ static int xen_wdt_start(void)
>  	} else
>  		BUG_ON(!err);
>  
> -	spin_unlock(&wdt_lock);
> -
>  	return err;
>  }
>  
> -static int xen_wdt_stop(void)
> +static int xen_wdt_stop(struct watchdog_device *wdd)
>  {
>  	int err = 0;
>  
> -	spin_lock(&wdt_lock);
> -
>  	wdt.timeout = 0;
>  	if (wdt.id)
>  		err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
>  	if (!err)
>  		wdt.id = 0;
>  
> -	spin_unlock(&wdt_lock);
> -
>  	return err;
>  }
>  
> -static int xen_wdt_kick(void)
> +static int xen_wdt_kick(struct watchdog_device *wdd)
>  {
>  	__kernel_time_t expires;
>  	int err;
>  
> -	spin_lock(&wdt_lock);
> -
> -	expires = set_timeout();
> +	expires = set_timeout(wdd);
>  	if (wdt.id)
>  		err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
>  	else
> @@ -111,137 +99,31 @@ static int xen_wdt_kick(void)
>  	if (!err)
>  		wdt_expires = expires;
>  
> -	spin_unlock(&wdt_lock);
> -
> -	return err;
> -}
> -
> -static int xen_wdt_open(struct inode *inode, struct file *file)
> -{
> -	int err;
> -
> -	/* /dev/watchdog can only be opened once */
> -	if (xchg(&is_active, true))
> -		return -EBUSY;
> -
> -	err = xen_wdt_start();
> -	if (err == -EBUSY)
> -		err = xen_wdt_kick();
> -	return err ?: nonseekable_open(inode, file);
> -}
> -
> -static int xen_wdt_release(struct inode *inode, struct file *file)
> -{
> -	int err = 0;
> -
> -	if (expect_release)
> -		err = xen_wdt_stop();
> -	else {
> -		pr_crit("unexpected close, not stopping watchdog!\n");
> -		xen_wdt_kick();
> -	}
> -	is_active = err;
> -	expect_release = false;
>  	return err;
>  }
>  
> -static ssize_t xen_wdt_write(struct file *file, const char __user *data,
> -			     size_t len, loff_t *ppos)
> +static unsigned int xen_wdt_get_timeleft(struct watchdog_device *wdd)
>  {
> -	/* See if we got the magic character 'V' and reload the timer */
> -	if (len) {
> -		if (!nowayout) {
> -			size_t i;
> -
> -			/* in case it was set long ago */
> -			expect_release = false;
> -
> -			/* scan to see whether or not we got the magic
> -			   character */
> -			for (i = 0; i != len; i++) {
> -				char c;
> -				if (get_user(c, data + i))
> -					return -EFAULT;
> -				if (c == 'V')
> -					expect_release = true;
> -			}
> -		}
> -
> -		/* someone wrote to us, we should reload the timer */
> -		xen_wdt_kick();
> -	}
> -	return len;
> +	return wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
>  }
>  
> -static long xen_wdt_ioctl(struct file *file, unsigned int cmd,
> -			  unsigned long arg)
> -{
> -	int new_options, retval = -EINVAL;
> -	int new_timeout;
> -	int __user *argp = (void __user *)arg;
> -	static const struct watchdog_info ident = {
> -		.options =		WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
> -		.firmware_version =	0,
> -		.identity =		DRV_NAME,
> -	};
> -
> -	switch (cmd) {
> -	case WDIOC_GETSUPPORT:
> -		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
> -
> -	case WDIOC_GETSTATUS:
> -	case WDIOC_GETBOOTSTATUS:
> -		return put_user(0, argp);
> -
> -	case WDIOC_SETOPTIONS:
> -		if (get_user(new_options, argp))
> -			return -EFAULT;
> -
> -		if (new_options & WDIOS_DISABLECARD)
> -			retval = xen_wdt_stop();
> -		if (new_options & WDIOS_ENABLECARD) {
> -			retval = xen_wdt_start();
> -			if (retval == -EBUSY)
> -				retval = xen_wdt_kick();
> -		}
> -		return retval;
> -
> -	case WDIOC_KEEPALIVE:
> -		xen_wdt_kick();
> -		return 0;
> -
> -	case WDIOC_SETTIMEOUT:
> -		if (get_user(new_timeout, argp))
> -			return -EFAULT;
> -		if (!new_timeout)
> -			return -EINVAL;
> -		timeout = new_timeout;
> -		xen_wdt_kick();
> -		/* fall through */
> -	case WDIOC_GETTIMEOUT:
> -		return put_user(timeout, argp);
> -
> -	case WDIOC_GETTIMELEFT:
> -		retval = wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
> -		return put_user(retval, argp);
> -	}
> -
> -	return -ENOTTY;
> -}
> +static struct watchdog_info xen_wdt_info = {
> +	.identity = DRV_NAME,
> +	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
> +};
>  
> -static const struct file_operations xen_wdt_fops = {
> -	.owner =		THIS_MODULE,
> -	.llseek =		no_llseek,
> -	.write =		xen_wdt_write,
> -	.unlocked_ioctl =	xen_wdt_ioctl,
> -	.open =			xen_wdt_open,
> -	.release =		xen_wdt_release,
> +static const struct watchdog_ops xen_wdt_ops = {
> +	.owner = THIS_MODULE,
> +	.start = xen_wdt_start,
> +	.stop = xen_wdt_stop,
> +	.ping = xen_wdt_kick,
> +	.get_timeleft = xen_wdt_get_timeleft,
>  };
>  
> -static struct miscdevice xen_wdt_miscdev = {
> -	.minor =	WATCHDOG_MINOR,
> -	.name =		"watchdog",
> -	.fops =		&xen_wdt_fops,
> +static struct watchdog_device xen_wdt_dev = {
> +	.info = &xen_wdt_info,
> +	.ops = &xen_wdt_ops,
> +	.timeout = WATCHDOG_TIMEOUT,
>  };
>  
>  static int xen_wdt_probe(struct platform_device *dev)
> @@ -251,20 +133,21 @@ static int xen_wdt_probe(struct platform_device *dev)
>  
>  	switch (ret) {
>  	case -EINVAL:
> -		if (!timeout) {
> -			timeout = WATCHDOG_TIMEOUT;
> -			pr_info("timeout value invalid, using %d\n", timeout);
> -		}
> -
> -		ret = misc_register(&xen_wdt_miscdev);
> +		if (watchdog_init_timeout(&xen_wdt_dev, timeout, NULL))
> +			pr_info("timeout value invalid, using %d\n",
> +				xen_wdt_dev.timeout);
> +		watchdog_set_nowayout(&xen_wdt_dev, nowayout);
> +		watchdog_stop_on_reboot(&xen_wdt_dev);
> +		watchdog_stop_on_unregister(&xen_wdt_dev);
> +
> +		ret = watchdog_register_device(&xen_wdt_dev);

Please consider using devm_watchdog_register_device() and drop the remove
function entirely.

>  		if (ret) {
> -			pr_err("cannot register miscdev on minor=%d (%d)\n",
> -			       WATCHDOG_MINOR, ret);
> +			pr_err("cannot register watchdog device (%d)\n", ret);
>  			break;
>  		}
>  
>  		pr_info("initialized (timeout=%ds, nowayout=%d)\n",
> -			timeout, nowayout);
> +			xen_wdt_dev.timeout, nowayout);

Maybe convert messages to dev_err() and dev_info().

>  		break;
>  
>  	case -ENOSYS:
> @@ -282,24 +165,14 @@ static int xen_wdt_probe(struct platform_device *dev)
>  

The probe function is quite odd. It may return 0 (no error) but not
initialize the watchdog. It might be better to reorganize the code
along the line of

	int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);

	if (ret != -EINVAL) {
		/* pick your preferred error message */
		dev_err(&pdev->dev, "Hypervisor error (%d)\n", ret);
		return -ENODEV;
	}

	...

>  static int xen_wdt_remove(struct platform_device *dev)
>  {
> -	/* Stop the timer before we leave */
> -	if (!nowayout)
> -		xen_wdt_stop();
> -
> -	misc_deregister(&xen_wdt_miscdev);
> -
> +	watchdog_unregister_device(&xen_wdt_dev);
>  	return 0;
>  }
>  
> -static void xen_wdt_shutdown(struct platform_device *dev)
> -{
> -	xen_wdt_stop();
> -}
> -
>  static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
>  {
>  	typeof(wdt.id) id = wdt.id;
> -	int rc = xen_wdt_stop();
> +	int rc = xen_wdt_stop(&xen_wdt_dev);
>  
>  	wdt.id = id;
>  	return rc;
> @@ -310,13 +183,12 @@ static int xen_wdt_resume(struct platform_device *dev)
>  	if (!wdt.id)
>  		return 0;
>  	wdt.id = 0;
> -	return xen_wdt_start();
> +	return xen_wdt_start(&xen_wdt_dev);
>  }
>  
>  static struct platform_driver xen_wdt_driver = {
>  	.probe          = xen_wdt_probe,
>  	.remove         = xen_wdt_remove,
> -	.shutdown       = xen_wdt_shutdown,
>  	.suspend        = xen_wdt_suspend,
>  	.resume         = xen_wdt_resume,
>  	.driver         = {

For module initialization: Any chance to use module_platform_driver_probe() ?

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux