Skip to content

Commit 58bc86c

Browse files
committed
Linux 5.10 compat: use iov_iter in uio structure
As of the 5.10 kernel the generic splice compatibility code has been removed. All filesystems are now responsible for registering a ->splice_read and ->splice_write callback to support this operation. The good news is the VFS provided generic_file_splice_read() and iter_file_splice_write() callbacks can be used provided the ->iter_read and ->iter_write callback support pipes. However, this is currently not the case and only iovecs and bvecs (not pipes) are ever attached to the uio structure. This commit changes that by allowing full iov_iter structures to be attached to uios. Ever since the 4.9 kernel the iov_iter structure has supported iovecs, kvecs, bvevs, and pipes so it's desirable to pass the entire thing when possible. In conjunction with this the uio helper functions (i.e uiomove(), uiocopy(), etc) have been updated to understand the new UIO_ITER type. Note that using the kernel provided uio_iter interfaces allowed the existing Linux specific uio handling code to be simplified. When there's no longer a need to support kernel's older than 4.9, then it will be possible to remove the iovec and bvec members from the uio structure and always use a uio_iter. Until then we need to maintain all of the existing types for older kernels. Some additional refactoring and cleanup was included in this change: - Added checks to configure to detect available iov_iter interfaces. Some are available all the way back to the 3.10 kernel and are used when available. In particular, uio_prefaultpages() now always uses iov_iter_fault_in_readable() which is available for all supported kernels. - The unused UIO_USERISPACE type has been removed. It is no longer needed now that the uio_seg enum is platform specific. - Moved zfs_uio.c from the zcommon.ko module to the Linux specific platform code for the zfs.ko module. This gets it out of libzfs where it was never needed and keeps this Linux specific code out of the common sources. - Removed unnecessary O_APPEND handling from zfs_iter_write(), this is redundant and O_APPEND is already handled in zfs_write(); NOTE: Cleanly applying this kernel compatibility change required applying the following commits. This makes the change larger than it absolutely needs to be, but the resulting code matches what's in the branch branch. This is both more tested and makes it easier to apply any future backports in this area. 7cf4cd8 Remove incorrect assertion 783be69 Reduce confusion in zfs_write af5626a Return EFAULT at the end of zfs_write() when set cc1f85b Simplify offset and length limit in zfs_write 9585538 Const some unchanging variables in zfs_write 86e74dc Remove redundant oid parameter to update_pages b3d723f Factor uid, gid, and projid out of loop in zfs_write 3d40b65 Share zfs_fsync, zfs_read, zfs_write, et al between Linux and FreeBSD Reviewed-by: Colin Ian King <[email protected]> Reviewed-by: Tony Hutter <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #11351
1 parent 7cf4cd8 commit 58bc86c

File tree

16 files changed

+576
-321
lines changed

16 files changed

+576
-321
lines changed

