[PATCH v3] powerpc/perf/hv-gpci: bound sysfs output with helpers
From: Pengpeng Hou <hidden>
Date: 2026-07-31 14:22:00
Also in:
lkml, stable
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Linus Torvalds
systeminfo_gpci_request() and
affinity_domain_via_partition_result_parse() hex-encode hypervisor data
into the single-page sysfs read buffer with sprintf(buf + *n, ...).
Both helpers only check PAGE_SIZE after the formatting loops have
already advanced past the end of the buffer.
Add small helpers around sysfs_emit_at() for hex-byte and newline
appends, and stop once the sysfs buffer is full. This keeps the repeated
bounds handling local instead of open-coding it at each append site.
Return errors from systeminfo_gpci_request() through an int and update
all of its callers accordingly, so negative formatting errors are not
converted through an unsigned return type.
Fixes: 71f1c39647d8 ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show processor bus topology information")
Fixes: a15e0d6a6929 ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show affinity domain via partition information")
Cc: stable@vger.kernel.org
Signed-off-by: Pengpeng Hou <redacted>
---
Changes since v2: https://lore.kernel.org/all/20260424070103.1-hv-gpci-v2-pengpeng@iscas.ac.cn/ (local)
- change systeminfo_gpci_request() to return int and update all callers,
as requested by Madhavan Srinivasan
- keep the raw hypervisor return in a signed long before mapping it to the
helper's documented return values
- rebase onto the current tree
arch/powerpc/perf/hv-gpci.c | 113 +++++++++++++++++++++++++++++++++-----------
1 file changed, 85 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
index 7269273d3aa8..0bfd8061969a 100644
--- a/arch/powerpc/perf/hv-gpci.c
+++ b/arch/powerpc/perf/hv-gpci.c@@ -130,11 +130,36 @@ static int sysinfo_counter_request[] = { static DEFINE_PER_CPU(char, hv_gpci_reqb[HGPCI_REQ_BUFFER_SIZE]) __aligned(sizeof(uint64_t)); -static unsigned long systeminfo_gpci_request(u32 req, u32 starting_index, - u16 secondary_index, char *buf, - size_t *n, struct hv_gpci_request_buffer *arg) +static int hv_gpci_emit_hex_byte(char *buf, size_t *n, u8 byte) { - unsigned long ret; + int len; + + len = sysfs_emit_at(buf, *n, "%02x", byte); + if (len <= 0) + return -EFBIG; + + *n += len; + return 0; +} + +static int hv_gpci_emit_newline(char *buf, size_t *n) +{ + int len; + + len = sysfs_emit_at(buf, *n, "\n"); + if (len <= 0) + return -EFBIG; + + *n += len; + return 0; +} + +static int systeminfo_gpci_request(u32 req, u32 starting_index, + u16 secondary_index, char *buf, + size_t *n, struct hv_gpci_request_buffer *arg) +{ + long ret; + int rc; size_t i, j; arg->params.counter_request = cpu_to_be32(req);
@@ -177,9 +202,14 @@ static unsigned long systeminfo_gpci_request(u32 req, u32 starting_index, for (i = 0; i < be16_to_cpu(arg->params.returned_values); i++) { j = i * be16_to_cpu(arg->params.cv_element_size); - for (; j < (i + 1) * be16_to_cpu(arg->params.cv_element_size); j++) - *n += sprintf(buf + *n, "%02x", (u8)arg->bytes[j]); - *n += sprintf(buf + *n, "\n"); + for (; j < (i + 1) * be16_to_cpu(arg->params.cv_element_size); j++) { + rc = hv_gpci_emit_hex_byte(buf, n, (u8)arg->bytes[j]); + if (rc) + return rc; + } + rc = hv_gpci_emit_newline(buf, n); + if (rc) + return rc; } if (*n >= PAGE_SIZE) {
@@ -194,7 +224,7 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att char *buf) { struct hv_gpci_request_buffer *arg; - unsigned long ret; + int ret; size_t n = 0; arg = (void *)get_cpu_var(hv_gpci_reqb);
@@ -264,7 +294,7 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute char *buf) { struct hv_gpci_request_buffer *arg; - unsigned long ret; + int ret; size_t n = 0; arg = (void *)get_cpu_var(hv_gpci_reqb);
@@ -334,7 +364,7 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hv_gpci_request_buffer *arg; - unsigned long ret; + int ret; size_t n = 0; arg = (void *)get_cpu_var(hv_gpci_reqb);
@@ -406,7 +436,7 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device char *buf) { struct hv_gpci_request_buffer *arg; - unsigned long ret; + int ret; size_t n = 0; arg = (void *)get_cpu_var(hv_gpci_reqb);
@@ -470,10 +500,12 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device return ret; } -static void affinity_domain_via_partition_result_parse(int returned_values, - int element_size, char *buf, size_t *last_element, - size_t *n, struct hv_gpci_request_buffer *arg) +static int affinity_domain_via_partition_result_parse(int returned_values, + int element_size, char *buf, + size_t *last_element, size_t *n, + struct hv_gpci_request_buffer *arg) { + int rc; size_t i = 0, j = 0; size_t k, l, m; uint16_t total_affinity_domain_ele, size_of_each_affinity_domain_ele;
@@ -492,27 +524,40 @@ static void affinity_domain_via_partition_result_parse(int returned_values, */ while (i < returned_values) { k = j; - for (; k < j + element_size; k++) - *n += sprintf(buf + *n, "%02x", (u8)arg->bytes[k]); - *n += sprintf(buf + *n, "\n"); + for (; k < j + element_size; k++) { + rc = hv_gpci_emit_hex_byte(buf, n, (u8)arg->bytes[k]); + if (rc) + return rc; + } + rc = hv_gpci_emit_newline(buf, n); + if (rc) + return rc; total_affinity_domain_ele = (u8)arg->bytes[k - 2] << 8 | (u8)arg->bytes[k - 3]; size_of_each_affinity_domain_ele = (u8)arg->bytes[k] << 8 | (u8)arg->bytes[k - 1]; for (l = 0; l < total_affinity_domain_ele; l++) { for (m = 0; m < size_of_each_affinity_domain_ele; m++) { - *n += sprintf(buf + *n, "%02x", (u8)arg->bytes[k]); + rc = hv_gpci_emit_hex_byte(buf, n, (u8)arg->bytes[k]); + if (rc) + return rc; k++; } - *n += sprintf(buf + *n, "\n"); + rc = hv_gpci_emit_newline(buf, n); + if (rc) + return rc; } - *n += sprintf(buf + *n, "\n"); + rc = hv_gpci_emit_newline(buf, n); + if (rc) + return rc; i++; j = k; } *last_element = k; + + return 0; } static ssize_t affinity_domain_via_partition_show(struct device *dev, struct device_attribute *attr,
@@ -523,6 +568,7 @@ static ssize_t affinity_domain_via_partition_show(struct device *dev, struct dev size_t n = 0; size_t last_element = 0; u32 starting_index; + int element_size, rc, returned_values; arg = (void *)get_cpu_var(hv_gpci_reqb); memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
@@ -555,10 +601,16 @@ static ssize_t affinity_domain_via_partition_show(struct device *dev, struct dev * to buffer util we get all the information. */ while (ret == H_PARAMETER) { - affinity_domain_via_partition_result_parse( - be16_to_cpu(arg->params.returned_values) - 1, - be16_to_cpu(arg->params.cv_element_size), buf, - &last_element, &n, arg); + returned_values = be16_to_cpu(arg->params.returned_values); + element_size = be16_to_cpu(arg->params.cv_element_size); + rc = affinity_domain_via_partition_result_parse(returned_values - 1, + element_size, buf, + &last_element, &n, + arg); + if (rc) { + put_cpu_var(hv_gpci_reqb); + return rc; + } if (n >= PAGE_SIZE) { put_cpu_var(hv_gpci_reqb);
@@ -587,10 +639,15 @@ static ssize_t affinity_domain_via_partition_show(struct device *dev, struct dev } parse_result: - affinity_domain_via_partition_result_parse( - be16_to_cpu(arg->params.returned_values), - be16_to_cpu(arg->params.cv_element_size), - buf, &last_element, &n, arg); + returned_values = be16_to_cpu(arg->params.returned_values); + element_size = be16_to_cpu(arg->params.cv_element_size); + rc = affinity_domain_via_partition_result_parse(returned_values, + element_size, buf, + &last_element, &n, arg); + if (rc) { + put_cpu_var(hv_gpci_reqb); + return rc; + } put_cpu_var(hv_gpci_reqb); return n;
--
2.50.1