[PATCH 04/10] bcachefs: thread_with_stdio: fix bch2_stdio_redirect_readline()

From: Darrick J. Wong
Date: Fri Feb 23 2024 - 20:15:28 EST


From: Kent Overstreet <kent.overstreet@xxxxxxxxx>

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@xxxxxxxxx>
Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx>
Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
---
fs/bcachefs/thread_with_file.c | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)


diff --git a/fs/bcachefs/thread_with_file.c b/fs/bcachefs/thread_with_file.c
index eb8ab4c47a94b..830efb06ef0be 100644
--- a/fs/bcachefs/thread_with_file.c
+++ b/fs/bcachefs/thread_with_file.c
@@ -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)