config/kernel-vfs-iov_iter.m4

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
dnl #
2+
dnl # Check for available iov_iter functionality.
3+
dnl #
4+
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_IOV_ITER], [
5+
ZFS_LINUX_TEST_SRC([iov_iter_types], [
6+
#include <linux/fs.h>
7+
#include <linux/uio.h>
8+
],[
9+
int type __attribute__ ((unused)) =
10+
ITER_IOVEC | ITER_KVEC | ITER_BVEC | ITER_PIPE;
11+
])
12+
13+
ZFS_LINUX_TEST_SRC([iov_iter_init], [
14+
#include <linux/fs.h>
15+
#include <linux/uio.h>
16+
],[
17+
struct iov_iter iter = { 0 };
18+
struct iovec iov;
19+
unsigned long nr_segs = 1;
20+
size_t count = 1024;
21+
22+
iov_iter_init(&iter, WRITE, &iov, nr_segs, count);
23+
])
24+
25+
ZFS_LINUX_TEST_SRC([iov_iter_init_legacy], [
26+
#include <linux/fs.h>
27+
#include <linux/uio.h>
28+
],[
29+
struct iov_iter iter = { 0 };
30+
struct iovec iov;
31+
unsigned long nr_segs = 1;
32+
size_t count = 1024;
33+
size_t written = 0;
34+
35+
iov_iter_init(&iter, &iov, nr_segs, count, written);
36+
])
37+
38+
ZFS_LINUX_TEST_SRC([iov_iter_advance], [
39+
#include <linux/fs.h>
40+
#include <linux/uio.h>
41+
],[
42+
struct iov_iter iter = { 0 };
43+
size_t advance = 512;
44+
45+
iov_iter_advance(&iter, advance);
46+
])
47+
48+
ZFS_LINUX_TEST_SRC([iov_iter_revert], [
49+
#include <linux/fs.h>
50+
#include <linux/uio.h>
51+
],[
52+
struct iov_iter iter = { 0 };
53+
size_t revert = 512;
54+
55+
iov_iter_revert(&iter, revert);
56+
])
57+
58+
ZFS_LINUX_TEST_SRC([iov_iter_fault_in_readable], [
59+
#include <linux/fs.h>
60+
#include <linux/uio.h>
61+
],[
62+
struct iov_iter iter = { 0 };
63+
size_t size = 512;
64+
int error __attribute__ ((unused));
65+
66+
error = iov_iter_fault_in_readable(&iter, size);
67+
])
68+
69+
ZFS_LINUX_TEST_SRC([iov_iter_count], [
70+
#include <linux/fs.h>
71+
#include <linux/uio.h>
72+
],[
73+
struct iov_iter iter = { 0 };
74+
size_t bytes __attribute__ ((unused));
75+
76+
bytes = iov_iter_count(&iter);
77+
])
78+
79+
ZFS_LINUX_TEST_SRC([copy_to_iter], [
80+
#include <linux/fs.h>
81+
#include <linux/uio.h>
82+
],[
83+
struct iov_iter iter = { 0 };
84+
char buf[512] = { 0 };
85+
size_t size = 512;
86+
size_t bytes __attribute__ ((unused));
87+
88+
bytes = copy_to_iter((const void *)&buf, size, &iter);
89+
])
90+
91+
ZFS_LINUX_TEST_SRC([copy_from_iter], [
92+
#include <linux/fs.h>
93+
#include <linux/uio.h>
94+
],[
95+
struct iov_iter iter = { 0 };
96+
char buf[512] = { 0 };
97+
size_t size = 512;
98+
size_t bytes __attribute__ ((unused));
99+
100+
bytes = copy_from_iter((void *)&buf, size, &iter);
101+
])
102+
])
103+
104+
AC_DEFUN([ZFS_AC_KERNEL_VFS_IOV_ITER], [
105+
enable_vfs_iov_iter="yes"
106+
107+
AC_MSG_CHECKING([whether iov_iter types are available])
108+
ZFS_LINUX_TEST_RESULT([iov_iter_types], [
109+
AC_MSG_RESULT(yes)
110+
AC_DEFINE(HAVE_IOV_ITER_TYPES, 1,
111+
[iov_iter types are available])
112+
],[
113+
AC_MSG_RESULT(no)
114+
enable_vfs_iov_iter="no"
115+
])
116+
117+
dnl #
118+
dnl # 'iov_iter_init' available in Linux 3.16 and newer.
119+
dnl # 'iov_iter_init_legacy' available in Linux 3.15 and older.
120+
dnl #
121+
AC_MSG_CHECKING([whether iov_iter_init() is available])
122+
ZFS_LINUX_TEST_RESULT([iov_iter_init], [
123+
AC_MSG_RESULT(yes)
124+
AC_DEFINE(HAVE_IOV_ITER_INIT, 1,
125+
[iov_iter_init() is available])
126+
],[
127+
ZFS_LINUX_TEST_RESULT([iov_iter_init_legacy], [
128+
AC_MSG_RESULT(yes)
129+
AC_DEFINE(HAVE_IOV_ITER_INIT_LEGACY, 1,
130+
[iov_iter_init() is available])
131+
],[
132+
ZFS_LINUX_TEST_ERROR([iov_iter_init()])
133+
])
134+
])
135+
136+
AC_MSG_CHECKING([whether iov_iter_advance() is available])
137+
ZFS_LINUX_TEST_RESULT([iov_iter_advance], [
138+
AC_MSG_RESULT(yes)
139+
AC_DEFINE(HAVE_IOV_ITER_ADVANCE, 1,
140+
[iov_iter_advance() is available])
141+
],[
142+
AC_MSG_RESULT(no)
143+
enable_vfs_iov_iter="no"
144+
])
145+
146+
AC_MSG_CHECKING([whether iov_iter_revert() is available])
147+
ZFS_LINUX_TEST_RESULT([iov_iter_revert], [
148+
AC_MSG_RESULT(yes)
149+
AC_DEFINE(HAVE_IOV_ITER_REVERT, 1,
150+
[iov_iter_revert() is available])
151+
],[
152+
AC_MSG_RESULT(no)
153+
enable_vfs_iov_iter="no"
154+
])
155+
156+
AC_MSG_CHECKING([whether iov_iter_fault_in_readable() is available])
157+
ZFS_LINUX_TEST_RESULT([iov_iter_fault_in_readable], [
158+
AC_MSG_RESULT(yes)
159+
AC_DEFINE(HAVE_IOV_ITER_FAULT_IN_READABLE, 1,
160+
[iov_iter_fault_in_readable() is available])
161+
],[
162+
AC_MSG_RESULT(no)
163+
enable_vfs_iov_iter="no"
164+
])
165+
166+
AC_MSG_CHECKING([whether iov_iter_count() is available])
167+
ZFS_LINUX_TEST_RESULT([iov_iter_count], [
168+
AC_MSG_RESULT(yes)
169+
AC_DEFINE(HAVE_IOV_ITER_COUNT, 1,
170+
[iov_iter_count() is available])
171+
],[
172+
AC_MSG_RESULT(no)
173+
enable_vfs_iov_iter="no"
174+
])
175+
176+
AC_MSG_CHECKING([whether copy_to_iter() is available])
177+
ZFS_LINUX_TEST_RESULT([copy_to_iter], [
178+
AC_MSG_RESULT(yes)
179+
AC_DEFINE(HAVE_COPY_TO_ITER, 1,
180+
[copy_to_iter() is available])
181+
],[
182+
AC_MSG_RESULT(no)
183+
enable_vfs_iov_iter="no"
184+
])
185+
186+
AC_MSG_CHECKING([whether copy_from_iter() is available])
187+
ZFS_LINUX_TEST_RESULT([copy_from_iter], [
188+
AC_MSG_RESULT(yes)
189+
AC_DEFINE(HAVE_COPY_FROM_ITER, 1,
190+
[copy_from_iter() is available])
191+
],[
192+
AC_MSG_RESULT(no)
193+
enable_vfs_iov_iter="no"
194+
])
195+
196+
dnl #
197+
dnl # As of the 4.9 kernel support is provided for iovecs, kvecs,
198+
dnl # bvecs and pipes in the iov_iter structure. As long as the
199+
dnl # other support interfaces are all available the iov_iter can
200+
dnl # be correctly used in the uio structure.
201+
dnl #
202+
AS_IF([test "x$enable_vfs_iov_iter" = "xyes"], [
203+
AC_DEFINE(HAVE_VFS_IOV_ITER, 1,
204+
[All required iov_iter interfaces are available])
205+
])
206+
])

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
106106
ZFS_AC_KERNEL_SRC_VFS_DIRECT_IO
107107
ZFS_AC_KERNEL_SRC_VFS_RW_ITERATE
108108
ZFS_AC_KERNEL_SRC_VFS_GENERIC_WRITE_CHECKS
109+
ZFS_AC_KERNEL_SRC_VFS_IOV_ITER
109110
ZFS_AC_KERNEL_SRC_KMAP_ATOMIC_ARGS
110111
ZFS_AC_KERNEL_SRC_FOLLOW_DOWN_ONE
111112
ZFS_AC_KERNEL_SRC_MAKE_REQUEST_FN
@@ -203,6 +204,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
203204
ZFS_AC_KERNEL_VFS_DIRECT_IO
204205
ZFS_AC_KERNEL_VFS_RW_ITERATE
205206
ZFS_AC_KERNEL_VFS_GENERIC_WRITE_CHECKS
207+
ZFS_AC_KERNEL_VFS_IOV_ITER
206208
ZFS_AC_KERNEL_KMAP_ATOMIC_ARGS
207209
ZFS_AC_KERNEL_FOLLOW_DOWN_ONE
208210
ZFS_AC_KERNEL_MAKE_REQUEST_FN

