diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
| -rw-r--r-- | fs/nfs/pagelist.c | 300 |
1 files changed, 250 insertions, 50 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 2b5e769beb16..d57190a0d533 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 | { |
| @@ -826,11 +933,15 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, | |||
| 826 | struct nfs_pageio_descriptor *pgio) | 933 | struct nfs_pageio_descriptor *pgio) |
| 827 | { | 934 | { |
| 828 | size_t size; | 935 | size_t size; |
| 936 | struct file_lock_context *flctx; | ||
| 829 | 937 | ||
| 830 | if (prev) { | 938 | if (prev) { |
| 831 | if (!nfs_match_open_context(req->wb_context, prev->wb_context)) | 939 | if (!nfs_match_open_context(req->wb_context, prev->wb_context)) |
| 832 | return false; | 940 | return false; |
| 833 | if (req->wb_context->dentry->d_inode->i_flock != NULL && | 941 | flctx = req->wb_context->dentry->d_inode->i_flctx; |
| 942 | if (flctx != NULL && | ||
| 943 | !(list_empty_careful(&flctx->flc_posix) && | ||
| 944 | list_empty_careful(&flctx->flc_flock)) && | ||
| 834 | !nfs_match_lock_context(req->wb_lock_context, | 945 | !nfs_match_lock_context(req->wb_lock_context, |
| 835 | prev->wb_lock_context)) | 946 | prev->wb_lock_context)) |
| 836 | return false; | 947 | return false; |
| @@ -863,19 +974,22 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, | |||
| 863 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | 974 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, |
| 864 | struct nfs_page *req) | 975 | struct nfs_page *req) |
| 865 | { | 976 | { |
| 977 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
| 978 | |||
| 866 | struct nfs_page *prev = NULL; | 979 | struct nfs_page *prev = NULL; |
| 867 | if (desc->pg_count != 0) { | 980 | |
| 868 | prev = nfs_list_entry(desc->pg_list.prev); | 981 | if (mirror->pg_count != 0) { |
| 982 | prev = nfs_list_entry(mirror->pg_list.prev); | ||
| 869 | } else { | 983 | } else { |
| 870 | if (desc->pg_ops->pg_init) | 984 | if (desc->pg_ops->pg_init) |
| 871 | desc->pg_ops->pg_init(desc, req); | 985 | desc->pg_ops->pg_init(desc, req); |
| 872 | desc->pg_base = req->wb_pgbase; | 986 | mirror->pg_base = req->wb_pgbase; |
| 873 | } | 987 | } |
| 874 | if (!nfs_can_coalesce_requests(prev, req, desc)) | 988 | if (!nfs_can_coalesce_requests(prev, req, desc)) |
| 875 | return 0; | 989 | return 0; |
| 876 | nfs_list_remove_request(req); | 990 | nfs_list_remove_request(req); |
| 877 | nfs_list_add_request(req, &desc->pg_list); | 991 | nfs_list_add_request(req, &mirror->pg_list); |
| 878 | desc->pg_count += req->wb_bytes; | 992 | mirror->pg_count += req->wb_bytes; |
| 879 | return 1; | 993 | return 1; |
| 880 | } | 994 | } |
| 881 | 995 | ||
| @@ -884,16 +998,19 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | |||
| 884 | */ | 998 | */ |
| 885 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | 999 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) |
| 886 | { | 1000 | { |
| 887 | if (!list_empty(&desc->pg_list)) { | 1001 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); |
| 1002 | |||
| 1003 | |||
| 1004 | if (!list_empty(&mirror->pg_list)) { | ||
| 888 | int error = desc->pg_ops->pg_doio(desc); | 1005 | int error = desc->pg_ops->pg_doio(desc); |
| 889 | if (error < 0) | 1006 | if (error < 0) |
| 890 | desc->pg_error = error; | 1007 | desc->pg_error = error; |
| 891 | else | 1008 | else |
| 892 | desc->pg_bytes_written += desc->pg_count; | 1009 | mirror->pg_bytes_written += mirror->pg_count; |
| 893 | } | 1010 | } |
| 894 | if (list_empty(&desc->pg_list)) { | 1011 | if (list_empty(&mirror->pg_list)) { |
| 895 | desc->pg_count = 0; | 1012 | mirror->pg_count = 0; |
| 896 | desc->pg_base = 0; | 1013 | mirror->pg_base = 0; |
| 897 | } | 1014 | } |
| 898 | } | 1015 | } |
| 899 | 1016 | ||
| @@ -911,6 +1028,8 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | |||
| 911 | static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 1028 | static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, |
| 912 | struct nfs_page *req) | 1029 | struct nfs_page *req) |
| 913 | { | 1030 | { |
| 1031 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
| 1032 | |||
| 914 | struct nfs_page *subreq; | 1033 | struct nfs_page *subreq; |
| 915 | unsigned int bytes_left = 0; | 1034 | unsigned int bytes_left = 0; |
| 916 | unsigned int offset, pgbase; | 1035 | unsigned int offset, pgbase; |
| @@ -934,7 +1053,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 934 | nfs_pageio_doio(desc); | 1053 | nfs_pageio_doio(desc); |
| 935 | if (desc->pg_error < 0) | 1054 | if (desc->pg_error < 0) |
| 936 | return 0; | 1055 | return 0; |
| 937 | if (desc->pg_recoalesce) | 1056 | if (mirror->pg_recoalesce) |
| 938 | return 0; | 1057 | return 0; |
| 939 | /* retry add_request for this subreq */ | 1058 | /* retry add_request for this subreq */ |
| 940 | nfs_page_group_lock(req, false); | 1059 | nfs_page_group_lock(req, false); |
| @@ -972,14 +1091,16 @@ err_ptr: | |||
| 972 | 1091 | ||
| 973 | static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | 1092 | static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) |
| 974 | { | 1093 | { |
| 1094 | struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); | ||
| 975 | LIST_HEAD(head); | 1095 | LIST_HEAD(head); |
| 976 | 1096 | ||
| 977 | do { | 1097 | do { |
| 978 | list_splice_init(&desc->pg_list, &head); | 1098 | list_splice_init(&mirror->pg_list, &head); |
| 979 | desc->pg_bytes_written -= desc->pg_count; | 1099 | mirror->pg_bytes_written -= mirror->pg_count; |
| 980 | desc->pg_count = 0; | 1100 | mirror->pg_count = 0; |
| 981 | desc->pg_base = 0; | 1101 | mirror->pg_base = 0; |
| 982 | desc->pg_recoalesce = 0; | 1102 | mirror->pg_recoalesce = 0; |
| 1103 | |||
| 983 | desc->pg_moreio = 0; | 1104 | desc->pg_moreio = 0; |
| 984 | 1105 | ||
| 985 | while (!list_empty(&head)) { | 1106 | while (!list_empty(&head)) { |
| @@ -993,11 +1114,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | |||
| 993 | return 0; | 1114 | return 0; |
| 994 | break; | 1115 | break; |
| 995 | } | 1116 | } |
| 996 | } while (desc->pg_recoalesce); | 1117 | } while (mirror->pg_recoalesce); |
| 997 | return 1; | 1118 | return 1; |
| 998 | } | 1119 | } |
| 999 | 1120 | ||
| 1000 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 1121 | static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc, |
| 1001 | struct nfs_page *req) | 1122 | struct nfs_page *req) |
| 1002 | { | 1123 | { |
| 1003 | int ret; | 1124 | int ret; |
| @@ -1010,9 +1131,80 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 1010 | break; | 1131 | break; |
| 1011 | ret = nfs_do_recoalesce(desc); | 1132 | ret = nfs_do_recoalesce(desc); |
| 1012 | } while (ret); | 1133 | } while (ret); |
| 1134 | |||
| 1013 | return ret; | 1135 | return ret; |
| 1014 | } | 1136 | } |
| 1015 | 1137 | ||
| 1138 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | ||
| 1139 | struct nfs_page *req) | ||
| 1140 | { | ||
| 1141 | u32 midx; | ||
| 1142 | unsigned int pgbase, offset, bytes; | ||
| 1143 | struct nfs_page *dupreq, *lastreq; | ||
| 1144 | |||
| 1145 | pgbase = req->wb_pgbase; | ||
| 1146 | offset = req->wb_offset; | ||
| 1147 | bytes = req->wb_bytes; | ||
| 1148 | |||
| 1149 | nfs_pageio_setup_mirroring(desc, req); | ||
| 1150 | |||
| 1151 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
| 1152 | if (midx) { | ||
| 1153 | nfs_page_group_lock(req, false); | ||
| 1154 | |||
| 1155 | /* find the last request */ | ||
| 1156 | for (lastreq = req->wb_head; | ||
| 1157 | lastreq->wb_this_page != req->wb_head; | ||
| 1158 | lastreq = lastreq->wb_this_page) | ||
| 1159 | ; | ||
| 1160 | |||
| 1161 | dupreq = nfs_create_request(req->wb_context, | ||
| 1162 | req->wb_page, lastreq, pgbase, bytes); | ||
| 1163 | |||
| 1164 | if (IS_ERR(dupreq)) { | ||
| 1165 | nfs_page_group_unlock(req); | ||
| 1166 | return 0; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | nfs_lock_request(dupreq); | ||
| 1170 | nfs_page_group_unlock(req); | ||
| 1171 | dupreq->wb_offset = offset; | ||
| 1172 | dupreq->wb_index = req->wb_index; | ||
| 1173 | } else | ||
| 1174 | dupreq = req; | ||
| 1175 | |||
| 1176 | if (nfs_pgio_has_mirroring(desc)) | ||
| 1177 | desc->pg_mirror_idx = midx; | ||
| 1178 | if (!nfs_pageio_add_request_mirror(desc, dupreq)) | ||
| 1179 | return 0; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | return 1; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | /* | ||
| 1186 | * nfs_pageio_complete_mirror - Complete I/O on the current mirror of an | ||
| 1187 | * nfs_pageio_descriptor | ||
| 1188 | * @desc: pointer to io descriptor | ||
| 1189 | */ | ||
| 1190 | static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc, | ||
| 1191 | u32 mirror_idx) | ||
| 1192 | { | ||
| 1193 | struct nfs_pgio_mirror *mirror = &desc->pg_mirrors[mirror_idx]; | ||
| 1194 | u32 restore_idx = desc->pg_mirror_idx; | ||
| 1195 | |||
| 1196 | if (nfs_pgio_has_mirroring(desc)) | ||
| 1197 | desc->pg_mirror_idx = mirror_idx; | ||
| 1198 | for (;;) { | ||
| 1199 | nfs_pageio_doio(desc); | ||
| 1200 | if (!mirror->pg_recoalesce) | ||
| 1201 | break; | ||
| 1202 | if (!nfs_do_recoalesce(desc)) | ||
| 1203 | break; | ||
| 1204 | } | ||
| 1205 | desc->pg_mirror_idx = restore_idx; | ||
| 1206 | } | ||
| 1207 | |||
| 1016 | /* | 1208 | /* |
| 1017 | * nfs_pageio_resend - Transfer requests to new descriptor and resend | 1209 | * nfs_pageio_resend - Transfer requests to new descriptor and resend |
| 1018 | * @hdr - the pgio header to move request from | 1210 | * @hdr - the pgio header to move request from |
| @@ -1046,18 +1238,19 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc, | |||
| 1046 | EXPORT_SYMBOL_GPL(nfs_pageio_resend); | 1238 | EXPORT_SYMBOL_GPL(nfs_pageio_resend); |
| 1047 | 1239 | ||
| 1048 | /** | 1240 | /** |
| 1049 | * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor | 1241 | * nfs_pageio_complete - Complete I/O then cleanup an nfs_pageio_descriptor |
| 1050 | * @desc: pointer to io descriptor | 1242 | * @desc: pointer to io descriptor |
| 1051 | */ | 1243 | */ |
| 1052 | void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | 1244 | void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) |
| 1053 | { | 1245 | { |
| 1054 | for (;;) { | 1246 | u32 midx; |
| 1055 | nfs_pageio_doio(desc); | 1247 | |
| 1056 | if (!desc->pg_recoalesce) | 1248 | for (midx = 0; midx < desc->pg_mirror_count; midx++) |
| 1057 | break; | 1249 | nfs_pageio_complete_mirror(desc, midx); |
| 1058 | if (!nfs_do_recoalesce(desc)) | 1250 | |
| 1059 | break; | 1251 | if (desc->pg_ops->pg_cleanup) |
| 1060 | } | 1252 | desc->pg_ops->pg_cleanup(desc); |
| 1253 | nfs_pageio_cleanup_mirroring(desc); | ||
| 1061 | } | 1254 | } |
| 1062 | 1255 | ||
| 1063 | /** | 1256 | /** |
| @@ -1073,10 +1266,17 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | |||
| 1073 | */ | 1266 | */ |
| 1074 | void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) | 1267 | void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) |
| 1075 | { | 1268 | { |
| 1076 | if (!list_empty(&desc->pg_list)) { | 1269 | struct nfs_pgio_mirror *mirror; |
| 1077 | struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); | 1270 | struct nfs_page *prev; |
| 1078 | if (index != prev->wb_index + 1) | 1271 | u32 midx; |
| 1079 | nfs_pageio_complete(desc); | 1272 | |
| 1273 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
| 1274 | mirror = &desc->pg_mirrors[midx]; | ||
| 1275 | if (!list_empty(&mirror->pg_list)) { | ||
| 1276 | prev = nfs_list_entry(mirror->pg_list.prev); | ||
| 1277 | if (index != prev->wb_index + 1) | ||
| 1278 | nfs_pageio_complete_mirror(desc, midx); | ||
| 1279 | } | ||
| 1080 | } | 1280 | } |
| 1081 | } | 1281 | } |
| 1082 | 1282 | ||
