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)
return YN_NO;
char buf[100];
darray_char line = {};
int ret;
do {
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);
if (r < 0)
return YN_NO;
buf[r] = '\0';
} while ((ret = parse_yn_response(buf)) < 0);
int r = bch2_stdio_redirect_readline(stdio, &line);
if (r < 0) {
ret = YN_NO;
break;
}
darray_last(line) = '\0';
} while ((ret = parse_yn_response(line.data)) < 0);
darray_exit(&line);
return ret;
}
#else

View file

@ -67,9 +67,14 @@ int bch2_run_thread_with_file(struct thread_with_file *thr,
/* 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)
{
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)
@ -181,9 +186,13 @@ static ssize_t thread_with_stdio_write(struct file *file, const char __user *ubu
}
spin_lock(&buf->lock);
if (buf->buf.nr < STDIO_REDIRECT_BUFSIZE)
darray_make_room_gfp(&buf->buf,
min(b, STDIO_REDIRECT_BUFSIZE - buf->buf.nr), GFP_NOWAIT);
size_t makeroom = b;
if (!buf->waiting_for_line || memchr(buf->buf.data, '\n', buf->buf.nr))
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));
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;
}
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;
size_t copied = 0;
ssize_t ret = 0;
size_t seen = 0;
again:
do {
wait_event_timeout(buf->wait, stdio_redirect_has_input(stdio),
sysctl_hung_task_timeout_secs * HZ / 2);
} while (!stdio_redirect_has_input(stdio));
wait_event_timeout(buf->wait, stdio_redirect_has_more_input(stdio, seen),
sysctl_hung_task_timeout_secs * HZ / 2);
if (stdio->done) {
ret = -1;
goto out;
}
if (stdio->done)
return -1;
spin_lock(&buf->lock);
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);
seen = buf->buf.nr;
char *n = memchr(buf->buf.data, '\n', seen);
if (!n) {
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;
memcpy(ubuf, buf->buf.data, b);
memcpy(line->data, buf->buf.data, b);
memmove(buf->buf.data,
buf->buf.data + b,
buf->buf.nr);
ubuf += b;
len -= b;
copied += b;
line->nr = b;
buf->waiting_for_line = false;
spin_unlock(&buf->lock);
wake_up(&buf->wait);
if (!n && len)
goto again;
out:
return copied ?: ret;
return 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 *,
const struct thread_with_stdio_ops *);
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, 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;
wait_queue_head_t wait;
darray_char buf;
bool waiting_for_line;
};
struct stdio_redirect {