Subject: [PATCH 10/11] treewide: Manually convert custom kernel_param_ops .get callbacks

From: Kees Cook <[email-masked]>
Date: Thu, 21 May 2026 06:33:23 -0700

Convert struct kernel_param_ops .get callbacks from legacy "char *" to
"struct seq_buf *".

Since seq_buf_printf() will return -1 on overflow, and struct
kernel_param_ops .get callbacks are expected to truncate without error,
we must ignore the return value from seq_buf_print() and always return 0
(as the length is calculated in the common dispatcher code).

No struct kernel_param_ops initializations need changing since
DEFINE_KERNEL_PARAM_OPS already routes the pointer to .get or .get_str
via _Generic based on the function signature, so converted callbacks
are automatically moved from the .get_str to the .get callback.

Signed-off-by: Kees Cook <[email-masked]>
---
 include/linux/dynamic_debug.h            |  8 ++-
 arch/um/drivers/vfio_kern.c              |  3 +-
 arch/um/drivers/virtio_uml.c             | 12 ++--
 drivers/acpi/button.c                    | 19 ++++--
 drivers/acpi/sysfs.c                     | 83 +++++++++++-------------
 drivers/char/ipmi/ipmi_watchdog.c        | 33 ++++------
 drivers/firmware/qemu_fw_cfg.c           | 34 +++++-----
 drivers/gpu/drm/i915/i915_mitigations.c  | 26 ++++----
 drivers/infiniband/ulp/srp/ib_srp.c      |  7 +-
 drivers/media/usb/uvc/uvc_driver.c       |  8 ++-
 drivers/pci/pcie/aspm.c                  | 17 +++--
 drivers/scsi/fcoe/fcoe_transport.c       | 22 +++----
 drivers/thermal/intel/intel_powerclamp.c | 14 ++--
 drivers/tty/hvc/hvc_iucv.c               | 18 ++---
 drivers/usb/storage/usb.c                | 20 +++---
 drivers/virtio/virtio_mmio.c             | 21 +++---
 lib/dynamic_debug.c                      | 10 ++-
 17 files changed, 178 insertions(+), 177 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 05743900a116..999a25671b6a 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -334,8 +334,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 extern int ddebug_dyndbg_module_param_cb(char *param, char *val,
 					const char *modname);
 struct kernel_param;
+struct seq_buf;
 int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp);
-int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
+int param_get_dyndbg_classes(struct seq_buf *buffer,
+			     const struct kernel_param *kp);
 
 #else
 
@@ -352,9 +354,11 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
 }
 
 struct kernel_param;
+struct seq_buf;
 static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
 { return 0; }
-static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
+static inline int param_get_dyndbg_classes(struct seq_buf *buffer,
+					   const struct kernel_param *kp)
 { return 0; }
 
 #endif
diff --git a/arch/um/drivers/vfio_kern.c b/arch/um/drivers/vfio_kern.c
index fb7988dc5482..7c1119d0d9c1 100644
--- a/arch/um/drivers/vfio_kern.c
+++ b/arch/um/drivers/vfio_kern.c
@@ -623,7 +623,8 @@ static int uml_vfio_cmdline_set(const char *device, const struct kernel_param *k
 	return 0;
 }
 
-static int uml_vfio_cmdline_get(char *buffer, const struct kernel_param *kp)
+static int uml_vfio_cmdline_get(struct seq_buf *buffer,
+				const struct kernel_param *kp)
 {
 	return 0;
 }
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
index f9ae745f4586..cea806540625 100644
--- a/arch/um/drivers/virtio_uml.c
+++ b/arch/um/drivers/virtio_uml.c
@@ -1379,23 +1379,21 @@ static int vu_cmdline_get_device(struct device *dev, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
-	char *buffer = data;
-	unsigned int len = strlen(buffer);
+	struct seq_buf *s = data;
 
-	snprintf(buffer + len, PAGE_SIZE - len, "%s:%d:%d\n",
-		 pdata->socket_path, pdata->virtio_device_id, pdev->id);
+	seq_buf_printf(s, "%s:%d:%d\n",
+		       pdata->socket_path, pdata->virtio_device_id, pdev->id);
 	return 0;
 }
 
