[rh7] fuse: allow kernel to access "direct_io" files

Submitted by Andrey Ryabinin on Sept. 26, 2019, 3:52 p.m.

Details

Message ID 20190926155258.24719-1-aryabinin@virtuozzo.com
State New
Series "fuse: allow kernel to access "direct_io" files"
Headers show

Commit Message

Andrey Ryabinin Sept. 26, 2019, 3:52 p.m.
From: Miklos Szeredi <mszeredi@suse.cz>

Allow the kernel read and write on "direct_io" files.  This is
necessary for nfs export and execute support.

The implementation is simple: if an access from the kernel is
detected, don't perform get_user_pages(), just use the kernel address
provided by the requester to copy from/to the userspace filesystem.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>

https://jira.sw.ru/browse/PSBM-97905
(cherry picked from commit f4975c67dd9ad8eb47a4c77af0521a2b16ee0197)
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 fs/fuse/file.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 344f35562bbe..ec8a0b07a5d6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1702,6 +1702,18 @@  static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
 			       size_t *nbytesp, int write)
 {
 	size_t nbytes = 0;  /* # bytes already packed in req */
+	/* Special case for kernel I/O: can copy directly into the buffer */
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		unsigned long user_addr = fuse_get_user_addr(ii);
+		size_t frag_size = fuse_get_frag_size(ii, *nbytesp);
+
+		if (write)
+			req->in.args[1].value = (void *) user_addr;
+		else
+			req->out.args[0].value = (void *) user_addr;
+
+		return 0;
+	}
 
 	while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
 		unsigned npages;

Comments

Evgenii Shatokhin Sept. 27, 2019, 11:18 a.m.
On 26.09.2019 18:52, Andrey Ryabinin wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Allow the kernel read and write on "direct_io" files.  This is
> necessary for nfs export and execute support.
> 
> The implementation is simple: if an access from the kernel is
> detected, don't perform get_user_pages(), just use the kernel address
> provided by the requester to copy from/to the userspace filesystem.
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> 
> https://jira.sw.ru/browse/PSBM-97905
> (cherry picked from commit f4975c67dd9ad8eb47a4c77af0521a2b16ee0197)
> Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
> ---
>   fs/fuse/file.c | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 344f35562bbe..ec8a0b07a5d6 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -1702,6 +1702,18 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
>   			       size_t *nbytesp, int write)
>   {
>   	size_t nbytes = 0;  /* # bytes already packed in req */
> +	/* Special case for kernel I/O: can copy directly into the buffer */
> +	if (segment_eq(get_fs(), KERNEL_DS)) {
> +		unsigned long user_addr = fuse_get_user_addr(ii);
> +		size_t frag_size = fuse_get_frag_size(ii, *nbytesp);

'frag_size' is not used here. Should it be removed?

> +
> +		if (write)
> +			req->in.args[1].value = (void *) user_addr;
> +		else
> +			req->out.args[0].value = (void *) user_addr;
> +
> +		return 0;
> +	}
>   
>   	while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
>   		unsigned npages;
>