diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-06-21 00:31:49 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-06-22 08:59:23 -0400 |
commit | c25d76bec84288b62e6f5484e9955f3201b7922b (patch) | |
tree | 1b06388a92cf551026f94b3386cee97c2d4f78be | |
parent | cea4c02f0fdb5c3b398de5bb33b14cab21dde088 (diff) |
bcachefs: fix bch2_dio_write_copy_iov() to check iov_iter type
iov_iter is a union type that can now iterate over _many_ different
sources of pages, we can't treat them all like they point to an iov.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/fs-io.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index 6d814164a4e9..f1588c4c03bc 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -2362,10 +2362,29 @@ static noinline bool bch2_dio_write_check_allocated(struct dio_write *dio) static void bch2_dio_write_loop_async(struct bch_write_op *); static __always_inline long bch2_dio_write_done(struct dio_write *dio); +/* + * We're going to return -EIOCBQUEUED, but we haven't finished consuming the + * iov_iter yet, so we need to stash a copy of the iovec: it might be on the + * caller's stack, we're not guaranteed that it will live for the duration of + * the IO: + */ static noinline int bch2_dio_write_copy_iov(struct dio_write *dio) { struct iovec *iov = dio->inline_vecs; + /* + * iov_iter has a single embedded iovec - nothing to do: + */ + if (iter_is_ubuf(&dio->iter)) + return 0; + + /* + * We don't currently handle non-iovec iov_iters here - return an error, + * and we'll fall back to doing the IO synchronously: + */ + if (!iter_is_iovec(&dio->iter)) + return -1; + if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) { iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov), GFP_KERNEL); |