Patchset related to hibernation resume:
- enhancement to make the use of an existing resume file more general
- add kstrimdup function which trims and duplicates a string
Both patches are based on the 3.13 tag. This was tested on a
Beaglebone black with partial hibernation support, and compiled for
x86_64.
[PATCH v5 1/2] mm: add kstrimdup function
include/linux/string.h | 1 +
mm/util.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
Adds the kstrimdup function to duplicate and trim whitespace
from a string. This is useful for working with user input to
sysfs.
[PATCH v5 2/2] PM / Hibernate: use name_to_dev_t to parse resume
kernel/power/hibernate.c | 33
+++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
Use name_to_dev_t to parse the /sys/power/resume file making the
syntax more flexible. It supports the previous use syntax
and additionally can support other formats such as
/dev/devicenode and UUID= formats.
By changing /sys/debug/resume to accept the same syntax as
the resume=device parameter, we can parse the resume=device
in the initrd init script and use the resume device directly
from the kernel command line.
Changes in v5:
--------------
* Change kstrimdup to minimize allocated memory. Now allocates only
the memory needed for the string instead of using strim.
Changes in v4:
--------------
* Dropped name_to_dev_t rework in favor of adding kstrimdup
* adjusted resume_store
Changes in v3:
--------------
* Dropped documentation patch as it went in through trivial
* Added patch for name_to_dev_t to support directly parsing userspace
buffer
Changes in v2:
--------------
* Added check for null return of kstrndup in hibernate.c
Thanks,
Sebastian
Use the name_to_dev_t call to parse the device name echo'd to
to /sys/power/resume. This imitates the method used in hibernate.c
in software_resume, and allows the resume partition to be specified
using other equivalent device formats as well. By allowing
/sys/debug/resume to accept the same syntax as the resume=device
parameter, we can parse the resume=device in the init script and
use the resume device directly from the kernel command line.
Signed-off-by: Sebastian Capella <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Cc: Len Brown <[email protected]>
Cc: "Rafael J. Wysocki" <[email protected]>
---
kernel/power/hibernate.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 0121dab..49d7a37 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -972,26 +972,27 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
- unsigned int maj, min;
dev_t res;
- int ret = -EINVAL;
+ char *name = kstrimdup(buf, GFP_KERNEL);
- if (sscanf(buf, "%u:%u", &maj, &min) != 2)
- goto out;
+ if (name == NULL)
+ return -ENOMEM;
- res = MKDEV(maj,min);
- if (maj != MAJOR(res) || min != MINOR(res))
- goto out;
+ res = name_to_dev_t(name);
- lock_system_sleep();
- swsusp_resume_device = res;
- unlock_system_sleep();
- printk(KERN_INFO "PM: Starting manual resume from disk\n");
- noresume = 0;
- software_resume();
- ret = n;
- out:
- return ret;
+ if (res != 0) {
+ lock_system_sleep();
+ swsusp_resume_device = res;
+ unlock_system_sleep();
+ printk(KERN_INFO "PM: Starting manual resume from disk\n");
+ noresume = 0;
+ software_resume();
+ } else {
+ n = -EINVAL;
+ }
+
+ kfree(name);
+ return n;
}
power_attr(resume);
--
1.7.9.5
kstrimdup will duplicate and trim spaces from the passed in
null terminated string. This is useful for strings coming from
sysfs that often include trailing whitespace due to user input.
Signed-off-by: Sebastian Capella <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Joe Perches <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: Rik van Riel <[email protected]> (commit_signer:5/10=50%)
Cc: Michel Lespinasse <[email protected]>
Cc: Shaohua Li <[email protected]>
Cc: Jerome Marchand <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: Joonsoo Kim <[email protected]>
---
include/linux/string.h | 1 +
mm/util.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h
index ac889c5..f29f9a0 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -114,6 +114,7 @@ void *memchr_inv(const void *s, int c, size_t n);
extern char *kstrdup(const char *s, gfp_t gfp);
extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
+extern char *kstrimdup(const char *s, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
diff --git a/mm/util.c b/mm/util.c
index 808f375..2066b33 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1,6 +1,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/ctype.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/sched.h>
@@ -63,6 +64,35 @@ char *kstrndup(const char *s, size_t max, gfp_t gfp)
EXPORT_SYMBOL(kstrndup);
/**
+ * kstrimdup - Trim and copy a %NUL terminated string.
+ * @s: the string to trim and duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Returns an address, which the caller must kfree, containing
+ * a duplicate of the passed string with leading and/or trailing
+ * whitespace (as defined by isspace) removed.
+ */
+char *kstrimdup(const char *s, gfp_t gfp)
+{
+ char *buf;
+ char *begin = skip_spaces(s);
+ size_t len = strlen(begin);
+
+ while (len > 1 && isspace(begin[len - 1]))
+ len--;
+
+ buf = kmalloc_track_caller(len + 1, gfp);
+ if (!buf)
+ return NULL;
+
+ memcpy(buf, begin, len);
+ buf[len] = '\0';
+
+ return buf;
+}
+EXPORT_SYMBOL(kstrimdup);
+
+/**
* kmemdup - duplicate region of memory
*
* @src: memory region to duplicate
--
1.7.9.5
On Thu, 30 Jan 2014 13:11:57 -0800 Sebastian Capella <[email protected]> wrote:
> kstrimdup will duplicate and trim spaces from the passed in
> null terminated string. This is useful for strings coming from
> sysfs that often include trailing whitespace due to user input.
>
> ...
>
> --- a/include/linux/string.h
> +++ b/include/linux/string.h
>
> ...
>
> @@ -63,6 +64,35 @@ char *kstrndup(const char *s, size_t max, gfp_t gfp)
> EXPORT_SYMBOL(kstrndup);
>
> /**
> + * kstrimdup - Trim and copy a %NUL terminated string.
> + * @s: the string to trim and duplicate
> + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
> + *
> + * Returns an address, which the caller must kfree, containing
> + * a duplicate of the passed string with leading and/or trailing
> + * whitespace (as defined by isspace) removed.
> + */
> +char *kstrimdup(const char *s, gfp_t gfp)
> +{
> + char *buf;
> + char *begin = skip_spaces(s);
> + size_t len = strlen(begin);
> +
> + while (len > 1 && isspace(begin[len - 1]))
> + len--;
That's off-by-one isn't it? kstrimdup(" ") should return "", not " ".
> + buf = kmalloc_track_caller(len + 1, gfp);
> + if (!buf)
> + return NULL;
> +
> + memcpy(buf, begin, len);
> + buf[len] = '\0';
> +
> + return buf;
> +}
> +EXPORT_SYMBOL(kstrimdup);
> +
On Thu, 30 Jan 2014, Andrew Morton wrote:
> > @@ -63,6 +64,35 @@ char *kstrndup(const char *s, size_t max, gfp_t gfp)
> > EXPORT_SYMBOL(kstrndup);
> >
> > /**
> > + * kstrimdup - Trim and copy a %NUL terminated string.
> > + * @s: the string to trim and duplicate
> > + * @gfp: the GFP mask used in the kmalloc() call when allocating memory
> > + *
> > + * Returns an address, which the caller must kfree, containing
> > + * a duplicate of the passed string with leading and/or trailing
> > + * whitespace (as defined by isspace) removed.
> > + */
> > +char *kstrimdup(const char *s, gfp_t gfp)
> > +{
> > + char *buf;
> > + char *begin = skip_spaces(s);
> > + size_t len = strlen(begin);
> > +
> > + while (len > 1 && isspace(begin[len - 1]))
> > + len--;
>
> That's off-by-one isn't it? kstrimdup(" ") should return "", not " ".
>
Yeah, this is an incorrect copy-and-paste of Joe Perches' suggested code
from http://marc.info/?l=linux-kernel&m=139104508317989.
On Thu, 30 Jan 2014 13:45:45 -0800 Sebastian Capella <[email protected]> wrote:
> Quoting Andrew Morton (2014-01-30 13:22:51)
> > On Thu, 30 Jan 2014 13:11:57 -0800 Sebastian Capella <[email protected]> wrote:
> > > +char *kstrimdup(const char *s, gfp_t gfp)
> > > +{
> > > + char *buf;
> > > + char *begin = skip_spaces(s);
> > > + size_t len = strlen(begin);
> > > +
> > > + while (len > 1 && isspace(begin[len - 1]))
> > > + len--;
> >
> > That's off-by-one isn't it? kstrimdup(" ") should return "", not " ".
> >
> > > + buf = kmalloc_track_caller(len + 1, gfp);
> > > + if (!buf)
> > > + return NULL;
> > > +
> > > + memcpy(buf, begin, len);
> > > + buf[len] = '\0';
> > > +
> > > + return buf;
> > > +}
>
> Hi Andrew,
>
> I think this is a little tricky.
>
> For an empty string, the function relies on skip_spaces to point begin
> at the \0'.
>
> Alternately, if we don't have an empty string, we know we have at least 1
> non-space, non-null character at begin[0], and there's no need to check it,
> so the loop stops at [1]. If there's a space at 1, we just put the '\0'
> there.
>
> We could check at [0], but I think its already been checked by skip_spaces.
heh, OK, tricky.