diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 98 |
1 files changed, 71 insertions, 27 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9f9845859fc1..a34fae21fe10 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | ||
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 31 | ||
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
52 | if (p) { | 53 | if (p) { |
53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
55 | } | 57 | } |
56 | return p; | 58 | return p; |
57 | } | 59 | } |
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
76 | else { | 79 | else { |
@@ -84,17 +87,15 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
84 | return p; | 87 | return p; |
85 | } | 88 | } |
86 | 89 | ||
87 | static void nfs_writedata_free(struct nfs_write_data *p) | 90 | void nfs_writedata_free(struct nfs_write_data *p) |
88 | { | 91 | { |
89 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
90 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
91 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
92 | } | 95 | } |
93 | 96 | ||
94 | void nfs_writedata_release(void *data) | 97 | static void nfs_writedata_release(struct nfs_write_data *wdata) |
95 | { | 98 | { |
96 | struct nfs_write_data *wdata = data; | ||
97 | |||
98 | put_nfs_open_context(wdata->args.context); | 99 | put_nfs_open_context(wdata->args.context); |
99 | nfs_writedata_free(wdata); | 100 | nfs_writedata_free(wdata); |
100 | } | 101 | } |
@@ -199,8 +200,10 @@ static int nfs_set_page_writeback(struct page *page) | |||
199 | struct nfs_server *nfss = NFS_SERVER(inode); | 200 | struct nfs_server *nfss = NFS_SERVER(inode); |
200 | 201 | ||
201 | if (atomic_long_inc_return(&nfss->writeback) > | 202 | if (atomic_long_inc_return(&nfss->writeback) > |
202 | NFS_CONGESTION_ON_THRESH) | 203 | NFS_CONGESTION_ON_THRESH) { |
203 | set_bdi_congested(&nfss->backing_dev_info, WRITE); | 204 | set_bdi_congested(&nfss->backing_dev_info, |
205 | BLK_RW_ASYNC); | ||
206 | } | ||
204 | } | 207 | } |
205 | return ret; | 208 | return ret; |
206 | } | 209 | } |
@@ -212,7 +215,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
212 | 215 | ||
213 | end_page_writeback(page); | 216 | end_page_writeback(page); |
214 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 217 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
215 | clear_bdi_congested(&nfss->backing_dev_info, WRITE); | 218 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
216 | } | 219 | } |
217 | 220 | ||
218 | /* | 221 | /* |
@@ -313,19 +316,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * | |||
313 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | 316 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) |
314 | { | 317 | { |
315 | struct inode *inode = mapping->host; | 318 | struct inode *inode = mapping->host; |
319 | unsigned long *bitlock = &NFS_I(inode)->flags; | ||
316 | struct nfs_pageio_descriptor pgio; | 320 | struct nfs_pageio_descriptor pgio; |
317 | int err; | 321 | int err; |
318 | 322 | ||
323 | /* Stop dirtying of new pages while we sync */ | ||
324 | err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING, | ||
325 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
326 | if (err) | ||
327 | goto out_err; | ||
328 | |||
319 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); | 329 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); |
320 | 330 | ||
321 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); | 331 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); |
322 | err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); | 332 | err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); |
323 | nfs_pageio_complete(&pgio); | 333 | nfs_pageio_complete(&pgio); |
334 | |||
335 | clear_bit_unlock(NFS_INO_FLUSHING, bitlock); | ||
336 | smp_mb__after_clear_bit(); | ||
337 | wake_up_bit(bitlock, NFS_INO_FLUSHING); | ||
338 | |||
324 | if (err < 0) | 339 | if (err < 0) |
325 | return err; | 340 | goto out_err; |
326 | if (pgio.pg_error < 0) | 341 | err = pgio.pg_error; |
327 | return pgio.pg_error; | 342 | if (err < 0) |
343 | goto out_err; | ||
328 | return 0; | 344 | return 0; |
345 | out_err: | ||
346 | return err; | ||
329 | } | 347 | } |
330 | 348 | ||
331 | /* | 349 | /* |
@@ -404,7 +422,6 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
404 | struct nfs_inode *nfsi = NFS_I(inode); | 422 | struct nfs_inode *nfsi = NFS_I(inode); |
405 | 423 | ||
406 | spin_lock(&inode->i_lock); | 424 | spin_lock(&inode->i_lock); |
407 | nfsi->ncommit++; | ||
408 | set_bit(PG_CLEAN, &(req)->wb_flags); | 425 | set_bit(PG_CLEAN, &(req)->wb_flags); |
409 | radix_tree_tag_set(&nfsi->nfs_page_tree, | 426 | radix_tree_tag_set(&nfsi->nfs_page_tree, |
410 | req->wb_index, | 427 | req->wb_index, |
@@ -524,6 +541,12 @@ static void nfs_cancel_commit_list(struct list_head *head) | |||
524 | } | 541 | } |
525 | 542 | ||
526 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 543 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
544 | static int | ||
545 | nfs_need_commit(struct nfs_inode *nfsi) | ||
546 | { | ||
547 | return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT); | ||
548 | } | ||
549 | |||
527 | /* | 550 | /* |
528 | * nfs_scan_commit - Scan an inode for commit requests | 551 | * nfs_scan_commit - Scan an inode for commit requests |
529 | * @inode: NFS inode to scan | 552 | * @inode: NFS inode to scan |
@@ -538,16 +561,18 @@ static int | |||
538 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 561 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
539 | { | 562 | { |
540 | struct nfs_inode *nfsi = NFS_I(inode); | 563 | struct nfs_inode *nfsi = NFS_I(inode); |
541 | int res = 0; | ||
542 | 564 | ||
543 | if (nfsi->ncommit != 0) { | 565 | if (!nfs_need_commit(nfsi)) |
544 | res = nfs_scan_list(nfsi, dst, idx_start, npages, | 566 | return 0; |
545 | NFS_PAGE_TAG_COMMIT); | 567 | |
546 | nfsi->ncommit -= res; | 568 | return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); |
547 | } | ||
548 | return res; | ||
549 | } | 569 | } |
550 | #else | 570 | #else |
571 | static inline int nfs_need_commit(struct nfs_inode *nfsi) | ||
572 | { | ||
573 | return 0; | ||
574 | } | ||
575 | |||
551 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 576 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
552 | { | 577 | { |
553 | return 0; | 578 | return 0; |
@@ -820,7 +845,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
820 | data->args.stable = NFS_UNSTABLE; | 845 | data->args.stable = NFS_UNSTABLE; |
821 | if (how & FLUSH_STABLE) { | 846 | if (how & FLUSH_STABLE) { |
822 | data->args.stable = NFS_DATA_SYNC; | 847 | data->args.stable = NFS_DATA_SYNC; |
823 | if (!NFS_I(inode)->ncommit) | 848 | if (!nfs_need_commit(NFS_I(inode))) |
824 | data->args.stable = NFS_FILE_SYNC; | 849 | data->args.stable = NFS_FILE_SYNC; |
825 | } | 850 | } |
826 | 851 | ||
@@ -1026,7 +1051,23 @@ out: | |||
1026 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
1027 | } | 1052 | } |
1028 | 1053 | ||
1054 | #if defined(CONFIG_NFS_V4_1) | ||
1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
1056 | { | ||
1057 | struct nfs_write_data *data = calldata; | ||
1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1059 | |||
1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
1061 | &data->res.seq_res, 1, task)) | ||
1062 | return; | ||
1063 | rpc_call_start(task); | ||
1064 | } | ||
1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
1066 | |||
1029 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1068 | #if defined(CONFIG_NFS_V4_1) | ||
1069 | .rpc_call_prepare = nfs_write_prepare, | ||
1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
1030 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
1031 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
1032 | }; | 1073 | }; |
@@ -1089,6 +1130,9 @@ remove_request: | |||
1089 | } | 1130 | } |
1090 | 1131 | ||
1091 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
1133 | #if defined(CONFIG_NFS_V4_1) | ||
1134 | .rpc_call_prepare = nfs_write_prepare, | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1092 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
1093 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
1094 | }; | 1138 | }; |
@@ -1101,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1101 | { | 1145 | { |
1102 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
1103 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1104 | int status; | 1149 | int status; |
1105 | 1150 | ||
1106 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1133,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1133 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
1134 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
1135 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
1136 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
1137 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
1138 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
1139 | } | 1184 | } |
@@ -1159,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1159 | */ | 1204 | */ |
1160 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
1161 | } | 1206 | } |
1162 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
1163 | return -EAGAIN; | 1208 | return -EAGAIN; |
1164 | } | 1209 | } |
1165 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
@@ -1171,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1171 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
1172 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
1173 | } | 1218 | } |
1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1174 | return 0; | 1220 | return 0; |
1175 | } | 1221 | } |
1176 | 1222 | ||
@@ -1327,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
1327 | } | 1373 | } |
1328 | 1374 | ||
1329 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
1376 | #if defined(CONFIG_NFS_V4_1) | ||
1377 | .rpc_call_prepare = nfs_write_prepare, | ||
1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
1330 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
1331 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
1332 | }; | 1381 | }; |
@@ -1425,18 +1474,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how) | |||
1425 | { | 1474 | { |
1426 | struct writeback_control wbc = { | 1475 | struct writeback_control wbc = { |
1427 | .bdi = mapping->backing_dev_info, | 1476 | .bdi = mapping->backing_dev_info, |
1428 | .sync_mode = WB_SYNC_NONE, | 1477 | .sync_mode = WB_SYNC_ALL, |
1429 | .nr_to_write = LONG_MAX, | 1478 | .nr_to_write = LONG_MAX, |
1430 | .range_start = 0, | 1479 | .range_start = 0, |
1431 | .range_end = LLONG_MAX, | 1480 | .range_end = LLONG_MAX, |
1432 | .for_writepages = 1, | 1481 | .for_writepages = 1, |
1433 | }; | 1482 | }; |
1434 | int ret; | ||
1435 | 1483 | ||
1436 | ret = __nfs_write_mapping(mapping, &wbc, how); | ||
1437 | if (ret < 0) | ||
1438 | return ret; | ||
1439 | wbc.sync_mode = WB_SYNC_ALL; | ||
1440 | return __nfs_write_mapping(mapping, &wbc, how); | 1484 | return __nfs_write_mapping(mapping, &wbc, how); |
1441 | } | 1485 | } |
1442 | 1486 | ||