linux-watchdog.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Hans de Goede <hdegoede@redhat.com>
To: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: linux-watchdog@vger.kernel.org, wim@iguana.be
Subject: Re: [PATCH 1/4] watchdog: Add multiple device support
Date: Fri, 13 Apr 2012 10:57:26 +0200	[thread overview]
Message-ID: <4F87EA76.1030707@redhat.com> (raw)
In-Reply-To: <20120321152418.20045.35525.stgit@bob.linux.org.uk>

Hi,

I've reviewed & tested this, it looks good and works as advertised.

But I'm afraid that I missed one item during my previous review,
this patch should also update:
Documentation/watchdog/watchdog-kernel-api.txt and the comment
above struct watchdog_device in include/linux/watchdog.h,
WRT the new members added to struct watchdog_device.

Besides that there are also some minor whitespace issues
noted by checkpatch / git am:

ERROR: space prohibited before that '++' (ctx:WxB)
#193: FILE: drivers/watchdog/watchdog_dev.c:395:
+       for (i = first; i < DOG_MAX; i ++) {
                                        ^
ERROR: trailing whitespace
#261: FILE: drivers/watchdog/watchdog_dev.c:450:
+}^I$

WARNING: please, no space before tabs
#265: FILE: drivers/watchdog/watchdog_dev.c:453:
+ *^Iwatchdog_dev_register ^I-^Iregister a watchdog$

/home/hans/projects/linux/.git/rebase-apply/patch:323: new blank line at EOF.

With these issues fixed, this patch is:
Acked-by: Hans de Goede <hdegoede@redhat.com>

(and/or Reviewed-by / Tested-by whichever you prefer :)

Regards,

Hans


