On Fri 2020-11-06 21:07:04, Matteo Croce wrote: > From: Matteo Croce <mcr...@microsoft.com> > > The kernel cmdline reboot= option offers some sort of control > on how the reboot is issued. > Add handles in sysfs to allow setting these reboot options, so they > can be changed when the system is booted, other than at boot time. > > The handlers are under <sysfs>/kernel/reboot, can be read to > get the current configuration and written to alter it. > > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-kernel-reboot > @@ -0,0 +1,26 @@ > +What: /sys/kernel/reboot > +Date: October 2020 > +KernelVersion: 5.11 > +Contact: Matteo Croce <mcr...@microsoft.com> > +Description: Interface to set the kernel reboot mode, similarly to > + what can be done via the reboot= cmdline option. > + (see Documentation/admin-guide/kernel-parameters.txt) > + > +What: /sys/kernel/reboot/mode > +What: /sys/kernel/reboot/type > +What: /sys/kernel/reboot/cpu > +What: /sys/kernel/reboot/force
I do not see any file where it is accumulated this way. It seems that each path is always described separately. I am not sure if it is really needed. But it might be needed when processing the API documentation. Please, split it. > + > +Date: October 2020 > +Contact: Matteo Croce <mcr...@microsoft.com> > +Description: Tune reboot parameters. > + > + mode: Reboot mode. Valid values are: > + cold warm hard soft gpio > + > + type: Reboot type. Valid values are: > + bios acpi kbd triple efi pci > + > + cpu: CPU number to use to reboot. > + > + force: Force an immediate reboot. > diff --git a/kernel/reboot.c b/kernel/reboot.c > index e7b78d5ae1ab..b9e607517ae3 100644 > --- a/kernel/reboot.c > +++ b/kernel/reboot.c > @@ -594,3 +594,196 @@ static int __init reboot_setup(char *str) > return 1; > } > __setup("reboot=", reboot_setup); > + > +#ifdef CONFIG_SYSFS > + > +#define STARTS_WITH(s, sc) (!strncmp(s, sc, sizeof(sc)-1)) > + > +static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, > char *buf) > +{ > + const char *val; > + > + switch (reboot_mode) { > + case REBOOT_COLD: > + val = "cold\n"; Using "\n" everywhere is weird. Also the same strings are repeated in the next functions. I suggest to define them only once, e.g. #define REBOOT_COLD_STR "cold" #define REBOOT_WARM_STR "warm" and use here: case REBOOT_COLD: val = REBOOT_COLD_STR; and then at the end return sprintf(buf, "%s\n", val); > + break; > + case REBOOT_WARM: > + val = "warm\n"; > + break; > + case REBOOT_HARD: > + val = "hard\n"; > + break; > + case REBOOT_SOFT: > + val = "soft\n"; > + break; > + case REBOOT_GPIO: > + val = "gpio\n"; > + break; > + default: > + val = "undefined\n"; > + } > + > + return strscpy(buf, val, 10); "undefined\n" needs 11 bytes to store also the trailing '\0'. Anyway, the buffer should be big enough for all variants. > +} > +static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + if (!capable(CAP_SYS_BOOT)) > + return -EPERM; > + > + if (STARTS_WITH(buf, "cold")) > + reboot_mode = REBOOT_COLD; I would prefer to open code this and use strlen(). It will be obvious what the code does immediately. And I am sure that compilators will optimize out the strlen(). if (strncmp(buf, REBOOT_COLD_STR, strlen(REBOOT_COLD_STR)) == 0) reboot_mode = REBOOT_COLD; else if (strncmp(buf, REBOOT_WARM_STR, strlen(REBOOT_WARM_STR) == 0) reboot_mode = REBOOT_WARM; ... > + else if (STARTS_WITH(buf, "warm")) > + reboot_mode = REBOOT_WARM; > + else if (STARTS_WITH(buf, "hard")) > + reboot_mode = REBOOT_HARD; > + else if (STARTS_WITH(buf, "soft")) > + reboot_mode = REBOOT_SOFT; > + else if (STARTS_WITH(buf, "gpio")) > + reboot_mode = REBOOT_GPIO; > + else > + return -EINVAL; > + > + return count; > +} > +static struct kobj_attribute reboot_mode_attr = __ATTR_RW(mode); > + > +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, > char *buf) > +{ > + const char *val; > + > + switch (reboot_type) { > + case BOOT_TRIPLE: > + val = "triple\n"; Same here var = BOOT_TRIPLE_STR; > + break; > + case BOOT_KBD: > + val = "kbd\n"; > + break; > + case BOOT_BIOS: > + val = "bios\n"; > + break; > + case BOOT_ACPI: > + val = "acpi\n"; > + break; > + case BOOT_EFI: > + val = "efi\n"; > + break; > + case BOOT_CF9_FORCE: > + val = "cf9_force\n"; > + break; > + case BOOT_CF9_SAFE: > + val = "cf9_safe\n"; > + break; > + default: > + val = "undefined\n"; > + } > + > + return strscpy(buf, val, 10); > +} > +static ssize_t type_store(struct kobject *kobj, struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + if (!capable(CAP_SYS_BOOT)) > + return -EPERM; > + > + if (STARTS_WITH(buf, "triple")) > + reboot_type = BOOT_TRIPLE; and here: if (strncmp(buf, REBOOT_TRIPLE_STR, strlen(REBOOT_TRIPLE_STR)) == 0) reboot_type = REBOOT_TRIPLE; > + else if (STARTS_WITH(buf, "kbd")) > + reboot_type = BOOT_KBD; > + else if (STARTS_WITH(buf, "bios")) > + reboot_type = BOOT_BIOS; > + else if (STARTS_WITH(buf, "acpi")) > + reboot_type = BOOT_ACPI; > + else if (STARTS_WITH(buf, "efi")) > + reboot_type = BOOT_EFI; > + else if (STARTS_WITH(buf, "cf9_force")) > + reboot_type = BOOT_CF9_FORCE; > + else if (STARTS_WITH(buf, "cf9_safe")) > + reboot_type = BOOT_CF9_SAFE; > + else > + return -EINVAL; > + > + return count; > +} > +static struct kobj_attribute reboot_type_attr = __ATTR_RW(type); > + > +static ssize_t force_show(struct kobject *kobj, struct kobj_attribute *attr, > char *buf) > +{ > + return sprintf(buf, "%d\n", reboot_force); > +} > +static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + if (!capable(CAP_SYS_BOOT)) > + return -EPERM; > + > + if (buf[0] != '0' && buf[0] != '1') > + return -EINVAL; Please use kstrtobool() that supports also other boolean values, for example, 'Y', 'n'. > + rc = kstrtouint(buf, 0, &cpunum); > + > + reboot_force = buf[0] - '0'; > + > + return count; > +} > +static int __init reboot_ksysfs_init(void) > +{ > + struct kobject *reboot_kobj; > + int ret; > + > + reboot_kobj = kobject_create_and_add("reboot", kernel_kobj); > + if (!reboot_kobj) > + return -ENOMEM; > + > + ret = sysfs_create_group(reboot_kobj, &reboot_attr_group); > + if (ret) { > + kobject_put(reboot_kobj); > + return ret; > + } > + > + return 0; > +} > +core_initcall(reboot_ksysfs_init); There is no need to create the sysfs interface this early. In fact, it might even break because the parent "kernel" node is defined as core_initcall() as well. The order is not defined in this case. I would do it as sybsys_initcall() like or even late_initcall(). Best Regards, Petr