single_open_size() allocates the buffer itself because it does the
single_open() too. A file whose seq_file is opened by somebody else,
like procfs does now, needs to do that after the fact. Add
seq_preallocate() for that and use it in single_open_size().

No functional changes.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
 fs/seq_file.c            | 36 ++++++++++++++++++++++++++++--------
 include/linux/seq_file.h |  1 +
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/fs/seq_file.c b/fs/seq_file.c
index 456c78719fd0..a4644cdda7e6 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -590,21 +590,41 @@ int single_open(struct file *file, int (*show)(struct 
seq_file *, void *),
 }
 EXPORT_SYMBOL(single_open);
 
-int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),
-               void *data, size_t size)
+/**
+ *     seq_preallocate -       start out with a buffer of @size
+ *     @m: the seq_file, before it is first read
+ *     @size: the size of the buffer
+ *
+ *     For files whose records don't fit into a page, so that the first read
+ *     doesn't have to work its way up to the right buffer size.
+ */
+int seq_preallocate(struct seq_file *m, size_t size)
 {
        char *buf = seq_buf_alloc(size);
-       int ret;
+
        if (!buf)
                return -ENOMEM;
+       kvfree(m->buf);
+       m->buf = buf;
+       m->size = size;
+       return 0;
+}
+EXPORT_SYMBOL(seq_preallocate);
+
+int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),
+               void *data, size_t size)
+{
+       int ret;
+
        ret = single_open(file, show, data);
-       if (ret) {
-               kvfree(buf);
+       if (ret)
                return ret;
+       ret = seq_preallocate(file->private_data, size);
+       if (ret) {
+               single_release(file_inode(file), file);
+               file->private_data = NULL;
        }
-       ((struct seq_file *)file->private_data)->buf = buf;
-       ((struct seq_file *)file->private_data)->size = size;
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(single_open_size);
 
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index b813b7e63d89..834daff48b7d 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -175,6 +175,7 @@ int seq_path_root(struct seq_file *m, const struct path 
*path,
 void *single_start(struct seq_file *, loff_t *);
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_open_size(struct file *, int (*)(struct seq_file *, void *), void 
*, size_t);
+int seq_preallocate(struct seq_file *m, size_t size);
 int single_release(struct inode *, struct file *);
 void *__seq_open_private(struct file *, const struct seq_operations *, int);
 int seq_open_private(struct file *, const struct seq_operations *, int);

-- 
2.53.0


Reply via email to