Commit 7933dd87 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Sasha Levin

fuse: direct-io: don't dirty ITER_BVEC pages

[ Upstream commit 8fba54ae ]

When reading from a loop device backed by a fuse file it deadlocks on
lock_page().

This is because the page is already locked by the read() operation done on
the loop device.  In this case we don't want to either lock the page or
dirty it.

So do what fs/direct-io.c does: only dirty the page for ITER_IOVEC vectors.
Reported-by: default avatarSheng Yang <sheng@yasker.org>
Fixes: aa4d8616 ("block: loop: switch to VFS ITER_BVEC")
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Cc: <stable@vger.kernel.org> # v4.1+
Reviewed-by: default avatarSheng Yang <sheng@yasker.org>
Reviewed-by: default avatarAshish Samant <ashish.samant@oracle.com>
Tested-by: default avatarSheng Yang <sheng@yasker.org>
Tested-by: default avatarAshish Samant <ashish.samant@oracle.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent bb5c68e0
...@@ -540,13 +540,13 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, ...@@ -540,13 +540,13 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
req->out.args[0].size = count; req->out.args[0].size = count;
} }
static void fuse_release_user_pages(struct fuse_req *req, int write) static void fuse_release_user_pages(struct fuse_req *req, bool should_dirty)
{ {
unsigned i; unsigned i;
for (i = 0; i < req->num_pages; i++) { for (i = 0; i < req->num_pages; i++) {
struct page *page = req->pages[i]; struct page *page = req->pages[i];
if (write) if (should_dirty)
set_page_dirty_lock(page); set_page_dirty_lock(page);
put_page(page); put_page(page);
} }
...@@ -1331,6 +1331,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, ...@@ -1331,6 +1331,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
loff_t *ppos, int flags) loff_t *ppos, int flags)
{ {
int write = flags & FUSE_DIO_WRITE; int write = flags & FUSE_DIO_WRITE;
bool should_dirty = !write && iter_is_iovec(iter);
int cuse = flags & FUSE_DIO_CUSE; int cuse = flags & FUSE_DIO_CUSE;
struct file *file = io->file; struct file *file = io->file;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
...@@ -1375,7 +1376,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, ...@@ -1375,7 +1376,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
nres = fuse_send_read(req, io, pos, nbytes, owner); nres = fuse_send_read(req, io, pos, nbytes, owner);
if (!io->async) if (!io->async)
fuse_release_user_pages(req, !write); fuse_release_user_pages(req, should_dirty);
if (req->out.h.error) { if (req->out.h.error) {
if (!res) if (!res)
res = req->out.h.error; res = req->out.h.error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment