1

bcachefs: twf: convert bch2_stdio_redirect_readline() to darray

We now read the line from the buffer atomically, which means we have to
allow the buffer to grow past STDIO_REDIRECT_BUFSIZE if we're waiting
for a full line - this behaviour is necessary for
stdio_redirect_readline_timeout() in the next patch.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-05-29 20:34:48 -04:00
parent 36008d5d01
commit 0c97c437e3
4 changed files with 54 additions and 35 deletions

View File

@ -109,18 +109,21 @@ static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c)
if (!stdio) if (!stdio)
return YN_NO; return YN_NO;
char buf[100]; darray_char line = {};
int ret; int ret;
do { do {
bch2_print(c, " (y,n, or Y,N for all errors of this type) "); bch2_print(c, " (y,n, or Y,N for all errors of this type) ");
int r = bch2_stdio_redirect_readline(stdio, buf, sizeof(buf) - 1); int r = bch2_stdio_redirect_readline(stdio, &line);
if (r < 0) if (r < 0) {
return YN_NO; ret = YN_NO;
buf[r] = '\0'; break;
} while ((ret = parse_yn_response(buf)) < 0); }
darray_last(line) = '\0';
} while ((ret = parse_yn_response(line.data)) < 0);
darray_exit(&line);
return ret; return ret;
} }
#else #else

View File

@ -67,9 +67,14 @@ err:
/* stdio_redirect */ /* stdio_redirect */
static bool stdio_redirect_has_more_input(struct stdio_redirect *stdio, size_t seen)
{
return stdio->input.buf.nr > seen || stdio->done;
}
static bool stdio_redirect_has_input(struct stdio_redirect *stdio) static bool stdio_redirect_has_input(struct stdio_redirect *stdio)
{ {
return stdio->input.buf.nr || stdio->done; return stdio_redirect_has_more_input(stdio, 0);
} }
static bool stdio_redirect_has_output(struct stdio_redirect *stdio) static bool stdio_redirect_has_output(struct stdio_redirect *stdio)
@ -181,9 +186,13 @@ static ssize_t thread_with_stdio_write(struct file *file, const char __user *ubu
} }
spin_lock(&buf->lock); spin_lock(&buf->lock);
if (buf->buf.nr < STDIO_REDIRECT_BUFSIZE) size_t makeroom = b;
darray_make_room_gfp(&buf->buf, if (!buf->waiting_for_line || memchr(buf->buf.data, '\n', buf->buf.nr))
min(b, STDIO_REDIRECT_BUFSIZE - buf->buf.nr), GFP_NOWAIT); makeroom = min_t(ssize_t, makeroom,
max_t(ssize_t, STDIO_REDIRECT_BUFSIZE - buf->buf.nr,
0));
darray_make_room_gfp(&buf->buf, makeroom, GFP_NOWAIT);
b = min(len, darray_room(buf->buf)); b = min(len, darray_room(buf->buf));
if (b && !copy_from_user_nofault(&darray_top(buf->buf), ubuf, b)) { if (b && !copy_from_user_nofault(&darray_top(buf->buf), ubuf, b)) {
@ -355,43 +364,48 @@ int bch2_stdio_redirect_read(struct stdio_redirect *stdio, char *ubuf, size_t le
return ret; return ret;
} }
int bch2_stdio_redirect_readline(struct stdio_redirect *stdio, char *ubuf, size_t len) int bch2_stdio_redirect_readline(struct stdio_redirect *stdio, darray_char *line)
{ {
struct stdio_buf *buf = &stdio->input; struct stdio_buf *buf = &stdio->input;
size_t copied = 0; size_t seen = 0;
ssize_t ret = 0;
again: again:
do { wait_event_timeout(buf->wait, stdio_redirect_has_more_input(stdio, seen),
wait_event_timeout(buf->wait, stdio_redirect_has_input(stdio), sysctl_hung_task_timeout_secs * HZ / 2);
sysctl_hung_task_timeout_secs * HZ / 2);
} while (!stdio_redirect_has_input(stdio));
if (stdio->done) { if (stdio->done)
ret = -1; return -1;
goto out;
}
spin_lock(&buf->lock); spin_lock(&buf->lock);
size_t b = min(len, buf->buf.nr); seen = buf->buf.nr;
char *n = memchr(buf->buf.data, '\n', b); char *n = memchr(buf->buf.data, '\n', seen);
if (n) if (!n) {
b = min_t(size_t, b, n + 1 - buf->buf.data); buf->waiting_for_line = true;
spin_unlock(&buf->lock);
goto again;
}
size_t b = n + 1 - buf->buf.data;
if (b > line->size) {
spin_unlock(&buf->lock);
int ret = darray_resize(line, b);
if (ret)
return ret;
seen = 0;
goto again;
}
buf->buf.nr -= b; buf->buf.nr -= b;
memcpy(ubuf, buf->buf.data, b); memcpy(line->data, buf->buf.data, b);
memmove(buf->buf.data, memmove(buf->buf.data,
buf->buf.data + b, buf->buf.data + b,
buf->buf.nr); buf->buf.nr);
ubuf += b; line->nr = b;
len -= b;
copied += b; buf->waiting_for_line = false;
spin_unlock(&buf->lock); spin_unlock(&buf->lock);
wake_up(&buf->wait); wake_up(&buf->wait);
return 0;
if (!n && len)
goto again;
out:
return copied ?: ret;
} }
__printf(3, 0) __printf(3, 0)

View File

@ -71,7 +71,8 @@ int bch2_run_thread_with_stdio(struct thread_with_stdio *,
int bch2_run_thread_with_stdout(struct thread_with_stdio *, int bch2_run_thread_with_stdout(struct thread_with_stdio *,
const struct thread_with_stdio_ops *); const struct thread_with_stdio_ops *);
int bch2_stdio_redirect_read(struct stdio_redirect *, char *, size_t); int bch2_stdio_redirect_read(struct stdio_redirect *, char *, size_t);
int bch2_stdio_redirect_readline(struct stdio_redirect *, char *, size_t);
int bch2_stdio_redirect_readline(struct stdio_redirect *, darray_char *);
__printf(3, 0) ssize_t bch2_stdio_redirect_vprintf(struct stdio_redirect *, bool, const char *, va_list); __printf(3, 0) ssize_t bch2_stdio_redirect_vprintf(struct stdio_redirect *, bool, const char *, va_list);
__printf(3, 4) ssize_t bch2_stdio_redirect_printf(struct stdio_redirect *, bool, const char *, ...); __printf(3, 4) ssize_t bch2_stdio_redirect_printf(struct stdio_redirect *, bool, const char *, ...);

View File

@ -8,6 +8,7 @@ struct stdio_buf {
spinlock_t lock; spinlock_t lock;
wait_queue_head_t wait; wait_queue_head_t wait;
darray_char buf; darray_char buf;
bool waiting_for_line;
}; };
struct stdio_redirect { struct stdio_redirect {