aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/direct.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index e4c9e03aff1..4cb3446220b 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -126,16 +126,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
126 return -EINVAL; 126 return -EINVAL;
127} 127}
128 128
129static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty) 129static void nfs_direct_dirty_pages(struct page **pages, int npages)
130{ 130{
131 int i; 131 int i;
132 for (i = 0; i < npages; i++) { 132 for (i = 0; i < npages; i++) {
133 struct page *page = pages[i]; 133 struct page *page = pages[i];
134 if (do_dirty && !PageCompound(page)) 134 if (!PageCompound(page))
135 set_page_dirty_lock(page); 135 set_page_dirty_lock(page);
136 page_cache_release(page);
137 } 136 }
138 kfree(pages); 137}
138
139static void nfs_direct_release_pages(struct page **pages, int npages)
140{
141 int i;
142 for (i = 0; i < npages; i++)
143 page_cache_release(pages[i]);
139} 144}
140 145
141static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages) 146static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
@@ -162,7 +167,7 @@ static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t siz
162 * end of a mapping; return EFAULT. 167 * end of a mapping; return EFAULT.
163 */ 168 */
164 if (result >= 0) { 169 if (result >= 0) {
165 nfs_free_user_pages(*pages, result, 0); 170 nfs_direct_release_pages(*pages, result);
166 result = -EFAULT; 171 result = -EFAULT;
167 } else 172 } else
168 kfree(*pages); 173 kfree(*pages);
@@ -238,8 +243,6 @@ out:
238 */ 243 */
239static void nfs_direct_complete(struct nfs_direct_req *dreq) 244static void nfs_direct_complete(struct nfs_direct_req *dreq)
240{ 245{
241 nfs_free_user_pages(dreq->pages, dreq->npages, 1);
242
243 if (dreq->iocb) { 246 if (dreq->iocb) {
244 long res = (long) dreq->error; 247 long res = (long) dreq->error;
245 if (!res) 248 if (!res)
@@ -311,8 +314,11 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
311 314
312 spin_unlock(&dreq->lock); 315 spin_unlock(&dreq->lock);
313 316
314 if (put_dreq(dreq)) 317 if (put_dreq(dreq)) {
318 nfs_direct_dirty_pages(dreq->pages, dreq->npages);
319 nfs_direct_release_pages(dreq->pages, dreq->npages);
315 nfs_direct_complete(dreq); 320 nfs_direct_complete(dreq);
321 }
316} 322}
317 323
318static const struct rpc_call_ops nfs_read_direct_ops = { 324static const struct rpc_call_ops nfs_read_direct_ops = {
@@ -422,6 +428,7 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
422 list_del(&data->pages); 428 list_del(&data->pages);
423 nfs_writedata_release(data); 429 nfs_writedata_release(data);
424 } 430 }
431 nfs_direct_release_pages(dreq->pages, dreq->npages);
425} 432}
426 433
427#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 434#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)