diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 294 |
1 files changed, 245 insertions, 49 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 2b5e769beb16..960c99f75d3f 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -42,21 +42,35 @@ static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) | |||
42 | return p->pagevec != NULL; | 42 | return p->pagevec != NULL; |
43 | } | 43 | } |
44 | 44 | ||
45 | struct nfs_pgio_mirror * | ||
46 | nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc) | ||
47 | { | ||
48 | return nfs_pgio_has_mirroring(desc) ? | ||
49 | &desc->pg_mirrors[desc->pg_mirror_idx] : | ||
50 | &desc->pg_mirrors[0]; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(nfs_pgio_current_mirror); | ||
53 | |||
45 | void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, | 54 | void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, |
46 | struct nfs_pgio_header *hdr, | 55 | struct nfs_pgio_header *hdr, |
47 | void (*release)(struct nfs_pgio_header *hdr)) | 56 | void (*release)(struct nfs_pgio_header *hdr)) |
48 | { | 57 | { |
49 | hdr->req = nfs_list_entry(desc->pg_list.next); | 58 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); |
59 | |||
60 | |||
61 | hdr->req = nfs_list_entry(mirror->pg_list.next); | ||
50 | hdr->inode = desc->pg_inode; | 62 | hdr->inode = desc->pg_inode; |
51 | hdr->cred = hdr->req->wb_context->cred; | 63 | hdr->cred = hdr->req->wb_context->cred; |
52 | hdr->io_start = req_offset(hdr->req); | 64 | hdr->io_start = req_offset(hdr->req); |
53 | hdr->good_bytes = desc->pg_count; | 65 | hdr->good_bytes = mirror->pg_count; |
54 | hdr->dreq = desc->pg_dreq; | 66 | hdr->dreq = desc->pg_dreq; |
55 | hdr->layout_private = desc->pg_layout_private; | 67 | hdr->layout_private = desc->pg_layout_private; |
56 | hdr->release = release; | 68 | hdr->release = release; |
57 | hdr->completion_ops = desc->pg_completion_ops; | 69 | hdr->completion_ops = desc->pg_completion_ops; |
58 | if (hdr->completion_ops->init_hdr) | 70 | if (hdr->completion_ops->init_hdr) |
59 | hdr->completion_ops->init_hdr(hdr); | 71 | hdr->completion_ops->init_hdr(hdr); |
72 | |||
73 | hdr->pgio_mirror_idx = desc->pg_mirror_idx; | ||
60 | } | 74 | } |
61 | EXPORT_SYMBOL_GPL(nfs_pgheader_init); | 75 | EXPORT_SYMBOL_GPL(nfs_pgheader_init); |
62 | 76 | ||
@@ -480,7 +494,10 @@ nfs_wait_on_request(struct nfs_page *req) | |||
480 | size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | 494 | size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, |
481 | struct nfs_page *prev, struct nfs_page *req) | 495 | struct nfs_page *prev, struct nfs_page *req) |
482 | { | 496 | { |
483 | if (desc->pg_count > desc->pg_bsize) { | 497 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); |
498 | |||
499 | |||
500 | if (mirror->pg_count > mirror->pg_bsize) { | ||
484 | /* should never happen */ | 501 | /* should never happen */ |
485 | WARN_ON_ONCE(1); | 502 | WARN_ON_ONCE(1); |
486 | return 0; | 503 | return 0; |
@@ -490,11 +507,11 @@ size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | |||
490 | * Limit the request size so that we can still allocate a page array | 507 | * Limit the request size so that we can still allocate a page array |
491 | * for it without upsetting the slab allocator. | 508 | * for it without upsetting the slab allocator. |
492 | */ | 509 | */ |
493 | if (((desc->pg_count + req->wb_bytes) >> PAGE_SHIFT) * | 510 | if (((mirror->pg_count + req->wb_bytes) >> PAGE_SHIFT) * |
494 | sizeof(struct page) > PAGE_SIZE) | 511 | sizeof(struct page) > PAGE_SIZE) |
495 | return 0; | 512 | return 0; |
496 | 513 | ||
497 | return min(desc->pg_bsize - desc->pg_count, (size_t)req->wb_bytes); | 514 | return min(mirror->pg_bsize - mirror->pg_count, (size_t)req->wb_bytes); |
498 | } | 515 | } |
499 | EXPORT_SYMBOL_GPL(nfs_generic_pg_test); | 516 | EXPORT_SYMBOL_GPL(nfs_generic_pg_test); |
500 | 517 | ||
@@ -597,13 +614,14 @@ static void nfs_pgio_prepare(struct rpc_task *task, void *calldata) | |||
597 | } | 614 | } |
598 | 615 | ||
599 | int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, | 616 | int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, |
617 | struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops, | ||
600 | const struct rpc_call_ops *call_ops, int how, int flags) | 618 | const struct rpc_call_ops *call_ops, int how, int flags) |
601 | { | 619 | { |
602 | struct rpc_task *task; | 620 | struct rpc_task *task; |
603 | struct rpc_message msg = { | 621 | struct rpc_message msg = { |
604 | .rpc_argp = &hdr->args, | 622 | .rpc_argp = &hdr->args, |
605 | .rpc_resp = &hdr->res, | 623 | .rpc_resp = &hdr->res, |
606 | .rpc_cred = hdr->cred, | 624 | .rpc_cred = cred, |
607 | }; | 625 | }; |
608 | struct rpc_task_setup task_setup_data = { | 626 | struct rpc_task_setup task_setup_data = { |
609 | .rpc_client = clnt, | 627 | .rpc_client = clnt, |
@@ -616,7 +634,7 @@ int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, | |||
616 | }; | 634 | }; |
617 | int ret = 0; | 635 | int ret = 0; |
618 | 636 | ||
619 | hdr->rw_ops->rw_initiate(hdr, &msg, &task_setup_data, how); | 637 | hdr->rw_ops->rw_initiate(hdr, &msg, rpc_ops, &task_setup_data, how); |
620 | 638 | ||
621 | dprintk("NFS: %5u initiated pgio call " | 639 | dprintk("NFS: %5u initiated pgio call " |
622 | "(req %s/%llu, %u bytes @ offset %llu)\n", | 640 | "(req %s/%llu, %u bytes @ offset %llu)\n", |
@@ -650,10 +668,18 @@ EXPORT_SYMBOL_GPL(nfs_initiate_pgio); | |||
650 | static int nfs_pgio_error(struct nfs_pageio_descriptor *desc, | 668 | static int nfs_pgio_error(struct nfs_pageio_descriptor *desc, |
651 | struct nfs_pgio_header *hdr) | 669 | struct nfs_pgio_header *hdr) |
652 | { | 670 | { |
671 | struct nfs_pgio_mirror *mirror; | ||
672 | u32 midx; | ||
673 | |||
653 | set_bit(NFS_IOHDR_REDO, &hdr->flags); | 674 | set_bit(NFS_IOHDR_REDO, &hdr->flags); |
654 | nfs_pgio_data_destroy(hdr); | 675 | nfs_pgio_data_destroy(hdr); |
655 | hdr->completion_ops->completion(hdr); | 676 | hdr->completion_ops->completion(hdr); |
656 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 677 | /* TODO: Make sure it's right to clean up all mirrors here |
678 | * and not just hdr->pgio_mirror_idx */ | ||
679 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
680 | mirror = &desc->pg_mirrors[midx]; | ||
681 | desc->pg_completion_ops->error_cleanup(&mirror->pg_list); | ||
682 | } | ||
657 | return -ENOMEM; | 683 | return -ENOMEM; |
658 | } | 684 | } |
659 | 685 | ||
@@ -670,6 +696,17 @@ static void nfs_pgio_release(void *calldata) | |||
670 | hdr->completion_ops->completion(hdr); | 696 | hdr->completion_ops->completion(hdr); |
671 | } | 697 | } |
672 | 698 | ||
699 | static void nfs_pageio_mirror_init(struct nfs_pgio_mirror *mirror, | ||
700 | unsigned int bsize) | ||
701 | { | ||
702 | INIT_LIST_HEAD(&mirror->pg_list); | ||
703 | mirror->pg_bytes_written = 0; | ||
704 | mirror->pg_count = 0; | ||
705 | mirror->pg_bsize = bsize; | ||
706 | mirror->pg_base = 0; | ||
707 | mirror->pg_recoalesce = 0; | ||
708 | } | ||
709 | |||
673 | /** | 710 | /** |
674 | * nfs_pageio_init - initialise a page io descriptor | 711 | * nfs_pageio_init - initialise a page io descriptor |
675 | * @desc: pointer to descriptor | 712 | * @desc: pointer to descriptor |
@@ -686,13 +723,10 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
686 | size_t bsize, | 723 | size_t bsize, |
687 | int io_flags) | 724 | int io_flags) |
688 | { | 725 | { |
689 | INIT_LIST_HEAD(&desc->pg_list); | 726 | struct nfs_pgio_mirror *new; |
690 | desc->pg_bytes_written = 0; | 727 | int i; |
691 | desc->pg_count = 0; | 728 | |
692 | desc->pg_bsize = bsize; | ||
693 | desc->pg_base = 0; | ||
694 | desc->pg_moreio = 0; | 729 | desc->pg_moreio = 0; |
695 | desc->pg_recoalesce = 0; | ||
696 | desc->pg_inode = inode; | 730 | desc->pg_inode = inode; |
697 | desc->pg_ops = pg_ops; | 731 | desc->pg_ops = pg_ops; |
698 | desc->pg_completion_ops = compl_ops; | 732 | desc->pg_completion_ops = compl_ops; |
@@ -702,6 +736,26 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
702 | desc->pg_lseg = NULL; | 736 | desc->pg_lseg = NULL; |
703 | desc->pg_dreq = NULL; | 737 | desc->pg_dreq = NULL; |
704 | desc->pg_layout_private = NULL; | 738 | desc->pg_layout_private = NULL; |
739 | desc->pg_bsize = bsize; | ||
740 | |||
741 | desc->pg_mirror_count = 1; | ||
742 | desc->pg_mirror_idx = 0; | ||
743 | |||
744 | if (pg_ops->pg_get_mirror_count) { | ||
745 | /* until we have a request, we don't have an lseg and no | ||
746 | * idea how many mirrors there will be */ | ||
747 | new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX, | ||
748 | sizeof(struct nfs_pgio_mirror), GFP_KERNEL); | ||
749 | desc->pg_mirrors_dynamic = new; | ||
750 | desc->pg_mirrors = new; | ||
751 | |||
752 | for (i = 0; i < NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX; i++) | ||
753 | nfs_pageio_mirror_init(&desc->pg_mirrors[i], bsize); | ||
754 | } else { | ||
755 | desc->pg_mirrors_dynamic = NULL; | ||
756 | desc->pg_mirrors = desc->pg_mirrors_static; | ||
757 | nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize); | ||
758 | } | ||
705 | } | 759 | } |
706 | EXPORT_SYMBOL_GPL(nfs_pageio_init); | 760 | EXPORT_SYMBOL_GPL(nfs_pageio_init); |
707 | 761 | ||
@@ -737,14 +791,16 @@ static void nfs_pgio_result(struct rpc_task *task, void *calldata) | |||
737 | int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | 791 | int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, |
738 | struct nfs_pgio_header *hdr) | 792 | struct nfs_pgio_header *hdr) |
739 | { | 793 | { |
794 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
795 | |||
740 | struct nfs_page *req; | 796 | struct nfs_page *req; |
741 | struct page **pages, | 797 | struct page **pages, |
742 | *last_page; | 798 | *last_page; |
743 | struct list_head *head = &desc->pg_list; | 799 | struct list_head *head = &mirror->pg_list; |
744 | struct nfs_commit_info cinfo; | 800 | struct nfs_commit_info cinfo; |
745 | unsigned int pagecount, pageused; | 801 | unsigned int pagecount, pageused; |
746 | 802 | ||
747 | pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); | 803 | pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); |
748 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) | 804 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) |
749 | return nfs_pgio_error(desc, hdr); | 805 | return nfs_pgio_error(desc, hdr); |
750 | 806 | ||
@@ -772,7 +828,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
772 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 828 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
773 | 829 | ||
774 | /* Set up the argument struct */ | 830 | /* Set up the argument struct */ |
775 | nfs_pgio_rpcsetup(hdr, desc->pg_count, 0, desc->pg_ioflags, &cinfo); | 831 | nfs_pgio_rpcsetup(hdr, mirror->pg_count, 0, desc->pg_ioflags, &cinfo); |
776 | desc->pg_rpc_callops = &nfs_pgio_common_ops; | 832 | desc->pg_rpc_callops = &nfs_pgio_common_ops; |
777 | return 0; | 833 | return 0; |
778 | } | 834 | } |
@@ -780,23 +836,74 @@ EXPORT_SYMBOL_GPL(nfs_generic_pgio); | |||
780 | 836 | ||
781 | static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) | 837 | static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) |
782 | { | 838 | { |
839 | struct nfs_pgio_mirror *mirror; | ||
783 | struct nfs_pgio_header *hdr; | 840 | struct nfs_pgio_header *hdr; |
784 | int ret; | 841 | int ret; |
785 | 842 | ||
843 | mirror = nfs_pgio_current_mirror(desc); | ||
844 | |||
786 | hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); | 845 | hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); |
787 | if (!hdr) { | 846 | if (!hdr) { |
788 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 847 | /* TODO: make sure this is right with mirroring - or |
848 | * should it back out all mirrors? */ | ||
849 | desc->pg_completion_ops->error_cleanup(&mirror->pg_list); | ||
789 | return -ENOMEM; | 850 | return -ENOMEM; |
790 | } | 851 | } |
791 | nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); | 852 | nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); |
792 | ret = nfs_generic_pgio(desc, hdr); | 853 | ret = nfs_generic_pgio(desc, hdr); |
793 | if (ret == 0) | 854 | if (ret == 0) |
794 | ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), | 855 | ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), |
795 | hdr, desc->pg_rpc_callops, | 856 | hdr, |
857 | hdr->cred, | ||
858 | NFS_PROTO(hdr->inode), | ||
859 | desc->pg_rpc_callops, | ||
796 | desc->pg_ioflags, 0); | 860 | desc->pg_ioflags, 0); |
797 | return ret; | 861 | return ret; |
798 | } | 862 | } |
799 | 863 | ||
864 | /* | ||
865 | * nfs_pageio_setup_mirroring - determine if mirroring is to be used | ||
866 | * by calling the pg_get_mirror_count op | ||
867 | */ | ||
868 | static int nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio, | ||
869 | struct nfs_page *req) | ||
870 | { | ||
871 | int mirror_count = 1; | ||
872 | |||
873 | if (!pgio->pg_ops->pg_get_mirror_count) | ||
874 | return 0; | ||
875 | |||
876 | mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req); | ||
877 | |||
878 | if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) | ||
879 | return -EINVAL; | ||
880 | |||
881 | if (WARN_ON_ONCE(!pgio->pg_mirrors_dynamic)) | ||
882 | return -EINVAL; | ||
883 | |||
884 | pgio->pg_mirror_count = mirror_count; | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1) | ||
891 | */ | ||
892 | void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio) | ||
893 | { | ||
894 | pgio->pg_mirror_count = 1; | ||
895 | pgio->pg_mirror_idx = 0; | ||
896 | } | ||
897 | |||
898 | static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio) | ||
899 | { | ||
900 | pgio->pg_mirror_count = 1; | ||
901 | pgio->pg_mirror_idx = 0; | ||
902 | pgio->pg_mirrors = pgio->pg_mirrors_static; | ||
903 | kfree(pgio->pg_mirrors_dynamic); | ||
904 | pgio->pg_mirrors_dynamic = NULL; | ||
905 | } | ||
906 | |||
800 | static bool nfs_match_open_context(const struct nfs_open_context *ctx1, | 907 | static bool nfs_match_open_context(const struct nfs_open_context *ctx1, |
801 | const struct nfs_open_context *ctx2) | 908 | const struct nfs_open_context *ctx2) |
802 | { | 909 | { |
@@ -863,19 +970,22 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, | |||
863 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | 970 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, |
864 | struct nfs_page *req) | 971 | struct nfs_page *req) |
865 | { | 972 | { |
973 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
974 | |||
866 | struct nfs_page *prev = NULL; | 975 | struct nfs_page *prev = NULL; |
867 | if (desc->pg_count != 0) { | 976 | |
868 | prev = nfs_list_entry(desc->pg_list.prev); | 977 | if (mirror->pg_count != 0) { |
978 | prev = nfs_list_entry(mirror->pg_list.prev); | ||
869 | } else { | 979 | } else { |
870 | if (desc->pg_ops->pg_init) | 980 | if (desc->pg_ops->pg_init) |
871 | desc->pg_ops->pg_init(desc, req); | 981 | desc->pg_ops->pg_init(desc, req); |
872 | desc->pg_base = req->wb_pgbase; | 982 | mirror->pg_base = req->wb_pgbase; |
873 | } | 983 | } |
874 | if (!nfs_can_coalesce_requests(prev, req, desc)) | 984 | if (!nfs_can_coalesce_requests(prev, req, desc)) |
875 | return 0; | 985 | return 0; |
876 | nfs_list_remove_request(req); | 986 | nfs_list_remove_request(req); |
877 | nfs_list_add_request(req, &desc->pg_list); | 987 | nfs_list_add_request(req, &mirror->pg_list); |
878 | desc->pg_count += req->wb_bytes; | 988 | mirror->pg_count += req->wb_bytes; |
879 | return 1; | 989 | return 1; |
880 | } | 990 | } |
881 | 991 | ||
@@ -884,16 +994,19 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | |||
884 | */ | 994 | */ |
885 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | 995 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) |
886 | { | 996 | { |
887 | if (!list_empty(&desc->pg_list)) { | 997 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); |
998 | |||
999 | |||
1000 | if (!list_empty(&mirror->pg_list)) { | ||
888 | int error = desc->pg_ops->pg_doio(desc); | 1001 | int error = desc->pg_ops->pg_doio(desc); |
889 | if (error < 0) | 1002 | if (error < 0) |
890 | desc->pg_error = error; | 1003 | desc->pg_error = error; |
891 | else | 1004 | else |
892 | desc->pg_bytes_written += desc->pg_count; | 1005 | mirror->pg_bytes_written += mirror->pg_count; |
893 | } | 1006 | } |
894 | if (list_empty(&desc->pg_list)) { | 1007 | if (list_empty(&mirror->pg_list)) { |
895 | desc->pg_count = 0; | 1008 | mirror->pg_count = 0; |
896 | desc->pg_base = 0; | 1009 | mirror->pg_base = 0; |
897 | } | 1010 | } |
898 | } | 1011 | } |
899 | 1012 | ||
@@ -911,6 +1024,8 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | |||
911 | static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 1024 | static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, |
912 | struct nfs_page *req) | 1025 | struct nfs_page *req) |
913 | { | 1026 | { |
1027 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
1028 | |||
914 | struct nfs_page *subreq; | 1029 | struct nfs_page *subreq; |
915 | unsigned int bytes_left = 0; | 1030 | unsigned int bytes_left = 0; |
916 | unsigned int offset, pgbase; | 1031 | unsigned int offset, pgbase; |
@@ -934,7 +1049,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
934 | nfs_pageio_doio(desc); | 1049 | nfs_pageio_doio(desc); |
935 | if (desc->pg_error < 0) | 1050 | if (desc->pg_error < 0) |
936 | return 0; | 1051 | return 0; |
937 | if (desc->pg_recoalesce) | 1052 | if (mirror->pg_recoalesce) |
938 | return 0; | 1053 | return 0; |
939 | /* retry add_request for this subreq */ | 1054 | /* retry add_request for this subreq */ |
940 | nfs_page_group_lock(req, false); | 1055 | nfs_page_group_lock(req, false); |
@@ -972,14 +1087,16 @@ err_ptr: | |||
972 | 1087 | ||
973 | static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | 1088 | static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) |
974 | { | 1089 | { |
1090 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
975 | LIST_HEAD(head); | 1091 | LIST_HEAD(head); |
976 | 1092 | ||
977 | do { | 1093 | do { |
978 | list_splice_init(&desc->pg_list, &head); | 1094 | list_splice_init(&mirror->pg_list, &head); |
979 | desc->pg_bytes_written -= desc->pg_count; | 1095 | mirror->pg_bytes_written -= mirror->pg_count; |
980 | desc->pg_count = 0; | 1096 | mirror->pg_count = 0; |
981 | desc->pg_base = 0; | 1097 | mirror->pg_base = 0; |
982 | desc->pg_recoalesce = 0; | 1098 | mirror->pg_recoalesce = 0; |
1099 | |||
983 | desc->pg_moreio = 0; | 1100 | desc->pg_moreio = 0; |
984 | 1101 | ||
985 | while (!list_empty(&head)) { | 1102 | while (!list_empty(&head)) { |
@@ -993,11 +1110,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | |||
993 | return 0; | 1110 | return 0; |
994 | break; | 1111 | break; |
995 | } | 1112 | } |
996 | } while (desc->pg_recoalesce); | 1113 | } while (mirror->pg_recoalesce); |
997 | return 1; | 1114 | return 1; |
998 | } | 1115 | } |
999 | 1116 | ||
1000 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 1117 | static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc, |
1001 | struct nfs_page *req) | 1118 | struct nfs_page *req) |
1002 | { | 1119 | { |
1003 | int ret; | 1120 | int ret; |
@@ -1010,9 +1127,80 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
1010 | break; | 1127 | break; |
1011 | ret = nfs_do_recoalesce(desc); | 1128 | ret = nfs_do_recoalesce(desc); |
1012 | } while (ret); | 1129 | } while (ret); |
1130 | |||
1013 | return ret; | 1131 | return ret; |
1014 | } | 1132 | } |
1015 | 1133 | ||
1134 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | ||
1135 | struct nfs_page *req) | ||
1136 | { | ||
1137 | u32 midx; | ||
1138 | unsigned int pgbase, offset, bytes; | ||
1139 | struct nfs_page *dupreq, *lastreq; | ||
1140 | |||
1141 | pgbase = req->wb_pgbase; | ||
1142 | offset = req->wb_offset; | ||
1143 | bytes = req->wb_bytes; | ||
1144 | |||
1145 | nfs_pageio_setup_mirroring(desc, req); | ||
1146 | |||
1147 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
1148 | if (midx) { | ||
1149 | nfs_page_group_lock(req, false); | ||
1150 | |||
1151 | /* find the last request */ | ||
1152 | for (lastreq = req->wb_head; | ||
1153 | lastreq->wb_this_page != req->wb_head; | ||
1154 | lastreq = lastreq->wb_this_page) | ||
1155 | ; | ||
1156 | |||
1157 | dupreq = nfs_create_request(req->wb_context, | ||
1158 | req->wb_page, lastreq, pgbase, bytes); | ||
1159 | |||
1160 | if (IS_ERR(dupreq)) { | ||
1161 | nfs_page_group_unlock(req); | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | nfs_lock_request(dupreq); | ||
1166 | nfs_page_group_unlock(req); | ||
1167 | dupreq->wb_offset = offset; | ||
1168 | dupreq->wb_index = req->wb_index; | ||
1169 | } else | ||
1170 | dupreq = req; | ||
1171 | |||
1172 | if (nfs_pgio_has_mirroring(desc)) | ||
1173 | desc->pg_mirror_idx = midx; | ||
1174 | if (!nfs_pageio_add_request_mirror(desc, dupreq)) | ||
1175 | return 0; | ||
1176 | } | ||
1177 | |||
1178 | return 1; | ||
1179 | } | ||
1180 | |||
1181 | /* | ||
1182 | * nfs_pageio_complete_mirror - Complete I/O on the current mirror of an | ||
1183 | * nfs_pageio_descriptor | ||
1184 | * @desc: pointer to io descriptor | ||
1185 | */ | ||
1186 | static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc, | ||
1187 | u32 mirror_idx) | ||
1188 | { | ||
1189 | struct nfs_pgio_mirror *mirror = &desc->pg_mirrors[mirror_idx]; | ||
1190 | u32 restore_idx = desc->pg_mirror_idx; | ||
1191 | |||
1192 | if (nfs_pgio_has_mirroring(desc)) | ||
1193 | desc->pg_mirror_idx = mirror_idx; | ||
1194 | for (;;) { | ||
1195 | nfs_pageio_doio(desc); | ||
1196 | if (!mirror->pg_recoalesce) | ||
1197 | break; | ||
1198 | if (!nfs_do_recoalesce(desc)) | ||
1199 | break; | ||
1200 | } | ||
1201 | desc->pg_mirror_idx = restore_idx; | ||
1202 | } | ||
1203 | |||
1016 | /* | 1204 | /* |
1017 | * nfs_pageio_resend - Transfer requests to new descriptor and resend | 1205 | * nfs_pageio_resend - Transfer requests to new descriptor and resend |
1018 | * @hdr - the pgio header to move request from | 1206 | * @hdr - the pgio header to move request from |
@@ -1046,18 +1234,19 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc, | |||
1046 | EXPORT_SYMBOL_GPL(nfs_pageio_resend); | 1234 | EXPORT_SYMBOL_GPL(nfs_pageio_resend); |
1047 | 1235 | ||
1048 | /** | 1236 | /** |
1049 | * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor | 1237 | * nfs_pageio_complete - Complete I/O then cleanup an nfs_pageio_descriptor |
1050 | * @desc: pointer to io descriptor | 1238 | * @desc: pointer to io descriptor |
1051 | */ | 1239 | */ |
1052 | void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | 1240 | void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) |
1053 | { | 1241 | { |
1054 | for (;;) { | 1242 | u32 midx; |
1055 | nfs_pageio_doio(desc); | 1243 | |
1056 | if (!desc->pg_recoalesce) | 1244 | for (midx = 0; midx < desc->pg_mirror_count; midx++) |
1057 | break; | 1245 | nfs_pageio_complete_mirror(desc, midx); |
1058 | if (!nfs_do_recoalesce(desc)) | 1246 | |
1059 | break; | 1247 | if (desc->pg_ops->pg_cleanup) |
1060 | } | 1248 | desc->pg_ops->pg_cleanup(desc); |
1249 | nfs_pageio_cleanup_mirroring(desc); | ||
1061 | } | 1250 | } |
1062 | 1251 | ||
1063 | /** | 1252 | /** |
@@ -1073,10 +1262,17 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | |||
1073 | */ | 1262 | */ |
1074 | void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) | 1263 | void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) |
1075 | { | 1264 | { |
1076 | if (!list_empty(&desc->pg_list)) { | 1265 | struct nfs_pgio_mirror *mirror; |
1077 | struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); | 1266 | struct nfs_page *prev; |
1078 | if (index != prev->wb_index + 1) | 1267 | u32 midx; |
1079 | nfs_pageio_complete(desc); | 1268 | |
1269 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
1270 | mirror = &desc->pg_mirrors[midx]; | ||
1271 | if (!list_empty(&mirror->pg_list)) { | ||
1272 | prev = nfs_list_entry(mirror->pg_list.prev); | ||
1273 | if (index != prev->wb_index + 1) | ||
1274 | nfs_pageio_complete_mirror(desc, midx); | ||
1275 | } | ||
1080 | } | 1276 | } |
1081 | } | 1277 | } |
1082 | 1278 | ||