aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2024-02-07 11:39:03 -0800
committerKent Overstreet <kent.overstreet@linux.dev>2024-03-13 21:22:10 -0400
commit1cbae651e5c875f4d128211b3c732ee545f45424 (patch)
tree611bcce0b30736e2312cb8842f2da40223bf371e
parentfcb1620edd4d59eff4b3466be1d61263cea958a8 (diff)
downloadvfs-1cbae651e5c875f4d128211b3c732ee545f45424.tar.gz
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.c53
-rw-r--r--fs/bcachefs/thread_with_file.h4
2 files changed, 37 insertions, 20 deletions
diff --git a/fs/bcachefs/thread_with_file.c b/fs/bcachefs/thread_with_file.c
index d1cd5f4ab06ede..fc4f97c56021ac 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 2b687723d6b9b7..e20f2d17ee59d9 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 */