diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/clntproc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 2 | ||||
-rw-r--r-- | fs/nfs/direct.c | 6 | ||||
-rw-r--r-- | fs/nfs/file.c | 28 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/internal.h | 18 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 52 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 99 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 67 | ||||
-rw-r--r-- | fs/nfs/proc.c | 31 | ||||
-rw-r--r-- | fs/nfs/read.c | 179 | ||||
-rw-r--r-- | fs/nfs/symlink.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 598 |
14 files changed, 474 insertions, 614 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 50643b6a5556..497c3cd59d52 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -730,7 +730,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) | |||
730 | goto retry_cancel; | 730 | goto retry_cancel; |
731 | } | 731 | } |
732 | 732 | ||
733 | dprintk("lockd: cancel status %d (task %d)\n", | 733 | dprintk("lockd: cancel status %u (task %u)\n", |
734 | req->a_res.status, task->tk_pid); | 734 | req->a_res.status, task->tk_pid); |
735 | 735 | ||
736 | switch (req->a_res.status) { | 736 | switch (req->a_res.status) { |
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 0ce5c81ff507..f67146a8199a 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -234,7 +234,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
234 | */ | 234 | */ |
235 | static void nlm4svc_callback_exit(struct rpc_task *task, void *data) | 235 | static void nlm4svc_callback_exit(struct rpc_task *task, void *data) |
236 | { | 236 | { |
237 | dprintk("lockd: %4d callback returned %d\n", task->tk_pid, | 237 | dprintk("lockd: %5u callback returned %d\n", task->tk_pid, |
238 | -task->tk_status); | 238 | -task->tk_status); |
239 | } | 239 | } |
240 | 240 | ||
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 32e99a6e8dca..3707c3a23e93 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -263,7 +263,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
263 | */ | 263 | */ |
264 | static void nlmsvc_callback_exit(struct rpc_task *task, void *data) | 264 | static void nlmsvc_callback_exit(struct rpc_task *task, void *data) |
265 | { | 265 | { |
266 | dprintk("lockd: %4d callback returned %d\n", task->tk_pid, | 266 | dprintk("lockd: %5u callback returned %d\n", task->tk_pid, |
267 | -task->tk_status); | 267 | -task->tk_status); |
268 | } | 268 | } |
269 | 269 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 2f488e1d9b6c..f9d678f4ae06 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -307,9 +307,7 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
307 | 307 | ||
308 | data->task.tk_cookie = (unsigned long) inode; | 308 | data->task.tk_cookie = (unsigned long) inode; |
309 | 309 | ||
310 | lock_kernel(); | ||
311 | rpc_execute(&data->task); | 310 | rpc_execute(&data->task); |
312 | unlock_kernel(); | ||
313 | 311 | ||
314 | dfprintk(VFS, "NFS: %5u initiated direct read call (req %s/%Ld, %zu bytes @ offset %Lu)\n", | 312 | dfprintk(VFS, "NFS: %5u initiated direct read call (req %s/%Ld, %zu bytes @ offset %Lu)\n", |
315 | data->task.tk_pid, | 313 | data->task.tk_pid, |
@@ -475,9 +473,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
475 | 473 | ||
476 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 474 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
477 | 475 | ||
478 | lock_kernel(); | ||
479 | rpc_execute(&data->task); | 476 | rpc_execute(&data->task); |
480 | unlock_kernel(); | ||
481 | } | 477 | } |
482 | 478 | ||
483 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) | 479 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
@@ -641,9 +637,7 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
641 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 637 | data->task.tk_priority = RPC_PRIORITY_NORMAL; |
642 | data->task.tk_cookie = (unsigned long) inode; | 638 | data->task.tk_cookie = (unsigned long) inode; |
643 | 639 | ||
644 | lock_kernel(); | ||
645 | rpc_execute(&data->task); | 640 | rpc_execute(&data->task); |
646 | unlock_kernel(); | ||
647 | 641 | ||
648 | dfprintk(VFS, "NFS: %5u initiated direct write call (req %s/%Ld, %zu bytes @ offset %Lu)\n", | 642 | dfprintk(VFS, "NFS: %5u initiated direct write call (req %s/%Ld, %zu bytes @ offset %Lu)\n", |
649 | data->task.tk_pid, | 643 | data->task.tk_pid, |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index cc93865cea93..8e28bffc35a0 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -307,28 +307,28 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse | |||
307 | 307 | ||
308 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 308 | static void nfs_invalidate_page(struct page *page, unsigned long offset) |
309 | { | 309 | { |
310 | struct inode *inode = page->mapping->host; | 310 | if (offset != 0) |
311 | 311 | return; | |
312 | /* Cancel any unstarted writes on this page */ | 312 | /* Cancel any unstarted writes on this page */ |
313 | if (offset == 0) | 313 | nfs_wb_page_priority(page->mapping->host, page, FLUSH_INVALIDATE); |
314 | nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE); | ||
315 | } | 314 | } |
316 | 315 | ||
317 | static int nfs_release_page(struct page *page, gfp_t gfp) | 316 | static int nfs_release_page(struct page *page, gfp_t gfp) |
318 | { | 317 | { |
319 | if (gfp & __GFP_FS) | 318 | /* |
320 | return !nfs_wb_page(page->mapping->host, page); | 319 | * Avoid deadlock on nfs_wait_on_request(). |
321 | else | 320 | */ |
322 | /* | 321 | if (!(gfp & __GFP_FS)) |
323 | * Avoid deadlock on nfs_wait_on_request(). | ||
324 | */ | ||
325 | return 0; | 322 | return 0; |
323 | /* Hack... Force nfs_wb_page() to write out the page */ | ||
324 | SetPageDirty(page); | ||
325 | return !nfs_wb_page(page->mapping->host, page); | ||
326 | } | 326 | } |
327 | 327 | ||
328 | const struct address_space_operations nfs_file_aops = { | 328 | const struct address_space_operations nfs_file_aops = { |
329 | .readpage = nfs_readpage, | 329 | .readpage = nfs_readpage, |
330 | .readpages = nfs_readpages, | 330 | .readpages = nfs_readpages, |
331 | .set_page_dirty = __set_page_dirty_nobuffers, | 331 | .set_page_dirty = nfs_set_page_dirty, |
332 | .writepage = nfs_writepage, | 332 | .writepage = nfs_writepage, |
333 | .writepages = nfs_writepages, | 333 | .writepages = nfs_writepages, |
334 | .prepare_write = nfs_prepare_write, | 334 | .prepare_write = nfs_prepare_write, |
@@ -375,6 +375,12 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
375 | 375 | ||
376 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | 376 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); |
377 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); | 377 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); |
378 | /* Return error values for O_SYNC and IS_SYNC() */ | ||
379 | if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) { | ||
380 | int err = nfs_fsync(iocb->ki_filp, dentry, 1); | ||
381 | if (err < 0) | ||
382 | result = err; | ||
383 | } | ||
378 | out: | 384 | out: |
379 | return result; | 385 | return result; |
380 | 386 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 15afa460e629..36680d1061b0 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -422,7 +422,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
422 | int err; | 422 | int err; |
423 | 423 | ||
424 | /* Flush out writes to the server in order to update c/mtime */ | 424 | /* Flush out writes to the server in order to update c/mtime */ |
425 | nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT); | 425 | nfs_sync_mapping_range(inode->i_mapping, 0, 0, FLUSH_NOCOMMIT); |
426 | 426 | ||
427 | /* | 427 | /* |
428 | * We may force a getattr if the user cares about atime. | 428 | * We may force a getattr if the user cares about atime. |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index d205466233f6..a28f6ce2e131 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -217,3 +217,21 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize) | |||
217 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) | 217 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) |
218 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 218 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
219 | } | 219 | } |
220 | |||
221 | /* | ||
222 | * Determine the number of bytes of data the page contains | ||
223 | */ | ||
224 | static inline | ||
225 | unsigned int nfs_page_length(struct page *page) | ||
226 | { | ||
227 | loff_t i_size = i_size_read(page->mapping->host); | ||
228 | |||
229 | if (i_size > 0) { | ||
230 | pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; | ||
231 | if (page->index < end_index) | ||
232 | return PAGE_CACHE_SIZE; | ||
233 | if (page->index == end_index) | ||
234 | return ((i_size - 1) & ~PAGE_CACHE_MASK) + 1; | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index e5f128ffc32d..510ae524f3fd 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -276,51 +276,6 @@ static int nfs3_proc_read(struct nfs_read_data *rdata) | |||
276 | return status; | 276 | return status; |
277 | } | 277 | } |
278 | 278 | ||
279 | static int nfs3_proc_write(struct nfs_write_data *wdata) | ||
280 | { | ||
281 | int rpcflags = wdata->flags; | ||
282 | struct inode * inode = wdata->inode; | ||
283 | struct nfs_fattr * fattr = wdata->res.fattr; | ||
284 | struct rpc_message msg = { | ||
285 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], | ||
286 | .rpc_argp = &wdata->args, | ||
287 | .rpc_resp = &wdata->res, | ||
288 | .rpc_cred = wdata->cred, | ||
289 | }; | ||
290 | int status; | ||
291 | |||
292 | dprintk("NFS call write %d @ %Ld\n", wdata->args.count, | ||
293 | (long long) wdata->args.offset); | ||
294 | nfs_fattr_init(fattr); | ||
295 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); | ||
296 | if (status >= 0) | ||
297 | nfs_post_op_update_inode(inode, fattr); | ||
298 | dprintk("NFS reply write: %d\n", status); | ||
299 | return status < 0? status : wdata->res.count; | ||
300 | } | ||
301 | |||
302 | static int nfs3_proc_commit(struct nfs_write_data *cdata) | ||
303 | { | ||
304 | struct inode * inode = cdata->inode; | ||
305 | struct nfs_fattr * fattr = cdata->res.fattr; | ||
306 | struct rpc_message msg = { | ||
307 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], | ||
308 | .rpc_argp = &cdata->args, | ||
309 | .rpc_resp = &cdata->res, | ||
310 | .rpc_cred = cdata->cred, | ||
311 | }; | ||
312 | int status; | ||
313 | |||
314 | dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, | ||
315 | (long long) cdata->args.offset); | ||
316 | nfs_fattr_init(fattr); | ||
317 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | ||
318 | if (status >= 0) | ||
319 | nfs_post_op_update_inode(inode, fattr); | ||
320 | dprintk("NFS reply commit: %d\n", status); | ||
321 | return status; | ||
322 | } | ||
323 | |||
324 | /* | 279 | /* |
325 | * Create a regular file. | 280 | * Create a regular file. |
326 | * For now, we don't implement O_EXCL. | 281 | * For now, we don't implement O_EXCL. |
@@ -369,7 +324,7 @@ again: | |||
369 | 324 | ||
370 | /* If the server doesn't support the exclusive creation semantics, | 325 | /* If the server doesn't support the exclusive creation semantics, |
371 | * try again with simple 'guarded' mode. */ | 326 | * try again with simple 'guarded' mode. */ |
372 | if (status == NFSERR_NOTSUPP) { | 327 | if (status == -ENOTSUPP) { |
373 | switch (arg.createmode) { | 328 | switch (arg.createmode) { |
374 | case NFS3_CREATE_EXCLUSIVE: | 329 | case NFS3_CREATE_EXCLUSIVE: |
375 | arg.createmode = NFS3_CREATE_GUARDED; | 330 | arg.createmode = NFS3_CREATE_GUARDED; |
@@ -690,8 +645,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
690 | }; | 645 | }; |
691 | int status; | 646 | int status; |
692 | 647 | ||
693 | lock_kernel(); | ||
694 | |||
695 | if (plus) | 648 | if (plus) |
696 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; | 649 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; |
697 | 650 | ||
@@ -702,7 +655,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
702 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 655 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
703 | nfs_refresh_inode(dir, &dir_attr); | 656 | nfs_refresh_inode(dir, &dir_attr); |
704 | dprintk("NFS reply readdir: %d\n", status); | 657 | dprintk("NFS reply readdir: %d\n", status); |
705 | unlock_kernel(); | ||
706 | return status; | 658 | return status; |
707 | } | 659 | } |
708 | 660 | ||
@@ -904,8 +856,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
904 | .access = nfs3_proc_access, | 856 | .access = nfs3_proc_access, |
905 | .readlink = nfs3_proc_readlink, | 857 | .readlink = nfs3_proc_readlink, |
906 | .read = nfs3_proc_read, | 858 | .read = nfs3_proc_read, |
907 | .write = nfs3_proc_write, | ||
908 | .commit = nfs3_proc_commit, | ||
909 | .create = nfs3_proc_create, | 859 | .create = nfs3_proc_create, |
910 | .remove = nfs3_proc_remove, | 860 | .remove = nfs3_proc_remove, |
911 | .unlink_setup = nfs3_proc_unlink_setup, | 861 | .unlink_setup = nfs3_proc_unlink_setup, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8118036cc449..ee458aeab24a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -636,7 +636,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
636 | smp_wmb(); | 636 | smp_wmb(); |
637 | } else | 637 | } else |
638 | status = data->rpc_status; | 638 | status = data->rpc_status; |
639 | rpc_release_task(task); | 639 | rpc_put_task(task); |
640 | return status; | 640 | return status; |
641 | } | 641 | } |
642 | 642 | ||
@@ -742,7 +742,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
742 | smp_wmb(); | 742 | smp_wmb(); |
743 | } else | 743 | } else |
744 | status = data->rpc_status; | 744 | status = data->rpc_status; |
745 | rpc_release_task(task); | 745 | rpc_put_task(task); |
746 | if (status != 0) | 746 | if (status != 0) |
747 | return status; | 747 | return status; |
748 | 748 | ||
@@ -1775,89 +1775,6 @@ static int nfs4_proc_read(struct nfs_read_data *rdata) | |||
1775 | return err; | 1775 | return err; |
1776 | } | 1776 | } |
1777 | 1777 | ||
1778 | static int _nfs4_proc_write(struct nfs_write_data *wdata) | ||
1779 | { | ||
1780 | int rpcflags = wdata->flags; | ||
1781 | struct inode *inode = wdata->inode; | ||
1782 | struct nfs_fattr *fattr = wdata->res.fattr; | ||
1783 | struct nfs_server *server = NFS_SERVER(inode); | ||
1784 | struct rpc_message msg = { | ||
1785 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], | ||
1786 | .rpc_argp = &wdata->args, | ||
1787 | .rpc_resp = &wdata->res, | ||
1788 | .rpc_cred = wdata->cred, | ||
1789 | }; | ||
1790 | int status; | ||
1791 | |||
1792 | dprintk("NFS call write %d @ %Ld\n", wdata->args.count, | ||
1793 | (long long) wdata->args.offset); | ||
1794 | |||
1795 | wdata->args.bitmask = server->attr_bitmask; | ||
1796 | wdata->res.server = server; | ||
1797 | wdata->timestamp = jiffies; | ||
1798 | nfs_fattr_init(fattr); | ||
1799 | status = rpc_call_sync(server->client, &msg, rpcflags); | ||
1800 | dprintk("NFS reply write: %d\n", status); | ||
1801 | if (status < 0) | ||
1802 | return status; | ||
1803 | renew_lease(server, wdata->timestamp); | ||
1804 | nfs_post_op_update_inode(inode, fattr); | ||
1805 | return wdata->res.count; | ||
1806 | } | ||
1807 | |||
1808 | static int nfs4_proc_write(struct nfs_write_data *wdata) | ||
1809 | { | ||
1810 | struct nfs4_exception exception = { }; | ||
1811 | int err; | ||
1812 | do { | ||
1813 | err = nfs4_handle_exception(NFS_SERVER(wdata->inode), | ||
1814 | _nfs4_proc_write(wdata), | ||
1815 | &exception); | ||
1816 | } while (exception.retry); | ||
1817 | return err; | ||
1818 | } | ||
1819 | |||
1820 | static int _nfs4_proc_commit(struct nfs_write_data *cdata) | ||
1821 | { | ||
1822 | struct inode *inode = cdata->inode; | ||
1823 | struct nfs_fattr *fattr = cdata->res.fattr; | ||
1824 | struct nfs_server *server = NFS_SERVER(inode); | ||
1825 | struct rpc_message msg = { | ||
1826 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | ||
1827 | .rpc_argp = &cdata->args, | ||
1828 | .rpc_resp = &cdata->res, | ||
1829 | .rpc_cred = cdata->cred, | ||
1830 | }; | ||
1831 | int status; | ||
1832 | |||
1833 | dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, | ||
1834 | (long long) cdata->args.offset); | ||
1835 | |||
1836 | cdata->args.bitmask = server->attr_bitmask; | ||
1837 | cdata->res.server = server; | ||
1838 | cdata->timestamp = jiffies; | ||
1839 | nfs_fattr_init(fattr); | ||
1840 | status = rpc_call_sync(server->client, &msg, 0); | ||
1841 | if (status >= 0) | ||
1842 | renew_lease(server, cdata->timestamp); | ||
1843 | dprintk("NFS reply commit: %d\n", status); | ||
1844 | if (status >= 0) | ||
1845 | nfs_post_op_update_inode(inode, fattr); | ||
1846 | return status; | ||
1847 | } | ||
1848 | |||
1849 | static int nfs4_proc_commit(struct nfs_write_data *cdata) | ||
1850 | { | ||
1851 | struct nfs4_exception exception = { }; | ||
1852 | int err; | ||
1853 | do { | ||
1854 | err = nfs4_handle_exception(NFS_SERVER(cdata->inode), | ||
1855 | _nfs4_proc_commit(cdata), | ||
1856 | &exception); | ||
1857 | } while (exception.retry); | ||
1858 | return err; | ||
1859 | } | ||
1860 | |||
1861 | /* | 1778 | /* |
1862 | * Got race? | 1779 | * Got race? |
1863 | * We will need to arrange for the VFS layer to provide an atomic open. | 1780 | * We will need to arrange for the VFS layer to provide an atomic open. |
@@ -2223,13 +2140,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2223 | dentry->d_parent->d_name.name, | 2140 | dentry->d_parent->d_name.name, |
2224 | dentry->d_name.name, | 2141 | dentry->d_name.name, |
2225 | (unsigned long long)cookie); | 2142 | (unsigned long long)cookie); |
2226 | lock_kernel(); | ||
2227 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2143 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2228 | res.pgbase = args.pgbase; | 2144 | res.pgbase = args.pgbase; |
2229 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2145 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
2230 | if (status == 0) | 2146 | if (status == 0) |
2231 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2147 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2232 | unlock_kernel(); | ||
2233 | dprintk("%s: returns %d\n", __FUNCTION__, status); | 2148 | dprintk("%s: returns %d\n", __FUNCTION__, status); |
2234 | return status; | 2149 | return status; |
2235 | } | 2150 | } |
@@ -3067,7 +2982,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3067 | if (status == 0) | 2982 | if (status == 0) |
3068 | nfs_post_op_update_inode(inode, &data->fattr); | 2983 | nfs_post_op_update_inode(inode, &data->fattr); |
3069 | } | 2984 | } |
3070 | rpc_release_task(task); | 2985 | rpc_put_task(task); |
3071 | return status; | 2986 | return status; |
3072 | } | 2987 | } |
3073 | 2988 | ||
@@ -3314,7 +3229,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3314 | if (IS_ERR(task)) | 3229 | if (IS_ERR(task)) |
3315 | goto out; | 3230 | goto out; |
3316 | status = nfs4_wait_for_completion_rpc_task(task); | 3231 | status = nfs4_wait_for_completion_rpc_task(task); |
3317 | rpc_release_task(task); | 3232 | rpc_put_task(task); |
3318 | out: | 3233 | out: |
3319 | return status; | 3234 | return status; |
3320 | } | 3235 | } |
@@ -3430,7 +3345,7 @@ static void nfs4_lock_release(void *calldata) | |||
3430 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | 3345 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, |
3431 | data->arg.lock_seqid); | 3346 | data->arg.lock_seqid); |
3432 | if (!IS_ERR(task)) | 3347 | if (!IS_ERR(task)) |
3433 | rpc_release_task(task); | 3348 | rpc_put_task(task); |
3434 | dprintk("%s: cancelling lock!\n", __FUNCTION__); | 3349 | dprintk("%s: cancelling lock!\n", __FUNCTION__); |
3435 | } else | 3350 | } else |
3436 | nfs_free_seqid(data->arg.lock_seqid); | 3351 | nfs_free_seqid(data->arg.lock_seqid); |
@@ -3472,7 +3387,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3472 | ret = -EAGAIN; | 3387 | ret = -EAGAIN; |
3473 | } else | 3388 | } else |
3474 | data->cancelled = 1; | 3389 | data->cancelled = 1; |
3475 | rpc_release_task(task); | 3390 | rpc_put_task(task); |
3476 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); | 3391 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); |
3477 | return ret; | 3392 | return ret; |
3478 | } | 3393 | } |
@@ -3732,8 +3647,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
3732 | .access = nfs4_proc_access, | 3647 | .access = nfs4_proc_access, |
3733 | .readlink = nfs4_proc_readlink, | 3648 | .readlink = nfs4_proc_readlink, |
3734 | .read = nfs4_proc_read, | 3649 | .read = nfs4_proc_read, |
3735 | .write = nfs4_proc_write, | ||
3736 | .commit = nfs4_proc_commit, | ||
3737 | .create = nfs4_proc_create, | 3650 | .create = nfs4_proc_create, |
3738 | .remove = nfs4_proc_remove, | 3651 | .remove = nfs4_proc_remove, |
3739 | .unlink_setup = nfs4_proc_unlink_setup, | 3652 | .unlink_setup = nfs4_proc_unlink_setup, |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 3fbfc2f03307..ca4b1d4ff42b 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_page.h> | 17 | #include <linux/nfs_page.h> |
18 | #include <linux/nfs_fs.h> | 18 | #include <linux/nfs_fs.h> |
19 | #include <linux/nfs_mount.h> | 19 | #include <linux/nfs_mount.h> |
20 | #include <linux/writeback.h> | ||
20 | 21 | ||
21 | #define NFS_PARANOIA 1 | 22 | #define NFS_PARANOIA 1 |
22 | 23 | ||
@@ -268,11 +269,10 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
268 | 269 | ||
269 | #define NFS_SCAN_MAXENTRIES 16 | 270 | #define NFS_SCAN_MAXENTRIES 16 |
270 | /** | 271 | /** |
271 | * nfs_scan_lock_dirty - Scan the radix tree for dirty requests | 272 | * nfs_scan_dirty - Scan the radix tree for dirty requests |
272 | * @nfsi: NFS inode | 273 | * @mapping: pointer to address space |
274 | * @wbc: writeback_control structure | ||
273 | * @dst: Destination list | 275 | * @dst: Destination list |
274 | * @idx_start: lower bound of page->index to scan | ||
275 | * @npages: idx_start + npages sets the upper bound to scan. | ||
276 | * | 276 | * |
277 | * Moves elements from one of the inode request lists. | 277 | * Moves elements from one of the inode request lists. |
278 | * If the number of requests is set to 0, the entire address_space | 278 | * If the number of requests is set to 0, the entire address_space |
@@ -280,46 +280,63 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
280 | * The requests are *not* checked to ensure that they form a contiguous set. | 280 | * The requests are *not* checked to ensure that they form a contiguous set. |
281 | * You must be holding the inode's req_lock when calling this function | 281 | * You must be holding the inode's req_lock when calling this function |
282 | */ | 282 | */ |
283 | int | 283 | long nfs_scan_dirty(struct address_space *mapping, |
284 | nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, | 284 | struct writeback_control *wbc, |
285 | unsigned long idx_start, unsigned int npages) | 285 | struct list_head *dst) |
286 | { | 286 | { |
287 | struct nfs_inode *nfsi = NFS_I(mapping->host); | ||
287 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | 288 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; |
288 | struct nfs_page *req; | 289 | struct nfs_page *req; |
289 | unsigned long idx_end; | 290 | pgoff_t idx_start, idx_end; |
291 | long res = 0; | ||
290 | int found, i; | 292 | int found, i; |
291 | int res; | ||
292 | 293 | ||
293 | res = 0; | 294 | if (nfsi->ndirty == 0) |
294 | if (npages == 0) | 295 | return 0; |
295 | idx_end = ~0; | 296 | if (wbc->range_cyclic) { |
296 | else | 297 | idx_start = 0; |
297 | idx_end = idx_start + npages - 1; | 298 | idx_end = ULONG_MAX; |
299 | } else if (wbc->range_end == 0) { | ||
300 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
301 | idx_end = ULONG_MAX; | ||
302 | } else { | ||
303 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
304 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
305 | } | ||
298 | 306 | ||
299 | for (;;) { | 307 | for (;;) { |
308 | unsigned int toscan = NFS_SCAN_MAXENTRIES; | ||
309 | |||
300 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | 310 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, |
301 | (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, | 311 | (void **)&pgvec[0], idx_start, toscan, |
302 | NFS_PAGE_TAG_DIRTY); | 312 | NFS_PAGE_TAG_DIRTY); |
313 | |||
314 | /* Did we make progress? */ | ||
303 | if (found <= 0) | 315 | if (found <= 0) |
304 | break; | 316 | break; |
317 | |||
305 | for (i = 0; i < found; i++) { | 318 | for (i = 0; i < found; i++) { |
306 | req = pgvec[i]; | 319 | req = pgvec[i]; |
307 | if (req->wb_index > idx_end) | 320 | if (!wbc->range_cyclic && req->wb_index > idx_end) |
308 | goto out; | 321 | goto out; |
309 | 322 | ||
323 | /* Try to lock request and mark it for writeback */ | ||
324 | if (!nfs_set_page_writeback_locked(req)) | ||
325 | goto next; | ||
326 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
327 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
328 | nfsi->ndirty--; | ||
329 | nfs_list_remove_request(req); | ||
330 | nfs_list_add_request(req, dst); | ||
331 | res++; | ||
332 | if (res == LONG_MAX) | ||
333 | goto out; | ||
334 | next: | ||
310 | idx_start = req->wb_index + 1; | 335 | idx_start = req->wb_index + 1; |
311 | |||
312 | if (nfs_set_page_writeback_locked(req)) { | ||
313 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
314 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
315 | nfs_list_remove_request(req); | ||
316 | nfs_list_add_request(req, dst); | ||
317 | dec_zone_page_state(req->wb_page, NR_FILE_DIRTY); | ||
318 | res++; | ||
319 | } | ||
320 | } | 336 | } |
321 | } | 337 | } |
322 | out: | 338 | out: |
339 | WARN_ON ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)); | ||
323 | return res; | 340 | return res; |
324 | } | 341 | } |
325 | 342 | ||
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 4529cc4f3f8f..10f5e80ca157 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -215,32 +215,6 @@ static int nfs_proc_read(struct nfs_read_data *rdata) | |||
215 | return status; | 215 | return status; |
216 | } | 216 | } |
217 | 217 | ||
218 | static int nfs_proc_write(struct nfs_write_data *wdata) | ||
219 | { | ||
220 | int flags = wdata->flags; | ||
221 | struct inode * inode = wdata->inode; | ||
222 | struct nfs_fattr * fattr = wdata->res.fattr; | ||
223 | struct rpc_message msg = { | ||
224 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], | ||
225 | .rpc_argp = &wdata->args, | ||
226 | .rpc_resp = &wdata->res, | ||
227 | .rpc_cred = wdata->cred, | ||
228 | }; | ||
229 | int status; | ||
230 | |||
231 | dprintk("NFS call write %d @ %Ld\n", wdata->args.count, | ||
232 | (long long) wdata->args.offset); | ||
233 | nfs_fattr_init(fattr); | ||
234 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); | ||
235 | if (status >= 0) { | ||
236 | nfs_post_op_update_inode(inode, fattr); | ||
237 | wdata->res.count = wdata->args.count; | ||
238 | wdata->verf.committed = NFS_FILE_SYNC; | ||
239 | } | ||
240 | dprintk("NFS reply write: %d\n", status); | ||
241 | return status < 0? status : wdata->res.count; | ||
242 | } | ||
243 | |||
244 | static int | 218 | static int |
245 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 219 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
246 | int flags, struct nameidata *nd) | 220 | int flags, struct nameidata *nd) |
@@ -545,13 +519,10 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
545 | }; | 519 | }; |
546 | int status; | 520 | int status; |
547 | 521 | ||
548 | lock_kernel(); | ||
549 | |||
550 | dprintk("NFS call readdir %d\n", (unsigned int)cookie); | 522 | dprintk("NFS call readdir %d\n", (unsigned int)cookie); |
551 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 523 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
552 | 524 | ||
553 | dprintk("NFS reply readdir: %d\n", status); | 525 | dprintk("NFS reply readdir: %d\n", status); |
554 | unlock_kernel(); | ||
555 | return status; | 526 | return status; |
556 | } | 527 | } |
557 | 528 | ||
@@ -696,8 +667,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
696 | .access = NULL, /* access */ | 667 | .access = NULL, /* access */ |
697 | .readlink = nfs_proc_readlink, | 668 | .readlink = nfs_proc_readlink, |
698 | .read = nfs_proc_read, | 669 | .read = nfs_proc_read, |
699 | .write = nfs_proc_write, | ||
700 | .commit = NULL, /* commit */ | ||
701 | .create = nfs_proc_create, | 670 | .create = nfs_proc_create, |
702 | .remove = nfs_proc_remove, | 671 | .remove = nfs_proc_remove, |
703 | .unlink_setup = nfs_proc_unlink_setup, | 672 | .unlink_setup = nfs_proc_unlink_setup, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 244a8c45b68e..a9c26521a9e2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include <asm/system.h> | 31 | #include <asm/system.h> |
32 | 32 | ||
33 | #include "internal.h" | ||
33 | #include "iostat.h" | 34 | #include "iostat.h" |
34 | 35 | ||
35 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 36 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
@@ -65,32 +66,22 @@ struct nfs_read_data *nfs_readdata_alloc(size_t len) | |||
65 | return p; | 66 | return p; |
66 | } | 67 | } |
67 | 68 | ||
68 | static void nfs_readdata_free(struct nfs_read_data *p) | 69 | static void nfs_readdata_rcu_free(struct rcu_head *head) |
69 | { | 70 | { |
71 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
70 | if (p && (p->pagevec != &p->page_array[0])) | 72 | if (p && (p->pagevec != &p->page_array[0])) |
71 | kfree(p->pagevec); | 73 | kfree(p->pagevec); |
72 | mempool_free(p, nfs_rdata_mempool); | 74 | mempool_free(p, nfs_rdata_mempool); |
73 | } | 75 | } |
74 | 76 | ||
75 | void nfs_readdata_release(void *data) | 77 | static void nfs_readdata_free(struct nfs_read_data *rdata) |
76 | { | 78 | { |
77 | nfs_readdata_free(data); | 79 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); |
78 | } | 80 | } |
79 | 81 | ||
80 | static | 82 | void nfs_readdata_release(void *data) |
81 | unsigned int nfs_page_length(struct inode *inode, struct page *page) | ||
82 | { | 83 | { |
83 | loff_t i_size = i_size_read(inode); | 84 | nfs_readdata_free(data); |
84 | unsigned long idx; | ||
85 | |||
86 | if (i_size <= 0) | ||
87 | return 0; | ||
88 | idx = (i_size - 1) >> PAGE_CACHE_SHIFT; | ||
89 | if (page->index > idx) | ||
90 | return 0; | ||
91 | if (page->index != idx) | ||
92 | return PAGE_CACHE_SIZE; | ||
93 | return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1)); | ||
94 | } | 85 | } |
95 | 86 | ||
96 | static | 87 | static |
@@ -139,12 +130,12 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
139 | { | 130 | { |
140 | unsigned int rsize = NFS_SERVER(inode)->rsize; | 131 | unsigned int rsize = NFS_SERVER(inode)->rsize; |
141 | unsigned int count = PAGE_CACHE_SIZE; | 132 | unsigned int count = PAGE_CACHE_SIZE; |
142 | int result; | 133 | int result = -ENOMEM; |
143 | struct nfs_read_data *rdata; | 134 | struct nfs_read_data *rdata; |
144 | 135 | ||
145 | rdata = nfs_readdata_alloc(count); | 136 | rdata = nfs_readdata_alloc(count); |
146 | if (!rdata) | 137 | if (!rdata) |
147 | return -ENOMEM; | 138 | goto out_unlock; |
148 | 139 | ||
149 | memset(rdata, 0, sizeof(*rdata)); | 140 | memset(rdata, 0, sizeof(*rdata)); |
150 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 141 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
@@ -212,8 +203,9 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
212 | result = 0; | 203 | result = 0; |
213 | 204 | ||
214 | io_error: | 205 | io_error: |
215 | unlock_page(page); | ||
216 | nfs_readdata_free(rdata); | 206 | nfs_readdata_free(rdata); |
207 | out_unlock: | ||
208 | unlock_page(page); | ||
217 | return result; | 209 | return result; |
218 | } | 210 | } |
219 | 211 | ||
@@ -224,7 +216,7 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
224 | struct nfs_page *new; | 216 | struct nfs_page *new; |
225 | unsigned int len; | 217 | unsigned int len; |
226 | 218 | ||
227 | len = nfs_page_length(inode, page); | 219 | len = nfs_page_length(page); |
228 | if (len == 0) | 220 | if (len == 0) |
229 | return nfs_return_empty_page(page); | 221 | return nfs_return_empty_page(page); |
230 | new = nfs_create_request(ctx, inode, page, 0, len); | 222 | new = nfs_create_request(ctx, inode, page, 0, len); |
@@ -316,9 +308,7 @@ static void nfs_execute_read(struct nfs_read_data *data) | |||
316 | sigset_t oldset; | 308 | sigset_t oldset; |
317 | 309 | ||
318 | rpc_clnt_sigmask(clnt, &oldset); | 310 | rpc_clnt_sigmask(clnt, &oldset); |
319 | lock_kernel(); | ||
320 | rpc_execute(&data->task); | 311 | rpc_execute(&data->task); |
321 | unlock_kernel(); | ||
322 | rpc_clnt_sigunmask(clnt, &oldset); | 312 | rpc_clnt_sigunmask(clnt, &oldset); |
323 | } | 313 | } |
324 | 314 | ||
@@ -455,6 +445,55 @@ nfs_pagein_list(struct list_head *head, int rpages) | |||
455 | } | 445 | } |
456 | 446 | ||
457 | /* | 447 | /* |
448 | * This is the callback from RPC telling us whether a reply was | ||
449 | * received or some error occurred (timeout or socket shutdown). | ||
450 | */ | ||
451 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | ||
452 | { | ||
453 | int status; | ||
454 | |||
455 | dprintk("%s: %4d, (status %d)\n", __FUNCTION__, task->tk_pid, | ||
456 | task->tk_status); | ||
457 | |||
458 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
459 | if (status != 0) | ||
460 | return status; | ||
461 | |||
462 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); | ||
463 | |||
464 | if (task->tk_status == -ESTALE) { | ||
465 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
466 | nfs_mark_for_revalidate(data->inode); | ||
467 | } | ||
468 | spin_lock(&data->inode->i_lock); | ||
469 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | ||
470 | spin_unlock(&data->inode->i_lock); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | ||
475 | { | ||
476 | struct nfs_readargs *argp = &data->args; | ||
477 | struct nfs_readres *resp = &data->res; | ||
478 | |||
479 | if (resp->eof || resp->count == argp->count) | ||
480 | return 0; | ||
481 | |||
482 | /* This is a short read! */ | ||
483 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
484 | /* Has the server at least made some progress? */ | ||
485 | if (resp->count == 0) | ||
486 | return 0; | ||
487 | |||
488 | /* Yes, so retry the read at the end of the data */ | ||
489 | argp->offset += resp->count; | ||
490 | argp->pgbase += resp->count; | ||
491 | argp->count -= resp->count; | ||
492 | rpc_restart_call(task); | ||
493 | return -EAGAIN; | ||
494 | } | ||
495 | |||
496 | /* | ||
458 | * Handle a read reply that fills part of a page. | 497 | * Handle a read reply that fills part of a page. |
459 | */ | 498 | */ |
460 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 499 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
@@ -463,12 +502,16 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | |||
463 | struct nfs_page *req = data->req; | 502 | struct nfs_page *req = data->req; |
464 | struct page *page = req->wb_page; | 503 | struct page *page = req->wb_page; |
465 | 504 | ||
466 | if (likely(task->tk_status >= 0)) | ||
467 | nfs_readpage_truncate_uninitialised_page(data); | ||
468 | else | ||
469 | SetPageError(page); | ||
470 | if (nfs_readpage_result(task, data) != 0) | 505 | if (nfs_readpage_result(task, data) != 0) |
471 | return; | 506 | return; |
507 | |||
508 | if (likely(task->tk_status >= 0)) { | ||
509 | nfs_readpage_truncate_uninitialised_page(data); | ||
510 | if (nfs_readpage_retry(task, data) != 0) | ||
511 | return; | ||
512 | } | ||
513 | if (unlikely(task->tk_status < 0)) | ||
514 | SetPageError(page); | ||
472 | if (atomic_dec_and_test(&req->wb_complete)) { | 515 | if (atomic_dec_and_test(&req->wb_complete)) { |
473 | if (!PageError(page)) | 516 | if (!PageError(page)) |
474 | SetPageUptodate(page); | 517 | SetPageUptodate(page); |
@@ -496,25 +539,13 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
496 | count += base; | 539 | count += base; |
497 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 540 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
498 | SetPageUptodate(*pages); | 541 | SetPageUptodate(*pages); |
499 | if (count != 0) | 542 | if (count == 0) |
543 | return; | ||
544 | /* Was this a short read? */ | ||
545 | if (data->res.eof || data->res.count == data->args.count) | ||
500 | SetPageUptodate(*pages); | 546 | SetPageUptodate(*pages); |
501 | } | 547 | } |
502 | 548 | ||
503 | static void nfs_readpage_set_pages_error(struct nfs_read_data *data) | ||
504 | { | ||
505 | unsigned int count = data->args.count; | ||
506 | unsigned int base = data->args.pgbase; | ||
507 | struct page **pages; | ||
508 | |||
509 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | ||
510 | base &= ~PAGE_CACHE_MASK; | ||
511 | count += base; | ||
512 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | ||
513 | SetPageError(*pages); | ||
514 | if (count != 0) | ||
515 | SetPageError(*pages); | ||
516 | } | ||
517 | |||
518 | /* | 549 | /* |
519 | * This is the callback from RPC telling us whether a reply was | 550 | * This is the callback from RPC telling us whether a reply was |
520 | * received or some error occurred (timeout or socket shutdown). | 551 | * received or some error occurred (timeout or socket shutdown). |
@@ -523,19 +554,20 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | |||
523 | { | 554 | { |
524 | struct nfs_read_data *data = calldata; | 555 | struct nfs_read_data *data = calldata; |
525 | 556 | ||
557 | if (nfs_readpage_result(task, data) != 0) | ||
558 | return; | ||
526 | /* | 559 | /* |
527 | * Note: nfs_readpage_result may change the values of | 560 | * Note: nfs_readpage_retry may change the values of |
528 | * data->args. In the multi-page case, we therefore need | 561 | * data->args. In the multi-page case, we therefore need |
529 | * to ensure that we call the next nfs_readpage_set_page_uptodate() | 562 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
530 | * first in the multi-page case. | 563 | * first. |
531 | */ | 564 | */ |
532 | if (likely(task->tk_status >= 0)) { | 565 | if (likely(task->tk_status >= 0)) { |
533 | nfs_readpage_truncate_uninitialised_page(data); | 566 | nfs_readpage_truncate_uninitialised_page(data); |
534 | nfs_readpage_set_pages_uptodate(data); | 567 | nfs_readpage_set_pages_uptodate(data); |
535 | } else | 568 | if (nfs_readpage_retry(task, data) != 0) |
536 | nfs_readpage_set_pages_error(data); | 569 | return; |
537 | if (nfs_readpage_result(task, data) != 0) | 570 | } |
538 | return; | ||
539 | while (!list_empty(&data->pages)) { | 571 | while (!list_empty(&data->pages)) { |
540 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 572 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
541 | 573 | ||
@@ -550,50 +582,6 @@ static const struct rpc_call_ops nfs_read_full_ops = { | |||
550 | }; | 582 | }; |
551 | 583 | ||
552 | /* | 584 | /* |
553 | * This is the callback from RPC telling us whether a reply was | ||
554 | * received or some error occurred (timeout or socket shutdown). | ||
555 | */ | ||
556 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | ||
557 | { | ||
558 | struct nfs_readargs *argp = &data->args; | ||
559 | struct nfs_readres *resp = &data->res; | ||
560 | int status; | ||
561 | |||
562 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", | ||
563 | task->tk_pid, task->tk_status); | ||
564 | |||
565 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
566 | if (status != 0) | ||
567 | return status; | ||
568 | |||
569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | ||
570 | |||
571 | if (task->tk_status < 0) { | ||
572 | if (task->tk_status == -ESTALE) { | ||
573 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
574 | nfs_mark_for_revalidate(data->inode); | ||
575 | } | ||
576 | } else if (resp->count < argp->count && !resp->eof) { | ||
577 | /* This is a short read! */ | ||
578 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
579 | /* Has the server at least made some progress? */ | ||
580 | if (resp->count != 0) { | ||
581 | /* Yes, so retry the read at the end of the data */ | ||
582 | argp->offset += resp->count; | ||
583 | argp->pgbase += resp->count; | ||
584 | argp->count -= resp->count; | ||
585 | rpc_restart_call(task); | ||
586 | return -EAGAIN; | ||
587 | } | ||
588 | task->tk_status = -EIO; | ||
589 | } | ||
590 | spin_lock(&data->inode->i_lock); | ||
591 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | ||
592 | spin_unlock(&data->inode->i_lock); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * Read a page over NFS. | 585 | * Read a page over NFS. |
598 | * We read the page synchronously in the following case: | 586 | * We read the page synchronously in the following case: |
599 | * - The error flag is set for this page. This happens only when a | 587 | * - The error flag is set for this page. This happens only when a |
@@ -626,9 +614,10 @@ int nfs_readpage(struct file *file, struct page *page) | |||
626 | goto out_error; | 614 | goto out_error; |
627 | 615 | ||
628 | if (file == NULL) { | 616 | if (file == NULL) { |
617 | error = -EBADF; | ||
629 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 618 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
630 | if (ctx == NULL) | 619 | if (ctx == NULL) |
631 | return -EBADF; | 620 | goto out_error; |
632 | } else | 621 | } else |
633 | ctx = get_nfs_open_context((struct nfs_open_context *) | 622 | ctx = get_nfs_open_context((struct nfs_open_context *) |
634 | file->private_data); | 623 | file->private_data); |
@@ -663,7 +652,7 @@ readpage_async_filler(void *data, struct page *page) | |||
663 | unsigned int len; | 652 | unsigned int len; |
664 | 653 | ||
665 | nfs_wb_page(inode, page); | 654 | nfs_wb_page(inode, page); |
666 | len = nfs_page_length(inode, page); | 655 | len = nfs_page_length(page); |
667 | if (len == 0) | 656 | if (len == 0) |
668 | return nfs_return_empty_page(page); | 657 | return nfs_return_empty_page(page); |
669 | new = nfs_create_request(desc->ctx, inode, page, 0, len); | 658 | new = nfs_create_request(desc->ctx, inode, page, 0, len); |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 600bbe630abd..6c686112cc03 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -33,9 +33,7 @@ static int nfs_symlink_filler(struct inode *inode, struct page *page) | |||
33 | { | 33 | { |
34 | int error; | 34 | int error; |
35 | 35 | ||
36 | lock_kernel(); | ||
37 | error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); | 36 | error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); |
38 | unlock_kernel(); | ||
39 | if (error < 0) | 37 | if (error < 0) |
40 | goto error; | 38 | goto error; |
41 | SetPageUptodate(page); | 39 | SetPageUptodate(page); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 41b07288f99e..594eb16879ef 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include <linux/smp_lock.h> | 63 | #include <linux/smp_lock.h> |
64 | 64 | ||
65 | #include "delegation.h" | 65 | #include "delegation.h" |
66 | #include "internal.h" | ||
66 | #include "iostat.h" | 67 | #include "iostat.h" |
67 | 68 | ||
68 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 69 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
@@ -74,13 +75,12 @@ | |||
74 | * Local function declarations | 75 | * Local function declarations |
75 | */ | 76 | */ |
76 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, | 77 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, |
77 | struct inode *, | ||
78 | struct page *, | 78 | struct page *, |
79 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
80 | static void nfs_mark_request_dirty(struct nfs_page *req); | ||
80 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 81 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
81 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | 82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); |
82 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 83 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); |
83 | unsigned int npages, int how); | ||
84 | static const struct rpc_call_ops nfs_write_partial_ops; | 84 | static const struct rpc_call_ops nfs_write_partial_ops; |
85 | static const struct rpc_call_ops nfs_write_full_ops; | 85 | static const struct rpc_call_ops nfs_write_full_ops; |
86 | static const struct rpc_call_ops nfs_commit_ops; | 86 | static const struct rpc_call_ops nfs_commit_ops; |
@@ -102,13 +102,19 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
102 | return p; | 102 | return p; |
103 | } | 103 | } |
104 | 104 | ||
105 | void nfs_commit_free(struct nfs_write_data *p) | 105 | void nfs_commit_rcu_free(struct rcu_head *head) |
106 | { | 106 | { |
107 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
107 | if (p && (p->pagevec != &p->page_array[0])) | 108 | if (p && (p->pagevec != &p->page_array[0])) |
108 | kfree(p->pagevec); | 109 | kfree(p->pagevec); |
109 | mempool_free(p, nfs_commit_mempool); | 110 | mempool_free(p, nfs_commit_mempool); |
110 | } | 111 | } |
111 | 112 | ||
113 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
114 | { | ||
115 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
116 | } | ||
117 | |||
112 | struct nfs_write_data *nfs_writedata_alloc(size_t len) | 118 | struct nfs_write_data *nfs_writedata_alloc(size_t len) |
113 | { | 119 | { |
114 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 120 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
@@ -131,18 +137,47 @@ struct nfs_write_data *nfs_writedata_alloc(size_t len) | |||
131 | return p; | 137 | return p; |
132 | } | 138 | } |
133 | 139 | ||
134 | static void nfs_writedata_free(struct nfs_write_data *p) | 140 | static void nfs_writedata_rcu_free(struct rcu_head *head) |
135 | { | 141 | { |
142 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
136 | if (p && (p->pagevec != &p->page_array[0])) | 143 | if (p && (p->pagevec != &p->page_array[0])) |
137 | kfree(p->pagevec); | 144 | kfree(p->pagevec); |
138 | mempool_free(p, nfs_wdata_mempool); | 145 | mempool_free(p, nfs_wdata_mempool); |
139 | } | 146 | } |
140 | 147 | ||
148 | static void nfs_writedata_free(struct nfs_write_data *wdata) | ||
149 | { | ||
150 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | ||
151 | } | ||
152 | |||
141 | void nfs_writedata_release(void *wdata) | 153 | void nfs_writedata_release(void *wdata) |
142 | { | 154 | { |
143 | nfs_writedata_free(wdata); | 155 | nfs_writedata_free(wdata); |
144 | } | 156 | } |
145 | 157 | ||
158 | static struct nfs_page *nfs_page_find_request_locked(struct page *page) | ||
159 | { | ||
160 | struct nfs_page *req = NULL; | ||
161 | |||
162 | if (PagePrivate(page)) { | ||
163 | req = (struct nfs_page *)page_private(page); | ||
164 | if (req != NULL) | ||
165 | atomic_inc(&req->wb_count); | ||
166 | } | ||
167 | return req; | ||
168 | } | ||
169 | |||
170 | static struct nfs_page *nfs_page_find_request(struct page *page) | ||
171 | { | ||
172 | struct nfs_page *req = NULL; | ||
173 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | ||
174 | |||
175 | spin_lock(req_lock); | ||
176 | req = nfs_page_find_request_locked(page); | ||
177 | spin_unlock(req_lock); | ||
178 | return req; | ||
179 | } | ||
180 | |||
146 | /* Adjust the file length if we're writing beyond the end */ | 181 | /* Adjust the file length if we're writing beyond the end */ |
147 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) | 182 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) |
148 | { | 183 | { |
@@ -164,113 +199,34 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
164 | */ | 199 | */ |
165 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) | 200 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) |
166 | { | 201 | { |
167 | loff_t end_offs; | ||
168 | |||
169 | if (PageUptodate(page)) | 202 | if (PageUptodate(page)) |
170 | return; | 203 | return; |
171 | if (base != 0) | 204 | if (base != 0) |
172 | return; | 205 | return; |
173 | if (count == PAGE_CACHE_SIZE) { | 206 | if (count != nfs_page_length(page)) |
174 | SetPageUptodate(page); | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | end_offs = i_size_read(page->mapping->host) - 1; | ||
179 | if (end_offs < 0) | ||
180 | return; | 207 | return; |
181 | /* Is this the last page? */ | 208 | if (count != PAGE_CACHE_SIZE) |
182 | if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT)) | ||
183 | return; | ||
184 | /* This is the last page: set PG_uptodate if we cover the entire | ||
185 | * extent of the data, then zero the rest of the page. | ||
186 | */ | ||
187 | if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) { | ||
188 | memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); | 209 | memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); |
189 | SetPageUptodate(page); | 210 | SetPageUptodate(page); |
190 | } | ||
191 | } | 211 | } |
192 | 212 | ||
193 | /* | 213 | static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, |
194 | * Write a page synchronously. | ||
195 | * Offset is the data offset within the page. | ||
196 | */ | ||
197 | static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | ||
198 | struct page *page, unsigned int offset, unsigned int count, | ||
199 | int how) | ||
200 | { | ||
201 | unsigned int wsize = NFS_SERVER(inode)->wsize; | ||
202 | int result, written = 0; | ||
203 | struct nfs_write_data *wdata; | ||
204 | |||
205 | wdata = nfs_writedata_alloc(wsize); | ||
206 | if (!wdata) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | wdata->flags = how; | ||
210 | wdata->cred = ctx->cred; | ||
211 | wdata->inode = inode; | ||
212 | wdata->args.fh = NFS_FH(inode); | ||
213 | wdata->args.context = ctx; | ||
214 | wdata->args.pages = &page; | ||
215 | wdata->args.stable = NFS_FILE_SYNC; | ||
216 | wdata->args.pgbase = offset; | ||
217 | wdata->args.count = wsize; | ||
218 | wdata->res.fattr = &wdata->fattr; | ||
219 | wdata->res.verf = &wdata->verf; | ||
220 | |||
221 | dprintk("NFS: nfs_writepage_sync(%s/%Ld %d@%Ld)\n", | ||
222 | inode->i_sb->s_id, | ||
223 | (long long)NFS_FILEID(inode), | ||
224 | count, (long long)(page_offset(page) + offset)); | ||
225 | |||
226 | set_page_writeback(page); | ||
227 | nfs_begin_data_update(inode); | ||
228 | do { | ||
229 | if (count < wsize) | ||
230 | wdata->args.count = count; | ||
231 | wdata->args.offset = page_offset(page) + wdata->args.pgbase; | ||
232 | |||
233 | result = NFS_PROTO(inode)->write(wdata); | ||
234 | |||
235 | if (result < 0) { | ||
236 | /* Must mark the page invalid after I/O error */ | ||
237 | ClearPageUptodate(page); | ||
238 | goto io_error; | ||
239 | } | ||
240 | if (result < wdata->args.count) | ||
241 | printk(KERN_WARNING "NFS: short write, count=%u, result=%d\n", | ||
242 | wdata->args.count, result); | ||
243 | |||
244 | wdata->args.offset += result; | ||
245 | wdata->args.pgbase += result; | ||
246 | written += result; | ||
247 | count -= result; | ||
248 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, result); | ||
249 | } while (count); | ||
250 | /* Update file length */ | ||
251 | nfs_grow_file(page, offset, written); | ||
252 | /* Set the PG_uptodate flag? */ | ||
253 | nfs_mark_uptodate(page, offset, written); | ||
254 | |||
255 | if (PageError(page)) | ||
256 | ClearPageError(page); | ||
257 | |||
258 | io_error: | ||
259 | nfs_end_data_update(inode); | ||
260 | end_page_writeback(page); | ||
261 | nfs_writedata_free(wdata); | ||
262 | return written ? written : result; | ||
263 | } | ||
264 | |||
265 | static int nfs_writepage_async(struct nfs_open_context *ctx, | ||
266 | struct inode *inode, struct page *page, | ||
267 | unsigned int offset, unsigned int count) | 214 | unsigned int offset, unsigned int count) |
268 | { | 215 | { |
269 | struct nfs_page *req; | 216 | struct nfs_page *req; |
217 | int ret; | ||
270 | 218 | ||
271 | req = nfs_update_request(ctx, inode, page, offset, count); | 219 | for (;;) { |
272 | if (IS_ERR(req)) | 220 | req = nfs_update_request(ctx, page, offset, count); |
273 | return PTR_ERR(req); | 221 | if (!IS_ERR(req)) |
222 | break; | ||
223 | ret = PTR_ERR(req); | ||
224 | if (ret != -EBUSY) | ||
225 | return ret; | ||
226 | ret = nfs_wb_page(page->mapping->host, page); | ||
227 | if (ret != 0) | ||
228 | return ret; | ||
229 | } | ||
274 | /* Update file length */ | 230 | /* Update file length */ |
275 | nfs_grow_file(page, offset, count); | 231 | nfs_grow_file(page, offset, count); |
276 | /* Set the PG_uptodate flag? */ | 232 | /* Set the PG_uptodate flag? */ |
@@ -289,73 +245,94 @@ static int wb_priority(struct writeback_control *wbc) | |||
289 | } | 245 | } |
290 | 246 | ||
291 | /* | 247 | /* |
248 | * Find an associated nfs write request, and prepare to flush it out | ||
249 | * Returns 1 if there was no write request, or if the request was | ||
250 | * already tagged by nfs_set_page_dirty.Returns 0 if the request | ||
251 | * was not tagged. | ||
252 | * May also return an error if the user signalled nfs_wait_on_request(). | ||
253 | */ | ||
254 | static int nfs_page_mark_flush(struct page *page) | ||
255 | { | ||
256 | struct nfs_page *req; | ||
257 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | ||
258 | int ret; | ||
259 | |||
260 | spin_lock(req_lock); | ||
261 | for(;;) { | ||
262 | req = nfs_page_find_request_locked(page); | ||
263 | if (req == NULL) { | ||
264 | spin_unlock(req_lock); | ||
265 | return 1; | ||
266 | } | ||
267 | if (nfs_lock_request_dontget(req)) | ||
268 | break; | ||
269 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | ||
270 | * then the call to nfs_lock_request_dontget() will always | ||
271 | * succeed provided that someone hasn't already marked the | ||
272 | * request as dirty (in which case we don't care). | ||
273 | */ | ||
274 | spin_unlock(req_lock); | ||
275 | ret = nfs_wait_on_request(req); | ||
276 | nfs_release_request(req); | ||
277 | if (ret != 0) | ||
278 | return ret; | ||
279 | spin_lock(req_lock); | ||
280 | } | ||
281 | spin_unlock(req_lock); | ||
282 | if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) { | ||
283 | nfs_mark_request_dirty(req); | ||
284 | set_page_writeback(page); | ||
285 | } | ||
286 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | ||
287 | nfs_unlock_request(req); | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Write an mmapped page to the server. | 292 | * Write an mmapped page to the server. |
293 | */ | 293 | */ |
294 | int nfs_writepage(struct page *page, struct writeback_control *wbc) | 294 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) |
295 | { | 295 | { |
296 | struct nfs_open_context *ctx; | 296 | struct nfs_open_context *ctx; |
297 | struct inode *inode = page->mapping->host; | 297 | struct inode *inode = page->mapping->host; |
298 | unsigned long end_index; | 298 | unsigned offset; |
299 | unsigned offset = PAGE_CACHE_SIZE; | ||
300 | loff_t i_size = i_size_read(inode); | ||
301 | int inode_referenced = 0; | ||
302 | int priority = wb_priority(wbc); | ||
303 | int err; | 299 | int err; |
304 | 300 | ||
305 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 301 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
306 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 302 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
307 | 303 | ||
308 | /* | 304 | err = nfs_page_mark_flush(page); |
309 | * Note: We need to ensure that we have a reference to the inode | 305 | if (err <= 0) |
310 | * if we are to do asynchronous writes. If not, waiting | 306 | goto out; |
311 | * in nfs_wait_on_request() may deadlock with clear_inode(). | 307 | err = 0; |
312 | * | 308 | offset = nfs_page_length(page); |
313 | * If igrab() fails here, then it is in any case safe to | 309 | if (!offset) |
314 | * call nfs_wb_page(), since there will be no pending writes. | ||
315 | */ | ||
316 | if (igrab(inode) != 0) | ||
317 | inode_referenced = 1; | ||
318 | end_index = i_size >> PAGE_CACHE_SHIFT; | ||
319 | |||
320 | /* Ensure we've flushed out any previous writes */ | ||
321 | nfs_wb_page_priority(inode, page, priority); | ||
322 | |||
323 | /* easy case */ | ||
324 | if (page->index < end_index) | ||
325 | goto do_it; | ||
326 | /* things got complicated... */ | ||
327 | offset = i_size & (PAGE_CACHE_SIZE-1); | ||
328 | |||
329 | /* OK, are we completely out? */ | ||
330 | err = 0; /* potential race with truncate - ignore */ | ||
331 | if (page->index >= end_index+1 || !offset) | ||
332 | goto out; | 310 | goto out; |
333 | do_it: | 311 | |
334 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); | 312 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); |
335 | if (ctx == NULL) { | 313 | if (ctx == NULL) { |
336 | err = -EBADF; | 314 | err = -EBADF; |
337 | goto out; | 315 | goto out; |
338 | } | 316 | } |
339 | lock_kernel(); | 317 | err = nfs_writepage_setup(ctx, page, 0, offset); |
340 | if (!IS_SYNC(inode) && inode_referenced) { | ||
341 | err = nfs_writepage_async(ctx, inode, page, 0, offset); | ||
342 | if (!wbc->for_writepages) | ||
343 | nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); | ||
344 | } else { | ||
345 | err = nfs_writepage_sync(ctx, inode, page, 0, | ||
346 | offset, priority); | ||
347 | if (err >= 0) { | ||
348 | if (err != offset) | ||
349 | redirty_page_for_writepage(wbc, page); | ||
350 | err = 0; | ||
351 | } | ||
352 | } | ||
353 | unlock_kernel(); | ||
354 | put_nfs_open_context(ctx); | 318 | put_nfs_open_context(ctx); |
319 | if (err != 0) | ||
320 | goto out; | ||
321 | err = nfs_page_mark_flush(page); | ||
322 | if (err > 0) | ||
323 | err = 0; | ||
355 | out: | 324 | out: |
325 | if (!wbc->for_writepages) | ||
326 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | int nfs_writepage(struct page *page, struct writeback_control *wbc) | ||
331 | { | ||
332 | int err; | ||
333 | |||
334 | err = nfs_writepage_locked(page, wbc); | ||
356 | unlock_page(page); | 335 | unlock_page(page); |
357 | if (inode_referenced) | ||
358 | iput(inode); | ||
359 | return err; | 336 | return err; |
360 | } | 337 | } |
361 | 338 | ||
@@ -379,21 +356,18 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
379 | return 0; | 356 | return 0; |
380 | nfs_wait_on_write_congestion(mapping, 0); | 357 | nfs_wait_on_write_congestion(mapping, 0); |
381 | } | 358 | } |
382 | err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); | 359 | err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc)); |
383 | if (err < 0) | 360 | if (err < 0) |
384 | goto out; | 361 | goto out; |
385 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | 362 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); |
386 | wbc->nr_to_write -= err; | ||
387 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { | 363 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { |
388 | err = nfs_wait_on_requests(inode, 0, 0); | 364 | err = nfs_wait_on_requests(inode, 0, 0); |
389 | if (err < 0) | 365 | if (err < 0) |
390 | goto out; | 366 | goto out; |
391 | } | 367 | } |
392 | err = nfs_commit_inode(inode, wb_priority(wbc)); | 368 | err = nfs_commit_inode(inode, wb_priority(wbc)); |
393 | if (err > 0) { | 369 | if (err > 0) |
394 | wbc->nr_to_write -= err; | ||
395 | err = 0; | 370 | err = 0; |
396 | } | ||
397 | out: | 371 | out: |
398 | clear_bit(BDI_write_congested, &bdi->state); | 372 | clear_bit(BDI_write_congested, &bdi->state); |
399 | wake_up_all(&nfs_write_congestion); | 373 | wake_up_all(&nfs_write_congestion); |
@@ -420,6 +394,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
420 | nfsi->change_attr++; | 394 | nfsi->change_attr++; |
421 | } | 395 | } |
422 | SetPagePrivate(req->wb_page); | 396 | SetPagePrivate(req->wb_page); |
397 | set_page_private(req->wb_page, (unsigned long)req); | ||
423 | nfsi->npages++; | 398 | nfsi->npages++; |
424 | atomic_inc(&req->wb_count); | 399 | atomic_inc(&req->wb_count); |
425 | return 0; | 400 | return 0; |
@@ -436,6 +411,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
436 | BUG_ON (!NFS_WBACK_BUSY(req)); | 411 | BUG_ON (!NFS_WBACK_BUSY(req)); |
437 | 412 | ||
438 | spin_lock(&nfsi->req_lock); | 413 | spin_lock(&nfsi->req_lock); |
414 | set_page_private(req->wb_page, 0); | ||
439 | ClearPagePrivate(req->wb_page); | 415 | ClearPagePrivate(req->wb_page); |
440 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 416 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
441 | nfsi->npages--; | 417 | nfsi->npages--; |
@@ -450,33 +426,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
450 | } | 426 | } |
451 | 427 | ||
452 | /* | 428 | /* |
453 | * Find a request | ||
454 | */ | ||
455 | static inline struct nfs_page * | ||
456 | _nfs_find_request(struct inode *inode, unsigned long index) | ||
457 | { | ||
458 | struct nfs_inode *nfsi = NFS_I(inode); | ||
459 | struct nfs_page *req; | ||
460 | |||
461 | req = (struct nfs_page*)radix_tree_lookup(&nfsi->nfs_page_tree, index); | ||
462 | if (req) | ||
463 | atomic_inc(&req->wb_count); | ||
464 | return req; | ||
465 | } | ||
466 | |||
467 | static struct nfs_page * | ||
468 | nfs_find_request(struct inode *inode, unsigned long index) | ||
469 | { | ||
470 | struct nfs_page *req; | ||
471 | struct nfs_inode *nfsi = NFS_I(inode); | ||
472 | |||
473 | spin_lock(&nfsi->req_lock); | ||
474 | req = _nfs_find_request(inode, index); | ||
475 | spin_unlock(&nfsi->req_lock); | ||
476 | return req; | ||
477 | } | ||
478 | |||
479 | /* | ||
480 | * Add a request to the inode's dirty list. | 429 | * Add a request to the inode's dirty list. |
481 | */ | 430 | */ |
482 | static void | 431 | static void |
@@ -491,8 +440,14 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
491 | nfs_list_add_request(req, &nfsi->dirty); | 440 | nfs_list_add_request(req, &nfsi->dirty); |
492 | nfsi->ndirty++; | 441 | nfsi->ndirty++; |
493 | spin_unlock(&nfsi->req_lock); | 442 | spin_unlock(&nfsi->req_lock); |
494 | inc_zone_page_state(req->wb_page, NR_FILE_DIRTY); | 443 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
495 | mark_inode_dirty(inode); | 444 | } |
445 | |||
446 | static void | ||
447 | nfs_redirty_request(struct nfs_page *req) | ||
448 | { | ||
449 | clear_bit(PG_FLUSHING, &req->wb_flags); | ||
450 | __set_page_dirty_nobuffers(req->wb_page); | ||
496 | } | 451 | } |
497 | 452 | ||
498 | /* | 453 | /* |
@@ -501,8 +456,7 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
501 | static inline int | 456 | static inline int |
502 | nfs_dirty_request(struct nfs_page *req) | 457 | nfs_dirty_request(struct nfs_page *req) |
503 | { | 458 | { |
504 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | 459 | return test_bit(PG_FLUSHING, &req->wb_flags) == 0; |
505 | return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty; | ||
506 | } | 460 | } |
507 | 461 | ||
508 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 462 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -520,7 +474,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
520 | nfsi->ncommit++; | 474 | nfsi->ncommit++; |
521 | spin_unlock(&nfsi->req_lock); | 475 | spin_unlock(&nfsi->req_lock); |
522 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 476 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
523 | mark_inode_dirty(inode); | 477 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
524 | } | 478 | } |
525 | #endif | 479 | #endif |
526 | 480 | ||
@@ -597,31 +551,6 @@ static void nfs_cancel_commit_list(struct list_head *head) | |||
597 | } | 551 | } |
598 | } | 552 | } |
599 | 553 | ||
600 | /* | ||
601 | * nfs_scan_dirty - Scan an inode for dirty requests | ||
602 | * @inode: NFS inode to scan | ||
603 | * @dst: destination list | ||
604 | * @idx_start: lower bound of page->index to scan. | ||
605 | * @npages: idx_start + npages sets the upper bound to scan. | ||
606 | * | ||
607 | * Moves requests from the inode's dirty page list. | ||
608 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
609 | */ | ||
610 | static int | ||
611 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | ||
612 | { | ||
613 | struct nfs_inode *nfsi = NFS_I(inode); | ||
614 | int res = 0; | ||
615 | |||
616 | if (nfsi->ndirty != 0) { | ||
617 | res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); | ||
618 | nfsi->ndirty -= res; | ||
619 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | ||
620 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | ||
621 | } | ||
622 | return res; | ||
623 | } | ||
624 | |||
625 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 554 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
626 | /* | 555 | /* |
627 | * nfs_scan_commit - Scan an inode for commit requests | 556 | * nfs_scan_commit - Scan an inode for commit requests |
@@ -698,27 +627,27 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) | |||
698 | * Note: Should always be called with the Page Lock held! | 627 | * Note: Should always be called with the Page Lock held! |
699 | */ | 628 | */ |
700 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | 629 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, |
701 | struct inode *inode, struct page *page, | 630 | struct page *page, unsigned int offset, unsigned int bytes) |
702 | unsigned int offset, unsigned int bytes) | ||
703 | { | 631 | { |
704 | struct nfs_server *server = NFS_SERVER(inode); | 632 | struct inode *inode = page->mapping->host; |
705 | struct nfs_inode *nfsi = NFS_I(inode); | 633 | struct nfs_inode *nfsi = NFS_I(inode); |
706 | struct nfs_page *req, *new = NULL; | 634 | struct nfs_page *req, *new = NULL; |
707 | unsigned long rqend, end; | 635 | unsigned long rqend, end; |
708 | 636 | ||
709 | end = offset + bytes; | 637 | end = offset + bytes; |
710 | 638 | ||
711 | if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR)) | 639 | if (nfs_wait_on_write_congestion(page->mapping, NFS_SERVER(inode)->flags & NFS_MOUNT_INTR)) |
712 | return ERR_PTR(-ERESTARTSYS); | 640 | return ERR_PTR(-ERESTARTSYS); |
713 | for (;;) { | 641 | for (;;) { |
714 | /* Loop over all inode entries and see if we find | 642 | /* Loop over all inode entries and see if we find |
715 | * A request for the page we wish to update | 643 | * A request for the page we wish to update |
716 | */ | 644 | */ |
717 | spin_lock(&nfsi->req_lock); | 645 | spin_lock(&nfsi->req_lock); |
718 | req = _nfs_find_request(inode, page->index); | 646 | req = nfs_page_find_request_locked(page); |
719 | if (req) { | 647 | if (req) { |
720 | if (!nfs_lock_request_dontget(req)) { | 648 | if (!nfs_lock_request_dontget(req)) { |
721 | int error; | 649 | int error; |
650 | |||
722 | spin_unlock(&nfsi->req_lock); | 651 | spin_unlock(&nfsi->req_lock); |
723 | error = nfs_wait_on_request(req); | 652 | error = nfs_wait_on_request(req); |
724 | nfs_release_request(req); | 653 | nfs_release_request(req); |
@@ -745,7 +674,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
745 | return ERR_PTR(error); | 674 | return ERR_PTR(error); |
746 | } | 675 | } |
747 | spin_unlock(&nfsi->req_lock); | 676 | spin_unlock(&nfsi->req_lock); |
748 | nfs_mark_request_dirty(new); | ||
749 | return new; | 677 | return new; |
750 | } | 678 | } |
751 | spin_unlock(&nfsi->req_lock); | 679 | spin_unlock(&nfsi->req_lock); |
@@ -786,9 +714,8 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
786 | int nfs_flush_incompatible(struct file *file, struct page *page) | 714 | int nfs_flush_incompatible(struct file *file, struct page *page) |
787 | { | 715 | { |
788 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 716 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
789 | struct inode *inode = page->mapping->host; | ||
790 | struct nfs_page *req; | 717 | struct nfs_page *req; |
791 | int status = 0; | 718 | int do_flush, status; |
792 | /* | 719 | /* |
793 | * Look for a request corresponding to this page. If there | 720 | * Look for a request corresponding to this page. If there |
794 | * is one, and it belongs to another file, we flush it out | 721 | * is one, and it belongs to another file, we flush it out |
@@ -797,13 +724,18 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
797 | * Also do the same if we find a request from an existing | 724 | * Also do the same if we find a request from an existing |
798 | * dropped page. | 725 | * dropped page. |
799 | */ | 726 | */ |
800 | req = nfs_find_request(inode, page->index); | 727 | do { |
801 | if (req) { | 728 | req = nfs_page_find_request(page); |
802 | if (req->wb_page != page || ctx != req->wb_context) | 729 | if (req == NULL) |
803 | status = nfs_wb_page(inode, page); | 730 | return 0; |
731 | do_flush = req->wb_page != page || req->wb_context != ctx | ||
732 | || !nfs_dirty_request(req); | ||
804 | nfs_release_request(req); | 733 | nfs_release_request(req); |
805 | } | 734 | if (!do_flush) |
806 | return (status < 0) ? status : 0; | 735 | return 0; |
736 | status = nfs_wb_page(page->mapping->host, page); | ||
737 | } while (status == 0); | ||
738 | return status; | ||
807 | } | 739 | } |
808 | 740 | ||
809 | /* | 741 | /* |
@@ -817,7 +749,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
817 | { | 749 | { |
818 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 750 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
819 | struct inode *inode = page->mapping->host; | 751 | struct inode *inode = page->mapping->host; |
820 | struct nfs_page *req; | ||
821 | int status = 0; | 752 | int status = 0; |
822 | 753 | ||
823 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); | 754 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); |
@@ -827,62 +758,18 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
827 | file->f_dentry->d_name.name, count, | 758 | file->f_dentry->d_name.name, count, |
828 | (long long)(page_offset(page) +offset)); | 759 | (long long)(page_offset(page) +offset)); |
829 | 760 | ||
830 | if (IS_SYNC(inode)) { | ||
831 | status = nfs_writepage_sync(ctx, inode, page, offset, count, 0); | ||
832 | if (status > 0) { | ||
833 | if (offset == 0 && status == PAGE_CACHE_SIZE) | ||
834 | SetPageUptodate(page); | ||
835 | return 0; | ||
836 | } | ||
837 | return status; | ||
838 | } | ||
839 | |||
840 | /* If we're not using byte range locks, and we know the page | 761 | /* If we're not using byte range locks, and we know the page |
841 | * is entirely in cache, it may be more efficient to avoid | 762 | * is entirely in cache, it may be more efficient to avoid |
842 | * fragmenting write requests. | 763 | * fragmenting write requests. |
843 | */ | 764 | */ |
844 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { | 765 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
845 | loff_t end_offs = i_size_read(inode) - 1; | 766 | count = max(count + offset, nfs_page_length(page)); |
846 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; | ||
847 | |||
848 | count += offset; | ||
849 | offset = 0; | 767 | offset = 0; |
850 | if (unlikely(end_offs < 0)) { | ||
851 | /* Do nothing */ | ||
852 | } else if (page->index == end_index) { | ||
853 | unsigned int pglen; | ||
854 | pglen = (unsigned int)(end_offs & (PAGE_CACHE_SIZE-1)) + 1; | ||
855 | if (count < pglen) | ||
856 | count = pglen; | ||
857 | } else if (page->index < end_index) | ||
858 | count = PAGE_CACHE_SIZE; | ||
859 | } | 768 | } |
860 | 769 | ||
861 | /* | 770 | status = nfs_writepage_setup(ctx, page, offset, count); |
862 | * Try to find an NFS request corresponding to this page | 771 | __set_page_dirty_nobuffers(page); |
863 | * and update it. | ||
864 | * If the existing request cannot be updated, we must flush | ||
865 | * it out now. | ||
866 | */ | ||
867 | do { | ||
868 | req = nfs_update_request(ctx, inode, page, offset, count); | ||
869 | status = (IS_ERR(req)) ? PTR_ERR(req) : 0; | ||
870 | if (status != -EBUSY) | ||
871 | break; | ||
872 | /* Request could not be updated. Flush it out and try again */ | ||
873 | status = nfs_wb_page(inode, page); | ||
874 | } while (status >= 0); | ||
875 | if (status < 0) | ||
876 | goto done; | ||
877 | |||
878 | status = 0; | ||
879 | 772 | ||
880 | /* Update file length */ | ||
881 | nfs_grow_file(page, offset, count); | ||
882 | /* Set the PG_uptodate flag? */ | ||
883 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | ||
884 | nfs_unlock_request(req); | ||
885 | done: | ||
886 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 773 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
887 | status, (long long)i_size_read(inode)); | 774 | status, (long long)i_size_read(inode)); |
888 | if (status < 0) | 775 | if (status < 0) |
@@ -897,7 +784,7 @@ static void nfs_writepage_release(struct nfs_page *req) | |||
897 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 784 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
898 | if (!PageError(req->wb_page)) { | 785 | if (!PageError(req->wb_page)) { |
899 | if (NFS_NEED_RESCHED(req)) { | 786 | if (NFS_NEED_RESCHED(req)) { |
900 | nfs_mark_request_dirty(req); | 787 | nfs_redirty_request(req); |
901 | goto out; | 788 | goto out; |
902 | } else if (NFS_NEED_COMMIT(req)) { | 789 | } else if (NFS_NEED_COMMIT(req)) { |
903 | nfs_mark_request_commit(req); | 790 | nfs_mark_request_commit(req); |
@@ -979,9 +866,7 @@ static void nfs_execute_write(struct nfs_write_data *data) | |||
979 | sigset_t oldset; | 866 | sigset_t oldset; |
980 | 867 | ||
981 | rpc_clnt_sigmask(clnt, &oldset); | 868 | rpc_clnt_sigmask(clnt, &oldset); |
982 | lock_kernel(); | ||
983 | rpc_execute(&data->task); | 869 | rpc_execute(&data->task); |
984 | unlock_kernel(); | ||
985 | rpc_clnt_sigunmask(clnt, &oldset); | 870 | rpc_clnt_sigunmask(clnt, &oldset); |
986 | } | 871 | } |
987 | 872 | ||
@@ -1015,7 +900,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
1015 | atomic_set(&req->wb_complete, requests); | 900 | atomic_set(&req->wb_complete, requests); |
1016 | 901 | ||
1017 | ClearPageError(page); | 902 | ClearPageError(page); |
1018 | set_page_writeback(page); | ||
1019 | offset = 0; | 903 | offset = 0; |
1020 | nbytes = req->wb_bytes; | 904 | nbytes = req->wb_bytes; |
1021 | do { | 905 | do { |
@@ -1043,9 +927,9 @@ out_bad: | |||
1043 | while (!list_empty(&list)) { | 927 | while (!list_empty(&list)) { |
1044 | data = list_entry(list.next, struct nfs_write_data, pages); | 928 | data = list_entry(list.next, struct nfs_write_data, pages); |
1045 | list_del(&data->pages); | 929 | list_del(&data->pages); |
1046 | nfs_writedata_free(data); | 930 | nfs_writedata_release(data); |
1047 | } | 931 | } |
1048 | nfs_mark_request_dirty(req); | 932 | nfs_redirty_request(req); |
1049 | nfs_clear_page_writeback(req); | 933 | nfs_clear_page_writeback(req); |
1050 | return -ENOMEM; | 934 | return -ENOMEM; |
1051 | } | 935 | } |
@@ -1076,7 +960,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
1076 | nfs_list_remove_request(req); | 960 | nfs_list_remove_request(req); |
1077 | nfs_list_add_request(req, &data->pages); | 961 | nfs_list_add_request(req, &data->pages); |
1078 | ClearPageError(req->wb_page); | 962 | ClearPageError(req->wb_page); |
1079 | set_page_writeback(req->wb_page); | ||
1080 | *pages++ = req->wb_page; | 963 | *pages++ = req->wb_page; |
1081 | count += req->wb_bytes; | 964 | count += req->wb_bytes; |
1082 | } | 965 | } |
@@ -1091,7 +974,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
1091 | while (!list_empty(head)) { | 974 | while (!list_empty(head)) { |
1092 | struct nfs_page *req = nfs_list_entry(head->next); | 975 | struct nfs_page *req = nfs_list_entry(head->next); |
1093 | nfs_list_remove_request(req); | 976 | nfs_list_remove_request(req); |
1094 | nfs_mark_request_dirty(req); | 977 | nfs_redirty_request(req); |
1095 | nfs_clear_page_writeback(req); | 978 | nfs_clear_page_writeback(req); |
1096 | } | 979 | } |
1097 | return -ENOMEM; | 980 | return -ENOMEM; |
@@ -1126,7 +1009,7 @@ out_err: | |||
1126 | while (!list_empty(head)) { | 1009 | while (!list_empty(head)) { |
1127 | req = nfs_list_entry(head->next); | 1010 | req = nfs_list_entry(head->next); |
1128 | nfs_list_remove_request(req); | 1011 | nfs_list_remove_request(req); |
1129 | nfs_mark_request_dirty(req); | 1012 | nfs_redirty_request(req); |
1130 | nfs_clear_page_writeback(req); | 1013 | nfs_clear_page_writeback(req); |
1131 | } | 1014 | } |
1132 | return error; | 1015 | return error; |
@@ -1442,7 +1325,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1442 | } | 1325 | } |
1443 | /* We have a mismatch. Write the page again */ | 1326 | /* We have a mismatch. Write the page again */ |
1444 | dprintk(" mismatch\n"); | 1327 | dprintk(" mismatch\n"); |
1445 | nfs_mark_request_dirty(req); | 1328 | nfs_redirty_request(req); |
1446 | next: | 1329 | next: |
1447 | nfs_clear_page_writeback(req); | 1330 | nfs_clear_page_writeback(req); |
1448 | } | 1331 | } |
@@ -1459,18 +1342,17 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i | |||
1459 | } | 1342 | } |
1460 | #endif | 1343 | #endif |
1461 | 1344 | ||
1462 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 1345 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) |
1463 | unsigned int npages, int how) | ||
1464 | { | 1346 | { |
1465 | struct nfs_inode *nfsi = NFS_I(inode); | 1347 | struct nfs_inode *nfsi = NFS_I(mapping->host); |
1466 | LIST_HEAD(head); | 1348 | LIST_HEAD(head); |
1467 | int res; | 1349 | long res; |
1468 | 1350 | ||
1469 | spin_lock(&nfsi->req_lock); | 1351 | spin_lock(&nfsi->req_lock); |
1470 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1352 | res = nfs_scan_dirty(mapping, wbc, &head); |
1471 | spin_unlock(&nfsi->req_lock); | 1353 | spin_unlock(&nfsi->req_lock); |
1472 | if (res) { | 1354 | if (res) { |
1473 | int error = nfs_flush_list(inode, &head, res, how); | 1355 | int error = nfs_flush_list(mapping->host, &head, res, how); |
1474 | if (error < 0) | 1356 | if (error < 0) |
1475 | return error; | 1357 | return error; |
1476 | } | 1358 | } |
@@ -1496,38 +1378,62 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1496 | } | 1378 | } |
1497 | #endif | 1379 | #endif |
1498 | 1380 | ||
1499 | int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, | 1381 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) |
1500 | unsigned int npages, int how) | ||
1501 | { | 1382 | { |
1383 | struct inode *inode = mapping->host; | ||
1502 | struct nfs_inode *nfsi = NFS_I(inode); | 1384 | struct nfs_inode *nfsi = NFS_I(inode); |
1385 | unsigned long idx_start, idx_end; | ||
1386 | unsigned int npages = 0; | ||
1503 | LIST_HEAD(head); | 1387 | LIST_HEAD(head); |
1504 | int nocommit = how & FLUSH_NOCOMMIT; | 1388 | int nocommit = how & FLUSH_NOCOMMIT; |
1505 | int pages, ret; | 1389 | long pages, ret; |
1506 | 1390 | ||
1391 | /* FIXME */ | ||
1392 | if (wbc->range_cyclic) | ||
1393 | idx_start = 0; | ||
1394 | else { | ||
1395 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
1396 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
1397 | if (idx_end > idx_start) { | ||
1398 | unsigned long l_npages = 1 + idx_end - idx_start; | ||
1399 | npages = l_npages; | ||
1400 | if (sizeof(npages) != sizeof(l_npages) && | ||
1401 | (unsigned long)npages != l_npages) | ||
1402 | npages = 0; | ||
1403 | } | ||
1404 | } | ||
1507 | how &= ~FLUSH_NOCOMMIT; | 1405 | how &= ~FLUSH_NOCOMMIT; |
1508 | spin_lock(&nfsi->req_lock); | 1406 | spin_lock(&nfsi->req_lock); |
1509 | do { | 1407 | do { |
1408 | wbc->pages_skipped = 0; | ||
1510 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | 1409 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); |
1511 | if (ret != 0) | 1410 | if (ret != 0) |
1512 | continue; | 1411 | continue; |
1513 | pages = nfs_scan_dirty(inode, &head, idx_start, npages); | 1412 | pages = nfs_scan_dirty(mapping, wbc, &head); |
1514 | if (pages != 0) { | 1413 | if (pages != 0) { |
1515 | spin_unlock(&nfsi->req_lock); | 1414 | spin_unlock(&nfsi->req_lock); |
1516 | if (how & FLUSH_INVALIDATE) | 1415 | if (how & FLUSH_INVALIDATE) { |
1517 | nfs_cancel_dirty_list(&head); | 1416 | nfs_cancel_dirty_list(&head); |
1518 | else | 1417 | ret = pages; |
1418 | } else | ||
1519 | ret = nfs_flush_list(inode, &head, pages, how); | 1419 | ret = nfs_flush_list(inode, &head, pages, how); |
1520 | spin_lock(&nfsi->req_lock); | 1420 | spin_lock(&nfsi->req_lock); |
1521 | continue; | 1421 | continue; |
1522 | } | 1422 | } |
1423 | if (wbc->pages_skipped != 0) | ||
1424 | continue; | ||
1523 | if (nocommit) | 1425 | if (nocommit) |
1524 | break; | 1426 | break; |
1525 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | 1427 | pages = nfs_scan_commit(inode, &head, idx_start, npages); |
1526 | if (pages == 0) | 1428 | if (pages == 0) { |
1429 | if (wbc->pages_skipped != 0) | ||
1430 | continue; | ||
1527 | break; | 1431 | break; |
1432 | } | ||
1528 | if (how & FLUSH_INVALIDATE) { | 1433 | if (how & FLUSH_INVALIDATE) { |
1529 | spin_unlock(&nfsi->req_lock); | 1434 | spin_unlock(&nfsi->req_lock); |
1530 | nfs_cancel_commit_list(&head); | 1435 | nfs_cancel_commit_list(&head); |
1436 | ret = pages; | ||
1531 | spin_lock(&nfsi->req_lock); | 1437 | spin_lock(&nfsi->req_lock); |
1532 | continue; | 1438 | continue; |
1533 | } | 1439 | } |
@@ -1540,6 +1446,106 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, | |||
1540 | return ret; | 1446 | return ret; |
1541 | } | 1447 | } |
1542 | 1448 | ||
1449 | /* | ||
1450 | * flush the inode to disk. | ||
1451 | */ | ||
1452 | int nfs_wb_all(struct inode *inode) | ||
1453 | { | ||
1454 | struct address_space *mapping = inode->i_mapping; | ||
1455 | struct writeback_control wbc = { | ||
1456 | .bdi = mapping->backing_dev_info, | ||
1457 | .sync_mode = WB_SYNC_ALL, | ||
1458 | .nr_to_write = LONG_MAX, | ||
1459 | .for_writepages = 1, | ||
1460 | .range_cyclic = 1, | ||
1461 | }; | ||
1462 | int ret; | ||
1463 | |||
1464 | ret = generic_writepages(mapping, &wbc); | ||
1465 | if (ret < 0) | ||
1466 | goto out; | ||
1467 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); | ||
1468 | if (ret >= 0) | ||
1469 | return 0; | ||
1470 | out: | ||
1471 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1472 | return ret; | ||
1473 | } | ||
1474 | |||
1475 | int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) | ||
1476 | { | ||
1477 | struct writeback_control wbc = { | ||
1478 | .bdi = mapping->backing_dev_info, | ||
1479 | .sync_mode = WB_SYNC_ALL, | ||
1480 | .nr_to_write = LONG_MAX, | ||
1481 | .range_start = range_start, | ||
1482 | .range_end = range_end, | ||
1483 | .for_writepages = 1, | ||
1484 | }; | ||
1485 | int ret; | ||
1486 | |||
1487 | if (!(how & FLUSH_NOWRITEPAGE)) { | ||
1488 | ret = generic_writepages(mapping, &wbc); | ||
1489 | if (ret < 0) | ||
1490 | goto out; | ||
1491 | } | ||
1492 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); | ||
1493 | if (ret >= 0) | ||
1494 | return 0; | ||
1495 | out: | ||
1496 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1497 | return ret; | ||
1498 | } | ||
1499 | |||
1500 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | ||
1501 | { | ||
1502 | loff_t range_start = page_offset(page); | ||
1503 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | ||
1504 | struct writeback_control wbc = { | ||
1505 | .bdi = page->mapping->backing_dev_info, | ||
1506 | .sync_mode = WB_SYNC_ALL, | ||
1507 | .nr_to_write = LONG_MAX, | ||
1508 | .range_start = range_start, | ||
1509 | .range_end = range_end, | ||
1510 | }; | ||
1511 | int ret; | ||
1512 | |||
1513 | BUG_ON(!PageLocked(page)); | ||
1514 | if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) { | ||
1515 | ret = nfs_writepage_locked(page, &wbc); | ||
1516 | if (ret < 0) | ||
1517 | goto out; | ||
1518 | } | ||
1519 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1520 | if (ret >= 0) | ||
1521 | return 0; | ||
1522 | out: | ||
1523 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | |||
1527 | /* | ||
1528 | * Write back all requests on one page - we do this before reading it. | ||
1529 | */ | ||
1530 | int nfs_wb_page(struct inode *inode, struct page* page) | ||
1531 | { | ||
1532 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | ||
1533 | } | ||
1534 | |||
1535 | int nfs_set_page_dirty(struct page *page) | ||
1536 | { | ||
1537 | struct nfs_page *req; | ||
1538 | |||
1539 | req = nfs_page_find_request(page); | ||
1540 | if (req != NULL) { | ||
1541 | /* Mark any existing write requests for flushing */ | ||
1542 | set_bit(PG_NEED_FLUSH, &req->wb_flags); | ||
1543 | nfs_release_request(req); | ||
1544 | } | ||
1545 | return __set_page_dirty_nobuffers(page); | ||
1546 | } | ||
1547 | |||
1548 | |||
1543 | int __init nfs_init_writepagecache(void) | 1549 | int __init nfs_init_writepagecache(void) |
1544 | { | 1550 | { |
1545 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1551 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |