diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 91 |
1 files changed, 20 insertions, 71 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 345492e78643..febdade91670 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1,47 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/nfs/write.c | 2 | * linux/fs/nfs/write.c |
3 | * | 3 | * |
4 | * Writing file data over NFS. | 4 | * Write file data over NFS. |
5 | * | ||
6 | * We do it like this: When a (user) process wishes to write data to an | ||
7 | * NFS file, a write request is allocated that contains the RPC task data | ||
8 | * plus some info on the page to be written, and added to the inode's | ||
9 | * write chain. If the process writes past the end of the page, an async | ||
10 | * RPC call to write the page is scheduled immediately; otherwise, the call | ||
11 | * is delayed for a few seconds. | ||
12 | * | ||
13 | * Just like readahead, no async I/O is performed if wsize < PAGE_SIZE. | ||
14 | * | ||
15 | * Write requests are kept on the inode's writeback list. Each entry in | ||
16 | * that list references the page (portion) to be written. When the | ||
17 | * cache timeout has expired, the RPC task is woken up, and tries to | ||
18 | * lock the page. As soon as it manages to do so, the request is moved | ||
19 | * from the writeback list to the writelock list. | ||
20 | * | ||
21 | * Note: we must make sure never to confuse the inode passed in the | ||
22 | * write_page request with the one in page->inode. As far as I understand | ||
23 | * it, these are different when doing a swap-out. | ||
24 | * | ||
25 | * To understand everything that goes on here and in the NFS read code, | ||
26 | * one should be aware that a page is locked in exactly one of the following | ||
27 | * cases: | ||
28 | * | ||
29 | * - A write request is in progress. | ||
30 | * - A user process is in generic_file_write/nfs_update_page | ||
31 | * - A user process is in generic_file_read | ||
32 | * | ||
33 | * Also note that because of the way pages are invalidated in | ||
34 | * nfs_revalidate_inode, the following assertions hold: | ||
35 | * | ||
36 | * - If a page is dirty, there will be no read requests (a page will | ||
37 | * not be re-read unless invalidated by nfs_revalidate_inode). | ||
38 | * - If the page is not uptodate, there will be no pending write | ||
39 | * requests, and no process will be in nfs_update_page. | ||
40 | * | ||
41 | * FIXME: Interaction with the vmscan routines is not optimal yet. | ||
42 | * Either vmscan must be made nfs-savvy, or we need a different page | ||
43 | * reclaim concept that supports something like FS-independent | ||
44 | * buffer_heads with a b_ops-> field. | ||
45 | * | 5 | * |
46 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> |
47 | */ | 7 | */ |
@@ -79,7 +39,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, | |||
79 | unsigned int, unsigned int); | 39 | unsigned int, unsigned int); |
80 | static void nfs_mark_request_dirty(struct nfs_page *req); | 40 | static void nfs_mark_request_dirty(struct nfs_page *req); |
81 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 41 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | ||
83 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); | 42 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); |
84 | static const struct rpc_call_ops nfs_write_partial_ops; | 43 | static const struct rpc_call_ops nfs_write_partial_ops; |
85 | static const struct rpc_call_ops nfs_write_full_ops; | 44 | static const struct rpc_call_ops nfs_write_full_ops; |
@@ -194,6 +153,13 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
194 | i_size_write(inode, end); | 153 | i_size_write(inode, end); |
195 | } | 154 | } |
196 | 155 | ||
156 | /* A writeback failed: mark the page as bad, and invalidate the page cache */ | ||
157 | static void nfs_set_pageerror(struct page *page) | ||
158 | { | ||
159 | SetPageError(page); | ||
160 | nfs_zap_mapping(page->mapping->host, page->mapping); | ||
161 | } | ||
162 | |||
197 | /* We can set the PG_uptodate flag if we see that a write request | 163 | /* We can set the PG_uptodate flag if we see that a write request |
198 | * covers the full page. | 164 | * covers the full page. |
199 | */ | 165 | */ |
@@ -323,7 +289,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
323 | err = 0; | 289 | err = 0; |
324 | out: | 290 | out: |
325 | if (!wbc->for_writepages) | 291 | if (!wbc->for_writepages) |
326 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); | 292 | nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc)); |
327 | return err; | 293 | return err; |
328 | } | 294 | } |
329 | 295 | ||
@@ -360,14 +326,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
360 | if (err < 0) | 326 | if (err < 0) |
361 | goto out; | 327 | goto out; |
362 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | 328 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); |
363 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { | 329 | err = 0; |
364 | err = nfs_wait_on_requests(inode, 0, 0); | ||
365 | if (err < 0) | ||
366 | goto out; | ||
367 | } | ||
368 | err = nfs_commit_inode(inode, wb_priority(wbc)); | ||
369 | if (err > 0) | ||
370 | err = 0; | ||
371 | out: | 330 | out: |
372 | clear_bit(BDI_write_congested, &bdi->state); | 331 | clear_bit(BDI_write_congested, &bdi->state); |
373 | wake_up_all(&nfs_write_congestion); | 332 | wake_up_all(&nfs_write_congestion); |
@@ -516,17 +475,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st | |||
516 | return res; | 475 | return res; |
517 | } | 476 | } |
518 | 477 | ||
519 | static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) | ||
520 | { | ||
521 | struct nfs_inode *nfsi = NFS_I(inode); | ||
522 | int ret; | ||
523 | |||
524 | spin_lock(&nfsi->req_lock); | ||
525 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | ||
526 | spin_unlock(&nfsi->req_lock); | ||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | static void nfs_cancel_dirty_list(struct list_head *head) | 478 | static void nfs_cancel_dirty_list(struct list_head *head) |
531 | { | 479 | { |
532 | struct nfs_page *req; | 480 | struct nfs_page *req; |
@@ -773,7 +721,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
773 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 721 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
774 | status, (long long)i_size_read(inode)); | 722 | status, (long long)i_size_read(inode)); |
775 | if (status < 0) | 723 | if (status < 0) |
776 | ClearPageUptodate(page); | 724 | nfs_set_pageerror(page); |
777 | return status; | 725 | return status; |
778 | } | 726 | } |
779 | 727 | ||
@@ -852,7 +800,8 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
852 | data->task.tk_priority = flush_task_priority(how); | 800 | data->task.tk_priority = flush_task_priority(how); |
853 | data->task.tk_cookie = (unsigned long)inode; | 801 | data->task.tk_cookie = (unsigned long)inode; |
854 | 802 | ||
855 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 803 | dprintk("NFS: %5u initiated write call " |
804 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | ||
856 | data->task.tk_pid, | 805 | data->task.tk_pid, |
857 | inode->i_sb->s_id, | 806 | inode->i_sb->s_id, |
858 | (long long)NFS_FILEID(inode), | 807 | (long long)NFS_FILEID(inode), |
@@ -1034,8 +983,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1034 | return; | 983 | return; |
1035 | 984 | ||
1036 | if (task->tk_status < 0) { | 985 | if (task->tk_status < 0) { |
1037 | ClearPageUptodate(page); | 986 | nfs_set_pageerror(page); |
1038 | SetPageError(page); | ||
1039 | req->wb_context->error = task->tk_status; | 987 | req->wb_context->error = task->tk_status; |
1040 | dprintk(", error = %d\n", task->tk_status); | 988 | dprintk(", error = %d\n", task->tk_status); |
1041 | } else { | 989 | } else { |
@@ -1092,8 +1040,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1092 | (long long)req_offset(req)); | 1040 | (long long)req_offset(req)); |
1093 | 1041 | ||
1094 | if (task->tk_status < 0) { | 1042 | if (task->tk_status < 0) { |
1095 | ClearPageUptodate(page); | 1043 | nfs_set_pageerror(page); |
1096 | SetPageError(page); | ||
1097 | req->wb_context->error = task->tk_status; | 1044 | req->wb_context->error = task->tk_status; |
1098 | end_page_writeback(page); | 1045 | end_page_writeback(page); |
1099 | nfs_inode_remove_request(req); | 1046 | nfs_inode_remove_request(req); |
@@ -1134,7 +1081,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1134 | struct nfs_writeres *resp = &data->res; | 1081 | struct nfs_writeres *resp = &data->res; |
1135 | int status; | 1082 | int status; |
1136 | 1083 | ||
1137 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1084 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
1138 | task->tk_pid, task->tk_status); | 1085 | task->tk_pid, task->tk_status); |
1139 | 1086 | ||
1140 | /* | 1087 | /* |
@@ -1250,7 +1197,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1250 | data->task.tk_priority = flush_task_priority(how); | 1197 | data->task.tk_priority = flush_task_priority(how); |
1251 | data->task.tk_cookie = (unsigned long)inode; | 1198 | data->task.tk_cookie = (unsigned long)inode; |
1252 | 1199 | ||
1253 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); | 1200 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1254 | } | 1201 | } |
1255 | 1202 | ||
1256 | /* | 1203 | /* |
@@ -1291,7 +1238,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1291 | struct nfs_write_data *data = calldata; | 1238 | struct nfs_write_data *data = calldata; |
1292 | struct nfs_page *req; | 1239 | struct nfs_page *req; |
1293 | 1240 | ||
1294 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", | 1241 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1295 | task->tk_pid, task->tk_status); | 1242 | task->tk_pid, task->tk_status); |
1296 | 1243 | ||
1297 | /* Call the NFS version-specific code */ | 1244 | /* Call the NFS version-specific code */ |
@@ -1516,6 +1463,8 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | |||
1516 | if (ret < 0) | 1463 | if (ret < 0) |
1517 | goto out; | 1464 | goto out; |
1518 | } | 1465 | } |
1466 | if (!PagePrivate(page)) | ||
1467 | return 0; | ||
1519 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | 1468 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); |
1520 | if (ret >= 0) | 1469 | if (ret >= 0) |
1521 | return 0; | 1470 | return 0; |