bcachefs: thread_with_file: fix various printf problems

Experimentally fix some problems with stdio_redirect_vprintf by creating
a MOO variant with which we can experiment.  We can't do a GFP_KERNEL
allocation while holding the spinlock, and I don't like how the printf
function can silently truncate the output if memory allocation fails.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Darrick J. Wong 2024-02-07 11:39:03 -08:00 committed by Kent Overstreet
parent fcb1620edd
commit 1cbae651e5
2 changed files with 37 additions and 20 deletions

View File

@ -366,48 +366,65 @@ out:
}
__printf(3, 0)
static void bch2_darray_vprintf(darray_char *out, gfp_t gfp, const char *fmt, va_list args)
static ssize_t bch2_darray_vprintf(darray_char *out, gfp_t gfp, const char *fmt, va_list args)
{
size_t len;
ssize_t ret;
do {
va_list args2;
size_t len;
va_copy(args2, args);
len = vsnprintf(out->data + out->nr, darray_room(*out), fmt, args2);
} while (len + 1 > darray_room(*out) && !darray_make_room_gfp(out, len + 1, gfp));
if (len + 1 <= darray_room(*out)) {
out->nr += len;
return len;
}
out->nr += min(len, darray_room(*out));
ret = darray_make_room_gfp(out, len + 1, gfp);
} while (ret == 0);
return ret;
}
void bch2_stdio_redirect_vprintf(struct stdio_redirect *stdio, bool nonblocking,
const char *fmt, va_list args)
ssize_t bch2_stdio_redirect_vprintf(struct stdio_redirect *stdio, bool nonblocking,
const char *fmt, va_list args)
{
struct stdio_buf *buf = &stdio->output;
unsigned long flags;
ssize_t ret;
if (!nonblocking)
wait_event(buf->wait, stdio_redirect_has_output_space(stdio));
else if (!stdio_redirect_has_output_space(stdio))
return;
if (stdio->done)
return;
again:
spin_lock_irqsave(&buf->lock, flags);
bch2_darray_vprintf(&buf->buf, nonblocking ? GFP_NOWAIT : GFP_KERNEL, fmt, args);
ret = bch2_darray_vprintf(&buf->buf, GFP_NOWAIT, fmt, args);
spin_unlock_irqrestore(&buf->lock, flags);
if (ret < 0) {
if (nonblocking)
return -EAGAIN;
ret = wait_event_interruptible(buf->wait,
stdio_redirect_has_output_space(stdio));
if (ret)
return ret;
goto again;
}
wake_up(&buf->wait);
return ret;
}
void bch2_stdio_redirect_printf(struct stdio_redirect *stdio, bool nonblocking,
ssize_t bch2_stdio_redirect_printf(struct stdio_redirect *stdio, bool nonblocking,
const char *fmt, ...)
{
va_list args;
ssize_t ret;
va_start(args, fmt);
bch2_stdio_redirect_vprintf(stdio, nonblocking, fmt, args);
ret = bch2_stdio_redirect_vprintf(stdio, nonblocking, fmt, args);
va_end(args);
return ret;
}
#endif /* NO_BCACHEFS_FS */

View File

@ -65,7 +65,7 @@ int bch2_run_thread_with_stdout(struct thread_with_stdio *,
int bch2_stdio_redirect_read(struct stdio_redirect *, char *, size_t);
int bch2_stdio_redirect_readline(struct stdio_redirect *, char *, size_t);
__printf(3, 0) void bch2_stdio_redirect_vprintf(struct stdio_redirect *, bool, const char *, va_list);
__printf(3, 4) void bch2_stdio_redirect_printf(struct stdio_redirect *, bool, const 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 *, ...);
#endif /* _BCACHEFS_THREAD_WITH_FILE_H */