bcachefs: thread_with_stdio: fix bch2_stdio_redirect_readline()
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 5 Feb 2024 03:56:16 +0000 (22:56 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 13 Mar 2024 22:39:13 +0000 (18:39 -0400)
This fixes a bug where we'd return data without waiting for a newline,
if data was present but a newline was not.

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

index eb8ab4c47a94ba506e081b3f2f4105f6bea34341..830efb06ef0be788dbd4f1420367ffce9aad0918 100644 (file)
@@ -277,25 +277,36 @@ int bch2_stdio_redirect_read(struct stdio_redirect *stdio, char *ubuf, size_t le
 int bch2_stdio_redirect_readline(struct stdio_redirect *stdio, char *ubuf, size_t len)
 {
        struct stdio_buf *buf = &stdio->input;
-
+       size_t copied = 0;
+       ssize_t ret = 0;
+again:
        wait_event(buf->wait, stdio_redirect_has_input(stdio));
-       if (stdio->done)
-               return -1;
+       if (stdio->done) {
+               ret = -1;
+               goto out;
+       }
 
        spin_lock(&buf->lock);
-       int ret = min(len, buf->buf.nr);
-       char *n = memchr(buf->buf.data, '\n', ret);
-       if (!n)
-               ret = min(ret, n + 1 - buf->buf.data);
-       buf->buf.nr -= ret;
-       memcpy(ubuf, buf->buf.data, ret);
+       size_t b = min(len, buf->buf.nr);
+       char *n = memchr(buf->buf.data, '\n', b);
+       if (n)
+               b = min_t(size_t, b, n + 1 - buf->buf.data);
+       buf->buf.nr -= b;
+       memcpy(ubuf, buf->buf.data, b);
        memmove(buf->buf.data,
-               buf->buf.data + ret,
+               buf->buf.data + b,
                buf->buf.nr);
+       ubuf += b;
+       len -= b;
+       copied += b;
        spin_unlock(&buf->lock);
 
        wake_up(&buf->wait);
-       return ret;
+
+       if (!n && len)
+               goto again;
+out:
+       return copied ?: ret;
 }
 
 __printf(3, 0)