[PATCH 008/437] kstrtox: add iov_iter versions of the string conversion helpers

Jens Axboe
2024-04-11T15:31:43Z

include/linux/kstrtox.h | 25 +++++++++++++++++++++++++
lib/kstrtox.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)

diff --git a/include/linux/kstrtox.h b/include/linux/kstrtox.h
index 7fcf29a4e0de..229e0162849a 100644
--- a/include/linux/kstrtox.h
+++ b/include/linux/kstrtox.h
@@ -109,11 +109,26 @@ int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned
int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res);

+struct iov_iter;
+int __must_check kstrtoull_from_iter(struct iov_iter *s, size_t count, unsigned int base, unsigned long long *res);
+int __must_check kstrtoul_from_iter(struct iov_iter *s, size_t count, unsigned int base, unsigned long *res);
+int __must_check kstrtol_from_iter(struct iov_iter *s, size_t count, unsigned int base, long *res);
+int __must_check kstrtouint_from_iter(struct iov_iter *s, size_t count, unsigned int base, unsigned int *res);
+int __must_check kstrtoint_from_iter(struct iov_iter *s, size_t count, unsigned int base, int *res);
+int __must_check kstrtou16_from_iter(struct iov_iter *s, size_t count, unsigned int base, u16 *res);
+int __must_check kstrtou8_from_iter(struct iov_iter *s, size_t count, unsigned int base, u8 *res);
+int __must_check kstrtobool_from_iter(struct iov_iter *src, size_t count, bool *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 kstrtou64_from_iter(struct iov_iter *src, size_t count, unsigned int base, u64 *res)
+{
+ return kstrtoull_from_iter(src, 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);
@@ -124,11 +139,21 @@ static inline int __must_check kstrtou32_from_user(const char __user *s, size_t
return kstrtouint_from_user(s, count, base, res);
}

+static inline int __must_check kstrtou32_from_iter(struct iov_iter *src, size_t count, unsigned int base, u32 *res)
+{
+ return kstrtouint_from_iter(src, 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);
}

+static inline int __must_check kstrtos32_from_iter(struct iov_iter *src, size_t count, unsigned int base, s32 *res)
+{
+ return kstrtoint_from_iter(src, count, base, res);
+}
+
/*
* Use kstrto<foo> instead.
*
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index d586e6af5e5a..111231cb4148 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -19,6 +19,7 @@
#include <linux/math64.h>
#include <linux/types.h>
#include <linux/uaccess.h>
+#include <linux/uio.h>

#include "kstrtox.h"

@@ -405,6 +406,23 @@ int kstrtobool_from_user(const char __user *s, size_t count, bool *res)
}
EXPORT_SYMBOL(kstrtobool_from_user);

+/*
+ * Like kstrtobool_from_user(), but takes a source iov_iter rather than a
+ * buffer.
+ */
+int kstrtobool_from_iter(struct iov_iter *src, size_t count, bool *res)
+{
+ /* Longest string needed to differentiate, newline, terminator */
+ char buf[4];
+
+ count = min(count, sizeof(buf) - 1);
+ if (!copy_from_iter_full(buf, count, src))
+ return -EFAULT;
+ buf[count] = '\0';
+ return kstrtobool(buf, res);
+}
+EXPORT_SYMBOL(kstrtobool_from_iter);
+
#define kstrto_from_user(f, g, type) \
int f(const char __user *s, size_t count, unsigned int base, type *res) \
{ \
@@ -429,3 +447,25 @@ kstrto_from_user(kstrtou16_from_user, kstrtou16, u16);
kstrto_from_user(kstrtos16_from_user, kstrtos16, s16);
kstrto_from_user(kstrtou8_from_user, kstrtou8, u8);
kstrto_from_user(kstrtos8_from_user, kstrtos8, s8);
+
+#define kstrto_from_iter(f, g, type) \
+int f(struct iov_iter *s, size_t count, unsigned int base, type *res) \
+{ \
+ /* sign, base 2 representation, newline, terminator */ \
+ char buf[1 + sizeof(type) * 8 + 1 + 1]; \
+ \
+ count = min(count, sizeof(buf) - 1); \
+ if (!copy_from_iter_full(buf, count, s)) \
+ return -EFAULT; \
+ buf[count] = '\0'; \
+ return g(buf, base, res); \
+} \
+EXPORT_SYMBOL(f)
+
+kstrto_from_iter(kstrtoull_from_iter, kstrtoull, unsigned long long);
+kstrto_from_iter(kstrtoul_from_iter, kstrtoul, unsigned long);
+kstrto_from_iter(kstrtol_from_iter, kstrtol, long);
+kstrto_from_iter(kstrtouint_from_iter, kstrtouint, unsigned int);
+kstrto_from_iter(kstrtoint_from_iter, kstrtoint, int);
+kstrto_from_iter(kstrtou16_from_iter, kstrtou16, u16);
+kstrto_from_iter(kstrtou8_from_iter, kstrtou8, u8);
--
2.43.0