-static int vu_cmdline_get(char *buffer, const struct kernel_param *kp)
+static int vu_cmdline_get(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	guard(mutex)(&vu_cmdline_lock);
 
-	buffer[0] = '\0';
 	if (vu_cmdline_parent_registered)
 		device_for_each_child(&vu_cmdline_parent, buffer,
 				      vu_cmdline_get_device);
-	return strlen(buffer) + 1;
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(vu_cmdline_param_ops, vu_cmdline_set,
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index dc064a388c23..31c624bebc65 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -715,19 +715,24 @@ static int param_set_lid_init_state(const char *val,
 	return 0;
 }
 
-static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
+static int param_get_lid_init_state(struct seq_buf *buf,
+				    const struct kernel_param *kp)
 {
-	int i, c = 0;
+	int i;
 
-	for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
+	for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++) {
 		if (i == lid_init_state)
-			c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
+			seq_buf_printf(buf, "[%s] ", lid_init_state_str[i]);
 		else
-			c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
+			seq_buf_printf(buf, "%s ", lid_init_state_str[i]);
+	}
 
-	buf[c - 1] = '\n'; /* Replace the final space with a newline */
+	/* Replace the final space with a newline. */
+	if (!seq_buf_has_overflowed(buf) && buf->len > 0 &&
+	    buf->buffer[buf->len - 1] == ' ')
+		buf->buffer[buf->len - 1] = '\n';
 
-	return c;
+	return 0;
 }
 
 module_param_call(lid_init_state,
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 5247ed7e05cc..dff7cc7da8bf 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -89,53 +89,49 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
 	ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
 };
 
-static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
+static int param_get_debug_layer(struct seq_buf *buffer,
+				 const struct kernel_param *kp)
 {
-	int result = 0;
 	int i;
 
-	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+	seq_buf_printf(buffer, "%-25s\tHex        SET\n", "Description");
 
 	for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
-		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
-				  acpi_debug_layers[i].name,
-				  acpi_debug_layers[i].value,
-				  (acpi_dbg_layer & acpi_debug_layers[i].value)
-				  ? '*' : ' ');
+		seq_buf_printf(buffer, "%-25s\t0x%08lX [%c]\n",
+			       acpi_debug_layers[i].name,
+			       acpi_debug_layers[i].value,
+			       (acpi_dbg_layer & acpi_debug_layers[i].value)
+			       ? '*' : ' ');
 	}
-	result +=
-	    sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
-		    ACPI_ALL_DRIVERS,
-		    (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
-		    ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS)
-		    == 0 ? ' ' : '-');
-	result +=
-	    sprintf(buffer + result,
-		    "--\ndebug_layer = 0x%08X ( * = enabled)\n",
-		    acpi_dbg_layer);
+	seq_buf_printf(buffer, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+		       ACPI_ALL_DRIVERS,
+		       (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS
+		       ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0
+		       ? ' ' : '-');
+	seq_buf_printf(buffer, "--\ndebug_layer = 0x%08X ( * = enabled)\n",
+		       acpi_dbg_layer);
 
-	return result;
+	return 0;
 }
 
-static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
+static int param_get_debug_level(struct seq_buf *buffer,
+				 const struct kernel_param *kp)
 {
-	int result = 0;
 	int i;
 
-	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+	seq_buf_printf(buffer, "%-25s\tHex        SET\n", "Description");
 
 	for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
-		result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
-				  acpi_debug_levels[i].name,
-				  acpi_debug_levels[i].value,
-				  (acpi_dbg_level & acpi_debug_levels[i].value)
-				  ? '*' : ' ');
+		seq_buf_printf(buffer, "%-25s\t0x%08lX [%c]\n",
+			       acpi_debug_levels[i].name,
+			       acpi_debug_levels[i].value,
+			       (acpi_dbg_level & acpi_debug_levels[i].value)
+			       ? '*' : ' ');
 	}
-	result +=
-	    sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n",
-		    acpi_dbg_level);
+	seq_buf_printf(buffer, "--\ndebug_level = 0x%08X (* = enabled)\n",
+		       acpi_dbg_level);
 
