diff options
Diffstat (limited to 'fs/nfs/filelayout/filelayout.c')
| -rw-r--r-- | fs/nfs/filelayout/filelayout.c | 317 |
1 files changed, 29 insertions, 288 deletions
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index 7afb52f6a25a..7ae1c263c5cf 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
| @@ -118,13 +118,6 @@ static void filelayout_reset_read(struct nfs_pgio_header *hdr) | |||
| 118 | } | 118 | } |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) | ||
| 122 | { | ||
| 123 | if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) | ||
| 124 | return; | ||
| 125 | pnfs_return_layout(inode); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int filelayout_async_handle_error(struct rpc_task *task, | 121 | static int filelayout_async_handle_error(struct rpc_task *task, |
| 129 | struct nfs4_state *state, | 122 | struct nfs4_state *state, |
| 130 | struct nfs_client *clp, | 123 | struct nfs_client *clp, |
| @@ -207,7 +200,7 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
| 207 | dprintk("%s DS connection error %d\n", __func__, | 200 | dprintk("%s DS connection error %d\n", __func__, |
| 208 | task->tk_status); | 201 | task->tk_status); |
| 209 | nfs4_mark_deviceid_unavailable(devid); | 202 | nfs4_mark_deviceid_unavailable(devid); |
| 210 | set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); | 203 | pnfs_error_mark_layout_for_return(inode, lseg); |
| 211 | rpc_wake_up(&tbl->slot_tbl_waitq); | 204 | rpc_wake_up(&tbl->slot_tbl_waitq); |
| 212 | /* fall through */ | 205 | /* fall through */ |
| 213 | default: | 206 | default: |
| @@ -339,16 +332,6 @@ static void filelayout_read_count_stats(struct rpc_task *task, void *data) | |||
| 339 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); | 332 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); |
| 340 | } | 333 | } |
| 341 | 334 | ||
| 342 | static void filelayout_read_release(void *data) | ||
| 343 | { | ||
| 344 | struct nfs_pgio_header *hdr = data; | ||
| 345 | struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; | ||
| 346 | |||
| 347 | filelayout_fenceme(lo->plh_inode, lo); | ||
| 348 | nfs_put_client(hdr->ds_clp); | ||
| 349 | hdr->mds_ops->rpc_release(data); | ||
| 350 | } | ||
| 351 | |||
| 352 | static int filelayout_write_done_cb(struct rpc_task *task, | 335 | static int filelayout_write_done_cb(struct rpc_task *task, |
| 353 | struct nfs_pgio_header *hdr) | 336 | struct nfs_pgio_header *hdr) |
| 354 | { | 337 | { |
| @@ -371,17 +354,6 @@ static int filelayout_write_done_cb(struct rpc_task *task, | |||
| 371 | return 0; | 354 | return 0; |
| 372 | } | 355 | } |
| 373 | 356 | ||
| 374 | /* Fake up some data that will cause nfs_commit_release to retry the writes. */ | ||
| 375 | static void prepare_to_resend_writes(struct nfs_commit_data *data) | ||
| 376 | { | ||
| 377 | struct nfs_page *first = nfs_list_entry(data->pages.next); | ||
| 378 | |||
| 379 | data->task.tk_status = 0; | ||
| 380 | memcpy(&data->verf.verifier, &first->wb_verf, | ||
| 381 | sizeof(data->verf.verifier)); | ||
| 382 | data->verf.verifier.data[0]++; /* ensure verifier mismatch */ | ||
| 383 | } | ||
| 384 | |||
| 385 | static int filelayout_commit_done_cb(struct rpc_task *task, | 357 | static int filelayout_commit_done_cb(struct rpc_task *task, |
| 386 | struct nfs_commit_data *data) | 358 | struct nfs_commit_data *data) |
| 387 | { | 359 | { |
| @@ -393,7 +365,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task, | |||
| 393 | 365 | ||
| 394 | switch (err) { | 366 | switch (err) { |
| 395 | case -NFS4ERR_RESET_TO_MDS: | 367 | case -NFS4ERR_RESET_TO_MDS: |
| 396 | prepare_to_resend_writes(data); | 368 | pnfs_generic_prepare_to_resend_writes(data); |
| 397 | return -EAGAIN; | 369 | return -EAGAIN; |
| 398 | case -EAGAIN: | 370 | case -EAGAIN: |
| 399 | rpc_restart_call_prepare(task); | 371 | rpc_restart_call_prepare(task); |
| @@ -451,16 +423,6 @@ static void filelayout_write_count_stats(struct rpc_task *task, void *data) | |||
| 451 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); | 423 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); |
| 452 | } | 424 | } |
| 453 | 425 | ||
| 454 | static void filelayout_write_release(void *data) | ||
| 455 | { | ||
| 456 | struct nfs_pgio_header *hdr = data; | ||
| 457 | struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; | ||
| 458 | |||
| 459 | filelayout_fenceme(lo->plh_inode, lo); | ||
| 460 | nfs_put_client(hdr->ds_clp); | ||
| 461 | hdr->mds_ops->rpc_release(data); | ||
| 462 | } | ||
| 463 | |||
| 464 | static void filelayout_commit_prepare(struct rpc_task *task, void *data) | 426 | static void filelayout_commit_prepare(struct rpc_task *task, void *data) |
| 465 | { | 427 | { |
| 466 | struct nfs_commit_data *wdata = data; | 428 | struct nfs_commit_data *wdata = data; |
| @@ -471,14 +433,6 @@ static void filelayout_commit_prepare(struct rpc_task *task, void *data) | |||
| 471 | task); | 433 | task); |
| 472 | } | 434 | } |
| 473 | 435 | ||
| 474 | static void filelayout_write_commit_done(struct rpc_task *task, void *data) | ||
| 475 | { | ||
| 476 | struct nfs_commit_data *wdata = data; | ||
| 477 | |||
| 478 | /* Note this may cause RPC to be resent */ | ||
| 479 | wdata->mds_ops->rpc_call_done(task, data); | ||
| 480 | } | ||
| 481 | |||
| 482 | static void filelayout_commit_count_stats(struct rpc_task *task, void *data) | 436 | static void filelayout_commit_count_stats(struct rpc_task *task, void *data) |
| 483 | { | 437 | { |
| 484 | struct nfs_commit_data *cdata = data; | 438 | struct nfs_commit_data *cdata = data; |
| @@ -486,35 +440,25 @@ static void filelayout_commit_count_stats(struct rpc_task *task, void *data) | |||
| 486 | rpc_count_iostats(task, NFS_SERVER(cdata->inode)->client->cl_metrics); | 440 | rpc_count_iostats(task, NFS_SERVER(cdata->inode)->client->cl_metrics); |
| 487 | } | 441 | } |
| 488 | 442 | ||
| 489 | static void filelayout_commit_release(void *calldata) | ||
| 490 | { | ||
| 491 | struct nfs_commit_data *data = calldata; | ||
| 492 | |||
| 493 | data->completion_ops->completion(data); | ||
| 494 | pnfs_put_lseg(data->lseg); | ||
| 495 | nfs_put_client(data->ds_clp); | ||
| 496 | nfs_commitdata_release(data); | ||
| 497 | } | ||
| 498 | |||
| 499 | static const struct rpc_call_ops filelayout_read_call_ops = { | 443 | static const struct rpc_call_ops filelayout_read_call_ops = { |
| 500 | .rpc_call_prepare = filelayout_read_prepare, | 444 | .rpc_call_prepare = filelayout_read_prepare, |
| 501 | .rpc_call_done = filelayout_read_call_done, | 445 | .rpc_call_done = filelayout_read_call_done, |
| 502 | .rpc_count_stats = filelayout_read_count_stats, | 446 | .rpc_count_stats = filelayout_read_count_stats, |
| 503 | .rpc_release = filelayout_read_release, | 447 | .rpc_release = pnfs_generic_rw_release, |
| 504 | }; | 448 | }; |
| 505 | 449 | ||
| 506 | static const struct rpc_call_ops filelayout_write_call_ops = { | 450 | static const struct rpc_call_ops filelayout_write_call_ops = { |
| 507 | .rpc_call_prepare = filelayout_write_prepare, | 451 | .rpc_call_prepare = filelayout_write_prepare, |
| 508 | .rpc_call_done = filelayout_write_call_done, | 452 | .rpc_call_done = filelayout_write_call_done, |
| 509 | .rpc_count_stats = filelayout_write_count_stats, | 453 | .rpc_count_stats = filelayout_write_count_stats, |
| 510 | .rpc_release = filelayout_write_release, | 454 | .rpc_release = pnfs_generic_rw_release, |
| 511 | }; | 455 | }; |
| 512 | 456 | ||
| 513 | static const struct rpc_call_ops filelayout_commit_call_ops = { | 457 | static const struct rpc_call_ops filelayout_commit_call_ops = { |
| 514 | .rpc_call_prepare = filelayout_commit_prepare, | 458 | .rpc_call_prepare = filelayout_commit_prepare, |
| 515 | .rpc_call_done = filelayout_write_commit_done, | 459 | .rpc_call_done = pnfs_generic_write_commit_done, |
| 516 | .rpc_count_stats = filelayout_commit_count_stats, | 460 | .rpc_count_stats = filelayout_commit_count_stats, |
| 517 | .rpc_release = filelayout_commit_release, | 461 | .rpc_release = pnfs_generic_commit_release, |
| 518 | }; | 462 | }; |
| 519 | 463 | ||
| 520 | static enum pnfs_try_status | 464 | static enum pnfs_try_status |
| @@ -548,7 +492,7 @@ filelayout_read_pagelist(struct nfs_pgio_header *hdr) | |||
| 548 | /* No multipath support. Use first DS */ | 492 | /* No multipath support. Use first DS */ |
| 549 | atomic_inc(&ds->ds_clp->cl_count); | 493 | atomic_inc(&ds->ds_clp->cl_count); |
| 550 | hdr->ds_clp = ds->ds_clp; | 494 | hdr->ds_clp = ds->ds_clp; |
| 551 | hdr->ds_idx = idx; | 495 | hdr->ds_commit_idx = idx; |
| 552 | fh = nfs4_fl_select_ds_fh(lseg, j); | 496 | fh = nfs4_fl_select_ds_fh(lseg, j); |
| 553 | if (fh) | 497 | if (fh) |
| 554 | hdr->args.fh = fh; | 498 | hdr->args.fh = fh; |
| @@ -557,8 +501,9 @@ filelayout_read_pagelist(struct nfs_pgio_header *hdr) | |||
| 557 | hdr->mds_offset = offset; | 501 | hdr->mds_offset = offset; |
| 558 | 502 | ||
| 559 | /* Perform an asynchronous read to ds */ | 503 | /* Perform an asynchronous read to ds */ |
| 560 | nfs_initiate_pgio(ds_clnt, hdr, | 504 | nfs_initiate_pgio(ds_clnt, hdr, hdr->cred, |
| 561 | &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN); | 505 | NFS_PROTO(hdr->inode), &filelayout_read_call_ops, |
| 506 | 0, RPC_TASK_SOFTCONN); | ||
| 562 | return PNFS_ATTEMPTED; | 507 | return PNFS_ATTEMPTED; |
| 563 | } | 508 | } |
| 564 | 509 | ||
| @@ -591,16 +536,16 @@ filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync) | |||
| 591 | hdr->pgio_done_cb = filelayout_write_done_cb; | 536 | hdr->pgio_done_cb = filelayout_write_done_cb; |
| 592 | atomic_inc(&ds->ds_clp->cl_count); | 537 | atomic_inc(&ds->ds_clp->cl_count); |
| 593 | hdr->ds_clp = ds->ds_clp; | 538 | hdr->ds_clp = ds->ds_clp; |
| 594 | hdr->ds_idx = idx; | 539 | hdr->ds_commit_idx = idx; |
| 595 | fh = nfs4_fl_select_ds_fh(lseg, j); | 540 | fh = nfs4_fl_select_ds_fh(lseg, j); |
| 596 | if (fh) | 541 | if (fh) |
| 597 | hdr->args.fh = fh; | 542 | hdr->args.fh = fh; |
| 598 | hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); | 543 | hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); |
| 599 | 544 | ||
| 600 | /* Perform an asynchronous write */ | 545 | /* Perform an asynchronous write */ |
| 601 | nfs_initiate_pgio(ds_clnt, hdr, | 546 | nfs_initiate_pgio(ds_clnt, hdr, hdr->cred, |
| 602 | &filelayout_write_call_ops, sync, | 547 | NFS_PROTO(hdr->inode), &filelayout_write_call_ops, |
| 603 | RPC_TASK_SOFTCONN); | 548 | sync, RPC_TASK_SOFTCONN); |
| 604 | return PNFS_ATTEMPTED; | 549 | return PNFS_ATTEMPTED; |
| 605 | } | 550 | } |
| 606 | 551 | ||
| @@ -988,12 +933,14 @@ static const struct nfs_pageio_ops filelayout_pg_read_ops = { | |||
| 988 | .pg_init = filelayout_pg_init_read, | 933 | .pg_init = filelayout_pg_init_read, |
| 989 | .pg_test = filelayout_pg_test, | 934 | .pg_test = filelayout_pg_test, |
| 990 | .pg_doio = pnfs_generic_pg_readpages, | 935 | .pg_doio = pnfs_generic_pg_readpages, |
| 936 | .pg_cleanup = pnfs_generic_pg_cleanup, | ||
| 991 | }; | 937 | }; |
| 992 | 938 | ||
| 993 | static const struct nfs_pageio_ops filelayout_pg_write_ops = { | 939 | static const struct nfs_pageio_ops filelayout_pg_write_ops = { |
| 994 | .pg_init = filelayout_pg_init_write, | 940 | .pg_init = filelayout_pg_init_write, |
| 995 | .pg_test = filelayout_pg_test, | 941 | .pg_test = filelayout_pg_test, |
| 996 | .pg_doio = pnfs_generic_pg_writepages, | 942 | .pg_doio = pnfs_generic_pg_writepages, |
| 943 | .pg_cleanup = pnfs_generic_pg_cleanup, | ||
| 997 | }; | 944 | }; |
| 998 | 945 | ||
| 999 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | 946 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) |
| @@ -1004,37 +951,11 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | |||
| 1004 | return j; | 951 | return j; |
| 1005 | } | 952 | } |
| 1006 | 953 | ||
| 1007 | /* The generic layer is about to remove the req from the commit list. | ||
| 1008 | * If this will make the bucket empty, it will need to put the lseg reference. | ||
| 1009 | * Note this is must be called holding the inode (/cinfo) lock | ||
| 1010 | */ | ||
| 1011 | static void | ||
| 1012 | filelayout_clear_request_commit(struct nfs_page *req, | ||
| 1013 | struct nfs_commit_info *cinfo) | ||
| 1014 | { | ||
| 1015 | struct pnfs_layout_segment *freeme = NULL; | ||
| 1016 | |||
| 1017 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) | ||
| 1018 | goto out; | ||
| 1019 | cinfo->ds->nwritten--; | ||
| 1020 | if (list_is_singular(&req->wb_list)) { | ||
| 1021 | struct pnfs_commit_bucket *bucket; | ||
| 1022 | |||
| 1023 | bucket = list_first_entry(&req->wb_list, | ||
| 1024 | struct pnfs_commit_bucket, | ||
| 1025 | written); | ||
| 1026 | freeme = bucket->wlseg; | ||
| 1027 | bucket->wlseg = NULL; | ||
| 1028 | } | ||
| 1029 | out: | ||
| 1030 | nfs_request_remove_commit_list(req, cinfo); | ||
| 1031 | pnfs_put_lseg_locked(freeme); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | static void | 954 | static void |
| 1035 | filelayout_mark_request_commit(struct nfs_page *req, | 955 | filelayout_mark_request_commit(struct nfs_page *req, |
| 1036 | struct pnfs_layout_segment *lseg, | 956 | struct pnfs_layout_segment *lseg, |
| 1037 | struct nfs_commit_info *cinfo) | 957 | struct nfs_commit_info *cinfo, |
| 958 | u32 ds_commit_idx) | ||
| 1038 | 959 | ||
| 1039 | { | 960 | { |
| 1040 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 961 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
| @@ -1064,7 +985,7 @@ filelayout_mark_request_commit(struct nfs_page *req, | |||
| 1064 | * is normally transferred to the COMMIT call and released | 985 | * is normally transferred to the COMMIT call and released |
| 1065 | * there. It could also be released if the last req is pulled | 986 | * there. It could also be released if the last req is pulled |
| 1066 | * off due to a rewrite, in which case it will be done in | 987 | * off due to a rewrite, in which case it will be done in |
| 1067 | * filelayout_clear_request_commit | 988 | * pnfs_generic_clear_request_commit |
| 1068 | */ | 989 | */ |
| 1069 | buckets[i].wlseg = pnfs_get_lseg(lseg); | 990 | buckets[i].wlseg = pnfs_get_lseg(lseg); |
| 1070 | } | 991 | } |
| @@ -1081,7 +1002,7 @@ mds_commit: | |||
| 1081 | spin_unlock(cinfo->lock); | 1002 | spin_unlock(cinfo->lock); |
| 1082 | if (!cinfo->dreq) { | 1003 | if (!cinfo->dreq) { |
| 1083 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1004 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 1084 | inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, | 1005 | inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host), |
| 1085 | BDI_RECLAIMABLE); | 1006 | BDI_RECLAIMABLE); |
| 1086 | __mark_inode_dirty(req->wb_context->dentry->d_inode, | 1007 | __mark_inode_dirty(req->wb_context->dentry->d_inode, |
| 1087 | I_DIRTY_DATASYNC); | 1008 | I_DIRTY_DATASYNC); |
| @@ -1138,101 +1059,15 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how) | |||
| 1138 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); | 1059 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); |
| 1139 | if (fh) | 1060 | if (fh) |
| 1140 | data->args.fh = fh; | 1061 | data->args.fh = fh; |
| 1141 | return nfs_initiate_commit(ds_clnt, data, | 1062 | return nfs_initiate_commit(ds_clnt, data, NFS_PROTO(data->inode), |
| 1142 | &filelayout_commit_call_ops, how, | 1063 | &filelayout_commit_call_ops, how, |
| 1143 | RPC_TASK_SOFTCONN); | 1064 | RPC_TASK_SOFTCONN); |
| 1144 | out_err: | 1065 | out_err: |
| 1145 | prepare_to_resend_writes(data); | 1066 | pnfs_generic_prepare_to_resend_writes(data); |
| 1146 | filelayout_commit_release(data); | 1067 | pnfs_generic_commit_release(data); |
| 1147 | return -EAGAIN; | 1068 | return -EAGAIN; |
| 1148 | } | 1069 | } |
| 1149 | 1070 | ||
| 1150 | static int | ||
| 1151 | transfer_commit_list(struct list_head *src, struct list_head *dst, | ||
| 1152 | struct nfs_commit_info *cinfo, int max) | ||
| 1153 | { | ||
| 1154 | struct nfs_page *req, *tmp; | ||
| 1155 | int ret = 0; | ||
| 1156 | |||
| 1157 | list_for_each_entry_safe(req, tmp, src, wb_list) { | ||
| 1158 | if (!nfs_lock_request(req)) | ||
| 1159 | continue; | ||
| 1160 | kref_get(&req->wb_kref); | ||
| 1161 | if (cond_resched_lock(cinfo->lock)) | ||
| 1162 | list_safe_reset_next(req, tmp, wb_list); | ||
| 1163 | nfs_request_remove_commit_list(req, cinfo); | ||
| 1164 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
| 1165 | nfs_list_add_request(req, dst); | ||
| 1166 | ret++; | ||
| 1167 | if ((ret == max) && !cinfo->dreq) | ||
| 1168 | break; | ||
| 1169 | } | ||
| 1170 | return ret; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | /* Note called with cinfo->lock held. */ | ||
| 1174 | static int | ||
| 1175 | filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, | ||
| 1176 | struct nfs_commit_info *cinfo, | ||
| 1177 | int max) | ||
| 1178 | { | ||
| 1179 | struct list_head *src = &bucket->written; | ||
| 1180 | struct list_head *dst = &bucket->committing; | ||
| 1181 | int ret; | ||
| 1182 | |||
| 1183 | ret = transfer_commit_list(src, dst, cinfo, max); | ||
| 1184 | if (ret) { | ||
| 1185 | cinfo->ds->nwritten -= ret; | ||
| 1186 | cinfo->ds->ncommitting += ret; | ||
| 1187 | bucket->clseg = bucket->wlseg; | ||
| 1188 | if (list_empty(src)) | ||
| 1189 | bucket->wlseg = NULL; | ||
| 1190 | else | ||
| 1191 | pnfs_get_lseg(bucket->clseg); | ||
| 1192 | } | ||
| 1193 | return ret; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | /* Move reqs from written to committing lists, returning count of number moved. | ||
| 1197 | * Note called with cinfo->lock held. | ||
| 1198 | */ | ||
| 1199 | static int filelayout_scan_commit_lists(struct nfs_commit_info *cinfo, | ||
| 1200 | int max) | ||
| 1201 | { | ||
| 1202 | int i, rv = 0, cnt; | ||
| 1203 | |||
| 1204 | for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) { | ||
| 1205 | cnt = filelayout_scan_ds_commit_list(&cinfo->ds->buckets[i], | ||
| 1206 | cinfo, max); | ||
| 1207 | max -= cnt; | ||
| 1208 | rv += cnt; | ||
| 1209 | } | ||
| 1210 | return rv; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | /* Pull everything off the committing lists and dump into @dst */ | ||
| 1214 | static void filelayout_recover_commit_reqs(struct list_head *dst, | ||
| 1215 | struct nfs_commit_info *cinfo) | ||
| 1216 | { | ||
| 1217 | struct pnfs_commit_bucket *b; | ||
| 1218 | struct pnfs_layout_segment *freeme; | ||
| 1219 | int i; | ||
| 1220 | |||
| 1221 | restart: | ||
| 1222 | spin_lock(cinfo->lock); | ||
| 1223 | for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { | ||
| 1224 | if (transfer_commit_list(&b->written, dst, cinfo, 0)) { | ||
| 1225 | freeme = b->wlseg; | ||
| 1226 | b->wlseg = NULL; | ||
| 1227 | spin_unlock(cinfo->lock); | ||
| 1228 | pnfs_put_lseg(freeme); | ||
| 1229 | goto restart; | ||
| 1230 | } | ||
| 1231 | } | ||
| 1232 | cinfo->ds->nwritten = 0; | ||
| 1233 | spin_unlock(cinfo->lock); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | /* filelayout_search_commit_reqs - Search lists in @cinfo for the head reqest | 1071 | /* filelayout_search_commit_reqs - Search lists in @cinfo for the head reqest |
| 1237 | * for @page | 1072 | * for @page |
| 1238 | * @cinfo - commit info for current inode | 1073 | * @cinfo - commit info for current inode |
| @@ -1263,108 +1098,14 @@ filelayout_search_commit_reqs(struct nfs_commit_info *cinfo, struct page *page) | |||
| 1263 | return NULL; | 1098 | return NULL; |
| 1264 | } | 1099 | } |
| 1265 | 1100 | ||
| 1266 | static void filelayout_retry_commit(struct nfs_commit_info *cinfo, int idx) | ||
| 1267 | { | ||
| 1268 | struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds; | ||
| 1269 | struct pnfs_commit_bucket *bucket; | ||
| 1270 | struct pnfs_layout_segment *freeme; | ||
| 1271 | int i; | ||
| 1272 | |||
| 1273 | for (i = idx; i < fl_cinfo->nbuckets; i++) { | ||
| 1274 | bucket = &fl_cinfo->buckets[i]; | ||
| 1275 | if (list_empty(&bucket->committing)) | ||
| 1276 | continue; | ||
| 1277 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); | ||
| 1278 | spin_lock(cinfo->lock); | ||
| 1279 | freeme = bucket->clseg; | ||
| 1280 | bucket->clseg = NULL; | ||
| 1281 | spin_unlock(cinfo->lock); | ||
| 1282 | pnfs_put_lseg(freeme); | ||
| 1283 | } | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | static unsigned int | ||
| 1287 | alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) | ||
| 1288 | { | ||
| 1289 | struct pnfs_ds_commit_info *fl_cinfo; | ||
| 1290 | struct pnfs_commit_bucket *bucket; | ||
| 1291 | struct nfs_commit_data *data; | ||
| 1292 | int i; | ||
| 1293 | unsigned int nreq = 0; | ||
| 1294 | |||
| 1295 | fl_cinfo = cinfo->ds; | ||
| 1296 | bucket = fl_cinfo->buckets; | ||
| 1297 | for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) { | ||
| 1298 | if (list_empty(&bucket->committing)) | ||
| 1299 | continue; | ||
| 1300 | data = nfs_commitdata_alloc(); | ||
| 1301 | if (!data) | ||
| 1302 | break; | ||
| 1303 | data->ds_commit_index = i; | ||
| 1304 | spin_lock(cinfo->lock); | ||
| 1305 | data->lseg = bucket->clseg; | ||
| 1306 | bucket->clseg = NULL; | ||
| 1307 | spin_unlock(cinfo->lock); | ||
| 1308 | list_add(&data->pages, list); | ||
| 1309 | nreq++; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | /* Clean up on error */ | ||
| 1313 | filelayout_retry_commit(cinfo, i); | ||
| 1314 | /* Caller will clean up entries put on list */ | ||
| 1315 | return nreq; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | /* This follows nfs_commit_list pretty closely */ | ||
| 1319 | static int | 1101 | static int |
| 1320 | filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | 1102 | filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, |
| 1321 | int how, struct nfs_commit_info *cinfo) | 1103 | int how, struct nfs_commit_info *cinfo) |
| 1322 | { | 1104 | { |
| 1323 | struct nfs_commit_data *data, *tmp; | 1105 | return pnfs_generic_commit_pagelist(inode, mds_pages, how, cinfo, |
| 1324 | LIST_HEAD(list); | 1106 | filelayout_initiate_commit); |
| 1325 | unsigned int nreq = 0; | ||
| 1326 | |||
| 1327 | if (!list_empty(mds_pages)) { | ||
| 1328 | data = nfs_commitdata_alloc(); | ||
| 1329 | if (data != NULL) { | ||
| 1330 | data->lseg = NULL; | ||
| 1331 | list_add(&data->pages, &list); | ||
| 1332 | nreq++; | ||
| 1333 | } else { | ||
| 1334 | nfs_retry_commit(mds_pages, NULL, cinfo); | ||
| 1335 | filelayout_retry_commit(cinfo, 0); | ||
| 1336 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
| 1337 | return -ENOMEM; | ||
| 1338 | } | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | nreq += alloc_ds_commits(cinfo, &list); | ||
| 1342 | |||
| 1343 | if (nreq == 0) { | ||
| 1344 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
| 1345 | goto out; | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | atomic_add(nreq, &cinfo->mds->rpcs_out); | ||
| 1349 | |||
| 1350 | list_for_each_entry_safe(data, tmp, &list, pages) { | ||
| 1351 | list_del_init(&data->pages); | ||
| 1352 | if (!data->lseg) { | ||
| 1353 | nfs_init_commit(data, mds_pages, NULL, cinfo); | ||
| 1354 | nfs_initiate_commit(NFS_CLIENT(inode), data, | ||
| 1355 | data->mds_ops, how, 0); | ||
| 1356 | } else { | ||
| 1357 | struct pnfs_commit_bucket *buckets; | ||
| 1358 | |||
| 1359 | buckets = cinfo->ds->buckets; | ||
| 1360 | nfs_init_commit(data, &buckets[data->ds_commit_index].committing, data->lseg, cinfo); | ||
| 1361 | filelayout_initiate_commit(data, how); | ||
| 1362 | } | ||
| 1363 | } | ||
| 1364 | out: | ||
| 1365 | cinfo->ds->ncommitting = 0; | ||
| 1366 | return PNFS_ATTEMPTED; | ||
| 1367 | } | 1107 | } |
| 1108 | |||
| 1368 | static struct nfs4_deviceid_node * | 1109 | static struct nfs4_deviceid_node * |
| 1369 | filelayout_alloc_deviceid_node(struct nfs_server *server, | 1110 | filelayout_alloc_deviceid_node(struct nfs_server *server, |
| 1370 | struct pnfs_device *pdev, gfp_t gfp_flags) | 1111 | struct pnfs_device *pdev, gfp_t gfp_flags) |
| @@ -1421,9 +1162,9 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
| 1421 | .pg_write_ops = &filelayout_pg_write_ops, | 1162 | .pg_write_ops = &filelayout_pg_write_ops, |
| 1422 | .get_ds_info = &filelayout_get_ds_info, | 1163 | .get_ds_info = &filelayout_get_ds_info, |
| 1423 | .mark_request_commit = filelayout_mark_request_commit, | 1164 | .mark_request_commit = filelayout_mark_request_commit, |
| 1424 | .clear_request_commit = filelayout_clear_request_commit, | 1165 | .clear_request_commit = pnfs_generic_clear_request_commit, |
| 1425 | .scan_commit_lists = filelayout_scan_commit_lists, | 1166 | .scan_commit_lists = pnfs_generic_scan_commit_lists, |
| 1426 | .recover_commit_reqs = filelayout_recover_commit_reqs, | 1167 | .recover_commit_reqs = pnfs_generic_recover_commit_reqs, |
| 1427 | .search_commit_reqs = filelayout_search_commit_reqs, | 1168 | .search_commit_reqs = filelayout_search_commit_reqs, |
| 1428 | .commit_pagelist = filelayout_commit_pagelist, | 1169 | .commit_pagelist = filelayout_commit_pagelist, |
| 1429 | .read_pagelist = filelayout_read_pagelist, | 1170 | .read_pagelist = filelayout_read_pagelist, |
