Re: [2/2] niwatchdog: add support for custom ioctls

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

 



Hi Guenter,

On Sat, Jan 16, 2016 at 08:29:41PM -0800, Guenter Roeck wrote:
> On Mon, Jan 11, 2016 at 06:23:01PM -0600, Kyle Roeschley wrote:
> > Add custom ioctls for features specific to the NI watchdog, including
> > disabling the watchdog, changing timeout behavior, and setting timeouts
> > with sub-second resolution.
> > 
> I don't really agree with any of the added functionality.
> Most of the added ioctls duplicate standard functionality.
> 
> 

The main thing that I think could be useful is the increased timeout
resolution. Aside from that, the other changes are specifically implemented for
the sake of maintaining compatability with our watchdog API--I think carrying
some (hopefully not all) of those changes out-of-tree is reasonable.

> > Signed-off-by: Kyle Roeschley <kyle.roeschley@xxxxxx>
> > Signed-off-by: Jeff Westfahl <jeff.westfahl@xxxxxx>
> > ---
> >  drivers/watchdog/niwatchdog.c   | 115 +++++++++++++++++++++++++++++++++++++++-
> >  include/uapi/linux/niwatchdog.h |  10 ++++
> >  2 files changed, 123 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/watchdog/niwatchdog.c b/drivers/watchdog/niwatchdog.c
> > index 3908846..fe637a3 100644
> > --- a/drivers/watchdog/niwatchdog.c
> > +++ b/drivers/watchdog/niwatchdog.c
> > @@ -131,6 +131,35 @@ out_unlock:
> >  	return ret;
> >  }
> >  
> > +static int niwatchdog_check_action(u32 action)
> > +{
> > +	int err = 0;
> > +
> > +	switch (action) {
> > +	case NIWD_CONTROL_PROC_INTERRUPT:
> > +	case NIWD_CONTROL_PROC_RESET:
> > +		break;
> > +	default:
> > +		err = -ENOTSUPP;
> > +	}
> > +
> > +	return err;
> > +}
> > +
> > +static void niwatchdog_get_actions(struct niwatchdog *niwatchdog, u8 *actions)
> > +{
> > +	u8 control;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&niwatchdog->lock, flags);
> > +
> > +	control = inb(niwatchdog->io_base + NIWD_CONTROL);
> > +	*actions = control & (NIWD_CONTROL_PROC_INTERRUPT +
> > +			      NIWD_CONTROL_PROC_RESET);
> > +
> > +	spin_unlock_irqrestore(&niwatchdog->lock, flags);
> > +}
> > +
> >  static int niwatchdog_add_action(struct niwatchdog *niwatchdog, u32 action)
> >  {
> >  	u8 action_mask;
> > @@ -233,12 +262,20 @@ static int niwatchdog_wdd_set_timeout(struct watchdog_device *wdd,
> >  {
> >  	struct niwatchdog *niwatchdog = to_niwatchdog(wdd);
> >  	u32 counter = timeout * (1000000000 / NIWD_PERIOD_NS);
> > +	u8 actions;
> >  
> > +	niwatchdog_get_actions(niwatchdog, &actions);
> >  	niwatchdog_reset(niwatchdog);
> >  	niwatchdog_counter_set(niwatchdog, counter);
> > -	niwatchdog_add_action(niwatchdog, NIWATCHDOG_ACTION_RESET);
> >  
> > -	return niwatchdog_start(niwatchdog);
> > +	if (actions & NIWD_CONTROL_PROC_RESET)
> > +		niwatchdog_add_action(niwatchdog, NIWATCHDOG_ACTION_RESET);
> > +	if (actions & NIWD_CONTROL_PROC_INTERRUPT)
> > +		niwatchdog_add_action(niwatchdog, NIWATCHDOG_ACTION_INTERRUPT);
> > +
> > +	niwatchdog_start(niwatchdog);
> > +
> > +	return 0;
> >  }
> >  
> >  static unsigned int niwatchdog_wdd_get_timeleft(struct watchdog_device *wdd)
> > @@ -319,6 +356,79 @@ static int niwatchdog_wdd_release(struct watchdog_device *wdd)
> >  	return 0;
> >  }
> >  
> > +static long niwatchdog_wdd_ioctl(struct watchdog_device *wdd, unsigned int cmd,
> > +				 unsigned long arg)
> > +{
> > +	struct niwatchdog *niwatchdog = to_niwatchdog(wdd);
> > +	int err = 0;
> > +
> > +	switch (cmd) {
> > +	case NIWATCHDOG_IOCTL_PERIOD_NS: {
> > +		__u32 period = NIWD_PERIOD_NS;
> > +
> > +		err = copy_to_user((__u32 *)arg, &period, sizeof(__u32));
> > +		break;
> > +	}
> > +	case NIWATCHDOG_IOCTL_MAX_COUNTER: {
> > +		__u32 counter = NIWD_MAX_COUNTER;
> > +
> > +		err = copy_to_user((__u32 *)arg, &counter, sizeof(__u32));
> > +		break;
> > +	}
> 
> Those are constants and can as well be defined in some documentation.
> 

True. The only reason they're here is that our API expects this function to be
implemented for all of our watchdog timers. As such, carrying this out-of-tree
would be reasonable.

> > +	case NIWATCHDOG_IOCTL_COUNTER_SET: {
> > +		__u32 counter;
> > +
> > +		err = copy_from_user(&counter, (__u32 *)arg, sizeof(__u32));
> > +		if (!err)
> > +			err = niwatchdog_counter_set(niwatchdog, counter);
> > +		break;
> > +	}
> Duplicates standard functionality
> 

It duplicates set_timeout(), but with much greater resolution. What would be an
appropriate way to expose this capability to users?

> > +	case NIWATCHDOG_IOCTL_CHECK_ACTION: {
> > +		__u32 action;
> > +
> > +		err = copy_from_user(&action, (__u32 *)arg, sizeof(__u32));
> > +		if (!err)
> > +			err = niwatchdog_check_action(action);
> > +		break;
> > +	}
> > +	case NIWATCHDOG_IOCTL_ADD_ACTION: {
> > +		__u32 action;
> > +
> > +		err = copy_from_user(&action, (__u32 *)arg, sizeof(__u32));
> > +		if (!err)
> > +			err = niwatchdog_add_action(niwatchdog, action);
> > +		break;
> > +	}
> 
> Use a module parameter or sysfs attribute for those.
> 

I'm a fan of using a sysfs attribute, specifically because the options can be
changed after opening the watchdog and you can have one, both, or neither of
the two timeout actions set.

> > +	case NIWATCHDOG_IOCTL_START: {
> > +		niwatchdog_start(niwatchdog);
> > +		break;
> > +	}
> 
> Duplicates standard functionality.
> 
> > +	case NIWATCHDOG_IOCTL_PET: {
> > +		__u32 state;
> > +
> > +		niwatchdog_pet(niwatchdog, &state);
> > +		err = copy_to_user((__u32 *)arg, &state, sizeof(__u32));
> > +		break;
> > +	}
> 
> Duplicates standard functionality.
> 
> > +	case NIWATCHDOG_IOCTL_RESET: {
> > +		niwatchdog_reset(niwatchdog);
> > +		break;
> > +	}
> 
> Duplicates standard functionality.
> 

These are just maps from old, non-standard iotcls to the standard ones. They
can be removed in favor of an out-of-tree commit.

> > +	case NIWATCHDOG_IOCTL_COUNTER_GET: {
> > +		__u32 counter;
> > +
> > +		niwatchdog_counter_get(niwatchdog, &counter);
> > +		err = copy_to_user((__u32 *)arg, &counter, sizeof(__u32));
> > +		break;
> > +	}
> 
> Duplicates standard functionality.
> 

Yes, but again I'm not sure how we should give the user a more accurate
remaining time.

> > +	default:
> > +		err = -ENOIOCTLCMD;
> > +		break;
> > +	};
> > +
> > +	return err;
> > +}
> > +
> >  static int niwatchdog_ping(struct watchdog_device *wdd)
> >  {
> >  	struct niwatchdog *niwatchdog = to_niwatchdog(wdd);
> > @@ -403,6 +513,7 @@ static const struct watchdog_ops niwatchdog_wdd_ops = {
> >  	.start		= niwatchdog_wdd_open,
> >  	.stop		= niwatchdog_wdd_release,
> >  	.ping		= niwatchdog_ping,
> > +	.ioctl		= niwatchdog_wdd_ioctl,
> >  	.set_timeout	= niwatchdog_wdd_set_timeout,
> >  	.get_timeleft	= niwatchdog_wdd_get_timeleft,
> >  };
> > diff --git a/include/uapi/linux/niwatchdog.h b/include/uapi/linux/niwatchdog.h
> > index 9d3613d..4fb8d47 100644
> > --- a/include/uapi/linux/niwatchdog.h
> > +++ b/include/uapi/linux/niwatchdog.h
> > @@ -25,6 +25,16 @@
> >  #define NIWATCHDOG_STATE_EXPIRED	1
> >  #define NIWATCHDOG_STATE_DISABLED	2
> >  
> > +#define NIWATCHDOG_IOCTL_PERIOD_NS	_IOR('W', 60, __u32)
> > +#define NIWATCHDOG_IOCTL_MAX_COUNTER	_IOR('W', 61, __u32)
> > +#define NIWATCHDOG_IOCTL_COUNTER_SET	_IOW('W', 62, __u32)
> > +#define NIWATCHDOG_IOCTL_CHECK_ACTION	_IOW('W', 63, __u32)
> > +#define NIWATCHDOG_IOCTL_ADD_ACTION	_IOW('W', 64, __u32)
> > +#define NIWATCHDOG_IOCTL_START		_IO('W', 65)
> > +#define NIWATCHDOG_IOCTL_PET		_IOR('W', 66, __u32)
> > +#define NIWATCHDOG_IOCTL_RESET		_IO('W', 67)
> > +#define NIWATCHDOG_IOCTL_COUNTER_GET	_IOR('W', 68, __u32)
> > +
> >  #define NIWATCHDOG_NAME			"niwatchdog"
> >  
> >  #endif /* _LINUX_NIWATCHDOG_H_ */
> --
> 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

Thanks again for the reviews.

-- 
Kyle Roeschley
Software Engineer
National Instruments
--
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