include/os/linux/spl/sys/uio.h

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,19 @@ typedef enum uio_rw {
4444
typedef enum uio_seg {
4545
UIO_USERSPACE = 0,
4646
UIO_SYSSPACE = 1,
47-
UIO_USERISPACE = 2,
48-
UIO_BVEC = 3,
47+
UIO_BVEC = 2,
48+
#if defined(HAVE_VFS_IOV_ITER)
49+
UIO_ITER = 3,
50+
#endif
4951
} uio_seg_t;
5052

5153
typedef struct uio {
5254
union {
5355
const struct iovec *uio_iov;
5456
const struct bio_vec *uio_bvec;
57+
#if defined(HAVE_VFS_IOV_ITER)
58+
struct iov_iter *uio_iter;
59+
#endif
5560
};
5661
int uio_iovcnt;
5762
offset_t uio_loffset;
@@ -140,4 +145,65 @@ uio_index_at_offset(uio_t *uio, offset_t off, uint_t *vec_idx)
140145
return (off);
141146
}
142147

148+
static inline void
149+
iov_iter_init_compat(struct iov_iter *iter, unsigned int dir,
150+
const struct iovec *iov, unsigned long nr_segs, size_t count)
151+
{
152+
#if defined(HAVE_IOV_ITER_INIT)
153+
iov_iter_init(iter, dir, iov, nr_segs, count);
154+
#elif defined(HAVE_IOV_ITER_INIT_LEGACY)
155+
iov_iter_init(iter, iov, nr_segs, count, 0);
156+
#else
157+
#error "Unsupported kernel"
158+
#endif
159+
}
160+
161+
static inline void
162+
uio_iovec_init(uio_t *uio, const struct iovec *iov, unsigned long nr_segs,
163+
offset_t offset, uio_seg_t seg, ssize_t resid, size_t skip)
164+
{
165+
ASSERT(seg == UIO_USERSPACE || seg == UIO_SYSSPACE);
166+
167+
uio->uio_iov = iov;
168+
uio->uio_iovcnt = nr_segs;
169+
uio->uio_loffset = offset;
170+
uio->uio_segflg = seg;
171+
uio->uio_fault_disable = B_FALSE;
172+
uio->uio_fmode = 0;
173+
uio->uio_extflg = 0;
174+
uio->uio_resid = resid;
175+
uio->uio_skip = skip;
176+
}
177+
178+
static inline void
179+
uio_bvec_init(uio_t *uio, struct bio *bio)
180+
{
181+
uio->uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)];
182+
uio->uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio);
183+
uio->uio_loffset = BIO_BI_SECTOR(bio) << 9;
184+
uio->uio_segflg = UIO_BVEC;
185+
uio->uio_fault_disable = B_FALSE;
186+
uio->uio_fmode = 0;
187+
uio->uio_extflg = 0;
188+
uio->uio_resid = BIO_BI_SIZE(bio);
189+
uio->uio_skip = BIO_BI_SKIP(bio);
190+
}
191+
192+
#if defined(HAVE_VFS_IOV_ITER)
193+
static inline void
194+
uio_iov_iter_init(uio_t *uio, struct iov_iter *iter, offset_t offset,
195+
ssize_t resid, size_t skip)
196+
{
197+
uio->uio_iter = iter;
198+
uio->uio_iovcnt = iter->nr_segs;
199+
uio->uio_loffset = offset;
200+
uio->uio_segflg = UIO_ITER;
201+
uio->uio_fault_disable = B_FALSE;
202+
uio->uio_fmode = 0;
203+
uio->uio_extflg = 0;
204+
uio->uio_resid = resid;
205+
uio->uio_skip = skip;
206+
}
207+
#endif
208+
143209
#endif /* SPL_UIO_H */

