diff options
author | Darrick J. Wong <djwong@kernel.org> | 2024-02-07 11:39:03 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-03-13 21:22:10 -0400 |
commit | 1cbae651e5c875f4d128211b3c732ee545f45424 (patch) | |
tree | 611bcce0b30736e2312cb8842f2da40223bf371e | |
parent | fcb1620edd4d59eff4b3466be1d61263cea958a8 (diff) | |
download | lwn-1cbae651e5c875f4d128211b3c732ee545f45424.tar.gz lwn-1cbae651e5c875f4d128211b3c732ee545f45424.zip |
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>
-rw-r--r-- | fs/bcachefs/thread_with_file.c | 53 | ||||
-rw-r--r-- | fs/bcachefs/thread_with_file.h | 4 |
2 files changed, 37 insertions, 20 deletions
diff --git a/fs/bcachefs/thread_with_file.c b/fs/bcachefs/thread_with_file.c index d1cd5f4ab06e..fc4f97c56021 100644 --- a/fs/bcachefs/thread_with_file.c +++ b/fs/bcachefs/thread_with_file.c @@ -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; - va_copy(args2, args); + 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 */ diff --git a/fs/bcachefs/thread_with_file.h b/fs/bcachefs/thread_with_file.h index 2b687723d6b9..e20f2d17ee59 100644 --- a/fs/bcachefs/thread_with_file.h +++ b/fs/bcachefs/thread_with_file.h @@ -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 */ |