On Thu, Jun 12, 2014 at 5:00 PM, Kees Cook <keesc...@chromium.org> wrote: > To support using kernel features that are not compatible with hibernation, > this creates the "nohibernate" kernel boot parameter to disable both > hibernation and resume. This allows hibernation support to be a boot-time > choice instead of only a compile-time choice. > > Signed-off-by: Kees Cook <keesc...@chromium.org>
This looks really useful. We have a similar mechanism in Fedora to disable hibernation for Secure Boot purposes, but this is much more generic. Other than the rather minor comment below, I think it looks good. > --- > Documentation/kernel-parameters.txt | 3 +++ > include/linux/suspend.h | 2 ++ > kernel/power/hibernate.c | 31 ++++++++++++++++++++++++++++++- > kernel/power/main.c | 6 ++---- > kernel/power/user.c | 3 +++ > 5 files changed, 40 insertions(+), 5 deletions(-) > > diff --git a/Documentation/kernel-parameters.txt > b/Documentation/kernel-parameters.txt > index 6eaa9cdb7094..f8f0466b8b1d 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -2184,6 +2184,8 @@ bytes respectively. Such letter suffixes can also be > entirely omitted. > in certain environments such as networked servers or > real-time systems. > > + nohibernate [HIBERNATION] Disable hibernation and resume. > + > nohz= [KNL] Boottime enable/disable dynamic ticks > Valid arguments: on, off > Default: on > @@ -2980,6 +2982,7 @@ bytes respectively. Such letter suffixes can also be > entirely omitted. > noresume Don't check if there's a hibernation image > present during boot. > nocompress Don't compress/decompress hibernation images. > + no Disable hibernation and resume. > > retain_initrd [RAM] Keep initrd memory after extraction > > diff --git a/include/linux/suspend.h b/include/linux/suspend.h > index f76994b9396c..519064e0c943 100644 > --- a/include/linux/suspend.h > +++ b/include/linux/suspend.h > @@ -327,6 +327,7 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); > extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); > extern int hibernate(void); > extern bool system_entering_hibernation(void); > +extern bool hibernation_available(void); > asmlinkage int swsusp_save(void); > extern struct pbe *restore_pblist; > #else /* CONFIG_HIBERNATION */ > @@ -339,6 +340,7 @@ static inline void swsusp_unset_page_free(struct page *p) > {} > static inline void hibernation_set_ops(const struct platform_hibernation_ops > *ops) {} > static inline int hibernate(void) { return -ENOSYS; } > static inline bool system_entering_hibernation(void) { return false; } > +static inline bool hibernation_available(void) { return false; } > #endif /* CONFIG_HIBERNATION */ > > /* Hibernation and suspend events */ > diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c > index df88d55dc436..fd3e785dbc37 100644 > --- a/kernel/power/hibernate.c > +++ b/kernel/power/hibernate.c > @@ -34,6 +34,7 @@ > > static int nocompress; > static int noresume; > +static int nohibernate; > static int resume_wait; > static unsigned int resume_delay; > static char resume_file[256] = CONFIG_PM_STD_PARTITION; > @@ -61,6 +62,11 @@ bool freezer_test_done; > > static const struct platform_hibernation_ops *hibernation_ops; > > +bool hibernation_available(void) > +{ > + return (nohibernate == 0); > +} > + > /** > * hibernation_set_ops - Set the global hibernate operations. > * @ops: Hibernation operations to use in subsequent hibernation transitions. > @@ -639,6 +645,11 @@ int hibernate(void) > { > int error; > > + if (!hibernation_available()) { > + pr_debug("PM: Hibernation not available.\n"); > + return -EINVAL; > + } > + > lock_system_sleep(); > /* The snapshot device should not be opened while we're running */ > if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { > @@ -731,7 +742,7 @@ static int software_resume(void) > /* > * If the user said "noresume".. bail out early. > */ > - if (noresume) > + if (noresume || !hibernation_available()) > return 0; > > /* > @@ -897,6 +908,9 @@ static ssize_t disk_show(struct kobject *kobj, struct > kobj_attribute *attr, > int i; > char *start = buf; > > + if (!hibernation_available()) > + return sprintf(buf, "[disabled]\n"); > + > for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { > if (!hibernation_modes[i]) > continue; > @@ -931,6 +945,9 @@ static ssize_t disk_store(struct kobject *kobj, struct > kobj_attribute *attr, > char *p; > int mode = HIBERNATION_INVALID; > > + if (!hibernation_available()) > + return -EINVAL; > + Similar to Pavel's comment, EINVAL works but isn't exactly clear. We use -EPERM in our current patch which might be more accurate. I could see arguments either way. > p = memchr(buf, '\n', n); > len = p ? p - buf : n; > > @@ -1098,6 +1115,10 @@ static int __init hibernate_setup(char *str) > noresume = 1; > else if (!strncmp(str, "nocompress", 10)) > nocompress = 1; > + else if (!strncmp(str, "no", 2)) { > + noresume = 1; > + nohibernate = 1; > + } > return 1; > } > > @@ -1122,9 +1143,17 @@ static int __init resumedelay_setup(char *str) > return 1; > } > > +static int __init nohibernate_setup(char *str) > +{ > + noresume = 1; > + nohibernate = 1; > + return 1; > +} > + > __setup("noresume", noresume_setup); > __setup("resume_offset=", resume_offset_setup); > __setup("resume=", resume_setup); > __setup("hibernate=", hibernate_setup); > __setup("resumewait", resumewait_setup); > __setup("resumedelay=", resumedelay_setup); > +__setup("nohibernate", nohibernate_setup); > diff --git a/kernel/power/main.c b/kernel/power/main.c > index 573410d6647e..8e90f330f139 100644 > --- a/kernel/power/main.c > +++ b/kernel/power/main.c > @@ -300,13 +300,11 @@ static ssize_t state_show(struct kobject *kobj, struct > kobj_attribute *attr, > s += sprintf(s,"%s ", pm_states[i].label); > > #endif > -#ifdef CONFIG_HIBERNATION > - s += sprintf(s, "%s\n", "disk"); > -#else > + if (hibernation_available()) > + s += sprintf(s, "disk "); > if (s != buf) > /* convert the last space to a newline */ > *(s-1) = '\n'; > -#endif > return (s - buf); > } > > diff --git a/kernel/power/user.c b/kernel/power/user.c > index 98d357584cd6..000b94419182 100644 > --- a/kernel/power/user.c > +++ b/kernel/power/user.c > @@ -49,6 +49,9 @@ static int snapshot_open(struct inode *inode, struct file > *filp) > struct snapshot_data *data; > int error; > > + if (!hibernation_available()) > + return -EINVAL; > + Same comment as above. josh -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/