[PATCH RFC 07/22] powerpc/pseries: let procfs copy in writes

From: Christian Brauner

Date: Mon Nov 02 2026 - 13:31:04 EST


Implement ->proc_write_buf() for lparcfg, ofdt and the vcpudispatch
files so procfs copies in what is written before it pins the entry, and
parse what was written from that copy. ofdt takes as much as
memdup_user_nul() could copy before since device tree updates can be
large.

Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
arch/powerpc/platforms/pseries/lpar.c | 14 ++++++--------
arch/powerpc/platforms/pseries/lparcfg.c | 7 +++----
arch/powerpc/platforms/pseries/reconfig.c | 22 ++++++++--------------
3 files changed, 17 insertions(+), 26 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 48fe0be71a89..dfd027cc9047 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -498,7 +498,7 @@ static void dtl_worker_disable(unsigned long *time_limit)
up_write(&dtl_access_lock);
}

-static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
+static ssize_t vcpudispatch_stats_write(struct file *file, char *p,
size_t count, loff_t *ppos)
{
unsigned long time_limit = jiffies + HZ;
@@ -509,8 +509,7 @@ static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p,
if (count > 15)
return -EINVAL;

- if (copy_from_user(buf, p, count))
- return -EFAULT;
+ memcpy(buf, p, count);

buf[count] = 0;
rc = kstrtoint(buf, 0, &cmd);
@@ -586,11 +585,11 @@ static int vcpudispatch_stats_display(struct seq_file *p, void *v)

static const struct proc_ops vcpudispatch_stats_proc_ops = {
.proc_show = vcpudispatch_stats_display,
- .proc_write = vcpudispatch_stats_write,
+ .proc_write_buf = vcpudispatch_stats_write,
};

static ssize_t vcpudispatch_stats_freq_write(struct file *file,
- const char __user *p, size_t count, loff_t *ppos)
+ char *p, size_t count, loff_t *ppos)
{
int rc, freq;
char buf[16];
@@ -598,8 +597,7 @@ static ssize_t vcpudispatch_stats_freq_write(struct file *file,
if (count > 15)
return -EINVAL;

- if (copy_from_user(buf, p, count))
- return -EFAULT;
+ memcpy(buf, p, count);

buf[count] = 0;
rc = kstrtoint(buf, 0, &freq);
@@ -622,7 +620,7 @@ static int vcpudispatch_stats_freq_display(struct seq_file *p, void *v)

static const struct proc_ops vcpudispatch_stats_freq_proc_ops = {
.proc_show = vcpudispatch_stats_freq_display,
- .proc_write = vcpudispatch_stats_freq_write,
+ .proc_write_buf = vcpudispatch_stats_freq_write,
};

static int __init vcpudispatch_stats_procfs_init(void)
diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c
index a6a137ce44ce..43af7f820fab 100644
--- a/arch/powerpc/platforms/pseries/lparcfg.c
+++ b/arch/powerpc/platforms/pseries/lparcfg.c
@@ -687,7 +687,7 @@ static ssize_t update_mpp(u64 *entitlement, u8 *weight)
* This function should be invoked only on systems with
* FW_FEATURE_SPLPAR.
*/
-static ssize_t lparcfg_write(struct file *file, const char __user * buf,
+static ssize_t lparcfg_write(struct file *file, char *buf,
size_t count, loff_t * off)
{
char kbuf[64];
@@ -702,8 +702,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
if (count == 0 || count > sizeof(kbuf))
return -EINVAL;

- if (copy_from_user(kbuf, buf, count))
- return -EFAULT;
+ memcpy(kbuf, buf, count);

kbuf[count - 1] = '\0';
tmp = strchr(kbuf, '=');
@@ -799,7 +798,7 @@ static int lparcfg_data(struct seq_file *m, void *v)
}

static const struct proc_ops lparcfg_proc_ops = {
- .proc_write = lparcfg_write,
+ .proc_write_buf = lparcfg_write,
.proc_show = lparcfg_data,
};

diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index b41c5db726c9..f406e826a03e 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -349,7 +349,7 @@ static int do_update_property(char *buf, size_t bufsize)
* ofdt_write - perform operations on the Open Firmware device tree
*
* @file: not used
- * @buf: command and arguments
+ * @kbuf: command and arguments
* @count: size of the command buffer
* @off: not used
*
@@ -357,26 +357,19 @@ static int do_update_property(char *buf, size_t bufsize)
* whole nodes along with their properties. Operations on individual
* properties are not implemented (yet).
*/
-static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count,
+static ssize_t ofdt_write(struct file *file, char *kbuf, size_t count,
loff_t *off)
{
int rv;
- char *kbuf;
char *tmp;

rv = security_locked_down(LOCKDOWN_DEVICE_TREE);
if (rv)
return rv;

- kbuf = memdup_user_nul(buf, count);
- if (IS_ERR(kbuf))
- return PTR_ERR(kbuf);
-
tmp = strchr(kbuf, ' ');
- if (!tmp) {
- rv = -EINVAL;
- goto out;
- }
+ if (!tmp)
+ return -EINVAL;
*tmp = '\0';
tmp++;

@@ -392,13 +385,14 @@ static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t coun
rv = do_update_property(tmp, count - (tmp - kbuf));
else
rv = -EINVAL;
-out:
- kfree(kbuf);
+
return rv ? rv : count;
}

static const struct proc_ops ofdt_proc_ops = {
- .proc_write = ofdt_write,
+ .proc_write_buf = ofdt_write,
+ /* what memdup_user_nul() could copy in */
+ .proc_write_size = KMALLOC_MAX_SIZE - 1,
.proc_lseek = noop_llseek,
};


--
2.53.0