From: Jérôme Glisse <jglisse@xxxxxxxxxx> For pages that were retained via get_user_pages*(), release those pages via the new put_user_page*() routines, instead of via put_page(). This is part a tree-wide conversion, as described in commit fc1d8e7cca2d ("mm: introduce put_user_page*(), placeholder versions"). Signed-off-by: Jérôme Glisse <jglisse@xxxxxxxxxx> Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx> Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: linux-block@xxxxxxxxxxxxxxx Cc: linux-mm@xxxxxxxxx Cc: linux-cifs@xxxxxxxxxxxxxxx Cc: Jan Kara <jack@xxxxxxx> Cc: Dan Williams <dan.j.williams@xxxxxxxxx> Cc: Alexander Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Johannes Thumshirn <jthumshirn@xxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Jens Axboe <axboe@xxxxxxxxx> Cc: Ming Lei <ming.lei@xxxxxxxxxx> Cc: Dave Chinner <david@xxxxxxxxxxxxx> Cc: Jason Gunthorpe <jgg@xxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Cc: Boaz Harrosh <boaz@xxxxxxxxxxxxx> Cc: Steve French <sfrench@xxxxxxxxx> --- fs/cifs/cifsglob.h | 3 +++ fs/cifs/file.c | 22 +++++++++++++++++----- fs/cifs/misc.c | 19 +++++++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index fe610e7e3670..e95cb82bfa50 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1283,6 +1283,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; @@ -1317,6 +1318,7 @@ struct cifs_readdata { struct cifs_credits credits; unsigned int nr_pages; struct page **pages; + bool from_gup; }; struct cifs_writedata; @@ -1343,6 +1345,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 97090693d182..84fa7e0a578f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2571,8 +2571,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); } @@ -2781,7 +2786,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 ? @@ -2797,6 +2802,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) { @@ -3238,8 +3244,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); } @@ -3502,6 +3512,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 ? @@ -3519,6 +3530,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 f383877a6511..5a04c34fea05 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -822,10 +822,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); } @@ -881,6 +889,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) { -- 2.22.0