diff mbox series

[v2,06/16] watchdog: hpwdt: drop warning after calling watchdog_init_timeout

Message ID 20190416102515.12269-7-wsa+renesas@sang-engineering.com (mailing list archive)
State Accepted
Headers show
Series watchdog: refactor init_timeout and update users | expand

Commit Message

Wolfram Sang April 16, 2019, 10:25 a.m. UTC
The core will print out details now.

Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
 drivers/watchdog/hpwdt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Comments

Jerry Hoemann April 16, 2019, 8:34 p.m. UTC | #1
On Tue, Apr 16, 2019 at 12:25:05PM +0200, Wolfram Sang wrote:
> The core will print out details now.
> 
> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> ---
>  drivers/watchdog/hpwdt.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
> index ef30c7e9728d..db1bf6f546ae 100644
> --- a/drivers/watchdog/hpwdt.c
> +++ b/drivers/watchdog/hpwdt.c
> @@ -311,8 +311,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
>  		goto error_init_nmi_decoding;
>  
>  	watchdog_set_nowayout(&hpwdt_dev, nowayout);
> -	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
> -		dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
> +	watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);

I applied patches 1,2 & 6 in testing.

Note, that hpwdt is passing NULL as the third parameter to watchdog_init_timeout().

The second patch in this series is using "dev" as input to dev_err and dev_warn.

This results in the following in dmesg when trying to load hpwdt w/ an invalid soft_margin:


[   80.848160] (NULL device *): driver supplied timeout (4294967295) out of range
[   80.855429] (NULL device *): falling back to default timeout (30)


if the call in hpwdt driver is changed to:

	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, &dev->dev))


We see the message like we'd desire:

[ 2061.167100] hpwdt 0000:01:00.0: driver supplied timeout (4294967295) out of range
[ 2061.174633] hpwdt 0000:01:00.0: falling back to default timeout (30)



watchdog_init_timeout() uses dev to "try to get the timeout_sec property"

I am not familiar with this part of the core and what effect having the hpwdt
driver pass in dev to watchdog_init_timeout would have.  (I.e. is the
change safe?)

Guenter, can you help on this question?

Note, hpwdt isn't the only watch dog device that is passing NULL to
watchdog_init_timeout.

Thanks,


Jerry


>  
>  	if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
>  		dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
> -- 
> 2.11.0
Guenter Roeck April 16, 2019, 8:48 p.m. UTC | #2
On Tue, Apr 16, 2019 at 02:34:31PM -0600, Jerry Hoemann wrote:
> On Tue, Apr 16, 2019 at 12:25:05PM +0200, Wolfram Sang wrote:
> > The core will print out details now.
> > 
> > Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> > Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > ---
> >  drivers/watchdog/hpwdt.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> > 
> > diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
> > index ef30c7e9728d..db1bf6f546ae 100644
> > --- a/drivers/watchdog/hpwdt.c
> > +++ b/drivers/watchdog/hpwdt.c
> > @@ -311,8 +311,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
> >  		goto error_init_nmi_decoding;
> >  
> >  	watchdog_set_nowayout(&hpwdt_dev, nowayout);
> > -	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
> > -		dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
> > +	watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
> 
> I applied patches 1,2 & 6 in testing.
> 
> Note, that hpwdt is passing NULL as the third parameter to watchdog_init_timeout().
> 
> The second patch in this series is using "dev" as input to dev_err and dev_warn.
> 
> This results in the following in dmesg when trying to load hpwdt w/ an invalid soft_margin:
> 
> 
> [   80.848160] (NULL device *): driver supplied timeout (4294967295) out of range
> [   80.855429] (NULL device *): falling back to default timeout (30)
> 
Good find. Thanks a lot for testing!

We'll have to address this. Wolfram - it looks like we'll need
separate error message handling for situations where dev is NULL.
We may have to leave it up to the parent after all to display
a message in that case (since we do want to see the driver name).

