Commit 0c97c437 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 36008d5d
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -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
+42 −28
Original line number Diff line number Diff line
@@ -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),
	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)
+2 −1
Original line number Diff line number Diff line
@@ -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 *, ...);
+1 −0
Original line number Diff line number Diff line
@@ -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 {