-	return result;
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_layer, param_set_uint,
@@ -247,16 +243,18 @@ static int param_set_trace_state(const char *val,
 	return 0;
 }
 
-static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
+static int param_get_trace_state(struct seq_buf *buffer,
+				 const struct kernel_param *kp)
 {
 	if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
-		return sprintf(buffer, "disable\n");
-	if (!acpi_gbl_trace_method_name)
-		return sprintf(buffer, "enable\n");
-	if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
-		return sprintf(buffer, "method-once\n");
+		seq_buf_printf(buffer, "disable\n");
+	else if (!acpi_gbl_trace_method_name)
+		seq_buf_printf(buffer, "enable\n");
+	else if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
+		seq_buf_printf(buffer, "method-once\n");
 	else
-		return sprintf(buffer, "method\n");
+		seq_buf_printf(buffer, "method\n");
+	return 0;
 }
 
 module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
@@ -272,14 +270,11 @@ MODULE_PARM_DESC(aml_debug_output,
 		 "To enable/disable the ACPI Debug Object output.");
 
 /* /sys/module/acpi/parameters/acpica_version */
-static int param_get_acpica_version(char *buffer,
+static int param_get_acpica_version(struct seq_buf *buffer,
 				    const struct kernel_param *kp)
 {
-	int result;
-
-	result = sprintf(buffer, "%x\n", ACPI_CA_VERSION);
-
-	return result;
+	seq_buf_printf(buffer, "%x\n", ACPI_CA_VERSION);
+	return 0;
 }
 
 module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 91a99417d204..2bfec85ef331 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -197,11 +197,11 @@ static DEFINE_KERNEL_PARAM_OPS(param_ops_timeout, set_param_timeout,
 			       param_get_int);
 #define param_check_timeout param_check_int
 
-typedef int (*action_fn)(const char *intval, char *outval);
+typedef int (*action_fn)(const char *intval, struct seq_buf *outval);
 
-static int action_op(const char *inval, char *outval);
-static int preaction_op(const char *inval, char *outval);
-static int preop_op(const char *inval, char *outval);
+static int action_op(const char *inval, struct seq_buf *outval);
+static int preaction_op(const char *inval, struct seq_buf *outval);
+static int preop_op(const char *inval, struct seq_buf *outval);
 static void check_parms(void);
 
 static int set_param_str(const char *val, const struct kernel_param *kp)
@@ -227,20 +227,11 @@ static int set_param_str(const char *val, const struct kernel_param *kp)
 	return rv;
 }
 
-static int get_param_str(char *buffer, const struct kernel_param *kp)
+static int get_param_str(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	action_fn fn = (action_fn) kp->arg;
-	int rv, len;
 
-	rv = fn(NULL, buffer);
-	if (rv)
-		return rv;
-
-	len = strlen(buffer);
-	buffer[len++] = '\n';
-	buffer[len] = 0;
-
-	return len;
+	return fn(NULL, buffer);
 }

@@ -1154,12 +1145,12 @@ static int action_op_set_val(const char *inval)
 	return 0;
 }
 
-static int action_op(const char *inval, char *outval)
+static int action_op(const char *inval, struct seq_buf *outval)
 {
 	int rv;
 
 	if (outval)
-		strcpy(outval, action);
+		seq_buf_printf(outval, "%s\n", action);
 
 	if (!inval)
 		return 0;
@@ -1186,12 +1177,12 @@ static int preaction_op_set_val(const char *inval)
 	return 0;
 }
 
-static int preaction_op(const char *inval, char *outval)
+static int preaction_op(const char *inval, struct seq_buf *outval)
 {
 	int rv;
 
 	if (outval)
-		strcpy(outval, preaction);
+		seq_buf_printf(outval, "%s\n", preaction);
 
 	if (!inval)
 		return 0;
@@ -1214,12 +1205,12 @@ static int preop_op_set_val(const char *inval)
 	return 0;
 }
 
-static int preop_op(const char *inval, char *outval)
+static int preop_op(const char *inval, struct seq_buf *outval)
 {
 	int rv;
 
 	if (outval)
-		strcpy(outval, preop);
+		seq_buf_printf(outval, "%s\n", preop);
 
 	if (!inval)
 		return 0;
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index c87a5449ba8c..4ebc1e327849 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -860,7 +860,8 @@ static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 	return PTR_ERR_OR_ZERO(fw_cfg_cmdline_dev);
 }
 
