summaryrefslogtreecommitdiff
path: root/extra
diff options
context:
space:
mode:
authorMatthew Blecker <matthewb@chromium.org>2020-05-15 13:13:30 -0700
committerCommit Bot <commit-bot@chromium.org>2020-05-19 01:17:51 +0000
commitc40fdee1c634403769d77a928f5bd28a14bce702 (patch)
tree9b87ee1cefc494019677047bebe7de5f07d419d8 /extra
parent8367dadb445d99a407f3f8e943c8971b9c3bc947 (diff)
downloadchrome-ec-c40fdee1c634403769d77a928f5bd28a14bce702.tar.gz
i2c-pseudo: Bring in FROMLIST v3 revision.
This is mostly a copy of: https://lore.kernel.org/linux-i2c/20200511234817.59365-1-matthewb@google.com/ https://patchwork.ozlabs.org/project/linux-i2c/patch/20200511234817.59365-1-matthewb@google.com/ Changes in this diff: - Move anprintf() into i2c-pseudo.c. - Use sizeof_field() instead of FIELD_SIZEOF(). - Add CONST_STRLEN macro for i2cp_cmds[].cmd_size values, because on some architectures strlen("literal") is not a compile-time constant. - Use stream_open() instead of nonseekable_open(). - When copy_from_user() returns non-zero, return -EFAULT instead of 0. BRANCH=none BUG=none TEST=With Linux 5.2: $ make $ make clean $ ./install Signed-off-by: Matthew Blecker <matthewb@chromium.org> Change-Id: Idd2b7a2c5630e95de3021c1920ded4cf303db721 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2205293 Reviewed-by: Harry Cutts <hcutts@chromium.org>
Diffstat (limited to 'extra')
-rw-r--r--extra/i2c_pseudo/anprintf.h144
-rw-r--r--extra/i2c_pseudo/i2c-pseudo.c122
2 files changed, 108 insertions, 158 deletions
diff --git a/extra/i2c_pseudo/anprintf.h b/extra/i2c_pseudo/anprintf.h
deleted file mode 100644
index c2d66c494b..0000000000
--- a/extra/i2c_pseudo/anprintf.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <stdarg.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-/*
- * vanprintf - Format a string and place it into a newly allocated buffer.
- * @out: Address of the pointer to place the buffer address into. Will only be
- * written to with a successful positive return value.
- * @max_size: If non-negative, the maximum buffer size that this function will
- * attempt to allocate. If the formatted string including trailing null
- * character would not fit, no buffer will be allocated, and an error will
- * be returned. (Thus max_size of 0 will always result in an error.)
- * @gfp: GFP flags for kmalloc().
- * @fmt: The format string to use.
- * @ap: Arguments for the format string.
- *
- * Return value meanings:
- *
- * >=0: A buffer of this size was allocated and its address written to *out.
- * The caller now owns the buffer and is responsible for freeing it with
- * kfree(). The final character in the buffer, not counted in this
- * return value, is the trailing null. This is the same return value
- * meaning as snprintf(3).
- *
- * <0: An error occurred. Negate the return value for the error number.
- * @out will not have been written to. Errors that might come from
- * snprintf(3) may come from this function as well. Additionally, the
- * following errors may occur from this function:
- *
- * ERANGE: A buffer larger than @max_size would be needed to fit the
- * formatted string including its trailing null character.
- *
- * ENOMEM: Allocation of the output buffer failed.
- *
- * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
- * a bug.
- */
-static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp,
- const char *fmt, va_list ap)
-{
- int ret;
- ssize_t buf_size;
- char *buf = NULL;
- va_list args1;
-
- va_copy(args1, ap);
- ret = vsnprintf(NULL, 0, fmt, ap);
- if (ret < 0) {
- pr_err("%s: Formatting failed with error %d.\n", __func__,
- -ret);
- goto fail_before_args1;
- }
- if (max_size >= 0 && ret > max_size) {
- ret = -ERANGE;
- goto fail_before_args1;
- }
-
- buf_size = ret + 1;
- buf = kmalloc(buf_size, gfp);
- if (buf == NULL) {
- pr_err("%s: kmalloc(%zd, %u) returned NULL\n", __func__,
- buf_size, gfp);
- ret = -ENOMEM;
- goto fail_before_args1;
- }
-
- ret = vsnprintf(buf, buf_size, fmt, args1);
- va_end(args1);
- if (ret < 0) {
- pr_err("%s: Second formatting pass produced error %d after the first pass succeeded. This is a bug.\n",
- __func__, -ret);
- goto fail_after_args1;
- }
- if (ret + 1 != buf_size) {
- pr_err("%s: Second formatting pass produced a different formatted output size than the first. This is a bug. Will return -ENOTRECOVERABLE. first_sans_null=%zd second_sans_null=%d\n",
- __func__, buf_size - 1, ret);
- ret = -ENOTRECOVERABLE;
- goto fail_after_args1;
- }
-
- *out = buf;
- return ret;
-
- fail_before_args1:
- va_end(args1);
- fail_after_args1:
- kfree(buf);
- if (ret >= 0) {
- pr_err("%s: Jumped to failure cleanup section with non-negative return value %d set. This is a bug. Will return -ENOTRECOVERABLE instead.\n",
- __func__, ret);
- ret = -ENOTRECOVERABLE;
- }
- return ret;
-}
-
-/*
- * anprintf - Format a string and place it into a newly allocated buffer.
- * @out: Address of the pointer to place the buffer address into. Will only be
- * written to with a successful positive return value.
- * @max_size: If non-negative, the maximum buffer size that this function will
- * attempt to allocate. If the formatted string including trailing null
- * character would not fit, no buffer will be allocated, and an error will
- * be returned. (Thus max_size of 0 will always result in an error.)
- * @gfp: GFP flags for kmalloc().
- * @fmt: The format string to use.
- * @...: Arguments for the format string.
- *
- * Return value meanings:
- *
- * >=0: A buffer of this size was allocated and its address written to *out.
- * The caller now owns the buffer and is responsible for freeing it with
- * kfree(). The final character in the buffer, not counted in this
- * return value, is the trailing null. This is the same return value
- * meaning as snprintf(3).
- *
- * <0: An error occurred. Negate the return value for the error number.
- * @out will not have been written to. Errors that might come from
- * snprintf(3) may come from this function as well. Additionally, the
- * following errors may occur from this function:
- *
- * ERANGE: A buffer larger than @max_size would be needed to fit the
- * formatted string including its trailing null character.
- *
- * ENOMEM: Allocation of the output buffer failed.
- *
- * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
- * a bug.
- */
-__attribute__((__format__(__printf__, 4, 5)))
-static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp,
- const char *fmt, ...)
-{
- ssize_t ret;
- va_list args;
-
- va_start(args, fmt);
- ret = vanprintf(out, max_size, gfp, fmt, args);
- va_end(args);
- return ret;
-}
diff --git a/extra/i2c_pseudo/i2c-pseudo.c b/extra/i2c_pseudo/i2c-pseudo.c
index 2fbac6dc1f..69fc9dbc52 100644
--- a/extra/i2c_pseudo/i2c-pseudo.c
+++ b/extra/i2c_pseudo/i2c-pseudo.c
@@ -27,8 +27,7 @@
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
-
-#include "anprintf.h"
+#include <stdarg.h>
/* Minimum i2cp_limit module parameter value. */
#define I2CP_ADAPTERS_MIN 0
@@ -102,8 +101,10 @@ static const char i2cp_ctrlr_data_sep_char = ':';
#define STRING_NEQ(in_str, in_size, other_str) \
(in_size != strlen(other_str) || memcmp(other_str, in_str, in_size))
-#define STR_HELPER(x) #x
-#define STR(x) STR_HELPER(x)
+#define STR_HELPER(num) #num
+#define STR(num) STR_HELPER(num)
+
+#define CONST_STRLEN(str) (sizeof(str) - 1)
/*
* The number of pseudo I2C adapters permitted. This default value can be
@@ -657,7 +658,7 @@ struct i2cp_cmd_mxfer_reply_data {
};
struct i2cp_cmd_set_name_suffix_data {
- char name_suffix[FIELD_SIZEOF(struct i2c_adapter, name)];
+ char name_suffix[sizeof_field(struct i2c_adapter, name)];
size_t name_suffix_len;
};
@@ -754,6 +755,97 @@ struct i2cp_rsp_master_xfer {
size_t buf_start_plus_one;
};
+/* vanprintf - See anprintf() documentation. */
+static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp,
+ const char *fmt, va_list ap)
+{
+ int ret;
+ ssize_t buf_size;
+ char *buf = NULL;
+ va_list args1;
+
+ va_copy(args1, ap);
+ ret = vsnprintf(NULL, 0, fmt, ap);
+ if (ret < 0)
+ goto fail_before_args1;
+ if (max_size >= 0 && ret > max_size) {
+ ret = -ERANGE;
+ goto fail_before_args1;
+ }
+
+ buf_size = ret + 1;
+ buf = kmalloc(buf_size, gfp);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto fail_before_args1;
+ }
+
+ ret = vsnprintf(buf, buf_size, fmt, args1);
+ va_end(args1);
+ if (ret < 0)
+ goto fail_after_args1;
+ if (ret + 1 != buf_size) {
+ ret = -ENOTRECOVERABLE;
+ goto fail_after_args1;
+ }
+
+ *out = buf;
+ return ret;
+
+ fail_before_args1:
+ va_end(args1);
+ fail_after_args1:
+ kfree(buf);
+ if (ret >= 0)
+ ret = -ENOTRECOVERABLE;
+ return ret;
+}
+
+/*
+ * anprintf - Format a string and place it into a newly allocated buffer.
+ * @out: Address of the pointer to place the buffer address into. Will only be
+ * written to with a successful positive return value.
+ * @max_size: If non-negative, the maximum buffer size that this function will
+ * attempt to allocate. If the formatted string including trailing null
+ * character would not fit, no buffer will be allocated, and an error will
+ * be returned. (Thus max_size of 0 will always result in an error.)
+ * @gfp: GFP flags for kmalloc().
+ * @fmt: The format string to use.
+ * @...: Arguments for the format string.
+ *
+ * Return value meanings:
+ *
+ * >=0: A buffer of this size was allocated and its address written to *out.
+ * The caller now owns the buffer and is responsible for freeing it with
+ * kfree(). The final character in the buffer, not counted in this
+ * return value, is the trailing null. This is the same return value
+ * meaning as snprintf(3).
+ *
+ * <0: An error occurred. Negate the return value for the error number.
+ * @out will not have been written to. Errors that might come from
+ * snprintf(3) may come from this function as well. Additionally, the
+ * following errors may occur from this function:
+ *
+ * ERANGE: A buffer larger than @max_size would be needed to fit the
+ * formatted string including its trailing null character.
+ *
+ * ENOMEM: Allocation of the output buffer failed.
+ *
+ * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
+ * a bug.
+ */
+static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp,
+ const char *fmt, ...)
+{
+ ssize_t ret;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = vanprintf(out, max_size, gfp, fmt, args);
+ va_end(args);
+ return ret;
+}
+
static ssize_t i2cp_rsp_buffer_formatter(void *data, char **out)
{
struct i2cp_rsp_buffer *rsp_buf;
@@ -1763,7 +1855,7 @@ static int i2cp_cmd_set_timeout_cmd_completer(void *data,
static const struct i2cp_cmd i2cp_cmds[] = {
[I2CP_CMD_MXFER_REPLY_IDX] = {
.cmd_string = I2CP_MXFER_REPLY_CMD,
- .cmd_size = strlen(I2CP_MXFER_REPLY_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_MXFER_REPLY_CMD),
.data_creator = i2cp_cmd_mxfer_reply_data_creator,
.data_shutdown = i2cp_cmd_mxfer_reply_data_shutdown,
.data_destroyer = i2cp_cmd_mxfer_reply_data_destroyer,
@@ -1773,35 +1865,35 @@ static const struct i2cp_cmd i2cp_cmds[] = {
},
[I2CP_CMD_ADAP_START_IDX] = {
.cmd_string = I2CP_ADAP_START_CMD,
- .cmd_size = strlen(I2CP_ADAP_START_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_ADAP_START_CMD),
.header_receiver = i2cp_cmd_adap_start_header_receiver,
.data_receiver = i2cp_cmd_adap_start_data_receiver,
.cmd_completer = i2cp_cmd_adap_start_cmd_completer,
},
[I2CP_CMD_ADAP_SHUTDOWN_IDX] = {
.cmd_string = I2CP_ADAP_SHUTDOWN_CMD,
- .cmd_size = strlen(I2CP_ADAP_SHUTDOWN_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_ADAP_SHUTDOWN_CMD),
.header_receiver = i2cp_cmd_adap_shutdown_header_receiver,
.data_receiver = i2cp_cmd_adap_shutdown_data_receiver,
.cmd_completer = i2cp_cmd_adap_shutdown_cmd_completer,
},
[I2CP_CMD_GET_NUMBER_IDX] = {
.cmd_string = I2CP_GET_NUMBER_CMD,
- .cmd_size = strlen(I2CP_GET_NUMBER_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_GET_NUMBER_CMD),
.header_receiver = i2cp_cmd_get_number_header_receiver,
.data_receiver = i2cp_cmd_get_number_data_receiver,
.cmd_completer = i2cp_cmd_get_number_cmd_completer,
},
[I2CP_CMD_GET_PSEUDO_ID_IDX] = {
.cmd_string = I2CP_GET_PSEUDO_ID_CMD,
- .cmd_size = strlen(I2CP_GET_PSEUDO_ID_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_GET_PSEUDO_ID_CMD),
.header_receiver = i2cp_cmd_get_pseudo_id_header_receiver,
.data_receiver = i2cp_cmd_get_pseudo_id_data_receiver,
.cmd_completer = i2cp_cmd_get_pseudo_id_cmd_completer,
},
[I2CP_CMD_SET_NAME_SUFFIX_IDX] = {
.cmd_string = I2CP_SET_NAME_SUFFIX_CMD,
- .cmd_size = strlen(I2CP_SET_NAME_SUFFIX_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_SET_NAME_SUFFIX_CMD),
.data_creator = i2cp_cmd_set_name_suffix_data_creator,
.data_destroyer = i2cp_cmd_set_name_suffix_data_destroyer,
.header_receiver = i2cp_cmd_set_name_suffix_header_receiver,
@@ -1810,7 +1902,7 @@ static const struct i2cp_cmd i2cp_cmds[] = {
},
[I2CP_CMD_SET_TIMEOUT_IDX] = {
.cmd_string = I2CP_SET_TIMEOUT_CMD,
- .cmd_size = strlen(I2CP_SET_TIMEOUT_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_SET_TIMEOUT_CMD),
.data_creator = i2cp_cmd_set_timeout_data_creator,
.data_destroyer = i2cp_cmd_set_timeout_data_destroyer,
.header_receiver = i2cp_cmd_set_timeout_header_receiver,
@@ -2114,7 +2206,7 @@ static int i2cp_cdev_open(struct inode *inodep, struct file *filep)
this_pseudo = i2cp_device;
/* I2C pseudo adapter controllers are not seekable. */
- nonseekable_open(inodep, filep);
+ stream_open(inodep, filep);
/* Refuse fsnotify events. Modeled after /dev/ptmx implementation. */
filep->f_mode |= FMODE_NONOTIFY;
@@ -2810,8 +2902,10 @@ static ssize_t i2cp_cdev_write(struct file *filep, const char __user *buf,
ret = -ENOMEM;
goto free_kbuf;
}
- if (copy_from_user(kbuf, buf, count))
+ if (copy_from_user(kbuf, buf, count)) {
+ ret = -EFAULT;
goto free_kbuf;
+ }
start = kbuf;
remaining = count;