diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 1ff5a6b21db0bcdc0220cd32ec85904d9b2c1cf4..0ff26588335e79f26ba08d51d33c281001aa5b50 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -993,7 +993,17 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep, while (count) { if (cs->write && cs->pipebufs && page) { - return fuse_ref_page(cs, page, offset, count); + /* + * Can't control lifetime of pipe buffers, so always + * copy user pages. + */ + if (cs->req->in.user_pages) { + err = fuse_copy_fill(cs); + if (err) + return err; + } else { + return fuse_ref_page(cs, page, offset, count); + } } else if (!cs->len) { if (cs->move_pages && page && offset == 0 && count == PAGE_SIZE) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c1af038920dc5642127aafaf609d164be3683124..d90d91232dfe2740ec67b427b2e2541631169a08 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1320,10 +1320,12 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, (PAGE_SIZE - ret) & (PAGE_SIZE - 1); } - if (write) + if (write) { + req->in.user_pages = 1; req->in.argpages = 1; - else + } else { req->out.argpages = 1; + } *nbytesp = nbytes; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 853d37ec81e0c1ccefd9b86223d0eec1bbd09eeb..0981011c10c6e2f5c3ada577ebdaafc0f6c98d8f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -174,6 +174,11 @@ struct fuse_in { /** True if the data for the last argument is in req->pages */ unsigned argpages:1; +#ifndef __GENKSYMS__ + /** True if direct write */ + unsigned user_pages:1; +#endif + /** Number of arguments */ unsigned numargs;