diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 52 |
1 files changed, 33 insertions, 19 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4ae66f416eb9..bcf83e535f29 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -473,13 +473,18 @@ try_again: | |||
473 | do { | 473 | do { |
474 | /* | 474 | /* |
475 | * Subrequests are always contiguous, non overlapping | 475 | * Subrequests are always contiguous, non overlapping |
476 | * and in order. If not, it's a programming error. | 476 | * and in order - but may be repeated (mirrored writes). |
477 | */ | 477 | */ |
478 | WARN_ON_ONCE(subreq->wb_offset != | 478 | if (subreq->wb_offset == (head->wb_offset + total_bytes)) { |
479 | (head->wb_offset + total_bytes)); | 479 | /* keep track of how many bytes this group covers */ |
480 | 480 | total_bytes += subreq->wb_bytes; | |
481 | /* keep track of how many bytes this group covers */ | 481 | } else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset || |
482 | total_bytes += subreq->wb_bytes; | 482 | ((subreq->wb_offset + subreq->wb_bytes) > |
483 | (head->wb_offset + total_bytes)))) { | ||
484 | nfs_page_group_unlock(head); | ||
485 | spin_unlock(&inode->i_lock); | ||
486 | return ERR_PTR(-EIO); | ||
487 | } | ||
483 | 488 | ||
484 | if (!nfs_lock_request(subreq)) { | 489 | if (!nfs_lock_request(subreq)) { |
485 | /* releases page group bit lock and | 490 | /* releases page group bit lock and |
@@ -842,9 +847,9 @@ EXPORT_SYMBOL_GPL(nfs_init_cinfo); | |||
842 | */ | 847 | */ |
843 | void | 848 | void |
844 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, | 849 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, |
845 | struct nfs_commit_info *cinfo) | 850 | struct nfs_commit_info *cinfo, u32 ds_commit_idx) |
846 | { | 851 | { |
847 | if (pnfs_mark_request_commit(req, lseg, cinfo)) | 852 | if (pnfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx)) |
848 | return; | 853 | return; |
849 | nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo); | 854 | nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo); |
850 | } | 855 | } |
@@ -900,7 +905,8 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) | |||
900 | } | 905 | } |
901 | if (nfs_write_need_commit(hdr)) { | 906 | if (nfs_write_need_commit(hdr)) { |
902 | memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); | 907 | memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); |
903 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); | 908 | nfs_mark_request_commit(req, hdr->lseg, &cinfo, |
909 | hdr->pgio_mirror_idx); | ||
904 | goto next; | 910 | goto next; |
905 | } | 911 | } |
906 | remove_req: | 912 | remove_req: |
@@ -1269,15 +1275,15 @@ static int flush_task_priority(int how) | |||
1269 | 1275 | ||
1270 | static void nfs_initiate_write(struct nfs_pgio_header *hdr, | 1276 | static void nfs_initiate_write(struct nfs_pgio_header *hdr, |
1271 | struct rpc_message *msg, | 1277 | struct rpc_message *msg, |
1278 | const struct nfs_rpc_ops *rpc_ops, | ||
1272 | struct rpc_task_setup *task_setup_data, int how) | 1279 | struct rpc_task_setup *task_setup_data, int how) |
1273 | { | 1280 | { |
1274 | struct inode *inode = hdr->inode; | ||
1275 | int priority = flush_task_priority(how); | 1281 | int priority = flush_task_priority(how); |
1276 | 1282 | ||
1277 | task_setup_data->priority = priority; | 1283 | task_setup_data->priority = priority; |
1278 | NFS_PROTO(inode)->write_setup(hdr, msg); | 1284 | rpc_ops->write_setup(hdr, msg); |
1279 | 1285 | ||
1280 | nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client, | 1286 | nfs4_state_protect_write(NFS_SERVER(hdr->inode)->nfs_client, |
1281 | &task_setup_data->rpc_client, msg, hdr); | 1287 | &task_setup_data->rpc_client, msg, hdr); |
1282 | } | 1288 | } |
1283 | 1289 | ||
@@ -1327,8 +1333,14 @@ EXPORT_SYMBOL_GPL(nfs_pageio_init_write); | |||
1327 | 1333 | ||
1328 | void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio) | 1334 | void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio) |
1329 | { | 1335 | { |
1336 | struct nfs_pgio_mirror *mirror; | ||
1337 | |||
1330 | pgio->pg_ops = &nfs_pgio_rw_ops; | 1338 | pgio->pg_ops = &nfs_pgio_rw_ops; |
1331 | pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize; | 1339 | |
1340 | nfs_pageio_stop_mirroring(pgio); | ||
1341 | |||
1342 | mirror = &pgio->pg_mirrors[0]; | ||
1343 | mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize; | ||
1332 | } | 1344 | } |
1333 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); | 1345 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); |
1334 | 1346 | ||
@@ -1494,6 +1506,7 @@ void nfs_commitdata_release(struct nfs_commit_data *data) | |||
1494 | EXPORT_SYMBOL_GPL(nfs_commitdata_release); | 1506 | EXPORT_SYMBOL_GPL(nfs_commitdata_release); |
1495 | 1507 | ||
1496 | int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, | 1508 | int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, |
1509 | const struct nfs_rpc_ops *nfs_ops, | ||
1497 | const struct rpc_call_ops *call_ops, | 1510 | const struct rpc_call_ops *call_ops, |
1498 | int how, int flags) | 1511 | int how, int flags) |
1499 | { | 1512 | { |
@@ -1515,7 +1528,7 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, | |||
1515 | .priority = priority, | 1528 | .priority = priority, |
1516 | }; | 1529 | }; |
1517 | /* Set up the initial task struct. */ | 1530 | /* Set up the initial task struct. */ |
1518 | NFS_PROTO(data->inode)->commit_setup(data, &msg); | 1531 | nfs_ops->commit_setup(data, &msg); |
1519 | 1532 | ||
1520 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1533 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1521 | 1534 | ||
@@ -1583,14 +1596,15 @@ EXPORT_SYMBOL_GPL(nfs_init_commit); | |||
1583 | 1596 | ||
1584 | void nfs_retry_commit(struct list_head *page_list, | 1597 | void nfs_retry_commit(struct list_head *page_list, |
1585 | struct pnfs_layout_segment *lseg, | 1598 | struct pnfs_layout_segment *lseg, |
1586 | struct nfs_commit_info *cinfo) | 1599 | struct nfs_commit_info *cinfo, |
1600 | u32 ds_commit_idx) | ||
1587 | { | 1601 | { |
1588 | struct nfs_page *req; | 1602 | struct nfs_page *req; |
1589 | 1603 | ||
1590 | while (!list_empty(page_list)) { | 1604 | while (!list_empty(page_list)) { |
1591 | req = nfs_list_entry(page_list->next); | 1605 | req = nfs_list_entry(page_list->next); |
1592 | nfs_list_remove_request(req); | 1606 | nfs_list_remove_request(req); |
1593 | nfs_mark_request_commit(req, lseg, cinfo); | 1607 | nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx); |
1594 | if (!cinfo->dreq) { | 1608 | if (!cinfo->dreq) { |
1595 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1609 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
1596 | dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, | 1610 | dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, |
@@ -1618,10 +1632,10 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, | |||
1618 | /* Set up the argument struct */ | 1632 | /* Set up the argument struct */ |
1619 | nfs_init_commit(data, head, NULL, cinfo); | 1633 | nfs_init_commit(data, head, NULL, cinfo); |
1620 | atomic_inc(&cinfo->mds->rpcs_out); | 1634 | atomic_inc(&cinfo->mds->rpcs_out); |
1621 | return nfs_initiate_commit(NFS_CLIENT(inode), data, data->mds_ops, | 1635 | return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode), |
1622 | how, 0); | 1636 | data->mds_ops, how, 0); |
1623 | out_bad: | 1637 | out_bad: |
1624 | nfs_retry_commit(head, NULL, cinfo); | 1638 | nfs_retry_commit(head, NULL, cinfo, 0); |
1625 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | 1639 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); |
1626 | return -ENOMEM; | 1640 | return -ENOMEM; |
1627 | } | 1641 | } |