-static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
+static int fw_cfg_cmdline_get(struct seq_buf *buf,
+			      const struct kernel_param *kp)
 {
 	/* stay silent if device was not configured via the command
 	 * line, or if the parameter name (ioport/mmio) doesn't match
@@ -873,22 +874,25 @@ static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
 
 	switch (fw_cfg_cmdline_dev->num_resources) {
 	case 1:
-		return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_1_FMT,
-				resource_size(&fw_cfg_cmdline_dev->resource[0]),
-				fw_cfg_cmdline_dev->resource[0].start);
+		seq_buf_printf(buf, PH_ADDR_PR_1_FMT,
+			       resource_size(&fw_cfg_cmdline_dev->resource[0]),
+			       fw_cfg_cmdline_dev->resource[0].start);
+		return 0;
 	case 3:
-		return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_3_FMT,
-				resource_size(&fw_cfg_cmdline_dev->resource[0]),
-				fw_cfg_cmdline_dev->resource[0].start,
-				fw_cfg_cmdline_dev->resource[1].start,
-				fw_cfg_cmdline_dev->resource[2].start);
+		seq_buf_printf(buf, PH_ADDR_PR_3_FMT,
+			       resource_size(&fw_cfg_cmdline_dev->resource[0]),
+			       fw_cfg_cmdline_dev->resource[0].start,
+			       fw_cfg_cmdline_dev->resource[1].start,
+			       fw_cfg_cmdline_dev->resource[2].start);
+		return 0;
 	case 4:
-		return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_4_FMT,
-				resource_size(&fw_cfg_cmdline_dev->resource[0]),
-				fw_cfg_cmdline_dev->resource[0].start,
-				fw_cfg_cmdline_dev->resource[1].start,
-				fw_cfg_cmdline_dev->resource[2].start,
-				fw_cfg_cmdline_dev->resource[3].start);
+		seq_buf_printf(buf, PH_ADDR_PR_4_FMT,
+			       resource_size(&fw_cfg_cmdline_dev->resource[0]),
+			       fw_cfg_cmdline_dev->resource[0].start,
+			       fw_cfg_cmdline_dev->resource[1].start,
+			       fw_cfg_cmdline_dev->resource[2].start,
+			       fw_cfg_cmdline_dev->resource[3].start);
+		return 0;
 	}
 
 	/* Should never get here */
diff --git a/drivers/gpu/drm/i915/i915_mitigations.c b/drivers/gpu/drm/i915/i915_mitigations.c
index 6061eae84e9c..99cb38f355b6 100644
--- a/drivers/gpu/drm/i915/i915_mitigations.c
+++ b/drivers/gpu/drm/i915/i915_mitigations.c
@@ -95,33 +95,37 @@ static int mitigations_set(const char *val, const struct kernel_param *kp)
 	return 0;
 }
 
