2019-11-05 12:33:08

by Rasmus Villemoes

[permalink] [raw]
Subject: [PATCH] watchdog: make nowayout sysfs file writable

It can be useful to delay setting the nowayout feature for a watchdog
device. Moreover, not every driver (notably gpio_wdt) implements a
nowayout module parameter/otherwise respects CONFIG_WATCHDOG_NOWAYOUT,
and modifying those drivers carries a risk of causing a regression for
someone who has two watchdog devices, sets CONFIG_WATCHDOG_NOWAYOUT
and somehow relies on the gpio_wdt driver being ignorant of
that (i.e., allowing one to gracefully close a gpio_wdt but not the
other watchdog in the system).

So instead, simply make the nowayout sysfs file writable. Obviously,
setting nowayout is a one-way street.

Signed-off-by: Rasmus Villemoes <[email protected]>
---
.../ABI/testing/sysfs-class-watchdog | 9 ++++++--
drivers/watchdog/watchdog_dev.c | 22 ++++++++++++++++++-
2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
index 675f9b537661..9860a8b2ba75 100644
--- a/Documentation/ABI/testing/sysfs-class-watchdog
+++ b/Documentation/ABI/testing/sysfs-class-watchdog
@@ -17,8 +17,13 @@ What: /sys/class/watchdog/watchdogn/nowayout
Date: August 2015
Contact: Wim Van Sebroeck <[email protected]>
Description:
- It is a read only file. While reading, it gives '1' if that
- device supports nowayout feature else, it gives '0'.
+ It is a read/write file. While reading, it gives '1'
+ if the device has the nowayout feature set, otherwise
+ it gives '0'. Writing a '1' to the file enables the
+ nowayout feature. Once set, the nowayout feature
+ cannot be disabled, so writing a '0' either has no
+ effect (if the feature was already disabled) or
+ results in a permission error.

What: /sys/class/watchdog/watchdogn/state
Date: August 2015
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index dbd2ad4c9294..0c478b8f8d5a 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -452,7 +452,27 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,

return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
}
-static DEVICE_ATTR_RO(nowayout);
+
+static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+ unsigned int value, current;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &value);
+ if (ret)
+ return ret;
+ if (value > 1)
+ return -EINVAL;
+ current = !!test_bit(WDOG_NO_WAY_OUT, &wdd->status);
+ /* nowayout cannot be disabled once set */
+ if (current && !value)
+ return -EPERM;
+ watchdog_set_nowayout(wdd, value);
+ return len;
+}
+static DEVICE_ATTR_RW(nowayout);

static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf)
--
2.23.0


2019-11-05 14:24:26

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH] watchdog: make nowayout sysfs file writable

On 11/5/19 4:31 AM, Rasmus Villemoes wrote:
> It can be useful to delay setting the nowayout feature for a watchdog
> device. Moreover, not every driver (notably gpio_wdt) implements a
> nowayout module parameter/otherwise respects CONFIG_WATCHDOG_NOWAYOUT,
> and modifying those drivers carries a risk of causing a regression for
> someone who has two watchdog devices, sets CONFIG_WATCHDOG_NOWAYOUT
> and somehow relies on the gpio_wdt driver being ignorant of
> that (i.e., allowing one to gracefully close a gpio_wdt but not the
> other watchdog in the system).
>
> So instead, simply make the nowayout sysfs file writable. Obviously,
> setting nowayout is a one-way street.
>
> Signed-off-by: Rasmus Villemoes <[email protected]>
> ---
> .../ABI/testing/sysfs-class-watchdog | 9 ++++++--
> drivers/watchdog/watchdog_dev.c | 22 ++++++++++++++++++-
> 2 files changed, 28 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
> index 675f9b537661..9860a8b2ba75 100644
> --- a/Documentation/ABI/testing/sysfs-class-watchdog
> +++ b/Documentation/ABI/testing/sysfs-class-watchdog
> @@ -17,8 +17,13 @@ What: /sys/class/watchdog/watchdogn/nowayout
> Date: August 2015
> Contact: Wim Van Sebroeck <[email protected]>
> Description:
> - It is a read only file. While reading, it gives '1' if that
> - device supports nowayout feature else, it gives '0'.
> + It is a read/write file. While reading, it gives '1'
> + if the device has the nowayout feature set, otherwise
> + it gives '0'. Writing a '1' to the file enables the
> + nowayout feature. Once set, the nowayout feature
> + cannot be disabled, so writing a '0' either has no
> + effect (if the feature was already disabled) or
> + results in a permission error.
> > What: /sys/class/watchdog/watchdogn/state
> Date: August 2015
> diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
> index dbd2ad4c9294..0c478b8f8d5a 100644
> --- a/drivers/watchdog/watchdog_dev.c
> +++ b/drivers/watchdog/watchdog_dev.c
> @@ -452,7 +452,27 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
>
> return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
> }
> -static DEVICE_ATTR_RO(nowayout);
> +
> +static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct watchdog_device *wdd = dev_get_drvdata(dev);
> + unsigned int value, current;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &value);
> + if (ret)
> + return ret;
> + if (value > 1)
> + return -EINVAL;
> + current = !!test_bit(WDOG_NO_WAY_OUT, &wdd->status);

