summarylogtreecommitdiffstats
path: root/0001-Linux-4.14-compat-vfs_read-vfs_write.patch
blob: bf04af065d701af65f8310fe5f7cd0b5135f2671 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
From ed19bccfb651843fa208232b3a2d3d22a4152bc8 Mon Sep 17 00:00:00 2001
From: Brian Behlendorf <behlendorf1@llnl.gov>
Date: Wed, 15 Nov 2017 17:19:23 -0800
Subject: [PATCH] Linux 4.14 compat: vfs_read & vfs_write

The kernel_read & kernel_write functions have always wrapped the
vfs_read & vfs_write functions respectively.  However, they could
not be used by vn_rdwr() since the offset wasn't passed as a
pointer.  This prevented us from being able to properly update
the file offset.

Linux 4.14 unexported vfs_read & vfs_write but also changed the
signature of kernel_read & kernel_write to provide the needed
functionality.  Use these updated functions when available.

Reviewed-by: Pritam Baral <pritam@pritambaral.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #656
Closes #667
---
 config/spl-build.m4         | 60 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/file_compat.h | 41 +++++++++++++++++++++++++++++++
 module/spl/spl-vnode.c      | 21 +++-------------
 3 files changed, 105 insertions(+), 17 deletions(-)

diff --git a/config/spl-build.m4 b/config/spl-build.m4
index 8e9dc99..7b66f2c 100644
--- a/config/spl-build.m4
+++ b/config/spl-build.m4
@@ -52,6 +52,8 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
 	SPL_AC_KMEM_CACHE_CREATE_USERCOPY
 	SPL_AC_WAIT_QUEUE_ENTRY_T
 	SPL_AC_WAIT_QUEUE_HEAD_ENTRY
+	SPL_AC_KERNEL_WRITE
+	SPL_AC_KERNEL_READ
 ])
 
 AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
@@ -1594,3 +1596,61 @@ AC_DEFUN([SPL_AC_WAIT_QUEUE_HEAD_ENTRY], [
 		AC_MSG_RESULT(no)
 	])
 ])
+
+dnl #
+dnl # 4.14 API change
+dnl # kernel_write() which was introduced in 3.9 was updated to take
+dnl # the offset as a pointer which is needed by vn_rdwr().
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_WRITE], [
+	AC_MSG_CHECKING([whether kernel_write() takes loff_t pointer])
+	tmp_flags="$EXTRA_KCFLAGS"
+	EXTRA_KCFLAGS="-Werror"
+	SPL_LINUX_TRY_COMPILE([
+		#include <linux/fs.h>
+	],[
+		struct file *file = NULL;
+		const void *buf = NULL;
+		size_t count = 0;
+		loff_t *pos = NULL;
+		ssize_t ret;
+
+		ret = kernel_write(file, buf, count, pos);
+	],[
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(HAVE_KERNEL_WRITE_PPOS, 1,
+		    [kernel_write() take loff_t pointer])
+	],[
+		AC_MSG_RESULT(no)
+	])
+	EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 4.14 API change
+dnl # kernel_read() which has existed for forever was updated to take
+dnl # the offset as a pointer which is needed by vn_rdwr().
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_READ], [
+	AC_MSG_CHECKING([whether kernel_read() takes loff_t pointer])
+	tmp_flags="$EXTRA_KCFLAGS"
+	EXTRA_KCFLAGS="-Werror"
+	SPL_LINUX_TRY_COMPILE([
+		#include <linux/fs.h>
+	],[
+		struct file *file = NULL;
+		void *buf = NULL;
+		size_t count = 0;
+		loff_t *pos = NULL;
+		ssize_t ret;
+
+		ret = kernel_read(file, buf, count, pos);
+	],[
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(HAVE_KERNEL_READ_PPOS, 1,
+		    [kernel_read() take loff_t pointer])
+	],[
+		AC_MSG_RESULT(no)
+	])
+	EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/include/linux/file_compat.h b/include/linux/file_compat.h
index 7d61ba5..55ba2cc 100644
--- a/include/linux/file_compat.h
+++ b/include/linux/file_compat.h
@@ -26,6 +26,7 @@
 #define	_SPL_FILE_COMPAT_H
 
 #include <linux/fs.h>
+#include <linux/uaccess.h>
 #ifdef HAVE_FDTABLE_HEADER
 #include <linux/fdtable.h>
 #endif
@@ -70,6 +71,46 @@ spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len)
 	return (error);
 }
 
+static inline ssize_t
+spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
+{
+#if defined(HAVE_KERNEL_WRITE_PPOS)
+	return (kernel_write(file, buf, count, pos));
+#else
+	mm_segment_t saved_fs;
+	ssize_t ret;
+
+	saved_fs = get_fs();
+	set_fs(get_ds());
+
+	ret = vfs_write(file, (__force const char __user *)buf, count, pos);
+
+	set_fs(saved_fs);
+
+	return (ret);
+#endif
+}
+
+static inline ssize_t
+spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
+{
+#if defined(HAVE_KERNEL_READ_PPOS)
+	return (kernel_read(file, buf, count, pos));
+#else
+	mm_segment_t saved_fs;
+	ssize_t ret;
+
+	saved_fs = get_fs();
+	set_fs(get_ds());
+
+	ret = vfs_read(file, (void __user *)buf, count, pos);
+
+	set_fs(saved_fs);
+
+	return (ret);
+#endif
+}
+
 #ifdef HAVE_2ARGS_VFS_FSYNC
 #define	spl_filp_fsync(fp, sync)	vfs_fsync(fp, sync)
 #else
diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c
index 0e4c386..19b3b76 100644
--- a/module/spl/spl-vnode.c
+++ b/module/spl/spl-vnode.c
@@ -211,35 +211,22 @@ int
 vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
 	uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
 {
-	loff_t offset;
-	mm_segment_t saved_fs;
-	struct file *fp;
+	struct file *fp = vp->v_file;
+	loff_t offset = off;
 	int rc;
 
 	ASSERT(uio == UIO_WRITE || uio == UIO_READ);
-	ASSERT(vp);
-	ASSERT(vp->v_file);
 	ASSERT(seg == UIO_SYSSPACE);
 	ASSERT((ioflag & ~FAPPEND) == 0);
 
-	fp = vp->v_file;
-
-	offset = off;
 	if (ioflag & FAPPEND)
 		offset = fp->f_pos;
 
-	/* Writable user data segment must be briefly increased for this
-	 * process so we can use the user space read call paths to write
-	 * in to memory allocated by the kernel. */
-	saved_fs = get_fs();
-        set_fs(get_ds());
-
 	if (uio & UIO_WRITE)
-		rc = vfs_write(fp, addr, len, &offset);
+		rc = spl_kernel_write(fp, addr, len, &offset);
 	else
-		rc = vfs_read(fp, addr, len, &offset);
+		rc = spl_kernel_read(fp, addr, len, &offset);
 
-	set_fs(saved_fs);
 	fp->f_pos = offset;
 
 	if (rc < 0)
-- 
2.15.1