> 
> if the call in hpwdt driver is changed to:
> 
> 	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, &dev->dev))
> 
> 
> We see the message like we'd desire:
> 
> [ 2061.167100] hpwdt 0000:01:00.0: driver supplied timeout (4294967295) out of range
> [ 2061.174633] hpwdt 0000:01:00.0: falling back to default timeout (30)
> 
> 
> 
> watchdog_init_timeout() uses dev to "try to get the timeout_sec property"
> 
> I am not familiar with this part of the core and what effect having the hpwdt
> driver pass in dev to watchdog_init_timeout would have.  (I.e. is the
> change safe?)
> 
Yes, in general it is safe. watchdog_init_timeout() only uses dev to extract
a timeout value from devicetree (and now to display error messages).

> Guenter, can you help on this question?
> 
> Note, hpwdt isn't the only watch dog device that is passing NULL to
> watchdog_init_timeout.
> 
That is indeed a problem: the pointer will be NULL if there is no parent
device (such as in softdog.c). Otherwise it should never be NULL.

Thanks,
Guenter
Wolfram Sang April 16, 2019, 8:50 p.m. UTC | #3
Hi Jerry,

> I applied patches 1,2 & 6 in testing.
> 
> Note, that hpwdt is passing NULL as the third parameter to watchdog_init_timeout().
> 
> The second patch in this series is using "dev" as input to dev_err and dev_warn.
> 
> This results in the following in dmesg when trying to load hpwdt w/ an invalid soft_margin:
> 
> 
> [   80.848160] (NULL device *): driver supplied timeout (4294967295) out of range
> [   80.855429] (NULL device *): falling back to default timeout (30)

Thank you for this report. Yes, using 'dev' blindly is a bug.

> if the call in hpwdt driver is changed to:
> 
> 	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, &dev->dev))
> 
> 
> We see the message like we'd desire:
> 
> [ 2061.167100] hpwdt 0000:01:00.0: driver supplied timeout (4294967295) out of range
> [ 2061.174633] hpwdt 0000:01:00.0: falling back to default timeout (30)

The above observation makes sense, but I think we should fix the core
code and not the hpwdt driver. My suggestion would be to add something
like this to watchdog_init_timeout():

	struct device *err_dev = dev ?: wdd->parent;

And then use err_dev for all the printing. Guenter?

Regards,

   Wolfram
Wolfram Sang April 16, 2019, 8:55 p.m. UTC | #4
> That is indeed a problem: the pointer will be NULL if there is no parent
> device (such as in softdog.c). Otherwise it should never be NULL.

Okay, this spoils my err_dev solution. So, we probably go this route
then:

	pr_<errlvl>("watchdog%d: <err_msg>\n", wdd->id);

?
Guenter Roeck April 16, 2019, 9:14 p.m. UTC | #5
On Tue, Apr 16, 2019 at 10:50:03PM +0200, Wolfram Sang wrote:
> Hi Jerry,
> 
> > I applied patches 1,2 & 6 in testing.
> > 
> > Note, that hpwdt is passing NULL as the third parameter to watchdog_init_timeout().
> > 
> > The second patch in this series is using "dev" as input to dev_err and dev_warn.
> > 
> > This results in the following in dmesg when trying to load hpwdt w/ an invalid soft_margin:
> > 
> > 
> > [   80.848160] (NULL device *): driver supplied timeout (4294967295) out of range
> > [   80.855429] (NULL device *): falling back to default timeout (30)
> 
> Thank you for this report. Yes, using 'dev' blindly is a bug.
> 
> > if the call in hpwdt driver is changed to:
> > 
> > 	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, &dev->dev))
> > 
> > 
> > We see the message like we'd desire:
> > 
> > [ 2061.167100] hpwdt 0000:01:00.0: driver supplied timeout (4294967295) out of range
> > [ 2061.174633] hpwdt 0000:01:00.0: falling back to default timeout (30)
> 
> The above observation makes sense, but I think we should fix the core
> code and not the hpwdt driver. My suggestion would be to add something
> like this to watchdog_init_timeout():
> 
> 	struct device *err_dev = dev ?: wdd->parent;
> 
> And then use err_dev for all the printing. Guenter?
> 

That is a good idea, and we should do that. Unfortunately, wdd->parent can also
be NULL, either because there is no parent device (e.g. softdog.c), or because
the driver author forgot to set ->parent. So we still need a fallback.
Does it make sense to print watchdog_info->identity if both dev and wdd->parent
are NULL ?

