diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 8a98ffd5e4b67500d76e94fde34e790e5cac6408..bd5293e01e48695fb52bf9998b012f7f58b1c833 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -999,7 +999,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 5ecabacabd47757203f8f01d17b6623abfeb15d1..8d238d965db17b6da66bbf5824e0625f0399d515 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1321,10 +1321,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..27f3b6d4f11c0a683aa65c4b9a993adb4c586930 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -174,6 +174,9 @@ struct fuse_in { /** True if the data for the last argument is in req->pages */ unsigned argpages:1; + /** True if direct write */ + unsigned user_pages:1; + /** Number of arguments */ unsigned numargs;