diff options
Diffstat (limited to 'fs/nfs/write.c')
| -rw-r--r-- | fs/nfs/write.c | 227 |
1 files changed, 147 insertions, 80 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 47a3ad63e0d5..af0c6279a4a7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -59,6 +59,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
| 59 | } | 59 | } |
| 60 | return p; | 60 | return p; |
| 61 | } | 61 | } |
| 62 | EXPORT_SYMBOL_GPL(nfs_commitdata_alloc); | ||
| 62 | 63 | ||
| 63 | void nfs_commit_free(struct nfs_write_data *p) | 64 | void nfs_commit_free(struct nfs_write_data *p) |
| 64 | { | 65 | { |
| @@ -66,6 +67,7 @@ void nfs_commit_free(struct nfs_write_data *p) | |||
| 66 | kfree(p->pagevec); | 67 | kfree(p->pagevec); |
| 67 | mempool_free(p, nfs_commit_mempool); | 68 | mempool_free(p, nfs_commit_mempool); |
| 68 | } | 69 | } |
| 70 | EXPORT_SYMBOL_GPL(nfs_commit_free); | ||
| 69 | 71 | ||
| 70 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 72 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
| 71 | { | 73 | { |
| @@ -179,8 +181,8 @@ static int wb_priority(struct writeback_control *wbc) | |||
| 179 | if (wbc->for_reclaim) | 181 | if (wbc->for_reclaim) |
| 180 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 182 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
| 181 | if (wbc->for_kupdate || wbc->for_background) | 183 | if (wbc->for_kupdate || wbc->for_background) |
| 182 | return FLUSH_LOWPRI; | 184 | return FLUSH_LOWPRI | FLUSH_COND_STABLE; |
| 183 | return 0; | 185 | return FLUSH_COND_STABLE; |
| 184 | } | 186 | } |
| 185 | 187 | ||
| 186 | /* | 188 | /* |
| @@ -387,11 +389,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
| 387 | spin_lock(&inode->i_lock); | 389 | spin_lock(&inode->i_lock); |
| 388 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 390 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
| 389 | BUG_ON(error); | 391 | BUG_ON(error); |
| 390 | if (!nfsi->npages) { | 392 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) |
| 391 | igrab(inode); | 393 | nfsi->change_attr++; |
| 392 | if (nfs_have_delegation(inode, FMODE_WRITE)) | ||
| 393 | nfsi->change_attr++; | ||
| 394 | } | ||
| 395 | set_bit(PG_MAPPED, &req->wb_flags); | 394 | set_bit(PG_MAPPED, &req->wb_flags); |
| 396 | SetPagePrivate(req->wb_page); | 395 | SetPagePrivate(req->wb_page); |
| 397 | set_page_private(req->wb_page, (unsigned long)req); | 396 | set_page_private(req->wb_page, (unsigned long)req); |
| @@ -421,11 +420,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
| 421 | clear_bit(PG_MAPPED, &req->wb_flags); | 420 | clear_bit(PG_MAPPED, &req->wb_flags); |
| 422 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 421 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
| 423 | nfsi->npages--; | 422 | nfsi->npages--; |
| 424 | if (!nfsi->npages) { | 423 | spin_unlock(&inode->i_lock); |
| 425 | spin_unlock(&inode->i_lock); | ||
| 426 | iput(inode); | ||
| 427 | } else | ||
| 428 | spin_unlock(&inode->i_lock); | ||
| 429 | nfs_release_request(req); | 424 | nfs_release_request(req); |
| 430 | } | 425 | } |
| 431 | 426 | ||
| @@ -441,7 +436,7 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
| 441 | * Add a request to the inode's commit list. | 436 | * Add a request to the inode's commit list. |
| 442 | */ | 437 | */ |
| 443 | static void | 438 | static void |
| 444 | nfs_mark_request_commit(struct nfs_page *req) | 439 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
| 445 | { | 440 | { |
| 446 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 441 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
| 447 | struct nfs_inode *nfsi = NFS_I(inode); | 442 | struct nfs_inode *nfsi = NFS_I(inode); |
| @@ -453,6 +448,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
| 453 | NFS_PAGE_TAG_COMMIT); | 448 | NFS_PAGE_TAG_COMMIT); |
| 454 | nfsi->ncommit++; | 449 | nfsi->ncommit++; |
| 455 | spin_unlock(&inode->i_lock); | 450 | spin_unlock(&inode->i_lock); |
| 451 | pnfs_mark_request_commit(req, lseg); | ||
| 456 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 452 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 457 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 453 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
| 458 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 454 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
| @@ -474,14 +470,18 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
| 474 | static inline | 470 | static inline |
| 475 | int nfs_write_need_commit(struct nfs_write_data *data) | 471 | int nfs_write_need_commit(struct nfs_write_data *data) |
| 476 | { | 472 | { |
| 477 | return data->verf.committed != NFS_FILE_SYNC; | 473 | if (data->verf.committed == NFS_DATA_SYNC) |
| 474 | return data->lseg == NULL; | ||
| 475 | else | ||
| 476 | return data->verf.committed != NFS_FILE_SYNC; | ||
| 478 | } | 477 | } |
| 479 | 478 | ||
| 480 | static inline | 479 | static inline |
| 481 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 480 | int nfs_reschedule_unstable_write(struct nfs_page *req, |
| 481 | struct nfs_write_data *data) | ||
| 482 | { | 482 | { |
| 483 | if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 483 | if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
| 484 | nfs_mark_request_commit(req); | 484 | nfs_mark_request_commit(req, data->lseg); |
| 485 | return 1; | 485 | return 1; |
| 486 | } | 486 | } |
| 487 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 487 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
| @@ -492,7 +492,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
| 492 | } | 492 | } |
| 493 | #else | 493 | #else |
| 494 | static inline void | 494 | static inline void |
| 495 | nfs_mark_request_commit(struct nfs_page *req) | 495 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
| 496 | { | 496 | { |
| 497 | } | 497 | } |
| 498 | 498 | ||
| @@ -509,7 +509,8 @@ int nfs_write_need_commit(struct nfs_write_data *data) | |||
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | static inline | 511 | static inline |
| 512 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 512 | int nfs_reschedule_unstable_write(struct nfs_page *req, |
| 513 | struct nfs_write_data *data) | ||
| 513 | { | 514 | { |
| 514 | return 0; | 515 | return 0; |
| 515 | } | 516 | } |
| @@ -612,9 +613,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
| 612 | } | 613 | } |
| 613 | 614 | ||
| 614 | if (nfs_clear_request_commit(req) && | 615 | if (nfs_clear_request_commit(req) && |
| 615 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, | 616 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, |
| 616 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) | 617 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) { |
| 617 | NFS_I(inode)->ncommit--; | 618 | NFS_I(inode)->ncommit--; |
| 619 | pnfs_clear_request_commit(req); | ||
| 620 | } | ||
| 618 | 621 | ||
| 619 | /* Okay, the request matches. Update the region */ | 622 | /* Okay, the request matches. Update the region */ |
| 620 | if (offset < req->wb_offset) { | 623 | if (offset < req->wb_offset) { |
| @@ -762,11 +765,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 762 | return status; | 765 | return status; |
| 763 | } | 766 | } |
| 764 | 767 | ||
| 765 | static void nfs_writepage_release(struct nfs_page *req) | 768 | static void nfs_writepage_release(struct nfs_page *req, |
| 769 | struct nfs_write_data *data) | ||
| 766 | { | 770 | { |
| 767 | struct page *page = req->wb_page; | 771 | struct page *page = req->wb_page; |
| 768 | 772 | ||
| 769 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) | 773 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data)) |
| 770 | nfs_inode_remove_request(req); | 774 | nfs_inode_remove_request(req); |
| 771 | nfs_clear_page_tag_locked(req); | 775 | nfs_clear_page_tag_locked(req); |
| 772 | nfs_end_page_writeback(page); | 776 | nfs_end_page_writeback(page); |
| @@ -863,7 +867,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 863 | data->args.context = get_nfs_open_context(req->wb_context); | 867 | data->args.context = get_nfs_open_context(req->wb_context); |
| 864 | data->args.lock_context = req->wb_lock_context; | 868 | data->args.lock_context = req->wb_lock_context; |
| 865 | data->args.stable = NFS_UNSTABLE; | 869 | data->args.stable = NFS_UNSTABLE; |
| 866 | if (how & FLUSH_STABLE) { | 870 | if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { |
| 867 | data->args.stable = NFS_DATA_SYNC; | 871 | data->args.stable = NFS_DATA_SYNC; |
| 868 | if (!nfs_need_commit(NFS_I(inode))) | 872 | if (!nfs_need_commit(NFS_I(inode))) |
| 869 | data->args.stable = NFS_FILE_SYNC; | 873 | data->args.stable = NFS_FILE_SYNC; |
| @@ -912,6 +916,12 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
| 912 | 916 | ||
| 913 | nfs_list_remove_request(req); | 917 | nfs_list_remove_request(req); |
| 914 | 918 | ||
| 919 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
| 920 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit || | ||
| 921 | desc->pg_count > wsize)) | ||
| 922 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
| 923 | |||
| 924 | |||
| 915 | nbytes = desc->pg_count; | 925 | nbytes = desc->pg_count; |
| 916 | do { | 926 | do { |
| 917 | size_t len = min(nbytes, wsize); | 927 | size_t len = min(nbytes, wsize); |
| @@ -1002,6 +1012,10 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | |||
| 1002 | if ((!lseg) && list_is_singular(&data->pages)) | 1012 | if ((!lseg) && list_is_singular(&data->pages)) |
| 1003 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); | 1013 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); |
| 1004 | 1014 | ||
| 1015 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
| 1016 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) | ||
| 1017 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
| 1018 | |||
| 1005 | /* Set up the argument struct */ | 1019 | /* Set up the argument struct */ |
| 1006 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); | 1020 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); |
| 1007 | out: | 1021 | out: |
| @@ -1074,7 +1088,7 @@ static void nfs_writeback_release_partial(void *calldata) | |||
| 1074 | 1088 | ||
| 1075 | out: | 1089 | out: |
| 1076 | if (atomic_dec_and_test(&req->wb_complete)) | 1090 | if (atomic_dec_and_test(&req->wb_complete)) |
| 1077 | nfs_writepage_release(req); | 1091 | nfs_writepage_release(req, data); |
| 1078 | nfs_writedata_release(calldata); | 1092 | nfs_writedata_release(calldata); |
| 1079 | } | 1093 | } |
| 1080 | 1094 | ||
| @@ -1141,7 +1155,7 @@ static void nfs_writeback_release_full(void *calldata) | |||
| 1141 | 1155 | ||
| 1142 | if (nfs_write_need_commit(data)) { | 1156 | if (nfs_write_need_commit(data)) { |
| 1143 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1157 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
| 1144 | nfs_mark_request_commit(req); | 1158 | nfs_mark_request_commit(req, data->lseg); |
| 1145 | dprintk(" marked for commit\n"); | 1159 | dprintk(" marked for commit\n"); |
| 1146 | goto next; | 1160 | goto next; |
| 1147 | } | 1161 | } |
| @@ -1251,57 +1265,82 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1251 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1265 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
| 1252 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | 1266 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) |
| 1253 | { | 1267 | { |
| 1268 | int ret; | ||
| 1269 | |||
| 1254 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | 1270 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) |
| 1255 | return 1; | 1271 | return 1; |
| 1256 | if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, | 1272 | if (!may_wait) |
| 1257 | NFS_INO_COMMIT, nfs_wait_bit_killable, | 1273 | return 0; |
| 1258 | TASK_KILLABLE)) | 1274 | ret = out_of_line_wait_on_bit_lock(&nfsi->flags, |
| 1259 | return 1; | 1275 | NFS_INO_COMMIT, |
| 1260 | return 0; | 1276 | nfs_wait_bit_killable, |
| 1277 | TASK_KILLABLE); | ||
| 1278 | return (ret < 0) ? ret : 1; | ||
| 1261 | } | 1279 | } |
| 1262 | 1280 | ||
| 1263 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | 1281 | void nfs_commit_clear_lock(struct nfs_inode *nfsi) |
| 1264 | { | 1282 | { |
| 1265 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | 1283 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); |
| 1266 | smp_mb__after_clear_bit(); | 1284 | smp_mb__after_clear_bit(); |
| 1267 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | 1285 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); |
| 1268 | } | 1286 | } |
| 1287 | EXPORT_SYMBOL_GPL(nfs_commit_clear_lock); | ||
| 1269 | 1288 | ||
| 1270 | 1289 | void nfs_commitdata_release(void *data) | |
| 1271 | static void nfs_commitdata_release(void *data) | ||
| 1272 | { | 1290 | { |
| 1273 | struct nfs_write_data *wdata = data; | 1291 | struct nfs_write_data *wdata = data; |
| 1274 | 1292 | ||
| 1293 | put_lseg(wdata->lseg); | ||
| 1275 | put_nfs_open_context(wdata->args.context); | 1294 | put_nfs_open_context(wdata->args.context); |
| 1276 | nfs_commit_free(wdata); | 1295 | nfs_commit_free(wdata); |
| 1277 | } | 1296 | } |
| 1297 | EXPORT_SYMBOL_GPL(nfs_commitdata_release); | ||
| 1278 | 1298 | ||
| 1279 | /* | 1299 | int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt, |
| 1280 | * Set up the argument/result storage required for the RPC call. | 1300 | const struct rpc_call_ops *call_ops, |
| 1281 | */ | 1301 | int how) |
| 1282 | static int nfs_commit_rpcsetup(struct list_head *head, | ||
| 1283 | struct nfs_write_data *data, | ||
| 1284 | int how) | ||
| 1285 | { | 1302 | { |
| 1286 | struct nfs_page *first = nfs_list_entry(head->next); | ||
| 1287 | struct inode *inode = first->wb_context->path.dentry->d_inode; | ||
| 1288 | int priority = flush_task_priority(how); | ||
| 1289 | struct rpc_task *task; | 1303 | struct rpc_task *task; |
| 1304 | int priority = flush_task_priority(how); | ||
| 1290 | struct rpc_message msg = { | 1305 | struct rpc_message msg = { |
| 1291 | .rpc_argp = &data->args, | 1306 | .rpc_argp = &data->args, |
| 1292 | .rpc_resp = &data->res, | 1307 | .rpc_resp = &data->res, |
| 1293 | .rpc_cred = first->wb_context->cred, | 1308 | .rpc_cred = data->cred, |
| 1294 | }; | 1309 | }; |
| 1295 | struct rpc_task_setup task_setup_data = { | 1310 | struct rpc_task_setup task_setup_data = { |
| 1296 | .task = &data->task, | 1311 | .task = &data->task, |
| 1297 | .rpc_client = NFS_CLIENT(inode), | 1312 | .rpc_client = clnt, |
| 1298 | .rpc_message = &msg, | 1313 | .rpc_message = &msg, |
| 1299 | .callback_ops = &nfs_commit_ops, | 1314 | .callback_ops = call_ops, |
| 1300 | .callback_data = data, | 1315 | .callback_data = data, |
| 1301 | .workqueue = nfsiod_workqueue, | 1316 | .workqueue = nfsiod_workqueue, |
| 1302 | .flags = RPC_TASK_ASYNC, | 1317 | .flags = RPC_TASK_ASYNC, |
| 1303 | .priority = priority, | 1318 | .priority = priority, |
| 1304 | }; | 1319 | }; |
| 1320 | /* Set up the initial task struct. */ | ||
| 1321 | NFS_PROTO(data->inode)->commit_setup(data, &msg); | ||
| 1322 | |||
| 1323 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | ||
| 1324 | |||
| 1325 | task = rpc_run_task(&task_setup_data); | ||
| 1326 | if (IS_ERR(task)) | ||
| 1327 | return PTR_ERR(task); | ||
| 1328 | if (how & FLUSH_SYNC) | ||
| 1329 | rpc_wait_for_completion_task(task); | ||
| 1330 | rpc_put_task(task); | ||
| 1331 | return 0; | ||
| 1332 | } | ||
| 1333 | EXPORT_SYMBOL_GPL(nfs_initiate_commit); | ||
| 1334 | |||
| 1335 | /* | ||
| 1336 | * Set up the argument/result storage required for the RPC call. | ||
| 1337 | */ | ||
| 1338 | void nfs_init_commit(struct nfs_write_data *data, | ||
| 1339 | struct list_head *head, | ||
| 1340 | struct pnfs_layout_segment *lseg) | ||
| 1341 | { | ||
| 1342 | struct nfs_page *first = nfs_list_entry(head->next); | ||
| 1343 | struct inode *inode = first->wb_context->path.dentry->d_inode; | ||
| 1305 | 1344 | ||
| 1306 | /* Set up the RPC argument and reply structs | 1345 | /* Set up the RPC argument and reply structs |
| 1307 | * NB: take care not to mess about with data->commit et al. */ | 1346 | * NB: take care not to mess about with data->commit et al. */ |
| @@ -1309,7 +1348,9 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1309 | list_splice_init(head, &data->pages); | 1348 | list_splice_init(head, &data->pages); |
| 1310 | 1349 | ||
| 1311 | data->inode = inode; | 1350 | data->inode = inode; |
| 1312 | data->cred = msg.rpc_cred; | 1351 | data->cred = first->wb_context->cred; |
| 1352 | data->lseg = lseg; /* reference transferred */ | ||
| 1353 | data->mds_ops = &nfs_commit_ops; | ||
| 1313 | 1354 | ||
| 1314 | data->args.fh = NFS_FH(data->inode); | 1355 | data->args.fh = NFS_FH(data->inode); |
| 1315 | /* Note: we always request a commit of the entire inode */ | 1356 | /* Note: we always request a commit of the entire inode */ |
| @@ -1320,20 +1361,25 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1320 | data->res.fattr = &data->fattr; | 1361 | data->res.fattr = &data->fattr; |
| 1321 | data->res.verf = &data->verf; | 1362 | data->res.verf = &data->verf; |
| 1322 | nfs_fattr_init(&data->fattr); | 1363 | nfs_fattr_init(&data->fattr); |
| 1364 | } | ||
| 1365 | EXPORT_SYMBOL_GPL(nfs_init_commit); | ||
| 1323 | 1366 | ||
| 1324 | /* Set up the initial task struct. */ | 1367 | void nfs_retry_commit(struct list_head *page_list, |
| 1325 | NFS_PROTO(inode)->commit_setup(data, &msg); | 1368 | struct pnfs_layout_segment *lseg) |
| 1326 | 1369 | { | |
| 1327 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1370 | struct nfs_page *req; |
| 1328 | 1371 | ||
| 1329 | task = rpc_run_task(&task_setup_data); | 1372 | while (!list_empty(page_list)) { |
| 1330 | if (IS_ERR(task)) | 1373 | req = nfs_list_entry(page_list->next); |
| 1331 | return PTR_ERR(task); | 1374 | nfs_list_remove_request(req); |
| 1332 | if (how & FLUSH_SYNC) | 1375 | nfs_mark_request_commit(req, lseg); |
| 1333 | rpc_wait_for_completion_task(task); | 1376 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 1334 | rpc_put_task(task); | 1377 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, |
| 1335 | return 0; | 1378 | BDI_RECLAIMABLE); |
| 1379 | nfs_clear_page_tag_locked(req); | ||
| 1380 | } | ||
| 1336 | } | 1381 | } |
| 1382 | EXPORT_SYMBOL_GPL(nfs_retry_commit); | ||
| 1337 | 1383 | ||
| 1338 | /* | 1384 | /* |
| 1339 | * Commit dirty pages | 1385 | * Commit dirty pages |
| @@ -1342,7 +1388,6 @@ static int | |||
| 1342 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) | 1388 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
| 1343 | { | 1389 | { |
| 1344 | struct nfs_write_data *data; | 1390 | struct nfs_write_data *data; |
| 1345 | struct nfs_page *req; | ||
| 1346 | 1391 | ||
| 1347 | data = nfs_commitdata_alloc(); | 1392 | data = nfs_commitdata_alloc(); |
| 1348 | 1393 | ||
| @@ -1350,17 +1395,10 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
| 1350 | goto out_bad; | 1395 | goto out_bad; |
| 1351 | 1396 | ||
| 1352 | /* Set up the argument struct */ | 1397 | /* Set up the argument struct */ |
| 1353 | return nfs_commit_rpcsetup(head, data, how); | 1398 | nfs_init_commit(data, head, NULL); |
| 1399 | return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how); | ||
| 1354 | out_bad: | 1400 | out_bad: |
| 1355 | while (!list_empty(head)) { | 1401 | nfs_retry_commit(head, NULL); |
| 1356 | req = nfs_list_entry(head->next); | ||
| 1357 | nfs_list_remove_request(req); | ||
| 1358 | nfs_mark_request_commit(req); | ||
| 1359 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | ||
| 1360 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, | ||
| 1361 | BDI_RECLAIMABLE); | ||
| 1362 | nfs_clear_page_tag_locked(req); | ||
| 1363 | } | ||
| 1364 | nfs_commit_clear_lock(NFS_I(inode)); | 1402 | nfs_commit_clear_lock(NFS_I(inode)); |
| 1365 | return -ENOMEM; | 1403 | return -ENOMEM; |
| 1366 | } | 1404 | } |
| @@ -1380,10 +1418,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
| 1380 | return; | 1418 | return; |
| 1381 | } | 1419 | } |
| 1382 | 1420 | ||
| 1383 | static void nfs_commit_release(void *calldata) | 1421 | void nfs_commit_release_pages(struct nfs_write_data *data) |
| 1384 | { | 1422 | { |
| 1385 | struct nfs_write_data *data = calldata; | 1423 | struct nfs_page *req; |
| 1386 | struct nfs_page *req; | ||
| 1387 | int status = data->task.tk_status; | 1424 | int status = data->task.tk_status; |
| 1388 | 1425 | ||
| 1389 | while (!list_empty(&data->pages)) { | 1426 | while (!list_empty(&data->pages)) { |
| @@ -1417,6 +1454,14 @@ static void nfs_commit_release(void *calldata) | |||
| 1417 | next: | 1454 | next: |
| 1418 | nfs_clear_page_tag_locked(req); | 1455 | nfs_clear_page_tag_locked(req); |
| 1419 | } | 1456 | } |
| 1457 | } | ||
| 1458 | EXPORT_SYMBOL_GPL(nfs_commit_release_pages); | ||
| 1459 | |||
| 1460 | static void nfs_commit_release(void *calldata) | ||
| 1461 | { | ||
| 1462 | struct nfs_write_data *data = calldata; | ||
| 1463 | |||
| 1464 | nfs_commit_release_pages(data); | ||
| 1420 | nfs_commit_clear_lock(NFS_I(data->inode)); | 1465 | nfs_commit_clear_lock(NFS_I(data->inode)); |
| 1421 | nfs_commitdata_release(calldata); | 1466 | nfs_commitdata_release(calldata); |
| 1422 | } | 1467 | } |
| @@ -1433,23 +1478,30 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
| 1433 | { | 1478 | { |
| 1434 | LIST_HEAD(head); | 1479 | LIST_HEAD(head); |
| 1435 | int may_wait = how & FLUSH_SYNC; | 1480 | int may_wait = how & FLUSH_SYNC; |
| 1436 | int res = 0; | 1481 | int res; |
| 1437 | 1482 | ||
| 1438 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | 1483 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); |
| 1484 | if (res <= 0) | ||
| 1439 | goto out_mark_dirty; | 1485 | goto out_mark_dirty; |
| 1440 | spin_lock(&inode->i_lock); | 1486 | spin_lock(&inode->i_lock); |
| 1441 | res = nfs_scan_commit(inode, &head, 0, 0); | 1487 | res = nfs_scan_commit(inode, &head, 0, 0); |
| 1442 | spin_unlock(&inode->i_lock); | 1488 | spin_unlock(&inode->i_lock); |
| 1443 | if (res) { | 1489 | if (res) { |
| 1444 | int error = nfs_commit_list(inode, &head, how); | 1490 | int error; |
| 1491 | |||
| 1492 | error = pnfs_commit_list(inode, &head, how); | ||
| 1493 | if (error == PNFS_NOT_ATTEMPTED) | ||
| 1494 | error = nfs_commit_list(inode, &head, how); | ||
| 1445 | if (error < 0) | 1495 | if (error < 0) |
| 1446 | return error; | 1496 | return error; |
| 1447 | if (may_wait) | 1497 | if (!may_wait) |
| 1448 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | ||
| 1449 | nfs_wait_bit_killable, | ||
| 1450 | TASK_KILLABLE); | ||
| 1451 | else | ||
| 1452 | goto out_mark_dirty; | 1498 | goto out_mark_dirty; |
| 1499 | error = wait_on_bit(&NFS_I(inode)->flags, | ||
| 1500 | NFS_INO_COMMIT, | ||
| 1501 | nfs_wait_bit_killable, | ||
| 1502 | TASK_KILLABLE); | ||
| 1503 | if (error < 0) | ||
| 1504 | return error; | ||
| 1453 | } else | 1505 | } else |
| 1454 | nfs_commit_clear_lock(NFS_I(inode)); | 1506 | nfs_commit_clear_lock(NFS_I(inode)); |
| 1455 | return res; | 1507 | return res; |
| @@ -1503,7 +1555,22 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
| 1503 | 1555 | ||
| 1504 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1556 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
| 1505 | { | 1557 | { |
| 1506 | return nfs_commit_unstable_pages(inode, wbc); | 1558 | int ret; |
| 1559 | |||
| 1560 | ret = nfs_commit_unstable_pages(inode, wbc); | ||
| 1561 | if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { | ||
| 1562 | int status; | ||
| 1563 | bool sync = true; | ||
| 1564 | |||
| 1565 | if (wbc->sync_mode == WB_SYNC_NONE || wbc->nonblocking || | ||
| 1566 | wbc->for_background) | ||
| 1567 | sync = false; | ||
| 1568 | |||
| 1569 | status = pnfs_layoutcommit_inode(inode, sync); | ||
| 1570 | if (status < 0) | ||
| 1571 | return status; | ||
| 1572 | } | ||
| 1573 | return ret; | ||
| 1507 | } | 1574 | } |
| 1508 | 1575 | ||
| 1509 | /* | 1576 | /* |