-static int mitigations_get(char *buffer, const struct kernel_param *kp)
+static int mitigations_get(struct seq_buf *buffer,
+			   const struct kernel_param *kp)
 {
 	unsigned long local = READ_ONCE(mitigations);
-	int count, i;
 	bool enable;
+	int i;
 
-	if (!local)
-		return scnprintf(buffer, PAGE_SIZE, "%s\n", "off");
+	if (!local) {
+		seq_buf_printf(buffer, "%s\n", "off");
+		return 0;
+	}
 
 	if (local & BIT(BITS_PER_LONG - 1)) {
-		count = scnprintf(buffer, PAGE_SIZE, "%s,", "auto");
+		seq_buf_printf(buffer, "%s,", "auto");
 		enable = false;
 	} else {
 		enable = true;
-		count = 0;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(names); i++) {
 		if ((local & BIT(i)) != enable)
 			continue;
-
-		count += scnprintf(buffer + count, PAGE_SIZE - count,
-				   "%s%s,", enable ? "" : "!", names[i]);
+		seq_buf_printf(buffer, "%s%s,", enable ? "" : "!", names[i]);
 	}
 
-	buffer[count - 1] = '\n';
-	return count;
+	/* Replace the trailing comma with a newline. */
+	if (!seq_buf_has_overflowed(buffer) && buffer->len > 0 &&
+	    buffer->buffer[buffer->len - 1] == ',')
+		buffer->buffer[buffer->len - 1] = '\n';
+
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(ops, mitigations_set, mitigations_get);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index a81515f52a4f..4f53e939eec1 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -161,14 +161,15 @@ static struct ib_client srp_client = {
 
 static struct ib_sa_client srp_sa_client;
 
-static int srp_tmo_get(char *buffer, const struct kernel_param *kp)
+static int srp_tmo_get(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	int tmo = *(int *)kp->arg;
 
 	if (tmo >= 0)
-		return sysfs_emit(buffer, "%d\n", tmo);
+		seq_buf_printf(buffer, "%d\n", tmo);
 	else
-		return sysfs_emit(buffer, "off\n");
+		seq_buf_printf(buffer, "off\n");
+	return 0;
 }
 
 static int srp_tmo_set(const char *val, const struct kernel_param *kp)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 2338cab7fef9..1c5c40ce852d 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2451,12 +2451,14 @@ static int uvc_reset_resume(struct usb_interface *intf)
  * Module parameters
  */
 
-static int uvc_clock_param_get(char *buffer, const struct kernel_param *kp)
+static int uvc_clock_param_get(struct seq_buf *buffer,
+			       const struct kernel_param *kp)
 {
 	if (uvc_clock_param == CLOCK_MONOTONIC)
-		return sprintf(buffer, "CLOCK_MONOTONIC");
+		seq_buf_printf(buffer, "CLOCK_MONOTONIC");
 	else
-		return sprintf(buffer, "CLOCK_REALTIME");
+		seq_buf_printf(buffer, "CLOCK_REALTIME");
+	return 0;
 }
 
 static int uvc_clock_param_set(const char *val, const struct kernel_param *kp)
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 925373b98dff..af2dd668fe4d 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1572,16 +1572,19 @@ static int pcie_aspm_set_policy(const char *val,
 	return 0;
 }
 
-static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp)
+static int pcie_aspm_get_policy(struct seq_buf *buffer,
+				const struct kernel_param *kp)
 {
-	int i, cnt = 0;
-	for (i = 0; i < ARRAY_SIZE(policy_str); i++)
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(policy_str); i++) {
 		if (i == aspm_policy)
-			cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
+			seq_buf_printf(buffer, "[%s] ", policy_str[i]);
 		else
-			cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
-	cnt += sprintf(buffer + cnt, "\n");
-	return cnt;
+			seq_buf_printf(buffer, "%s ", policy_str[i]);
+	}
+	seq_buf_putc(buffer, '\n');
+	return 0;
 }
 
 module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 88d85fc9a52a..aa10514ec46e 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -23,7 +23,8 @@ MODULE_LICENSE("GPL v2");
 
 static int fcoe_transport_create(const char *, const struct kernel_param *);
 static int fcoe_transport_destroy(const char *, const struct kernel_param *);
-static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
+static int fcoe_transport_show(struct seq_buf *buffer,
+			       const struct kernel_param *kp);
 static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
 static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
 static int fcoe_transport_enable(const char *, const struct kernel_param *);
@@ -595,22 +596,21 @@ int fcoe_transport_detach(struct fcoe_transport *ft)
 }
 EXPORT_SYMBOL(fcoe_transport_detach);
 
