aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/direct.c53
-rw-r--r--fs/nfs/pagelist.c20
-rw-r--r--fs/nfs/write.c6
-rw-r--r--include/linux/nfs_page.h1
4 files changed, 58 insertions, 22 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 345aa5c0f382..0c542ec92d5b 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -122,19 +122,25 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
122 return -EINVAL; 122 return -EINVAL;
123} 123}
124 124
125static void nfs_direct_dirty_pages(struct page **pages, int npages) 125static void nfs_direct_dirty_pages(struct page **pages, unsigned int pgbase, size_t count)
126{ 126{
127 int i; 127 unsigned int npages;
128 unsigned int i;
129
130 if (count == 0)
131 return;
132 pages += (pgbase >> PAGE_SHIFT);
133 npages = (count + (pgbase & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
128 for (i = 0; i < npages; i++) { 134 for (i = 0; i < npages; i++) {
129 struct page *page = pages[i]; 135 struct page *page = pages[i];
130 if (!PageCompound(page)) 136 if (!PageCompound(page))
131 set_page_dirty_lock(page); 137 set_page_dirty(page);
132 } 138 }
133} 139}
134 140
135static void nfs_direct_release_pages(struct page **pages, int npages) 141static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
136{ 142{
137 int i; 143 unsigned int i;
138 for (i = 0; i < npages; i++) 144 for (i = 0; i < npages; i++)
139 page_cache_release(pages[i]); 145 page_cache_release(pages[i]);
140} 146}
@@ -224,17 +230,18 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
224 if (nfs_readpage_result(task, data) != 0) 230 if (nfs_readpage_result(task, data) != 0)
225 return; 231 return;
226 232
227 nfs_direct_dirty_pages(data->pagevec, data->npages);
228 nfs_direct_release_pages(data->pagevec, data->npages);
229
230 spin_lock(&dreq->lock); 233 spin_lock(&dreq->lock);
231 234 if (unlikely(task->tk_status < 0)) {
232 if (likely(task->tk_status >= 0))
233 dreq->count += data->res.count;
234 else
235 dreq->error = task->tk_status; 235 dreq->error = task->tk_status;
236 236 spin_unlock(&dreq->lock);
237 spin_unlock(&dreq->lock); 237 } else {
238 dreq->count += data->res.count;
239 spin_unlock(&dreq->lock);
240 nfs_direct_dirty_pages(data->pagevec,
241 data->args.pgbase,
242 data->res.count);
243 }
244 nfs_direct_release_pages(data->pagevec, data->npages);
238 245
239 if (put_dreq(dreq)) 246 if (put_dreq(dreq))
240 nfs_direct_complete(dreq); 247 nfs_direct_complete(dreq);
@@ -279,9 +286,12 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
279 result = get_user_pages(current, current->mm, user_addr, 286 result = get_user_pages(current, current->mm, user_addr,
280 data->npages, 1, 0, data->pagevec, NULL); 287 data->npages, 1, 0, data->pagevec, NULL);
281 up_read(&current->mm->mmap_sem); 288 up_read(&current->mm->mmap_sem);
282 if (unlikely(result < data->npages)) { 289 if (result < 0) {
283 if (result > 0) 290 nfs_readdata_release(data);
284 nfs_direct_release_pages(data->pagevec, result); 291 break;
292 }
293 if ((unsigned)result < data->npages) {
294 nfs_direct_release_pages(data->pagevec, result);
285 nfs_readdata_release(data); 295 nfs_readdata_release(data);
286 break; 296 break;
287 } 297 }
@@ -610,9 +620,12 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
610 result = get_user_pages(current, current->mm, user_addr, 620 result = get_user_pages(current, current->mm, user_addr,
611 data->npages, 0, 0, data->pagevec, NULL); 621 data->npages, 0, 0, data->pagevec, NULL);
612 up_read(&current->mm->mmap_sem); 622 up_read(&current->mm->mmap_sem);
613 if (unlikely(result < data->npages)) { 623 if (result < 0) {
614 if (result > 0) 624 nfs_writedata_release(data);
615 nfs_direct_release_pages(data->pagevec, result); 625 break;
626 }
627 if ((unsigned)result < data->npages) {
628 nfs_direct_release_pages(data->pagevec, result);
616 nfs_writedata_release(data); 629 nfs_writedata_release(data);
617 break; 630 break;
618 } 631 }
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index cbdd1c6aaa94..c5bb51a29e80 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -355,6 +355,26 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
355 nfs_pageio_doio(desc); 355 nfs_pageio_doio(desc);
356} 356}
357 357
358/**
359 * nfs_pageio_cond_complete - Conditional I/O completion
360 * @desc: pointer to io descriptor
361 * @index: page index
362 *
363 * It is important to ensure that processes don't try to take locks
364 * on non-contiguous ranges of pages as that might deadlock. This
365 * function should be called before attempting to wait on a locked
366 * nfs_page. It will complete the I/O if the page index 'index'
367 * is not contiguous with the existing list of pages in 'desc'.
368 */
369void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
370{
371 if (!list_empty(&desc->pg_list)) {
372 struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
373 if (index != prev->wb_index + 1)
374 nfs_pageio_doio(desc);
375 }
376}
377
358#define NFS_SCAN_MAXENTRIES 16 378#define NFS_SCAN_MAXENTRIES 16
359/** 379/**
360 * nfs_scan_list - Scan a list for matching requests 380 * nfs_scan_list - Scan a list for matching requests
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b084c03ce493..af344a158e01 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -273,8 +273,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
273 * request as dirty (in which case we don't care). 273 * request as dirty (in which case we don't care).
274 */ 274 */
275 spin_unlock(req_lock); 275 spin_unlock(req_lock);
276 /* Prevent deadlock! */
277 nfs_pageio_complete(pgio);
278 ret = nfs_wait_on_request(req); 276 ret = nfs_wait_on_request(req);
279 nfs_release_request(req); 277 nfs_release_request(req);
280 if (ret != 0) 278 if (ret != 0)
@@ -321,6 +319,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
321 pgio = &mypgio; 319 pgio = &mypgio;
322 } 320 }
323 321
322 nfs_pageio_cond_complete(pgio, page->index);
323
324 err = nfs_page_async_flush(pgio, page); 324 err = nfs_page_async_flush(pgio, page);
325 if (err <= 0) 325 if (err <= 0)
326 goto out; 326 goto out;
@@ -329,6 +329,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
329 if (!offset) 329 if (!offset)
330 goto out; 330 goto out;
331 331
332 nfs_pageio_cond_complete(pgio, page->index);
333
332 ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); 334 ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
333 if (ctx == NULL) { 335 if (ctx == NULL) {
334 err = -EBADF; 336 err = -EBADF;
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 41afab6b5f09..bd193af80162 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -81,6 +81,7 @@ extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
81extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *, 81extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
82 struct nfs_page *); 82 struct nfs_page *);
83extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); 83extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
84extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t);
84extern int nfs_wait_on_request(struct nfs_page *); 85extern int nfs_wait_on_request(struct nfs_page *);
85extern void nfs_unlock_request(struct nfs_page *req); 86extern void nfs_unlock_request(struct nfs_page *req);
86extern int nfs_set_page_writeback_locked(struct nfs_page *req); 87extern int nfs_set_page_writeback_locked(struct nfs_page *req);