On 03/21/2012 04:24 PM, Alan Cox wrote:
> From: Alan Cox<alan@linux.intel.com>
>
> We keep the old /dev/watchdog interface file for the first watchdog via
> miscdev. This is basically a cut and paste of the relevant interface code
> from the rtc driver layer tweaked for watchdog.
>
> Revised to fix problems noted by Hans de Goede
>
> Signed-off-by: Alan Cox<alan@linux.intel.com>
> ---
>
>   drivers/watchdog/watchdog_dev.c |  231 ++++++++++++++++++++++++++++++++-------
>   include/linux/watchdog.h        |    6 +
>   2 files changed, 193 insertions(+), 44 deletions(-)
>
>
> diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
> index c6e1b8d..40c557b 100644
> --- a/drivers/watchdog/watchdog_dev.c
> +++ b/drivers/watchdog/watchdog_dev.c
> @@ -42,10 +42,12 @@
>   #include<linux/init.h>		/* For __init/__exit/... */
>   #include<linux/uaccess.h>	/* For copy_to_user/put_user/... */
>
> -/* make sure we only register one /dev/watchdog device */
> -static unsigned long watchdog_dev_busy;
> +static dev_t dog_devt;		/* Watchdog device range */
> +static unsigned long dog_mask;	/* Watchdogs that are in use */
>   /* the watchdog device behind /dev/watchdog */
> -static struct watchdog_device *wdd;
> +static struct watchdog_device *old_wdd;
> +
> +#define DOG_MAX		32	/* assign_id must be changed to boost this */
>
>   /*
>    *	watchdog_ping: ping the watchdog.
> @@ -136,6 +138,7 @@ static int watchdog_stop(struct watchdog_device *wddev)
>   static ssize_t watchdog_write(struct file *file, const char __user *data,
>   						size_t len, loff_t *ppos)
>   {
> +	struct watchdog_device *wdd = file->private_data;
>   	size_t i;
>   	char c;
>
> @@ -175,6 +178,7 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
>   static long watchdog_ioctl(struct file *file, unsigned int cmd,
>   							unsigned long arg)
>   {
> +	struct watchdog_device *wdd = file->private_data;
>   	void __user *argp = (void __user *)arg;
>   	int __user *p = argp;
>   	unsigned int val;
> @@ -251,7 +255,8 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
>    *	it can only be opened once.
>    */
>
> -static int watchdog_open(struct inode *inode, struct file *file)
> +static int watchdog_do_open(struct watchdog_device *wdd,
> +				struct inode *inode, struct file *file)
>   {
>   	int err = -EBUSY;
>
> @@ -270,6 +275,8 @@ static int watchdog_open(struct inode *inode, struct file *file)
>   	if (err<  0)
>   		goto out_mod;
>
> +	file->private_data = wdd;
> +
>   	/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
>   	return nonseekable_open(inode, file);
>
> @@ -281,7 +288,40 @@ out:
>   }
>
>   /*
> - *      watchdog_release: release the /dev/watchdog device.
> + *	watchdog_open: open the /dev/watchdog device.
> + *	@inode: inode of device
> + *	@file: file handle to device
> + *
> + *	When the /dev/watchdog device gets opened, we start the watchdog.
> + *	Watch out: the /dev/watchdog device is single open, so we make sure
> + *	it can only be opened once.
> + */
> +
> +static int watchdog_open(struct inode *inode, struct file *file)
> +{
> +	return watchdog_do_open(old_wdd, inode, file);
> +}
> +
> +/*
> + *	watchdog_mopen: open the newer watchdog devices.
> + *	@inode: inode of device
> + *	@file: file handle to device
> + *
> + *	When the watchdog device gets opened, we start the watchdog.
> + *	Watch out: the /dev/watchdog device is single open, so we make sure
> + *	it can only be opened once.
> + */
> +
> +static int watchdog_mopen(struct inode *inode, struct file *file)
> +{
> +	struct watchdog_device *wdd = container_of(inode->i_cdev,
> +		struct watchdog_device, cdev);
> +
> +	return watchdog_do_open(wdd, inode, file);
> +}
> +
> +/*
> + *      watchdog_release: release the watchdog device.
>    *      @inode: inode of device
>    *      @file: file handle to device
>    *
> @@ -292,6 +332,7 @@ out:
>
>   static int watchdog_release(struct inode *inode, struct file *file)
>   {
> +	struct watchdog_device *wdd = file->private_data;
>   	int err = -EBUSY;
>
>   	/*
> @@ -326,69 +367,171 @@ static const struct file_operations watchdog_fops = {
>   	.release	= watchdog_release,
>   };
>
> +static const struct file_operations watchdog_multi_fops = {
> +	.owner		= THIS_MODULE,
> +	.write		= watchdog_write,
> +	.unlocked_ioctl	= watchdog_ioctl,
> +	.open		= watchdog_mopen,
> +	.release	= watchdog_release,
> +};
> +
>   static struct miscdevice watchdog_miscdev = {
>   	.minor		= WATCHDOG_MINOR,
>   	.name		= "watchdog",
>   	.fops		=&watchdog_fops,
>   };
>
> -/*
> - *	watchdog_dev_register:
> - *	@watchdog: watchdog device
> +/**
> + *	watchdog_assign_id	-	pick a free watchdog ident
> + *	@watchdog: the watchdog device
> + *	@first: number to scan from
>    *
> - *	Register a watchdog device as /dev/watchdog. /dev/watchdog
> - *	is actually a miscdevice and thus we set it up like that.
> + *	Assign a watchdog number to the device. For the moment we support
> + *	a starting offset so that a legacy watchdog can be worked around
>    */
> +static int watchdog_assign_id(struct watchdog_device *watchdog, int first)
> +{
> +	int i;
> +	for (i = first; i<  DOG_MAX; i ++) {
> +		if (test_and_set_bit(i,&dog_mask) == 0) {
> +			watchdog->id = i;
> +			return i;
> +		}
> +	}
> +	pr_err("no free watchdog slots.\n");
> +	return -EBUSY;
> +}
>
> -int watchdog_dev_register(struct watchdog_device *watchdog)
> +/**
> + *	watchdog_release_id	-	release a watchdg id
> + *	@watchdog: the watchdog device
> + *
> + *	Release the identifier associated with this watchdog. All cdev
> + *	resources must have been released first.
> + */
> +static void watchdog_release_id(struct watchdog_device *watchdog)
> +{
> +	clear_bit(watchdog->id,&dog_mask);
> +}
> +
> +/**
> + *	watchdog_add_device	-	add a watchdog device
> + *	@watchdog: the watchdog device
> + *
> + *	Add a watchdog device node to the system and set up all the
> + *	needed structures.
> + */
> +static int watchdog_add_device(struct watchdog_device *watchdog)
>   {
>   	int err;
>
> -	/* Only one device can register for /dev/watchdog */
> -	if (test_and_set_bit(0,&watchdog_dev_busy)) {
> -		pr_err("only one watchdog can use /dev/watchdog\n");
> -		return -EBUSY;
> -	}
> +	/* Fill in the data structures */
> +	watchdog->devt = MKDEV(MAJOR(dog_devt), watchdog->id);
> +	watchdog->cdev.owner = watchdog->ops->owner;
> +	cdev_init(&watchdog->cdev,&watchdog_multi_fops);
>
> -	wdd = watchdog;
> +	/* Add the device */
> +	err  = cdev_add(&watchdog->cdev, watchdog->devt, 1);
> +	if (err)
> +		pr_err("watchdog%d unable to add device %d:%d\n",
> +			watchdog->id,  MAJOR(dog_devt), watchdog->id);
> +	return err;
> +}
>
> -	err = misc_register(&watchdog_miscdev);
> -	if (err != 0) {
> -		pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n",
> -		       watchdog->info->identity, WATCHDOG_MINOR, err);
> -		goto out;
> -	}
> +/**
> + *	watchdog_del_device	-	delete a watchdog device
> + *	@watchdog: the watchdog device
> + *
> + *	Delete a watchdog device cdev object
> + */
> +static void watchdog_del_device(struct watchdog_device *watchdog)
> +{
> +	cdev_del(&watchdog->cdev);
> +}	
>
> -	return 0;
> +/**
> + *	watchdog_dev_register 	-	register a watchdog
> + *	@watchdog: watchdog device
> + *
> + *	Register a watchdog device including handling the legacy
> + *	/dev/watchdog node. /dev/watchdog is actually a miscdevice and
> + *	thus we set it up like that.
> + */
> +int watchdog_dev_register(struct watchdog_device *watchdog)
> +{
> +	int err;
>
> -out:
> -	wdd = NULL;
> -	clear_bit(0,&watchdog_dev_busy);
> +	err = watchdog_assign_id(watchdog, 0);
> +	if (err<  0)
> +		return err;
> +	if (err == 0) {
> +		err = misc_register(&watchdog_miscdev);
> +		if (err == 0)
> +			old_wdd = watchdog;
> +		else {
> +			pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
> +				watchdog->info->identity, WATCHDOG_MINOR, err);
> +			if (err == -EBUSY) {
> +				pr_err("%s: probably a legacy watchdog module is present.\n",
> +					watchdog->info->identity);
> +				watchdog_release_id(watchdog);
> +				err = watchdog_assign_id(watchdog, 1);
> +			}
> +			if (err<  0)
> +				return err;
> +		}
> +	}
> +	err = watchdog_add_device(watchdog);
> +	if (err<  0) {
> +		if (watchdog->id == 0) {
> +			misc_deregister(&watchdog_miscdev);
> +			old_wdd = NULL;
> +		}
> +		watchdog_release_id(watchdog);
> +	}
>   	return err;
>   }
>
> -/*
> - *	watchdog_dev_unregister:
> +/**
> + *	watchdog_dev_unregister		-	unregister a watchdog
>    *	@watchdog: watchdog device
>    *
> - *	Deregister the /dev/watchdog device.
> + *	Unregister the watchdog and if needed the legacy /dev/watchdog device.
>    */
> -
>   int watchdog_dev_unregister(struct watchdog_device *watchdog)
>   {
> -	/* Check that a watchdog device was registered in the past */
> -	if (!test_bit(0,&watchdog_dev_busy) || !wdd)
> -		return -ENODEV;
> -
> -	/* We can only unregister the watchdog device that was registered */
> -	if (watchdog != wdd) {
> -		pr_err("%s: watchdog was not registered as /dev/watchdog\n",
> -		       watchdog->info->identity);
> -		return -ENODEV;
> +	watchdog_del_device(watchdog);
> +	if (watchdog->id == 0) {
> +		misc_deregister(&watchdog_miscdev);
> +		old_wdd = NULL;
>   	}
> -
> -	misc_deregister(&watchdog_miscdev);
> -	wdd = NULL;
> -	clear_bit(0,&watchdog_dev_busy);
> +	watchdog_release_id(watchdog);
>   	return 0;
>   }
> +
> +/**
> + *	watchdog_init	-	module init call
> + *
> + *	Allocate a range of chardev nodes to use for watchdog devices
> + */
> +int __init watchdog_init(void)
> +{
> +	int err = alloc_chrdev_region(&dog_devt, 0, DOG_MAX, "watchdog");
> +	if (err<  0)
> +		pr_err("watchdog: unable to allocate char dev region\n");
> +	return err;
> +}
> +
> +/**
> + *	watchdog_exit	-	module exit
> + *
> + *	Release the range of chardev nodes used for watchdog devices
> + */
> +void __exit watchdog_exit(void)
> +{
> +	unregister_chrdev_region(dog_devt, DOG_MAX);
> +}
> +
> +module_init(watchdog_init);
> +module_exit(watchdog_exit);
> +
> diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
> index de75167..0d5c3af 100644
> --- a/include/linux/watchdog.h
> +++ b/include/linux/watchdog.h
> @@ -54,6 +54,8 @@ struct watchdog_info {
>   #ifdef __KERNEL__
>
>   #include<linux/bitops.h>
> +#include<linux/device.h>
> +#include<linux/cdev.h>
>
>   struct watchdog_ops;
>   struct watchdog_device;
> @@ -103,6 +105,10 @@ struct watchdog_ops {
>    * via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
>    */
>   struct watchdog_device {
> +	struct cdev cdev;		/* Character device */
> +	dev_t devt;			/* Our device */
> +	int id;				/* Watchdog id */
> +
>   	const struct watchdog_info *info;
>   	const struct watchdog_ops *ops;
>   	unsigned int bootstatus;
>

  parent reply	other threads:[~2012-04-13  8:55 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-21 15:24 [PATCH 1/4] watchdog: Add multiple device support Alan Cox
2012-03-21 15:25 ` [PATCH 2/4] watchdog: Add a flag to indicate the watchdog doesn't reboot things Alan Cox
2012-04-13  8:58   ` Hans de Goede
2012-04-24 19:35     ` Wim Van Sebroeck
2012-03-21 15:25 ` [PATCH 3/4] watchdog: create all the proper device files Alan Cox
2012-04-13  8:59   ` Hans de Goede
2012-03-21 15:25 ` [PATCH 4/4] watchdog: use dev_ functions Alan Cox
2012-04-13  9:00   ` Hans de Goede
2012-04-13  8:57 ` Hans de Goede [this message]
2012-05-04 12:38 ` [PATCH 1/4] watchdog: Add multiple device support Wim Van Sebroeck
2012-05-10 19:20   ` Wim Van Sebroeck
2012-05-11  7:50     ` Hans de Goede
2012-05-11  8:42       ` Hans de Goede
2012-05-11 16:02       ` Wim Van Sebroeck
2012-05-11 16:40         ` Hans de Goede
2012-05-13 12:15           ` Tomas Winkler
2012-05-14 13:35             ` Wim Van Sebroeck
2012-05-11  9:58     ` Hans de Goede

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F87EA76.1030707@redhat.com \
    --to=hdegoede@redhat.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=wim@iguana.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).