linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Alexey Dobriyan <adobriyan@gmail.com>, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 02/12] Add parse_integer() (replacement for simple_strto*())
Date: Fri, 08 May 2015 23:52:22 +0200	[thread overview]
Message-ID: <87ioc2lotl.fsf@rasmusvillemoes.dk> (raw)
In-Reply-To: <20150508134646.6b9bf4158d220b65c5a922f9@linux-foundation.org> (Andrew Morton's message of "Fri, 8 May 2015 13:46:46 -0700")

On Fri, May 08 2015, Andrew Morton <akpm@linux-foundation.org> wrote:

> My overall reaction to this is "oh god, not again".  Is it really worth
> it?

I think it is, if it's done right. The problem is to get consensus on
what right means, but I think Alexey's approach is ok. The huge macro
may be ugly, but it puts the ugliness in one place.

>> +/* internal, do not use */
>> +int _parse_integer_sc(const char *s, unsigned int base, signed char *val);
>> +int _parse_integer_uc(const char *s, unsigned int base, unsigned char *val);
>> +int _parse_integer_s(const char *s, unsigned int base, short *val);
>> +int _parse_integer_us(const char *s, unsigned int base, unsigned short *val);
>> +int _parse_integer_i(const char *s, unsigned int base, int *val);
>> +int _parse_integer_u(const char *s, unsigned int base, unsigned int *val);
>> +int _parse_integer_ll(const char *s, unsigned int base, long long *val);
>> +int _parse_integer_ull(const char *s, unsigned int base, unsigned long long *val);
>
> These all have fairly lengthy implementations.  Could it all be done
> with a single function?
>
> int __parse_integer(const char *s, unsigned int base, unsigned int size, void *val);
>
> Where "size" is 1,2,4,8 with the top bit set if signed?

I suggested something like that in private. These two patches roughly
correspond to 02/12 and 04/12 (they are just proof-of-concept).

Subject: [PATCH 1/2] lib: introduce parse_integer

This is an alternative implementation of parse_integer. It has a
slightly smaller code footprint (both in #LOC and in .text). Another
motivation was to expand on the idea of passing flags to the
underlying function, easing implementation of other interfaces in
terms of parse_integer.

In the other proposal, PARSE_INTEGER_NEWLINE means three things, which
I split into separate flags:

* Accept (but don't require) a single trailing newline.

* Require that the entire string is consumed (possibly after eating
  the trailing newline), otherwise return -EINVAL.

* Change return semantics: 0 for ok instead of #characters consumed.

Besides the three flags doing the above, I also added flags allowing
consuming leading and/or trailing whitespace. This may be used to
remove some boilerplate from code elsewhere. But this may be
over-engineering at this point, and it's easy enough to rip out (and
maybe add later). Still, I think it's nice to keep the
behaviour-changing flags separate.

Implementation-wise (and what saves ~500 bytes of .text), the main
difference is that there's only a single underlying function, and the
type of the destination is communicated to it with another few bits in
the base parameter. In the vast majority of cases, the combined
base_type_flags parameter will be a compile-time constant.

---
 include/linux/parse-integer.h |  78 ++++++++++++++++++++
 lib/Makefile                  |   1 +
 lib/kstrtox.c                 |  16 ----
 lib/kstrtox.h                 |   3 +-
 lib/parse-integer.c           | 166 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 247 insertions(+), 17 deletions(-)
 create mode 100644 include/linux/parse-integer.h
 create mode 100644 lib/parse-integer.c

diff --git a/include/linux/parse-integer.h b/include/linux/parse-integer.h
new file mode 100644
index 000000000000..bdeb6c06059a
--- /dev/null
+++ b/include/linux/parse-integer.h
@@ -0,0 +1,78 @@
+#ifndef LINUX_PARSE_INTEGER_H
+#define LINUX_PARSE_INTEGER_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define _PARSE_INTEGER_TYPE_SHIFT 8
+enum {
+	_PARSE_INTEGER_U8,
+	_PARSE_INTEGER_U16,
+	_PARSE_INTEGER_U32,
+	_PARSE_INTEGER_U64,
+	_PARSE_INTEGER_S8,
+	_PARSE_INTEGER_S16,
+	_PARSE_INTEGER_S32,
+	_PARSE_INTEGER_S64,
+};
+
+/*
+ * Various flags that can be ORed with the base to request slightly
+ * different semantics, to facilitate implementing various old
+ * interfaces in terms of parse_integer. Not to be used directly.
+ */
+
+/* allow (and skip) leading whitespace */
+#define _PARSE_INTEGER_LEAD_WS    0x08000000
+/* consume trailing whitespace */
+#define _PARSE_INTEGER_TRAIL_WS   0x10000000
+/* consume a single trailing newline */
+#define _PARSE_INTEGER_NEWLINE    0x20000000
+/* return 0 for success instead of #characters consumed */
+#define _PARSE_INTEGER_ZERO_ON_OK 0x40000000
+/* return -EINVAL unless the entire string was consumed */
+#define _PARSE_INTEGER_ALL        0x80000000
+
+/*
+ * This should just be BUILD_BUG(), but due to header dependency hell
+ * we can't use that.
+ */
+void __parse_integer_build_bug(void);
+
+#define parse_integer(s, base_flags, dest) ({			\
+	const char *_s = (s);					\
+	unsigned _btf = (base_flags);				\
+	typeof(&dest[0]) _dest = (dest);			\
+	unsigned _t;						\
+								\
+	if (__builtin_types_compatible_p(typeof(_dest), u8*))		\
+		_t = _PARSE_INTEGER_U8;					\
+	else if (__builtin_types_compatible_p(typeof(_dest), u16*))	\
+		_t = _PARSE_INTEGER_U16;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), u32*))	\
+		_t = _PARSE_INTEGER_U32;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), u64*))	\
+		_t = _PARSE_INTEGER_U64;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), s8*))	\
+		_t = _PARSE_INTEGER_S8;					\
+	else if (__builtin_types_compatible_p(typeof(_dest), s16*))	\
+		_t = _PARSE_INTEGER_S16;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), s32*))	\
+		_t = _PARSE_INTEGER_S32;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), s64*))	\
+		_t = _PARSE_INTEGER_S64;				\
+	else if (__builtin_types_compatible_p(typeof(_dest), unsigned long*)) \
+		_t = BITS_PER_LONG == 64 ? _PARSE_INTEGER_U64 : _PARSE_INTEGER_U32; \
+	else if (__builtin_types_compatible_p(typeof(_dest), long*))	\
+		_t = BITS_PER_LONG == 64 ? _PARSE_INTEGER_S64 : _PARSE_INTEGER_S32; \
+	else								\
+		__parse_integer_build_bug();				\
+	_btf |= _t << _PARSE_INTEGER_TYPE_SHIFT;			\
+	__parse_integer(_s, _btf, _dest);				\
+})
+
+/* internal, do not use directly */
+int __parse_integer(const char *s, unsigned base_type_flags, void *val);
+const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
+
+#endif /* LINUX_PARSE_INTEGER_H */
diff --git a/lib/Makefile b/lib/Makefile
index 6c37933336a0..e69b356fe327 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += hexdump.o
 obj-$(CONFIG_TEST_HEXDUMP) += test-hexdump.o
 obj-y += kstrtox.o