include/os/linux/zfs/sys/zpl.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,6 @@ extern const struct inode_operations zpl_dir_inode_operations;
4646
extern const struct inode_operations zpl_symlink_inode_operations;
4747
extern const struct inode_operations zpl_special_inode_operations;
4848
extern dentry_operations_t zpl_dentry_operations;
49-
50-
/* zpl_file.c */
51-
extern ssize_t zpl_read_common(struct inode *ip, const char *buf,
52-
size_t len, loff_t *ppos, uio_seg_t segment, int flags,
53-
cred_t *cr);
54-
extern ssize_t zpl_write_common(struct inode *ip, const char *buf,
55-
size_t len, loff_t *ppos, uio_seg_t segment, int flags,
56-
cred_t *cr);
57-
5849
extern const struct address_space_operations zpl_address_space_operations;
5950
extern const struct file_operations zpl_file_operations;
6051
extern const struct file_operations zpl_dir_file_operations;

lib/libspl/include/sys/uio.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ typedef enum uio_rw {
5959
typedef enum uio_seg {
6060
UIO_USERSPACE = 0,
6161
UIO_SYSSPACE = 1,
62-
UIO_USERISPACE = 2,
6362
} uio_seg_t;
6463

6564
#elif defined(__FreeBSD__)

lib/libzfs/Makefile.am

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ KERNEL_C = \
6161
zfs_fletcher_superscalar4.c \
6262
zfs_namecheck.c \
6363
zfs_prop.c \
64-
zfs_uio.c \
6564
zpool_prop.c \
6665
zprop_common.c
6766

lib/libzpool/Makefile.am

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ KERNEL_C = \
4747
zfs_fletcher_superscalar4.c \
4848
zfs_namecheck.c \
4949
zfs_prop.c \
50-
zfs_uio.c \
5150
zpool_prop.c \
5251
zprop_common.c \
5352
abd.c \

module/os/linux/zfs/Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ $(MODULE)-objs += ../os/linux/zfs/zfs_dir.o
2323
$(MODULE)-objs += ../os/linux/zfs/zfs_file_os.o
2424
$(MODULE)-objs += ../os/linux/zfs/zfs_ioctl_os.o
2525
$(MODULE)-objs += ../os/linux/zfs/zfs_sysfs.o
26+
$(MODULE)-objs += ../os/linux/zfs/zfs_uio.o
2627
$(MODULE)-objs += ../os/linux/zfs/zfs_vfsops.o
2728
$(MODULE)-objs += ../os/linux/zfs/zfs_vnops_os.o
2829
$(MODULE)-objs += ../os/linux/zfs/zfs_znode.o

0 commit comments

Comments
 (0)