-static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
+static int fcoe_transport_show(struct seq_buf *buffer,
+			       const struct kernel_param *kp)
 {
-	int i, j;
 	struct fcoe_transport *ft = NULL;
 
-	i = j = sprintf(buffer, "Attached FCoE transports:");
+	seq_buf_printf(buffer, "Attached FCoE transports:");
 	mutex_lock(&ft_mutex);
-	list_for_each_entry(ft, &fcoe_transports, list) {
-		if (i >= PAGE_SIZE - IFNAMSIZ)
-			break;
-		i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
+	if (list_empty(&fcoe_transports)) {
+		seq_buf_printf(buffer, "none");
+	} else {
+		list_for_each_entry(ft, &fcoe_transports, list)
+			seq_buf_printf(buffer, "%s ", ft->name);
 	}
 	mutex_unlock(&ft_mutex);
-	if (i == j)
-		i += snprintf(&buffer[i], IFNAMSIZ, "none");
-	return i;
+	return 0;
 }
 
 static int __init fcoe_transport_init(void)
diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
index 98fbc6892714..50ec1a0ff1ab 100644
--- a/drivers/thermal/intel/intel_powerclamp.c
+++ b/drivers/thermal/intel/intel_powerclamp.c
@@ -101,15 +101,13 @@ static int duration_set(const char *arg, const struct kernel_param *kp)
 	return ret;
 }
 
-static int duration_get(char *buf, const struct kernel_param *kp)
+static int duration_get(struct seq_buf *buf, const struct kernel_param *kp)
 {
-	int ret;
-
 	mutex_lock(&powerclamp_lock);
-	ret = sysfs_emit(buf, "%d\n", duration / 1000);
+	seq_buf_printf(buf, "%d\n", duration / 1000);
 	mutex_unlock(&powerclamp_lock);
 
-	return ret;
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(duration_ops, duration_set, duration_get);
@@ -192,12 +190,14 @@ static int cpumask_set(const char *arg, const struct kernel_param *kp)
 	return ret;
 }
 
-static int cpumask_get(char *buf, const struct kernel_param *kp)
+static int cpumask_get(struct seq_buf *buf, const struct kernel_param *kp)
 {
 	if (!cpumask_available(idle_injection_cpu_mask))
 		return -ENODEV;
 
-	return cpumap_print_to_pagebuf(false, buf, idle_injection_cpu_mask);
+	seq_buf_printf(buf, "%*pb\n", nr_cpu_ids,
+		       cpumask_bits(idle_injection_cpu_mask));
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(cpumask_ops, cpumask_set, cpumask_get);
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 29612a4a32cb..b27c1dfbd249 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -1256,36 +1256,32 @@ static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
 
 /**
  * param_get_vmidfilter() - Get z/VM user ID filter
- * @buffer:	Buffer to store z/VM user ID filter,
- *		(buffer size assumption PAGE_SIZE)
+ * @buffer:	seq_buf to store z/VM user ID filter
  * @kp:		Kernel parameter pointing to the hvc_iucv_filter array
  *
  * The function stores the filter as a comma-separated list of z/VM user IDs
  * in @buffer. Typically, sysfs routines call this function for attr show.
  */
-static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
+static int param_get_vmidfilter(struct seq_buf *buffer,
+				const struct kernel_param *kp)
 {
-	int rc;
 	size_t index, len;
 	void *start, *end;
 
 	if (!machine_is_vm() || !hvc_iucv_devices)
 		return -ENODEV;
 
-	rc = 0;
 	read_lock_bh(&hvc_iucv_filter_lock);
 	for (index = 0; index < hvc_iucv_filter_size; index++) {
 		start = hvc_iucv_filter + (8 * index);
 		end   = memchr(start, ' ', 8);
 		len   = (end) ? end - start : 8;
-		memcpy(buffer + rc, start, len);
-		rc += len;
-		buffer[rc++] = ',';
+		if (index)
+			seq_buf_putc(buffer, ',');
+		seq_buf_printf(buffer, "%.*s", (int)len, (char *)start);
 	}
 	read_unlock_bh(&hvc_iucv_filter_lock);
-	if (rc)
-		buffer[--rc] = '\0';	/* replace last comma and update rc */
-	return rc;
+	return 0;
 }
 
 #define param_check_vmidfilter(name, p) __param_check(name, p, void)
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 71dd623b95c9..637e1b8f622f 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -115,27 +115,22 @@ static int parse_delay_str(const char *str, int ndecimals, const char *suffix,
  * @val: The integer value to format, scaled by 10^(@ndecimals).
  * @ndecimals: Number of decimal to scale down.
  * @suffix: Suffix string to format.
- * @str: Where to store the formatted string.
- * @size: The size of buffer for @str.
+ * @s: Where to store the formatted string.
  *
  * Format an integer value in @val scale down by 10^(@ndecimals) without @suffix
  * if @val is divisible by 10^(@ndecimals).
  * Otherwise format a value in @val just as it is with @suffix
- *
- * Returns the number of characters written into @str.
  */
-static int format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
-			char *str, int size)
+static void format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
+			    struct seq_buf *s)
 {
 	u64 delay_ms = val;
 	unsigned int rem = do_div(delay_ms, int_pow(10, ndecimals));
-	int ret;
 
 	if (rem)
-		ret = scnprintf(str, size, "%u%s\n", val, suffix);
+		seq_buf_printf(s, "%u%s\n", val, suffix);
 	else
-		ret = scnprintf(str, size, "%u\n", (unsigned int)delay_ms);
-	return ret;
+		seq_buf_printf(s, "%u\n", (unsigned int)delay_ms);
 }
 
 static int delay_use_set(const char *s, const struct kernel_param *kp)