+obj-y += parse-integer.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_KASAN) += test_kasan.o
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index ec8da78df9be..5b26f283428f 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -20,22 +20,6 @@
 #include <asm/uaccess.h>
 #include "kstrtox.h"
 
-const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
-{
-	if (*base == 0) {
-		if (s[0] == '0') {
-			if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
-				*base = 16;
-			else
-				*base = 8;
-		} else
-			*base = 10;
-	}
-	if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
-		s += 2;
-	return s;
-}
-
 /*
  * Convert non-negative integer string representation in explicitly given radix
  * to an integer.
diff --git a/lib/kstrtox.h b/lib/kstrtox.h
index f13eeeaf441d..44d9ce227164 100644
--- a/lib/kstrtox.h
+++ b/lib/kstrtox.h
@@ -1,8 +1,9 @@
 #ifndef _LIB_KSTRTOX_H
 #define _LIB_KSTRTOX_H
 
+#include <linux/parse-integer.h>
+
 #define KSTRTOX_OVERFLOW	(1U << 31)
-const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
 unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res);
 
 #endif
diff --git a/lib/parse-integer.c b/lib/parse-integer.c
new file mode 100644
index 000000000000..88f60a02c019
--- /dev/null
+++ b/lib/parse-integer.c
@@ -0,0 +1,166 @@
+#include <linux/bug.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/math64.h>
+#include <linux/parse-integer.h>
+#include <linux/string.h>
+
+const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
+{
+	if (*base == 0) {
+		if (s[0] == '0') {
+			if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
+				*base = 16;
+			else
+				*base = 8;
+		} else
+			*base = 10;
+	}
+	if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
+		s += 2;
+	BUG_ON(*base < 2 || *base > 16);
+	return s;
+}
+
+
+static int do_parse_integer(const char *buf, unsigned base, u64 *dest)
+{
+	const char *s = buf, *s0;
+	u64 acc = 0;
+
+	s = _parse_integer_fixup_radix(s, &base);
+	s0 = s;
+	while (1) {
+		unsigned int d;
+
+		if ('0' <= *s && *s <= '9')
+			d = *s - '0';
+		else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
+			d = _tolower(*s) - 'a' + 10;
+		else
+			break;
+		if (d >= base)
+			break;
+		/* Overflow can't happen early enough. */
+		if ((acc >> 60) && acc > div_u64(ULLONG_MAX - d, base))
+			return -ERANGE;
+		acc = acc * base + d;
+		s++;
+	}
+	/* At least one digit has to be converted. */
+	if (s == s0)
+		return -EINVAL;
+	*dest = acc;
+	return s - buf;
+}
+
+int __parse_integer(const char *buf, unsigned btf, void *dest)
+{
+	unsigned base = btf & 0xff;
+	unsigned type = (btf >> _PARSE_INTEGER_TYPE_SHIFT) & 7;
+	unsigned flags = btf & 0xff000000;
+	const char *s = buf;
+	union {
+		s64 s;
+		u64 u;
+	} val;
+	int neg = 0;
+	int rv;
+
+	if (flags & _PARSE_INTEGER_LEAD_WS)
+		s = skip_spaces(s);
+	
+	if (*s == '-') {
+		/* We don't even allow "-0" for unsigned types. */
+		if (type <= _PARSE_INTEGER_U64)
+			return -EINVAL;
+		neg = 1;
+		s++;
+	} else if (*s == '+') {
+		s++;
+	}
+
+	rv = do_parse_integer(s, base, &val.u);
+	if (rv < 0)
+		return rv;
+	s += rv;
+
+	/*
+	 * If we're targetting an unsigned type, proper range checking
+	 * for val.u has already been done. If we're targeting a
+	 * signed type, we may need to apply the minus sign and then
+	 * check that the result has the expected sign. We do allow
+	 * both -0 and +0.
+	 */
+	if (type >= _PARSE_INTEGER_S8) {
+		if (neg)
+			val.s = -val.u;
+		else
+			val.s = val.u;
+		if ((neg && val.s > 0) || (!neg && val.s < 0))
+			return -ERANGE;
+	}
+
+	if (flags & _PARSE_INTEGER_NEWLINE && *s == '\n')
+		++s;
+	else if (flags & _PARSE_INTEGER_TRAIL_WS)
+		s = skip_spaces(s);
+
+	if (flags & _PARSE_INTEGER_ALL && *s++ != '\0')
+		return -EINVAL;
+
+	/*
+	 * So far so good. Do final range check and write to the
+	 * destination if ok.
+	 */
+	switch (type) {
+	case _PARSE_INTEGER_U8:
+		if ((u8)val.u != val.u)
+			return -ERANGE;
+		*(u8*)dest = val.u;
+		break;
+	case _PARSE_INTEGER_U16:
+		if ((u16)val.u != val.u)
+			return -ERANGE;
+		*(u16*)dest = val.u;
+		break;
+	case _PARSE_INTEGER_U32:
+		if ((u32)val.u != val.u)
+			return -ERANGE;
+		*(u32*)dest = val.u;
+		break;
+	case _PARSE_INTEGER_U64:
+		/* if ((u64)val.u != val.u) */
+		/* 	return -ERANGE; */
+		*(u64*)dest = val.u;
+		break;
+	case _PARSE_INTEGER_S8:
+		if ((s8)val.s != val.s)
+			return -ERANGE;
+		*(s8*)dest = val.s;
+		break;
+	case _PARSE_INTEGER_S16:
+		if ((s16)val.s != val.s)
+			return -ERANGE;
+		*(s16*)dest = val.s;
+		break;
+	case _PARSE_INTEGER_S32:
+		if ((s32)val.s != val.s)
+			return -ERANGE;
+		*(s32*)dest = val.s;
+		break;
+	case _PARSE_INTEGER_S64:
+		/* if ((s64)val.s != val.s) */
+		/* 	return -ERANGE; */
+		*(s64*)dest = val.s;
+		break;
+	default:
+		BUG();
+	}
+
+	if (flags & _PARSE_INTEGER_ZERO_ON_OK)
+		return 0;
+	return s - buf;
+}
+EXPORT_SYMBOL(__parse_integer);
-- 
2.1.3