"!!" on test_bit is unnecessary, and assigning the result to an unsigned int
doesn't really make sense. Might as well drop the variable and use test_bit
in the expression below directly.

Guenter

> + /* nowayout cannot be disabled once set */
> + if (current && !value)
> + return -EPERM;
> + watchdog_set_nowayout(wdd, value);
> + return len;
> +}
> +static DEVICE_ATTR_RW(nowayout);
>
> static ssize_t status_show(struct device *dev, struct device_attribute *attr,
> char *buf)
>

2019-11-05 20:55:03

by Rasmus Villemoes

[permalink] [raw]
Subject: [PATCH v2] watchdog: make nowayout sysfs file writable

It can be useful to delay setting the nowayout feature for a watchdog
device. Moreover, not every driver (notably gpio_wdt) implements a
nowayout module parameter/otherwise respects CONFIG_WATCHDOG_NOWAYOUT,
and modifying those drivers carries a risk of causing a regression for
someone who has two watchdog devices, sets CONFIG_WATCHDOG_NOWAYOUT
and somehow relies on the gpio_wdt driver being ignorant of
that (i.e., allowing one to gracefully close a gpio_wdt but not the
other watchdog in the system).

So instead, simply make the nowayout sysfs file writable. Obviously,
setting nowayout is a one-way street.

Signed-off-by: Rasmus Villemoes <[email protected]>
---
v2: drop redundant "current" variable and !!.

.../ABI/testing/sysfs-class-watchdog | 9 ++++++--
drivers/watchdog/watchdog_dev.c | 21 ++++++++++++++++++-
2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
index 675f9b537661..9860a8b2ba75 100644
--- a/Documentation/ABI/testing/sysfs-class-watchdog
+++ b/Documentation/ABI/testing/sysfs-class-watchdog
@@ -17,8 +17,13 @@ What: /sys/class/watchdog/watchdogn/nowayout
Date: August 2015
Contact: Wim Van Sebroeck <[email protected]>
Description:
- It is a read only file. While reading, it gives '1' if that
- device supports nowayout feature else, it gives '0'.
+ It is a read/write file. While reading, it gives '1'
+ if the device has the nowayout feature set, otherwise
+ it gives '0'. Writing a '1' to the file enables the
+ nowayout feature. Once set, the nowayout feature
+ cannot be disabled, so writing a '0' either has no
+ effect (if the feature was already disabled) or
+ results in a permission error.

What: /sys/class/watchdog/watchdogn/state
Date: August 2015
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index dbd2ad4c9294..d3bdcb144657 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -452,7 +452,26 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,

return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
}
-static DEVICE_ATTR_RO(nowayout);
+
+static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &value);
+ if (ret)
+ return ret;
+ if (value > 1)
+ return -EINVAL;
+ /* nowayout cannot be disabled once set */
+ if (test_bit(WDOG_NO_WAY_OUT, &wdd->status) && !value)
+ return -EPERM;
+ watchdog_set_nowayout(wdd, value);
+ return len;
+}
+static DEVICE_ATTR_RW(nowayout);

static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf)
--
2.23.0

2019-11-05 21:19:56

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] watchdog: make nowayout sysfs file writable

Hi Rasmus,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc6 next-20191105]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url: https://github.com/0day-ci/linux/commits/Rasmus-Villemoes/watchdog-make-nowayout-sysfs-file-writable/20191106-032539
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git a99d8080aaf358d5d23581244e5da23b35e340b9
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 7.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.4.0 make.cross ARCH=ia64

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <[email protected]>

All error/warnings (new ones prefixed by >>):