@@ -151,11 +146,12 @@ static int delay_use_set(const char *s, const struct kernel_param *kp)
 	return 0;
 }
 
-static int delay_use_get(char *s, const struct kernel_param *kp)
+static int delay_use_get(struct seq_buf *s, const struct kernel_param *kp)
 {
 	unsigned int delay_ms = *((unsigned int *)kp->arg);
 
-	return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE);
+	format_delay_ms(delay_ms, 3, "ms", s);
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(delay_use_ops, delay_use_set, delay_use_get);
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index f6df9c76ee81..81a7455e4643 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -728,24 +728,21 @@ static int vm_cmdline_set(const char *device,
 
 static int vm_cmdline_get_device(struct device *dev, void *data)
 {
-	char *buffer = data;
-	unsigned int len = strlen(buffer);
+	struct seq_buf *s = data;
 	struct platform_device *pdev = to_platform_device(dev);
 
-	snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n",
-			pdev->resource[0].end - pdev->resource[0].start + 1ULL,
-			(unsigned long long)pdev->resource[0].start,
-			(unsigned long long)pdev->resource[1].start,
-			pdev->id);
+	seq_buf_printf(s, "0x%llx@0x%llx:%llu:%d\n",
+		       pdev->resource[0].end - pdev->resource[0].start + 1ULL,
+		       (unsigned long long)pdev->resource[0].start,
+		       (unsigned long long)pdev->resource[1].start,
+		       pdev->id);
 	return 0;
 }
 
-static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
+static int vm_cmdline_get(struct seq_buf *s, const struct kernel_param *kp)
 {
-	buffer[0] = '\0';
-	device_for_each_child(&vm_cmdline_parent, buffer,
-			vm_cmdline_get_device);
-	return strlen(buffer) + 1;
+	device_for_each_child(&vm_cmdline_parent, s, vm_cmdline_get_device);
+	return 0;
 }
 
 static DEFINE_KERNEL_PARAM_OPS(vm_cmdline_param_ops, vm_cmdline_set,
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index cf0405ba0dbd..123f061c2fb2 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kallsyms.h>
+#include <linux/seq_buf.h>
 #include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/proc_fs.h>
@@ -787,7 +788,8 @@ EXPORT_SYMBOL(param_set_dyndbg_classes);
  * altered by direct >control.  Displays 0x for DISJOINT, 0-N for
  * LEVEL Returns: #chars written or <0 on error
  */
-int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
+int param_get_dyndbg_classes(struct seq_buf *buffer,
+			     const struct kernel_param *kp)
 {
 	const struct ddebug_class_param *dcp = kp->arg;
 	const struct ddebug_class_map *map = dcp->map;
@@ -796,11 +798,13 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
 
 	case DD_CLASS_TYPE_DISJOINT_NAMES:
 	case DD_CLASS_TYPE_DISJOINT_BITS:
-		return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
+		seq_buf_printf(buffer, "0x%lx\n", *dcp->bits);
+		return 0;
 
 	case DD_CLASS_TYPE_LEVEL_NAMES:
 	case DD_CLASS_TYPE_LEVEL_NUM:
-		return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
+		seq_buf_printf(buffer, "%d\n", *dcp->lvl);
+		return 0;
 	default:
 		return -1;
 	}
-- 
2.34.1