bcachefs: thread_with_stdio: eliminate double buffering
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 5 Feb 2024 01:19:49 +0000 (20:19 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 13 Mar 2024 22:39:13 +0000 (18:39 -0400)
The output buffer lock has to be a spinlock so that we can write to it
from interrupt context, so we can't use a direct copy_to_user; this
switches thread_with_file_read() to use fault_in_writeable() and
copy_to_user_nofault(), similar to how thread_with_file_write() works.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/thread_with_file.c
fs/bcachefs/thread_with_file.h

index 9220d7de10db67f6cd4a36040af7fe557756230b..8c3afb4c3204febe2e7d3102e2ec11696a904938 100644 (file)
@@ -67,16 +67,15 @@ err:
 
 static inline bool thread_with_stdio_has_output(struct thread_with_stdio *thr)
 {
-       return thr->stdio.output_buf.pos ||
-               thr->output2.nr ||
-               thr->thr.done;
+       return thr->stdio.output_buf.pos || thr->thr.done;
 }
 
-static ssize_t thread_with_stdio_read(struct file *file, char __user *buf,
+static ssize_t thread_with_stdio_read(struct file *file, char __user *ubuf,
                                      size_t len, loff_t *ppos)
 {
        struct thread_with_stdio *thr =
                container_of(file->private_data, struct thread_with_stdio, thr);
+       struct printbuf *buf = &thr->stdio.output_buf;
        size_t copied = 0, b;
        int ret = 0;
 
@@ -89,44 +88,25 @@ static ssize_t thread_with_stdio_read(struct file *file, char __user *buf,
        if (ret)
                return ret;
 
-       if (thr->thr.done)
-               return 0;
-
-       while (len) {
-               ret = darray_make_room(&thr->output2, thr->stdio.output_buf.pos);
-               if (ret)
-                       break;
-
-               spin_lock_irq(&thr->stdio.output_lock);
-               b = min_t(size_t, darray_room(thr->output2), thr->stdio.output_buf.pos);
-
-               memcpy(&darray_top(thr->output2), thr->stdio.output_buf.buf, b);
-               memmove(thr->stdio.output_buf.buf,
-                       thr->stdio.output_buf.buf + b,
-                       thr->stdio.output_buf.pos - b);
-
-               thr->output2.nr += b;
-               thr->stdio.output_buf.pos -= b;
-               spin_unlock_irq(&thr->stdio.output_lock);
-
-               b = min(len, thr->output2.nr);
-               if (!b)
-                       break;
-
-               b -= copy_to_user(buf, thr->output2.data, b);
-               if (!b) {
+       while (len && buf->pos) {
+               if (fault_in_writeable(ubuf, len) == len) {
                        ret = -EFAULT;
                        break;
                }
 
-               copied  += b;
-               buf     += b;
-               len     -= b;
-
-               memmove(thr->output2.data,
-                       thr->output2.data + b,
-                       thr->output2.nr - b);
-               thr->output2.nr -= b;
+               spin_lock_irq(&thr->stdio.output_lock);
+               b = min_t(size_t, len, buf->pos);
+
+               if (b && !copy_to_user_nofault(ubuf, buf->buf, b)) {
+                       memmove(buf->buf,
+                               buf->buf + b,
+                               buf->pos - b);
+                       buf->pos -= b;
+                       ubuf    += b;
+                       len     -= b;
+                       copied  += b;
+               }
+               spin_unlock_irq(&thr->stdio.output_lock);
        }
 
        return copied ?: ret;
@@ -140,7 +120,6 @@ static int thread_with_stdio_release(struct inode *inode, struct file *file)
        bch2_thread_with_file_exit(&thr->thr);
        printbuf_exit(&thr->stdio.input_buf);
        printbuf_exit(&thr->stdio.output_buf);
-       darray_exit(&thr->output2);
        thr->exit(thr);
        return 0;
 }
@@ -245,7 +224,6 @@ int bch2_run_thread_with_stdio(struct thread_with_stdio *thr,
        spin_lock_init(&thr->stdio.output_lock);
        init_waitqueue_head(&thr->stdio.output_wait);
 
-       darray_init(&thr->output2);
        thr->exit = exit;
 
        return bch2_run_thread_with_file(&thr->thr, &thread_with_stdio_fops, fn);
index 05879c5048c875b9df186a4cfb6a5866ddb36428..b5098b52db709b24c36386f2517d879a73549d06 100644 (file)
@@ -20,7 +20,6 @@ int bch2_run_thread_with_file(struct thread_with_file *,
 struct thread_with_stdio {
        struct thread_with_file thr;
        struct stdio_redirect   stdio;
-       DARRAY(char)            output2;
        void                    (*exit)(struct thread_with_stdio *);
 };