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;
>
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.