Guenter
Guenter Roeck April 16, 2019, 9:20 p.m. UTC | #6
On Tue, Apr 16, 2019 at 10:55:33PM +0200, Wolfram Sang wrote:
> 
> > That is indeed a problem: the pointer will be NULL if there is no parent
> > device (such as in softdog.c). Otherwise it should never be NULL.
> 
> Okay, this spoils my err_dev solution. So, we probably go this route
> then:
> 
> 	pr_<errlvl>("watchdog%d: <err_msg>\n", wdd->id);
> 

I don't like it because it doesn't show the driver name, and watchdog%d
can change with each reboot. How about something like this ?

static void pr_wdt_err(struct watchdog_device *wdd, char *text, int err)
{
	if (wdd->parent)
		dev_err(wdd->parent, "%s: %d\n", text, err);
	else
		pr_err("%s: %s: %d\n", wdd->info->identity, text, err);
}

We could then use the same mechanism to generate error messages for
watchdog_register_device().

Guenter
Wolfram Sang April 16, 2019, 10:17 p.m. UTC | #7
On Tue, Apr 16, 2019 at 02:20:46PM -0700, Guenter Roeck wrote:
> On Tue, Apr 16, 2019 at 10:55:33PM +0200, Wolfram Sang wrote:
> > 
> > > That is indeed a problem: the pointer will be NULL if there is no parent
> > > device (such as in softdog.c). Otherwise it should never be NULL.
> > 
> > Okay, this spoils my err_dev solution. So, we probably go this route
> > then:
> > 
> > 	pr_<errlvl>("watchdog%d: <err_msg>\n", wdd->id);
> > 
> 
> I don't like it because it doesn't show the driver name, and watchdog%d
> can change with each reboot. How about something like this ?
> 
> static void pr_wdt_err(struct watchdog_device *wdd, char *text, int err)
> {
> 	if (wdd->parent)
> 		dev_err(wdd->parent, "%s: %d\n", text, err);
> 	else
> 		pr_err("%s: %s: %d\n", wdd->info->identity, text, err);
> }
> 
> We could then use the same mechanism to generate error messages for
> watchdog_register_device().

'text' is a constant string then. Supporting a format string will make
this much more complicated. Yet, printing out the wrong timeout is
useful, I think.

What about:

	dev_str = wdd->parent ? dev_name(wdd->parent) : wdd->info->identity;
	pr_<errlvl>("%s: <errstr>\n", dev_str, ...);

?

This can be easily copied for watchdog_register_device, not much
overhead there.
Guenter Roeck April 16, 2019, 10:38 p.m. UTC | #8
On Wed, Apr 17, 2019 at 12:17:02AM +0200, Wolfram Sang wrote:
> On Tue, Apr 16, 2019 at 02:20:46PM -0700, Guenter Roeck wrote:
> > On Tue, Apr 16, 2019 at 10:55:33PM +0200, Wolfram Sang wrote:
> > > 
> > > > That is indeed a problem: the pointer will be NULL if there is no parent
> > > > device (such as in softdog.c). Otherwise it should never be NULL.
> > > 
> > > Okay, this spoils my err_dev solution. So, we probably go this route
> > > then:
> > > 
> > > 	pr_<errlvl>("watchdog%d: <err_msg>\n", wdd->id);
> > > 
> > 
> > I don't like it because it doesn't show the driver name, and watchdog%d
> > can change with each reboot. How about something like this ?
> > 
> > static void pr_wdt_err(struct watchdog_device *wdd, char *text, int err)
> > {
> > 	if (wdd->parent)
> > 		dev_err(wdd->parent, "%s: %d\n", text, err);
> > 	else
> > 		pr_err("%s: %s: %d\n", wdd->info->identity, text, err);
> > }
> > 
> > We could then use the same mechanism to generate error messages for
> > watchdog_register_device().
> 
> 'text' is a constant string then. Supporting a format string will make
> this much more complicated. Yet, printing out the wrong timeout is
> useful, I think.
> 
> What about:
> 
> 	dev_str = wdd->parent ? dev_name(wdd->parent) : wdd->info->identity;
> 	pr_<errlvl>("%s: <errstr>\n", dev_str, ...);
> 
Yes, that works as well. Note that it will actually print something like
"watchdog: <device>: ..." due to the pr_fmt() at the top of watchdog_core.c.
I guess that should be ok.

