git: 5fbfe9517b4d - main - linuxkpi: Define `seq_has_overflowed()` and `single_open_size()`

From: Jean-Sébastien Pédron <dumbbell_at_FreeBSD.org>
Date: Mon, 20 Mar 2023 20:47:51 UTC
The branch main has been updated by dumbbell:

URL: https://cgit.FreeBSD.org/src/commit/?id=5fbfe9517b4dab41a95e91b3fd8e73310c9eaa8b

commit 5fbfe9517b4dab41a95e91b3fd8e73310c9eaa8b
Author:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2023-02-20 20:53:36 +0000
Commit:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
CommitDate: 2023-03-20 20:47:36 +0000

    linuxkpi: Define `seq_has_overflowed()` and `single_open_size()`
    
    This required non-trivial changes to `linux_seq_file.c` to manage a new
    `(struct seq_file)->size` field. This field is read directly by DRM
    drivers, so we can't alias it to a call to sbuf_len(9).
    
    `single_open_size()` also depended on the ability to allocate the sbuf
    with a specified size instead of relying on `sbuf_new_auto()`.
    
    Reviewed by:    manu
    Approved by:    manu
    Differential Revision:  https://reviews.freebsd.org/D39056
---
 .../linuxkpi/common/include/linux/seq_file.h       |  8 +-
 sys/compat/linuxkpi/common/src/linux_seq_file.c    | 89 +++++++++++++++++++---
 2 files changed, 85 insertions(+), 12 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
index 8fb93646f9a5..d18d3cd906ab 100644
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -54,6 +54,7 @@ static const struct file_operations __name ## _fops = {			\
 
 struct seq_file {
 	struct sbuf *buf;
+	size_t size;
 	const struct seq_operations *op;
 	const struct linux_file *file;
 	void *private;
@@ -68,6 +69,9 @@ struct seq_operations {
 
 ssize_t seq_read(struct linux_file *, char *, size_t, off_t *);
 int seq_write(struct seq_file *seq, const void *data, size_t len);
+void seq_putc(struct seq_file *m, char c);
+void seq_puts(struct seq_file *m, const char *str);
+bool seq_has_overflowed(struct seq_file *m);
 
 void *__seq_open_private(struct linux_file *, const struct seq_operations *, int);
 int seq_release_private(struct inode *, struct linux_file *);
@@ -77,6 +81,7 @@ int seq_release(struct inode *inode, struct linux_file *file);
 
 off_t seq_lseek(struct linux_file *file, off_t offset, int whence);
 int single_open(struct linux_file *, int (*)(struct seq_file *, void *), void *);
+int single_open_size(struct linux_file *, int (*)(struct seq_file *, void *), void *, size_t);
 int single_release(struct inode *, struct linux_file *);
 
 void lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args);
@@ -85,9 +90,6 @@ void lkpi_seq_printf(struct seq_file *m, const char *fmt, ...);
 #define	seq_vprintf(...)	lkpi_seq_vprintf(__VA_ARGS__)
 #define	seq_printf(...)		lkpi_seq_printf(__VA_ARGS__)
 
-#define seq_puts(m, str)	sbuf_printf((m)->buf, str)
-#define seq_putc(m, str)	sbuf_putc((m)->buf, str)
-
 #define	file			linux_file
 
 #endif	/* _LINUXKPI_LINUX_SEQ_FILE_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_seq_file.c b/sys/compat/linuxkpi/common/src/linux_seq_file.c
index d4d8ef059ac4..80b13a3ac28f 100644
--- a/sys/compat/linuxkpi/common/src/linux_seq_file.c
+++ b/sys/compat/linuxkpi/common/src/linux_seq_file.c
@@ -79,8 +79,33 @@ seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos)
 int
 seq_write(struct seq_file *seq, const void *data, size_t len)
 {
+	int ret;
 
-	return (sbuf_bcpy(seq->buf, data, len));
+	ret = sbuf_bcpy(seq->buf, data, len);
+	if (ret == 0)
+		seq->size = sbuf_len(seq->buf);
+
+	return (ret);
+}
+
+void
+seq_putc(struct seq_file *seq, char c)
+{
+	int ret;
+
+	ret = sbuf_putc(seq->buf, c);
+	if (ret == 0)
+		seq->size = sbuf_len(seq->buf);
+}
+
+void
+seq_puts(struct seq_file *seq, const char *str)
+{
+	int ret;
+
+	ret = sbuf_printf(seq->buf, "%s", str);
+	if (ret == 0)
+		seq->size = sbuf_len(seq->buf);
 }
 
 /*
@@ -115,21 +140,32 @@ single_stop(struct seq_file *p, void *v)
 {
 }
 
-int
-seq_open(struct linux_file *f, const struct seq_operations *op)
+static int
+_seq_open_without_sbuf(struct linux_file *f, const struct seq_operations *op)
 {
 	struct seq_file *p;
 
 	if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL)
 		return (-ENOMEM);
 
-	p->buf = sbuf_new_auto();
 	p->file = f;
 	p->op = op;
 	f->private_data = (void *) p;
 	return (0);
 }
 
+int
+seq_open(struct linux_file *f, const struct seq_operations *op)
+{
+	int ret;
+
+	ret = _seq_open_without_sbuf(f, op);
+	if (ret == 0)
+		((struct seq_file *)f->private_data)->buf = sbuf_new_auto();
+
+	return (ret);
+}
+
 void *
 __seq_open_private(struct linux_file *f, const struct seq_operations *op, int size)
 {
@@ -153,8 +189,8 @@ __seq_open_private(struct linux_file *f, const struct seq_operations *op, int si
 	return (private);
 }
 
-int
-single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
+static int
+_single_open_without_sbuf(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
 {
 	struct seq_operations *op;
 	int rc = -ENOMEM;
@@ -165,7 +201,7 @@ single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *
 		op->next = single_next;
 		op->stop = single_stop;
 		op->show = show;
-		rc = seq_open(f, op);
+		rc = _seq_open_without_sbuf(f, op);
 		if (rc)
 			free(op, M_LSEQ);
 		else
@@ -174,6 +210,31 @@ single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *
 	return (rc);
 }
 
+int
+single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
+{
+	int ret;
+
+	ret = _single_open_without_sbuf(f, show, d);
+	if (ret == 0)
+		((struct seq_file *)f->private_data)->buf = sbuf_new_auto();
+
+	return (ret);
+}
+
+int
+single_open_size(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d, size_t size)
+{
+	int ret;
+
+	ret = _single_open_without_sbuf(f, show, d);
+	if (ret == 0)
+		((struct seq_file *)f->private_data)->buf = sbuf_new(
+		    NULL, NULL, size, SBUF_AUTOEXTEND);
+
+	return (ret);
+}
+
 int
 seq_release(struct inode *inode __unused, struct linux_file *file)
 {
@@ -219,7 +280,11 @@ single_release(struct vnode *v, struct linux_file *f)
 void
 lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args)
 {
-	sbuf_vprintf(m->buf, fmt, args);
+	int ret;
+
+	ret = sbuf_vprintf(m->buf, fmt, args);
+	if (ret == 0)
+		m->size = sbuf_len(m->buf);
 }
 
 void
@@ -228,6 +293,12 @@ lkpi_seq_printf(struct seq_file *m, const char *fmt, ...)
 	va_list args;
 
 	va_start(args, fmt);
-	seq_vprintf(m, fmt, args);
+	lkpi_seq_vprintf(m, fmt, args);
 	va_end(args);
 }
+
+bool
+seq_has_overflowed(struct seq_file *m)
+{
+	return (sbuf_len(m->buf) == -1);
+}