git: 78e25e65bf38 - main - lindebugfs: Add `debugfs_create_str()`

From: Jean-Sébastien Pédron <dumbbell_at_FreeBSD.org>
Date: Sun, 13 Apr 2025 10:00:55 UTC
The branch main has been updated by dumbbell:

URL: https://cgit.FreeBSD.org/src/commit/?id=78e25e65bf381303c8bdac9a713ab7b26a854b8c

commit 78e25e65bf381303c8bdac9a713ab7b26a854b8c
Author:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2025-02-08 19:10:53 +0000
Commit:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
CommitDate: 2025-04-13 09:50:14 +0000

    lindebugfs: Add `debugfs_create_str()`
    
    This function is used by the i915 DRM driver starting with Linux 6.8.
    
    Reviewed by:    bz, emaste
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D49067
---
 sys/compat/lindebugfs/lindebugfs.c                 | 115 +++++++++++++++++++++
 sys/compat/linuxkpi/common/include/linux/debugfs.h |   2 +
 sys/modules/lindebugfs/Makefile                    |   1 +
 3 files changed, 118 insertions(+)

diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
index 37028b667be8..97f73e79fb6c 100644
--- a/sys/compat/lindebugfs/lindebugfs.c
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -624,6 +624,121 @@ debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, a
 }
 
 
+static int
+fops_str_open(struct inode *inode, struct file *filp)
+{
+
+	return (simple_open(inode, filp));
+}
+
+static ssize_t
+fops_str_read(struct file *filp, char __user *ubuf, size_t read_size,
+    loff_t *ppos)
+{
+	ssize_t ret;
+	char *str, *str_with_newline;
+	size_t str_len, str_with_newline_len;
+
+	if (filp->private_data == NULL)
+		return (-EINVAL);
+
+	str = *(char **)filp->private_data;
+	str_len = strlen(str);
+
+	/*
+	 * `str_with_newline` is terminated with a newline, but is not
+	 * NUL-terminated.
+	 */
+	str_with_newline_len = str_len + 1;
+	str_with_newline = kmalloc(str_with_newline_len, GFP_KERNEL);
+	if (str_with_newline == NULL)
+		return (-ENOMEM);
+
+	strncpy(str_with_newline, str, str_len);
+	str_with_newline[str_len] = '\n';
+
+	ret = simple_read_from_buffer(ubuf, read_size, ppos,
+	    str_with_newline, str_with_newline_len);
+
+	kfree(str_with_newline);
+
+	return (ret);
+}
+
+static ssize_t
+fops_str_write(struct file *filp, const char *buf, size_t write_size,
+    loff_t *ppos)
+{
+	char *old, *new;
+	size_t old_len, new_len;
+
+	if (filp->private_data == NULL)
+		return (-EINVAL);
+
+	old = *(char **)filp->private_data;
+	new = NULL;
+
+	/*
+	 * We enforce concatenation of the newly written value to the existing
+	 * value.
+	 */
+	old_len = strlen(old);
+	if (*ppos && *ppos != old_len)
+		return (-EINVAL);
+
+	new_len = old_len + write_size;
+	if (new_len + 1 > PAGE_SIZE)
+		return (-E2BIG);
+
+	new = kmalloc(new_len + 1, GFP_KERNEL);
+	if (new == NULL)
+		return (-ENOMEM);
+
+	memcpy(new, old, old_len);
+	if (copy_from_user(new + old_len, buf, write_size) != 0) {
+		kfree(new);
+		return (-EFAULT);
+	}
+
+	new[new_len] = '\0';
+	strim(new);
+
+	filp->private_data = &new;
+
+	kfree(old);
+
+	return (write_size);
+}
+
+static const struct file_operations fops_str = {
+	.owner = THIS_MODULE,
+	.open = fops_str_open,
+	.read = fops_str_read,
+	.write = fops_str_write,
+	.llseek = no_llseek
+};
+static const struct file_operations fops_str_ro = {
+	.owner = THIS_MODULE,
+	.open = fops_str_open,
+	.read = fops_str_read,
+	.llseek = no_llseek
+};
+static const struct file_operations fops_str_wo = {
+	.owner = THIS_MODULE,
+	.open = fops_str_open,
+	.write = fops_str_write,
+	.llseek = no_llseek
+};
+
+void
+debugfs_create_str(const char *name, umode_t mode, struct dentry *parent,
+    char **value)
+{
+	debugfs_create_mode_unsafe(name, mode, parent, value,
+	    &fops_str, &fops_str_ro, &fops_str_wo);
+}
+
+
 static ssize_t
 fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
 {
diff --git a/sys/compat/linuxkpi/common/include/linux/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
index 54145b61503e..4d146e085a7b 100644
--- a/sys/compat/linuxkpi/common/include/linux/debugfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -115,6 +115,8 @@ void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent,
     unsigned long *value);
 void debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent,
     atomic_t *value);
+void debugfs_create_str(const char *name, umode_t mode, struct dentry *parent,
+    char **value);
 
 struct dentry *debugfs_create_blob(const char *name, umode_t mode,
     struct dentry *parent, struct debugfs_blob_wrapper *value);
diff --git a/sys/modules/lindebugfs/Makefile b/sys/modules/lindebugfs/Makefile
index dce9a2a3e955..44041011b407 100644
--- a/sys/modules/lindebugfs/Makefile
+++ b/sys/modules/lindebugfs/Makefile
@@ -14,6 +14,7 @@ EXPORT_SYMS+=	debugfs_create_file
 EXPORT_SYMS+=	debugfs_create_file_size
 EXPORT_SYMS+=	debugfs_create_file_unsafe
 EXPORT_SYMS+=	debugfs_create_mode_unsafe
+EXPORT_SYMS+=	debugfs_create_str
 EXPORT_SYMS+=	debugfs_create_symlink
 EXPORT_SYMS+=	debugfs_create_u8
 EXPORT_SYMS+=	debugfs_create_u16