Guenter
Wolfram Sang April 17, 2019, 7:45 p.m. UTC | #9
> Yes, that works as well. Note that it will actually print something like
> "watchdog: <device>: ..." due to the pr_fmt() at the top of watchdog_core.c.
> I guess that should be ok.

I have the following diff applied on top of patch 2. Works with and
without a parent device. I am not super happy casting 'identity' but
since its u8-type is exported to userspace, I think we can't avoid it.
Guenter, is this cast safe? Here is the diff:

diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index cd3ca6b366ef..62be9e52a4de 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -115,6 +115,8 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
 int watchdog_init_timeout(struct watchdog_device *wdd,
 				unsigned int timeout_parm, struct device *dev)
 {
+	const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
+			      (const char *)wdd->info->identity;
 	unsigned int t = 0;
 	int ret = 0;
 
@@ -126,8 +128,8 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
 			wdd->timeout = timeout_parm;
 			return 0;
 		}
-		dev_err(dev, "driver supplied timeout (%u) out of range\n",
-			timeout_parm);
+		pr_err("%s: driver supplied timeout (%u) out of range\n",
+			dev_str, timeout_parm);
 		ret = -EINVAL;
 	}
 
@@ -138,12 +140,13 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
 			wdd->timeout = t;
 			return 0;
 		}
-		dev_err(dev, "DT supplied timeout (%u) out of range\n", t);
+		pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t);
 		ret = -EINVAL;
 	}
 
 	if (ret < 0 && wdd->timeout)
-		dev_warn(dev, "falling back to default timeout (%u)\n", wdd->timeout);
+		pr_warn("%s: falling back to default timeout (%u)\n", dev_str,
+			wdd->timeout);
 
 	return ret;
 }
Guenter Roeck April 17, 2019, 8:17 p.m. UTC | #10
On Wed, Apr 17, 2019 at 09:45:28PM +0200, Wolfram Sang wrote:
> 
> > Yes, that works as well. Note that it will actually print something like
> > "watchdog: <device>: ..." due to the pr_fmt() at the top of watchdog_core.c.
> > I guess that should be ok.
> 
> I have the following diff applied on top of patch 2. Works with and
> without a parent device. I am not super happy casting 'identity' but
> since its u8-type is exported to userspace, I think we can't avoid it.
> Guenter, is this cast safe? Here is the diff:
> 
I would think it is safe, but question is if it is it needed - ie do you see
a warning if it isn't there ? Presumably yes; if so, let's just do it.

Thanks,
Guenter

> diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
> index cd3ca6b366ef..62be9e52a4de 100644
> --- a/drivers/watchdog/watchdog_core.c
> +++ b/drivers/watchdog/watchdog_core.c
> @@ -115,6 +115,8 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
>  int watchdog_init_timeout(struct watchdog_device *wdd,
>  				unsigned int timeout_parm, struct device *dev)
>  {
> +	const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
> +			      (const char *)wdd->info->identity;
>  	unsigned int t = 0;
>  	int ret = 0;
>  
> @@ -126,8 +128,8 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
>  			wdd->timeout = timeout_parm;
>  			return 0;
>  		}
> -		dev_err(dev, "driver supplied timeout (%u) out of range\n",
> -			timeout_parm);
> +		pr_err("%s: driver supplied timeout (%u) out of range\n",
> +			dev_str, timeout_parm);
>  		ret = -EINVAL;
>  	}
>  
> @@ -138,12 +140,13 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
>  			wdd->timeout = t;
>  			return 0;
>  		}
> -		dev_err(dev, "DT supplied timeout (%u) out of range\n", t);
> +		pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t);
>  		ret = -EINVAL;
>  	}
>  
>  	if (ret < 0 && wdd->timeout)
> -		dev_warn(dev, "falling back to default timeout (%u)\n", wdd->timeout);
> +		pr_warn("%s: falling back to default timeout (%u)\n", dev_str,
> +			wdd->timeout);
>  
>  	return ret;
>  }
>
Wolfram Sang April 17, 2019, 9:18 p.m. UTC | #11
> > I have the following diff applied on top of patch 2. Works with and
> > without a parent device. I am not super happy casting 'identity' but
> > since its u8-type is exported to userspace, I think we can't avoid it.
> > Guenter, is this cast safe? Here is the diff:
> > 
> I would think it is safe, but question is if it is it needed - ie do you see
> a warning if it isn't there ? Presumably yes; if so, let's just do it.

