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:
parent
36008d5d01
commit
0c97c437e3
@ -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
|
||||
|
@ -67,9 +67,14 @@ err:
|
||||
|
||||
/* 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),
|
||||
wait_event_timeout(buf->wait, stdio_redirect_has_more_input(stdio, seen),
|
||||
sysctl_hung_task_timeout_secs * HZ / 2);
|
||||
} while (!stdio_redirect_has_input(stdio));
|
||||
|
||||
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)
|
||||
|
@ -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 *, ...);
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user