summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérôme Glisse <jglisse@redhat.com>2019-05-22 17:07:33 -0400
committerJérôme Glisse <jglisse@redhat.com>2019-05-22 18:13:37 -0400
commitd75863f39f3347614fa52b271e7c7449de17fd9c (patch)
tree7dde3ed9d646e5653c20477593ddc1d99216bfb8
parentfa407f97a91ced623dc522d7afbd6254dbc3d457 (diff)
fs/cifs: differentiate GUPed pages from iov_iter_get_pages*()
We want to handle differently pages that are coming from GUP (get_user_pages*()) as they will need to be release through new put_user_page() function and not with put_page(). Signed-off-by: Jérôme Glisse <jglisse@redhat.com> Cc: linux-fsdevel@vger.kernel.org Cc: linux-block@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-cifs@vger.kernel.org Cc: John Hubbard <jhubbard@nvidia.com> Cc: Jan Kara <jack@suse.cz> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Johannes Thumshirn <jthumshirn@suse.de> Cc: Christoph Hellwig <hch@lst.de> Cc: Jens Axboe <axboe@kernel.dk> Cc: Ming Lei <ming.lei@redhat.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Matthew Wilcox <willy@infradead.org> Cc: Boaz Harrosh <boaz@plexistor.com> Cc: Steve French <sfrench@samba.org>
-rw-r--r--fs/cifs/cifsglob.h3
-rw-r--r--fs/cifs/file.c22
-rw-r--r--fs/cifs/misc.c19
3 files changed, 35 insertions, 9 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 334ff5f9c3f3..07565f6b214d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1280,6 +1280,7 @@ struct cifs_aio_ctx {
* If yes, iter is a copy of the user passed iov_iter
*/
bool direct_io;
+ bool from_gup;
};
struct cifs_readdata;
@@ -1314,6 +1315,7 @@ struct cifs_readdata {
struct cifs_credits credits;
unsigned int nr_pages;
struct page **pages;
+ bool from_gup;
};
struct cifs_writedata;
@@ -1340,6 +1342,7 @@ struct cifs_writedata {
struct cifs_credits credits;
unsigned int nr_pages;
struct page **pages;
+ bool from_gup;
};
/*
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ce9a5be11df5..67077a53dd56 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2567,8 +2567,13 @@ cifs_uncached_writedata_release(struct kref *refcount)
struct cifs_writedata, refcount);
kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release);
- for (i = 0; i < wdata->nr_pages; i++)
- put_page(wdata->pages[i]);
+ if (wdata->from_gup) {
+ for (i = 0; i < wdata->nr_pages; i++)
+ put_user_page(wdata->pages[i]);
+ } else {
+ for (i = 0; i < wdata->nr_pages; i++)
+ put_page(wdata->pages[i]);
+ }
cifs_writedata_release(refcount);
}
@@ -2777,7 +2782,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
break;
}
-
+ wdata->from_gup = iov_iter_get_pages_use_gup(from);
wdata->page_offset = start;
wdata->tailsz =
nr_pages > 1 ?
@@ -2793,6 +2798,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
add_credits_and_wake_if(server, credits, 0);
break;
}
+ wdata->from_gup = false;
rc = cifs_write_allocate_pages(wdata->pages, nr_pages);
if (rc) {
@@ -3232,8 +3238,12 @@ cifs_uncached_readdata_release(struct kref *refcount)
unsigned int i;
kref_put(&rdata->ctx->refcount, cifs_aio_ctx_release);
- for (i = 0; i < rdata->nr_pages; i++) {
- put_page(rdata->pages[i]);
+ if (rdata->from_gup) {
+ for (i = 0; i < rdata->nr_pages; i++)
+ put_user_page(rdata->pages[i]);
+ } else {
+ for (i = 0; i < rdata->nr_pages; i++)
+ put_page(rdata->pages[i]);
}
cifs_readdata_release(refcount);
}
@@ -3496,6 +3506,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
break;
}
+ rdata->from_gup = iov_iter_get_pages_use_gup(&direct_iov);
npages = (cur_len + start + PAGE_SIZE-1) / PAGE_SIZE;
rdata->page_offset = start;
rdata->tailsz = npages > 1 ?
@@ -3513,6 +3524,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
rc = -ENOMEM;
break;
}
+ rdata->from_gup = false;
rc = cifs_read_allocate_pages(rdata, npages);
if (rc) {
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index b1a696a73f7c..aa55743bf164 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -821,10 +821,18 @@ cifs_aio_ctx_release(struct kref *refcount)
if (ctx->bv) {
unsigned i;
- for (i = 0; i < ctx->npages; i++) {
- if (ctx->should_dirty)
- set_page_dirty(ctx->bv[i].bv_page);
- put_page(ctx->bv[i].bv_page);
+ if (ctx->from_gup) {
+ for (i = 0; i < ctx->npages; i++) {
+ if (ctx->should_dirty)
+ set_page_dirty(ctx->bv[i].bv_page);
+ put_user_page(ctx->bv[i].bv_page);
+ }
+ } else {
+ for (i = 0; i < ctx->npages; i++) {
+ if (ctx->should_dirty)
+ set_page_dirty(ctx->bv[i].bv_page);
+ put_page(ctx->bv[i].bv_page);
+ }
}
kvfree(ctx->bv);
}
@@ -880,6 +888,9 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
saved_len = count;
+ /* This is only use by cifs_aio_ctx_release() */
+ ctx->from_gup = iov_iter_get_pages_use_gup(iter);
+
while (count && npages < max_pages) {
rc = iov_iter_get_pages(iter, pages, count, max_pages, &start);
if (rc < 0) {