Subject: [PATCH 2/2] lib: implement kstrtox using parse_integer

The new parse_integer() interface makes it easy to implement the
kstrtox family of functions as simple one-line static inlines.
---
 include/linux/kernel.h        | 125 +---------------------
 include/linux/parse-integer.h | 112 ++++++++++++++++++++
 lib/kstrtox.c                 | 238 ------------------------------------------
 3 files changed, 113 insertions(+), 362 deletions(-)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 3a5b48e52a9e..27465774e00a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,7 @@
 #include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
 #include <uapi/linux/kernel.h>
+#include <linux/parse-integer.h>
 
 #define USHRT_MAX	((u16)(~0U))
 #define SHRT_MAX	((s16)(USHRT_MAX>>1))
@@ -263,130 +264,6 @@ void do_exit(long error_code)
 void complete_and_exit(struct completion *, long)
 	__noreturn;
 
-/* Internal, do not use. */
-int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
-int __must_check _kstrtol(const char *s, unsigned int base, long *res);
-
-int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res);
-int __must_check kstrtoll(const char *s, unsigned int base, long long *res);
-
-/**
- * kstrtoul - convert a string to an unsigned long
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign, but not a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
-*/
-static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
-{
-	/*
-	 * We want to shortcut function call, but
-	 * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
-	 */
-	if (sizeof(unsigned long) == sizeof(unsigned long long) &&
-	    __alignof__(unsigned long) == __alignof__(unsigned long long))
-		return kstrtoull(s, base, (unsigned long long *)res);
-	else
-		return _kstrtoul(s, base, res);
-}
-
-/**
- * kstrtol - convert a string to a long
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign or a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-static inline int __must_check kstrtol(const char *s, unsigned int base, long *res)
-{
-	/*
-	 * We want to shortcut function call, but
-	 * __builtin_types_compatible_p(long, long long) = 0.
-	 */
-	if (sizeof(long) == sizeof(long long) &&
-	    __alignof__(long) == __alignof__(long long))
-		return kstrtoll(s, base, (long long *)res);
-	else
-		return _kstrtol(s, base, res);
-}
-
-int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res);
-int __must_check kstrtoint(const char *s, unsigned int base, int *res);
-
-static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res)
-{
-	return kstrtoull(s, base, res);
-}
-
-static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res)
-{
-	return kstrtoll(s, base, res);
-}
-
-static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res)
-{
-	return kstrtouint(s, base, res);
-}
-
-static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res)
-{
-	return kstrtoint(s, base, res);
-}
-
-int __must_check kstrtou16(const char *s, unsigned int base, u16 *res);
-int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
-int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
-int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
-
-int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
-int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
-int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
-int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
-int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
-int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
-int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
-int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
-int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
-int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
-
-static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
-{
-	return kstrtoull_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
-{
-	return kstrtoll_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
-{
-	return kstrtouint_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
-{
-	return kstrtoint_from_user(s, count, base, res);
-}
-
 /* Obsolete, do not use.  Use kstrto<foo> instead */
 
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
diff --git a/include/linux/parse-integer.h b/include/linux/parse-integer.h
index bdeb6c06059a..3deebaa3e547 100644
--- a/include/linux/parse-integer.h
+++ b/include/linux/parse-integer.h
@@ -33,6 +33,10 @@ enum {
 /* return -EINVAL unless the entire string was consumed */
 #define _PARSE_INTEGER_ALL        0x80000000
 
+/* The kstrtox family can be implemented using this combination. */
+#define _PARSE_INTEGER_KSTRTOX \
+	(_PARSE_INTEGER_NEWLINE | _PARSE_INTEGER_ZERO_ON_OK | _PARSE_INTEGER_ALL)
+
 /*
  * This should just be BUILD_BUG(), but due to header dependency hell
  * we can't use that.
@@ -75,4 +79,112 @@ void __parse_integer_build_bug(void);
 int __parse_integer(const char *s, unsigned base_type_flags, void *val);
 const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
 
+/*
+ * Convert integer string representation terminated by \n\0 or \0 to an integer.
+ *
+ * Return 0 on success or -E.
+ *
+ * See parse_integer().
+ */
+static inline int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtoll(const char *s, unsigned int base, long long *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtol(const char *s, unsigned int base, long *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtoint(const char *s, unsigned int base, int *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res)
+{
+	return kstrtoull(s, base, res);
+}
+
+static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res)
+{
+	return kstrtoll(s, base, res);
+}
+
+static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res)
+{
+	return kstrtouint(s, base, res);
+}
+
+static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res)
+{
+	return kstrtoint(s, base, res);
+}
+
+static inline int __must_check kstrtou16(const char *s, unsigned int base, u16 *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtos16(const char *s, unsigned int base, s16 *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtou8(const char *s, unsigned int base, u8 *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+static inline int __must_check kstrtos8(const char *s, unsigned int base, s8 *res)
+{
+	return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res);
+}
+
+int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
+int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
+int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
+int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
+int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
+int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
+int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
+int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
+int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
+int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
+
+static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
+{
+	return kstrtoull_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
+{
+	return kstrtoll_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
+{
+	return kstrtouint_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
+{
+	return kstrtoint_from_user(s, count, base, res);
+}
+
 #endif /* LINUX_PARSE_INTEGER_H */
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index 5b26f283428f..1698b286d954 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -67,244 +67,6 @@ unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long
 	return rv;
 }
 
-static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
-{
-	unsigned long long _res;
-	unsigned int rv;
-
-	s = _parse_integer_fixup_radix(s, &base);
-	rv = _parse_integer(s, base, &_res);
-	if (rv & KSTRTOX_OVERFLOW)
-		return -ERANGE;
-	if (rv == 0)
-		return -EINVAL;
-	s += rv;
-	if (*s == '\n')
-		s++;
-	if (*s)
-		return -EINVAL;
-	*res = _res;
-	return 0;
-}
-
-/**
- * kstrtoull - convert a string to an unsigned long long
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign, but not a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
-{
-	if (s[0] == '+')
-		s++;
-	return _kstrtoull(s, base, res);
-}
-EXPORT_SYMBOL(kstrtoull);
-
-/**
- * kstrtoll - convert a string to a long long
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign or a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-int kstrtoll(const char *s, unsigned int base, long long *res)
-{
-	unsigned long long tmp;
-	int rv;
-
-	if (s[0] == '-') {
-		rv = _kstrtoull(s + 1, base, &tmp);
-		if (rv < 0)
-			return rv;
-		if ((long long)(-tmp) >= 0)
-			return -ERANGE;
-		*res = -tmp;
-	} else {
-		rv = kstrtoull(s, base, &tmp);
-		if (rv < 0)
-			return rv;
-		if ((long long)tmp < 0)
-			return -ERANGE;
-		*res = tmp;
-	}
-	return 0;
-}
-EXPORT_SYMBOL(kstrtoll);
-
-/* Internal, do not use. */
-int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
-{
-	unsigned long long tmp;
-	int rv;
-
-	rv = kstrtoull(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (unsigned long long)(unsigned long)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(_kstrtoul);
-
-/* Internal, do not use. */
-int _kstrtol(const char *s, unsigned int base, long *res)
-{
-	long long tmp;
-	int rv;
-
-	rv = kstrtoll(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (long long)(long)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(_kstrtol);
-
-/**
- * kstrtouint - convert a string to an unsigned int
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign, but not a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-int kstrtouint(const char *s, unsigned int base, unsigned int *res)
-{
-	unsigned long long tmp;
-	int rv;
-
-	rv = kstrtoull(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (unsigned long long)(unsigned int)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtouint);
-
-/**
- * kstrtoint - convert a string to an int
- * @s: The start of the string. The string must be null-terminated, and may also
- *  include a single newline before its terminating null. The first character
- *  may also be a plus sign or a minus sign.
- * @base: The number base to use. The maximum supported base is 16. If base is
- *  given as 0, then the base of the string is automatically detected with the
- *  conventional semantics - If it begins with 0x the number will be parsed as a
- *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
- *  parsed as an octal number. Otherwise it will be parsed as a decimal.
- * @res: Where to write the result of the conversion on success.
- *
- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-int kstrtoint(const char *s, unsigned int base, int *res)
-{
-	long long tmp;
-	int rv;
-
-	rv = kstrtoll(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (long long)(int)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtoint);
-
-int kstrtou16(const char *s, unsigned int base, u16 *res)
-{
-	unsigned long long tmp;
-	int rv;
-
-	rv = kstrtoull(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (unsigned long long)(u16)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtou16);
-
-int kstrtos16(const char *s, unsigned int base, s16 *res)
-{
-	long long tmp;
-	int rv;
-
-	rv = kstrtoll(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (long long)(s16)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtos16);
-
-int kstrtou8(const char *s, unsigned int base, u8 *res)
-{
-	unsigned long long tmp;
-	int rv;
-
-	rv = kstrtoull(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (unsigned long long)(u8)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtou8);
-
-int kstrtos8(const char *s, unsigned int base, s8 *res)
-{
-	long long tmp;
-	int rv;
-
-	rv = kstrtoll(s, base, &tmp);
-	if (rv < 0)
-		return rv;
-	if (tmp != (long long)(s8)tmp)
-		return -ERANGE;
-	*res = tmp;
-	return 0;
-}
-EXPORT_SYMBOL(kstrtos8);
-
 #define kstrto_from_user(f, g, type)					\
 int f(const char __user *s, size_t count, unsigned int base, type *res)	\
 {									\
-- 
2.1.3




  reply	other threads:[~2015-05-08 21:52 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-08 18:29 [PATCH 01/12] kstrto*: accept "-0" for signed conversion Alexey Dobriyan
2015-05-08 18:30 ` [PATCH 02/12] Add parse_integer() (replacement for simple_strto*()) Alexey Dobriyan
2015-05-08 20:46   ` Andrew Morton
2015-05-08 21:52     ` Rasmus Villemoes [this message]
2015-05-10 13:52     ` Alexey Dobriyan
2015-05-13 12:19       ` Alexey Dobriyan
2015-05-10 15:52   ` Noel Grandin
2015-07-09 19:28   ` Andrew Morton
2015-07-10  6:46     ` Alexey Dobriyan
2015-05-08 18:31 ` [PATCH 03/12] parse_integer: add runtime testsuite Alexey Dobriyan
2015-05-08 18:33 ` [PATCH 04/12] parse-integer: rewrite kstrto*() Alexey Dobriyan
2015-05-08 18:33 ` [PATCH 05/12] parse_integer: convert scanf() Alexey Dobriyan
2015-05-08 18:34 ` [PATCH 06/12] scanf: fix type range overflow Alexey Dobriyan
2015-05-08 18:35 ` [PATCH 07/12] parse_integer: convert lib/ Alexey Dobriyan
2015-05-08 18:35 ` [PATCH 08/12] parse_integer: convert mm/ Alexey Dobriyan
2015-05-08 18:36 ` [PATCH 09/12] parse_integer: convert fs/ Alexey Dobriyan
2015-05-08 18:37 ` [PATCH 10/37] parse_integer: convert fs/cachefiles/ Alexey Dobriyan
2015-05-08 18:39 ` [PATCH 11/12] parse_integer: convert ext2, ext3, ext4 Alexey Dobriyan
2015-05-08 18:40 ` [PATCH 12/12] parse_integer: convert fs/ocfs2/ Alexey Dobriyan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ioc2lotl.fsf@rasmusvillemoes.dk \
    --to=linux@rasmusvillemoes.dk \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --subject='Re: [PATCH 02/12] Add parse_integer() (replacement for simple_strto*())' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).