Update pin_user_pages() calls for Direct I/O

Originally #16856 updated Linux Direct I/O requests to use the new
pin_user_pages API. However, it was an oversight that this PR only
handled iov_iter's of type ITER_IOVEC and ITER_UBUF. Other iov_iter
types may try and use the pin_user_pages API if it is available. This
can lead to panics as the iov_iter is not being iterated over correctly
in zfs_uio_pin_user_pages().

Unfortunately, generic iov_iter API's that call pin_user_page_fast() are
protected as GPL only. Rather than update zfs_uio_pin_user_pages() to
account for all iov_iter types, we can simply just call
zfs_uio_get_dio_page_iov_iter() if the iov_iter type is not ITER_IOVEC
or ITER_UBUF. zfs_uio_get_dio_page_iov_iter() calls the
iov_iter_get_pages() calls that can handle any iov_iter type.

In the future it might be worth using the exposed iov_iter iterator
functions that are included in the header iov_iter.h since v6.7. These
functions allow for any iov_iter type to be iterated over and advanced
while applying a step function during iteration. This could possibly be
leveraged in zfs_uio_pin_user_pages().

A new ZFS test case was added to test that a ITER_BVEC is handled
correctly using this new code path. This test case was provided though
issue #16956.

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ameer Hamza <ahamza@ixsystems.com>
Signed-off-by: Brian Atkinson <batkinson@lanl.gov>
Closes #16956 
Closes #17006
This commit is contained in:
Brian Atkinson
2025-01-30 18:53:59 -05:00
committed by Ameer Hamza
parent 6e9911212e
commit 0e21e473a7
6 changed files with 159 additions and 27 deletions
+10
View File
@@ -63,6 +63,7 @@ typedef enum zfs_uio_seg {
typedef struct {
struct page **pages; /* Mapped pages */
long npages; /* Number of mapped pages */
boolean_t pinned; /* Whether FOLL_PIN was used */
} zfs_uio_dio_t;
typedef struct zfs_uio {
@@ -199,4 +200,13 @@ zfs_uio_iov_iter_init(zfs_uio_t *uio, struct iov_iter *iter, offset_t offset,
#define zfs_uio_iov_iter_type(iter) (iter)->type
#endif
#if defined(HAVE_ITER_IS_UBUF)
#define zfs_user_backed_iov_iter(iter) \
(iter_is_ubuf((iter)) || \
(zfs_uio_iov_iter_type((iter)) == ITER_IOVEC))
#else
#define zfs_user_backed_iov_iter(iter) \
(zfs_uio_iov_iter_type((iter)) == ITER_IOVEC)
#endif
#endif /* SPL_UIO_H */