Yes, the compiler rightfully complains otherwise.

Do you prefer resending only patch 2 or the whole series?
Guenter Roeck April 17, 2019, 10 p.m. UTC | #12
On Wed, Apr 17, 2019 at 11:18:32PM +0200, Wolfram Sang wrote:
> 
> > > I have the following diff applied on top of patch 2. Works with and
> > > without a parent device. I am not super happy casting 'identity' but
> > > since its u8-type is exported to userspace, I think we can't avoid it.
> > > Guenter, is this cast safe? Here is the diff:
> > > 
> > I would think it is safe, but question is if it is it needed - ie do you see
> > a warning if it isn't there ? Presumably yes; if so, let's just do it.
> 
> Yes, the compiler rightfully complains otherwise.
> 
> Do you prefer resending only patch 2 or the whole series?
> 
Please resend the whole series; that simplifies tracking.

Thanks,
Guenter
Geert Uytterhoeven April 24, 2019, 8:38 a.m. UTC | #13
Hi Wolfram,

On Wed, Apr 17, 2019 at 9:46 PM Wolfram Sang <wsa@the-dreams.de> wrote:
> > Yes, that works as well. Note that it will actually print something like
> > "watchdog: <device>: ..." due to the pr_fmt() at the top of watchdog_core.c.
> > I guess that should be ok.
>
> I have the following diff applied on top of patch 2. Works with and
> without a parent device. I am not super happy casting 'identity' but
> since its u8-type is exported to userspace, I think we can't avoid it.
> Guenter, is this cast safe? Here is the diff:
>
> diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
> index cd3ca6b366ef..62be9e52a4de 100644
> --- a/drivers/watchdog/watchdog_core.c
> +++ b/drivers/watchdog/watchdog_core.c
> @@ -115,6 +115,8 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
>  int watchdog_init_timeout(struct watchdog_device *wdd,
>                                 unsigned int timeout_parm, struct device *dev)
>  {
> +       const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
> +                             (const char *)wdd->info->identity;

    struct watchdog_info {
            ...
            __u8  identity[32];     /* Identity of the board */
    };

Is identity[] guaranteed to be NUL-terminated?

Gr{oetje,eeting}s,

                        Geert
Guenter Roeck April 24, 2019, 12:57 p.m. UTC | #14
On 4/24/19 1:38 AM, Geert Uytterhoeven wrote:
> Hi Wolfram,
> 
> On Wed, Apr 17, 2019 at 9:46 PM Wolfram Sang <wsa@the-dreams.de> wrote:
>>> Yes, that works as well. Note that it will actually print something like
>>> "watchdog: <device>: ..." due to the pr_fmt() at the top of watchdog_core.c.
>>> I guess that should be ok.
>>
>> I have the following diff applied on top of patch 2. Works with and
>> without a parent device. I am not super happy casting 'identity' but
>> since its u8-type is exported to userspace, I think we can't avoid it.
>> Guenter, is this cast safe? Here is the diff:
>>
>> diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
>> index cd3ca6b366ef..62be9e52a4de 100644
>> --- a/drivers/watchdog/watchdog_core.c
>> +++ b/drivers/watchdog/watchdog_core.c
>> @@ -115,6 +115,8 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
>>   int watchdog_init_timeout(struct watchdog_device *wdd,
>>                                  unsigned int timeout_parm, struct device *dev)
>>   {
>> +       const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
>> +                             (const char *)wdd->info->identity;
> 
>      struct watchdog_info {
>              ...
>              __u8  identity[32];     /* Identity of the board */
>      };
> 
> Is identity[] guaranteed to be NUL-terminated?
> 

I would hope so, because we export its contents via sysfs to userspace
with
	return sprintf(buf, "%s\n", wdd->info->identity);

Also, there are already several pr_err() assuming that it is
a string,

Guenter
diff mbox series

Patch

diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index ef30c7e9728d..db1bf6f546ae 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -311,8 +311,7 @@  static int hpwdt_init_one(struct pci_dev *dev,
 		goto error_init_nmi_decoding;
 
 	watchdog_set_nowayout(&hpwdt_dev, nowayout);
-	if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
-		dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
+	watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
 
 	if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
 		dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");