[PATCH RFC 21/23] ALSA: info: let procfs copy in writes
From: Christian Brauner
Date: Mon Nov 02 2026 - 12:51:29 EST
Implement ->proc_write_buf() for data and text entries so procfs copies
in what is written before it pins the entry.
Data entries take writes a page at a time with PROC_ENTRY_SHORT_WRITES.
They used to get the whole write at once. ->write() of struct
snd_info_entry_ops gets the kernel copy and opl4, its only user, writes
it to the sample memory without bouncing it through a vmalloc() buffer
of its own.
Text entries take up to SND_INFO_TEXT_WRITE_MAX bytes at once like
before. A single write that is larger fails with -EINVAL from procfs
instead of -EIO now.
Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
include/sound/info.h | 2 +-
sound/core/info.c | 21 ++++++++++++---------
sound/drivers/opl4/opl4_proc.c | 11 +----------
3 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/include/sound/info.h b/include/sound/info.h
index adbc506860d6..32fc608d056c 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -42,7 +42,7 @@ struct snd_info_entry_ops {
struct file *file, char __user *buf,
size_t count, loff_t pos);
ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data,
- struct file *file, const char __user *buf,
+ struct file *file, const char *buf,
size_t count, loff_t pos);
loff_t (*llseek)(struct snd_info_entry *entry,
void *file_private_data, struct file *file,
diff --git a/sound/core/info.c b/sound/core/info.c
index 8f905f398a0d..09d4420202e5 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -160,7 +160,7 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
return size;
}
-static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
+static ssize_t snd_info_entry_write(struct file *file, char *buffer,
size_t count, loff_t * offset)
{
struct snd_info_private_data *data = file->private_data;
@@ -277,9 +277,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
static const struct proc_ops snd_info_entry_operations =
{
+ .proc_flags = PROC_ENTRY_SHORT_WRITES,
.proc_lseek = snd_info_entry_llseek,
.proc_read = snd_info_entry_read,
- .proc_write = snd_info_entry_write,
+ .proc_write_buf = snd_info_entry_write,
+ .proc_write_size = PAGE_SIZE,
.proc_poll = snd_info_entry_poll,
.proc_ioctl = snd_info_entry_ioctl,
.proc_mmap = snd_info_entry_mmap,
@@ -287,11 +289,13 @@ static const struct proc_ops snd_info_entry_operations =
.proc_release = snd_info_entry_release,
};
+/* don't handle too large text inputs */
+#define SND_INFO_TEXT_WRITE_MAX (16 * 1024)
+
/*
* file ops for text proc files
*/
-static ssize_t snd_info_text_entry_write(struct file *file,
- const char __user *buffer,
+static ssize_t snd_info_text_entry_write(struct file *file, char *buffer,
size_t count, loff_t *offset)
{
struct seq_file *m = file->private_data;
@@ -307,8 +311,7 @@ static ssize_t snd_info_text_entry_write(struct file *file,
if (!valid_pos(pos, count))
return -EIO;
next = pos + count;
- /* don't handle too large text inputs */
- if (next > 16 * 1024)
+ if (next > SND_INFO_TEXT_WRITE_MAX)
return -EIO;
guard(mutex)(&entry->access);
buf = data->wbuffer;
@@ -325,8 +328,7 @@ static ssize_t snd_info_text_entry_write(struct file *file,
buf->buffer = nbuf;
buf->len = PAGE_ALIGN(next);
}
- if (copy_from_user(buf->buffer + pos, buffer, count))
- return -EFAULT;
+ memcpy(buf->buffer + pos, buffer, count);
buf->size = next;
*offset = next;
return count;
@@ -404,7 +406,8 @@ static const struct proc_ops snd_info_text_entry_ops =
.proc_show = snd_info_seq_show,
.proc_open = snd_info_text_entry_open,
.proc_release = snd_info_text_entry_release,
- .proc_write = snd_info_text_entry_write,
+ .proc_write_buf = snd_info_text_entry_write,
+ .proc_write_size = SND_INFO_TEXT_WRITE_MAX,
};
static struct snd_info_entry *create_subdir(struct module *mod,
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
index fd0ba4704d9f..bdcae02a4dc2 100644
--- a/sound/drivers/opl4/opl4_proc.c
+++ b/sound/drivers/opl4/opl4_proc.c
@@ -54,21 +54,12 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
void *file_private_data,
struct file *file,
- const char __user *_buf,
+ const char *buf,
size_t count, loff_t pos)
{
struct snd_opl4 *opl4 = entry->private_data;
- char *buf;
- buf = vmalloc(count);
- if (!buf)
- return -ENOMEM;
- if (copy_from_user(buf, _buf, count)) {
- vfree(buf);
- return -EFAULT;
- }
snd_opl4_write_memory(opl4, buf, pos, count);
- vfree(buf);
return count;
}
--
2.53.0