In file included from include/linux/mutex.h:14:0,
from include/linux/kernfs.h:12,
from include/linux/sysfs.h:16,
from include/linux/kobject.h:20,
from include/linux/cdev.h:5,
from drivers/watchdog/watchdog_dev.c:31:
drivers/watchdog/watchdog_dev.c: In function 'nowayout_store':
>> arch/ia64/include/asm/current.h:16:19: error: expected identifier or '(' before 'struct'
#define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
^
drivers/watchdog/watchdog_dev.c:460:22: note: in expansion of macro 'current'
unsigned int value, current;
^~~~~~~
In file included from arch/ia64/include/asm/gcc_intrin.h:10:0,
from arch/ia64/include/uapi/asm/intrinsics.h:20,
from arch/ia64/include/asm/intrinsics.h:11,
from arch/ia64/include/asm/bitops.h:19,
from include/linux/bitops.h:26,
from include/linux/kernel.h:12,
from include/linux/list.h:9,
from include/linux/kobject.h:19,
from include/linux/cdev.h:5,
from drivers/watchdog/watchdog_dev.c:31:
>> arch/ia64/include/uapi/asm/gcc_intrin.h:64:1: error: expected ')' before '(' token
({ \
^
>> arch/ia64/include/uapi/asm/intrinsics.h:92:36: note: in expansion of macro 'ia64_native_getreg'
#define IA64_INTRINSIC_MACRO(name) ia64_native_ ## name
^~~~~~~~~~~~
>> arch/ia64/include/uapi/asm/intrinsics.h:113:23: note: in expansion of macro 'IA64_INTRINSIC_MACRO'
#define ia64_getreg IA64_INTRINSIC_MACRO(getreg)
^~~~~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/current.h:16:41: note: in expansion of macro 'ia64_getreg'
#define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
^~~~~~~~~~~
drivers/watchdog/watchdog_dev.c:460:22: note: in expansion of macro 'current'
unsigned int value, current;
^~~~~~~
drivers/watchdog/watchdog_dev.c:468:10: error: lvalue required as left operand of assignment
current = !!test_bit(WDOG_NO_WAY_OUT, &wdd->status);
^
--
In file included from include/linux/mutex.h:14:0,
from include/linux/kernfs.h:12,
from include/linux/sysfs.h:16,
from include/linux/kobject.h:20,
from include/linux/cdev.h:5,
from drivers//watchdog/watchdog_dev.c:31:
drivers//watchdog/watchdog_dev.c: In function 'nowayout_store':
>> arch/ia64/include/asm/current.h:16:19: error: expected identifier or '(' before 'struct'
#define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
^
drivers//watchdog/watchdog_dev.c:460:22: note: in expansion of macro 'current'
unsigned int value, current;
^~~~~~~
In file included from arch/ia64/include/asm/gcc_intrin.h:10:0,
from arch/ia64/include/uapi/asm/intrinsics.h:20,
from arch/ia64/include/asm/intrinsics.h:11,
from arch/ia64/include/asm/bitops.h:19,
from include/linux/bitops.h:26,
from include/linux/kernel.h:12,
from include/linux/list.h:9,
from include/linux/kobject.h:19,
from include/linux/cdev.h:5,
from drivers//watchdog/watchdog_dev.c:31:
>> arch/ia64/include/uapi/asm/gcc_intrin.h:64:1: error: expected ')' before '(' token
({ \
^
>> arch/ia64/include/uapi/asm/intrinsics.h:92:36: note: in expansion of macro 'ia64_native_getreg'
#define IA64_INTRINSIC_MACRO(name) ia64_native_ ## name
^~~~~~~~~~~~
>> arch/ia64/include/uapi/asm/intrinsics.h:113:23: note: in expansion of macro 'IA64_INTRINSIC_MACRO'
#define ia64_getreg IA64_INTRINSIC_MACRO(getreg)
^~~~~~~~~~~~~~~~~~~~
>> arch/ia64/include/asm/current.h:16:41: note: in expansion of macro 'ia64_getreg'
#define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
^~~~~~~~~~~
drivers//watchdog/watchdog_dev.c:460:22: note: in expansion of macro 'current'
unsigned int value, current;
^~~~~~~
drivers//watchdog/watchdog_dev.c:468:10: error: lvalue required as left operand of assignment
current = !!test_bit(WDOG_NO_WAY_OUT, &wdd->status);
^

vim +16 arch/ia64/include/asm/current.h

^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 11
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 12 /*
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 13 * In kernel mode, thread pointer (r13) is used to point to the current task
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 14 * structure.
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 15 */
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 @16 #define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
^1da177e4c3f41 include/asm-ia64/current.h Linus Torvalds 2005-04-16 17

:::::: The code at line 16 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2

:::::: TO: Linus Torvalds <[email protected]>
:::::: CC: Linus Torvalds <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (6.89 kB)
.config.gz (53.63 kB)
Download all attachments

2019-11-06 07:47:58

by Rasmus Villemoes

[permalink] [raw]
Subject: Re: [PATCH] watchdog: make nowayout sysfs file writable

On 05/11/2019 22.16, kbuild test robot wrote:

> In file included from include/linux/mutex.h:14:0,
> from include/linux/kernfs.h:12,
> from include/linux/sysfs.h:16,
> from include/linux/kobject.h:20,
> from include/linux/cdev.h:5,
> from drivers/watchdog/watchdog_dev.c:31:
> drivers/watchdog/watchdog_dev.c: In function 'nowayout_store':
>>> arch/ia64/include/asm/current.h:16:19: error: expected identifier or '(' before 'struct'
> #define current ((struct task_struct *) ia64_getreg(_IA64_REG_TP))
> ^
> drivers/watchdog/watchdog_dev.c:460:22: note: in expansion of macro 'current'
> unsigned int value, current;
> ^~~~~~~

:facecpalm:

And it happened to work just fine in my test because I was targeting
ppc32 where unlike most other arches, current is not a macro but a
(more-or-less) ordinary global declaration

register struct task_struct *current asm ("r2");

Oh well, already fixed in v2 which dropped current for other reasons.

Rasmus

2019-11-06 14:40:13

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v2] watchdog: make nowayout sysfs file writable

On 11/5/19 12:51 PM, Rasmus Villemoes wrote:
> It can be useful to delay setting the nowayout feature for a watchdog
> device. Moreover, not every driver (notably gpio_wdt) implements a
> nowayout module parameter/otherwise respects CONFIG_WATCHDOG_NOWAYOUT,
> and modifying those drivers carries a risk of causing a regression for
> someone who has two watchdog devices, sets CONFIG_WATCHDOG_NOWAYOUT
> and somehow relies on the gpio_wdt driver being ignorant of
> that (i.e., allowing one to gracefully close a gpio_wdt but not the
> other watchdog in the system).
>
> So instead, simply make the nowayout sysfs file writable. Obviously,
> setting nowayout is a one-way street.
>
> Signed-off-by: Rasmus Villemoes <[email protected]>

Reviewed-by: Guenter Roeck <[email protected]>

> ---
> v2: drop redundant "current" variable and !!.
>
> .../ABI/testing/sysfs-class-watchdog | 9 ++++++--
> drivers/watchdog/watchdog_dev.c | 21 ++++++++++++++++++-
> 2 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
> index 675f9b537661..9860a8b2ba75 100644
> --- a/Documentation/ABI/testing/sysfs-class-watchdog
> +++ b/Documentation/ABI/testing/sysfs-class-watchdog
> @@ -17,8 +17,13 @@ What: /sys/class/watchdog/watchdogn/nowayout
> Date: August 2015
> Contact: Wim Van Sebroeck <[email protected]>
> Description:
> - It is a read only file. While reading, it gives '1' if that
> - device supports nowayout feature else, it gives '0'.
> + It is a read/write file. While reading, it gives '1'
> + if the device has the nowayout feature set, otherwise
> + it gives '0'. Writing a '1' to the file enables the
> + nowayout feature. Once set, the nowayout feature
> + cannot be disabled, so writing a '0' either has no
> + effect (if the feature was already disabled) or
> + results in a permission error.
>
> What: /sys/class/watchdog/watchdogn/state
> Date: August 2015
> diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
> index dbd2ad4c9294..d3bdcb144657 100644
> --- a/drivers/watchdog/watchdog_dev.c
> +++ b/drivers/watchdog/watchdog_dev.c
> @@ -452,7 +452,26 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
>
> return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
> }
> -static DEVICE_ATTR_RO(nowayout);
> +
> +static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct watchdog_device *wdd = dev_get_drvdata(dev);
> + unsigned int value;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &value);
> + if (ret)
> + return ret;
> + if (value > 1)
> + return -EINVAL;
> + /* nowayout cannot be disabled once set */
> + if (test_bit(WDOG_NO_WAY_OUT, &wdd->status) && !value)
> + return -EPERM;
> + watchdog_set_nowayout(wdd, value);
> + return len;
> +}
> +static DEVICE_ATTR_RW(nowayout);
>
> static ssize_t status_show(struct device *dev, struct device_attribute *attr,
> char *buf)
>