diff options
Diffstat (limited to 'fs/nfs/nfs4filelayout.c')
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 271 |
1 files changed, 214 insertions, 57 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 71ec08617e2..5acfd9ea8a3 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -33,7 +33,10 @@ | |||
33 | #include <linux/nfs_page.h> | 33 | #include <linux/nfs_page.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | 35 | ||
36 | #include <linux/sunrpc/metrics.h> | ||
37 | |||
36 | #include "internal.h" | 38 | #include "internal.h" |
39 | #include "delegation.h" | ||
37 | #include "nfs4filelayout.h" | 40 | #include "nfs4filelayout.h" |
38 | 41 | ||
39 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 42 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
@@ -84,12 +87,27 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
84 | struct nfs_client *clp, | 87 | struct nfs_client *clp, |
85 | int *reset) | 88 | int *reset) |
86 | { | 89 | { |
90 | struct nfs_server *mds_server = NFS_SERVER(state->inode); | ||
91 | struct nfs_client *mds_client = mds_server->nfs_client; | ||
92 | |||
87 | if (task->tk_status >= 0) | 93 | if (task->tk_status >= 0) |
88 | return 0; | 94 | return 0; |
89 | |||
90 | *reset = 0; | 95 | *reset = 0; |
91 | 96 | ||
92 | switch (task->tk_status) { | 97 | switch (task->tk_status) { |
98 | /* MDS state errors */ | ||
99 | case -NFS4ERR_DELEG_REVOKED: | ||
100 | case -NFS4ERR_ADMIN_REVOKED: | ||
101 | case -NFS4ERR_BAD_STATEID: | ||
102 | nfs_remove_bad_delegation(state->inode); | ||
103 | case -NFS4ERR_OPENMODE: | ||
104 | nfs4_schedule_stateid_recovery(mds_server, state); | ||
105 | goto wait_on_recovery; | ||
106 | case -NFS4ERR_EXPIRED: | ||
107 | nfs4_schedule_stateid_recovery(mds_server, state); | ||
108 | nfs4_schedule_lease_recovery(mds_client); | ||
109 | goto wait_on_recovery; | ||
110 | /* DS session errors */ | ||
93 | case -NFS4ERR_BADSESSION: | 111 | case -NFS4ERR_BADSESSION: |
94 | case -NFS4ERR_BADSLOT: | 112 | case -NFS4ERR_BADSLOT: |
95 | case -NFS4ERR_BAD_HIGH_SLOT: | 113 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -115,8 +133,14 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
115 | *reset = 1; | 133 | *reset = 1; |
116 | break; | 134 | break; |
117 | } | 135 | } |
136 | out: | ||
118 | task->tk_status = 0; | 137 | task->tk_status = 0; |
119 | return -EAGAIN; | 138 | return -EAGAIN; |
139 | wait_on_recovery: | ||
140 | rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); | ||
141 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) | ||
142 | rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task); | ||
143 | goto out; | ||
120 | } | 144 | } |
121 | 145 | ||
122 | /* NFS_PROTO call done callback routines */ | 146 | /* NFS_PROTO call done callback routines */ |
@@ -173,7 +197,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) | |||
173 | 197 | ||
174 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, | 198 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, |
175 | &rdata->args.seq_args, &rdata->res.seq_res, | 199 | &rdata->args.seq_args, &rdata->res.seq_res, |
176 | 0, task)) | 200 | task)) |
177 | return; | 201 | return; |
178 | 202 | ||
179 | rpc_call_start(task); | 203 | rpc_call_start(task); |
@@ -189,10 +213,18 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) | |||
189 | rdata->mds_ops->rpc_call_done(task, data); | 213 | rdata->mds_ops->rpc_call_done(task, data); |
190 | } | 214 | } |
191 | 215 | ||
216 | static void filelayout_read_count_stats(struct rpc_task *task, void *data) | ||
217 | { | ||
218 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | ||
219 | |||
220 | rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics); | ||
221 | } | ||
222 | |||
192 | static void filelayout_read_release(void *data) | 223 | static void filelayout_read_release(void *data) |
193 | { | 224 | { |
194 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | 225 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; |
195 | 226 | ||
227 | put_lseg(rdata->lseg); | ||
196 | rdata->mds_ops->rpc_release(data); | 228 | rdata->mds_ops->rpc_release(data); |
197 | } | 229 | } |
198 | 230 | ||
@@ -254,7 +286,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) | |||
254 | 286 | ||
255 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, | 287 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, |
256 | &wdata->args.seq_args, &wdata->res.seq_res, | 288 | &wdata->args.seq_args, &wdata->res.seq_res, |
257 | 0, task)) | 289 | task)) |
258 | return; | 290 | return; |
259 | 291 | ||
260 | rpc_call_start(task); | 292 | rpc_call_start(task); |
@@ -268,10 +300,18 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data) | |||
268 | wdata->mds_ops->rpc_call_done(task, data); | 300 | wdata->mds_ops->rpc_call_done(task, data); |
269 | } | 301 | } |
270 | 302 | ||
303 | static void filelayout_write_count_stats(struct rpc_task *task, void *data) | ||
304 | { | ||
305 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
306 | |||
307 | rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics); | ||
308 | } | ||
309 | |||
271 | static void filelayout_write_release(void *data) | 310 | static void filelayout_write_release(void *data) |
272 | { | 311 | { |
273 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | 312 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; |
274 | 313 | ||
314 | put_lseg(wdata->lseg); | ||
275 | wdata->mds_ops->rpc_release(data); | 315 | wdata->mds_ops->rpc_release(data); |
276 | } | 316 | } |
277 | 317 | ||
@@ -282,24 +322,28 @@ static void filelayout_commit_release(void *data) | |||
282 | nfs_commit_release_pages(wdata); | 322 | nfs_commit_release_pages(wdata); |
283 | if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) | 323 | if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) |
284 | nfs_commit_clear_lock(NFS_I(wdata->inode)); | 324 | nfs_commit_clear_lock(NFS_I(wdata->inode)); |
325 | put_lseg(wdata->lseg); | ||
285 | nfs_commitdata_release(wdata); | 326 | nfs_commitdata_release(wdata); |
286 | } | 327 | } |
287 | 328 | ||
288 | struct rpc_call_ops filelayout_read_call_ops = { | 329 | static const struct rpc_call_ops filelayout_read_call_ops = { |
289 | .rpc_call_prepare = filelayout_read_prepare, | 330 | .rpc_call_prepare = filelayout_read_prepare, |
290 | .rpc_call_done = filelayout_read_call_done, | 331 | .rpc_call_done = filelayout_read_call_done, |
332 | .rpc_count_stats = filelayout_read_count_stats, | ||
291 | .rpc_release = filelayout_read_release, | 333 | .rpc_release = filelayout_read_release, |
292 | }; | 334 | }; |
293 | 335 | ||
294 | struct rpc_call_ops filelayout_write_call_ops = { | 336 | static const struct rpc_call_ops filelayout_write_call_ops = { |
295 | .rpc_call_prepare = filelayout_write_prepare, | 337 | .rpc_call_prepare = filelayout_write_prepare, |
296 | .rpc_call_done = filelayout_write_call_done, | 338 | .rpc_call_done = filelayout_write_call_done, |
339 | .rpc_count_stats = filelayout_write_count_stats, | ||
297 | .rpc_release = filelayout_write_release, | 340 | .rpc_release = filelayout_write_release, |
298 | }; | 341 | }; |
299 | 342 | ||
300 | struct rpc_call_ops filelayout_commit_call_ops = { | 343 | static const struct rpc_call_ops filelayout_commit_call_ops = { |
301 | .rpc_call_prepare = filelayout_write_prepare, | 344 | .rpc_call_prepare = filelayout_write_prepare, |
302 | .rpc_call_done = filelayout_write_call_done, | 345 | .rpc_call_done = filelayout_write_call_done, |
346 | .rpc_count_stats = filelayout_write_count_stats, | ||
303 | .rpc_release = filelayout_commit_release, | 347 | .rpc_release = filelayout_commit_release, |
304 | }; | 348 | }; |
305 | 349 | ||
@@ -367,7 +411,8 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
367 | idx = nfs4_fl_calc_ds_index(lseg, j); | 411 | idx = nfs4_fl_calc_ds_index(lseg, j); |
368 | ds = nfs4_fl_prepare_ds(lseg, idx); | 412 | ds = nfs4_fl_prepare_ds(lseg, idx); |
369 | if (!ds) { | 413 | if (!ds) { |
370 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | 414 | printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n", |
415 | __func__); | ||
371 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | 416 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); |
372 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | 417 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); |
373 | return PNFS_NOT_ATTEMPTED; | 418 | return PNFS_NOT_ATTEMPTED; |
@@ -575,7 +620,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, | |||
575 | goto out_err_free; | 620 | goto out_err_free; |
576 | fl->fh_array[i]->size = be32_to_cpup(p++); | 621 | fl->fh_array[i]->size = be32_to_cpup(p++); |
577 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { | 622 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { |
578 | printk(KERN_ERR "Too big fh %d received %d\n", | 623 | printk(KERN_ERR "NFS: Too big fh %d received %d\n", |
579 | i, fl->fh_array[i]->size); | 624 | i, fl->fh_array[i]->size); |
580 | goto out_err_free; | 625 | goto out_err_free; |
581 | } | 626 | } |
@@ -640,14 +685,16 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | |||
640 | int size = (fl->stripe_type == STRIPE_SPARSE) ? | 685 | int size = (fl->stripe_type == STRIPE_SPARSE) ? |
641 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; | 686 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; |
642 | 687 | ||
643 | fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags); | 688 | fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags); |
644 | if (!fl->commit_buckets) { | 689 | if (!fl->commit_buckets) { |
645 | filelayout_free_lseg(&fl->generic_hdr); | 690 | filelayout_free_lseg(&fl->generic_hdr); |
646 | return NULL; | 691 | return NULL; |
647 | } | 692 | } |
648 | fl->number_of_buckets = size; | 693 | fl->number_of_buckets = size; |
649 | for (i = 0; i < size; i++) | 694 | for (i = 0; i < size; i++) { |
650 | INIT_LIST_HEAD(&fl->commit_buckets[i]); | 695 | INIT_LIST_HEAD(&fl->commit_buckets[i].written); |
696 | INIT_LIST_HEAD(&fl->commit_buckets[i].committing); | ||
697 | } | ||
651 | } | 698 | } |
652 | return &fl->generic_hdr; | 699 | return &fl->generic_hdr; |
653 | } | 700 | } |
@@ -679,7 +726,7 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
679 | return (p_stripe == r_stripe); | 726 | return (p_stripe == r_stripe); |
680 | } | 727 | } |
681 | 728 | ||
682 | void | 729 | static void |
683 | filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, | 730 | filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, |
684 | struct nfs_page *req) | 731 | struct nfs_page *req) |
685 | { | 732 | { |
@@ -696,7 +743,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
696 | nfs_pageio_reset_read_mds(pgio); | 743 | nfs_pageio_reset_read_mds(pgio); |
697 | } | 744 | } |
698 | 745 | ||
699 | void | 746 | static void |
700 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, | 747 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, |
701 | struct nfs_page *req) | 748 | struct nfs_page *req) |
702 | { | 749 | { |
@@ -725,11 +772,6 @@ static const struct nfs_pageio_ops filelayout_pg_write_ops = { | |||
725 | .pg_doio = pnfs_generic_pg_writepages, | 772 | .pg_doio = pnfs_generic_pg_writepages, |
726 | }; | 773 | }; |
727 | 774 | ||
728 | static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg) | ||
729 | { | ||
730 | return !FILELAYOUT_LSEG(lseg)->commit_through_mds; | ||
731 | } | ||
732 | |||
733 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | 775 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) |
734 | { | 776 | { |
735 | if (fl->stripe_type == STRIPE_SPARSE) | 777 | if (fl->stripe_type == STRIPE_SPARSE) |
@@ -738,13 +780,48 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | |||
738 | return j; | 780 | return j; |
739 | } | 781 | } |
740 | 782 | ||
741 | struct list_head *filelayout_choose_commit_list(struct nfs_page *req) | 783 | /* The generic layer is about to remove the req from the commit list. |
784 | * If this will make the bucket empty, it will need to put the lseg reference. | ||
785 | */ | ||
786 | static void | ||
787 | filelayout_clear_request_commit(struct nfs_page *req) | ||
788 | { | ||
789 | struct pnfs_layout_segment *freeme = NULL; | ||
790 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
791 | |||
792 | spin_lock(&inode->i_lock); | ||
793 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) | ||
794 | goto out; | ||
795 | if (list_is_singular(&req->wb_list)) { | ||
796 | struct pnfs_layout_segment *lseg; | ||
797 | |||
798 | /* From here we can find the bucket, but for the moment, | ||
799 | * since there is only one relevant lseg... | ||
800 | */ | ||
801 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { | ||
802 | if (lseg->pls_range.iomode == IOMODE_RW) { | ||
803 | freeme = lseg; | ||
804 | break; | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | out: | ||
809 | nfs_request_remove_commit_list(req); | ||
810 | spin_unlock(&inode->i_lock); | ||
811 | put_lseg(freeme); | ||
812 | } | ||
813 | |||
814 | static struct list_head * | ||
815 | filelayout_choose_commit_list(struct nfs_page *req, | ||
816 | struct pnfs_layout_segment *lseg) | ||
742 | { | 817 | { |
743 | struct pnfs_layout_segment *lseg = req->wb_commit_lseg; | ||
744 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 818 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
745 | u32 i, j; | 819 | u32 i, j; |
746 | struct list_head *list; | 820 | struct list_head *list; |
747 | 821 | ||
822 | if (fl->commit_through_mds) | ||
823 | return &NFS_I(req->wb_context->dentry->d_inode)->commit_list; | ||
824 | |||
748 | /* Note that we are calling nfs4_fl_calc_j_index on each page | 825 | /* Note that we are calling nfs4_fl_calc_j_index on each page |
749 | * that ends up being committed to a data server. An attractive | 826 | * that ends up being committed to a data server. An attractive |
750 | * alternative is to add a field to nfs_write_data and nfs_page | 827 | * alternative is to add a field to nfs_write_data and nfs_page |
@@ -754,14 +831,30 @@ struct list_head *filelayout_choose_commit_list(struct nfs_page *req) | |||
754 | j = nfs4_fl_calc_j_index(lseg, | 831 | j = nfs4_fl_calc_j_index(lseg, |
755 | (loff_t)req->wb_index << PAGE_CACHE_SHIFT); | 832 | (loff_t)req->wb_index << PAGE_CACHE_SHIFT); |
756 | i = select_bucket_index(fl, j); | 833 | i = select_bucket_index(fl, j); |
757 | list = &fl->commit_buckets[i]; | 834 | list = &fl->commit_buckets[i].written; |
758 | if (list_empty(list)) { | 835 | if (list_empty(list)) { |
759 | /* Non-empty buckets hold a reference on the lseg */ | 836 | /* Non-empty buckets hold a reference on the lseg. That ref |
837 | * is normally transferred to the COMMIT call and released | ||
838 | * there. It could also be released if the last req is pulled | ||
839 | * off due to a rewrite, in which case it will be done in | ||
840 | * filelayout_remove_commit_req | ||
841 | */ | ||
760 | get_lseg(lseg); | 842 | get_lseg(lseg); |
761 | } | 843 | } |
844 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
762 | return list; | 845 | return list; |
763 | } | 846 | } |
764 | 847 | ||
848 | static void | ||
849 | filelayout_mark_request_commit(struct nfs_page *req, | ||
850 | struct pnfs_layout_segment *lseg) | ||
851 | { | ||
852 | struct list_head *list; | ||
853 | |||
854 | list = filelayout_choose_commit_list(req, lseg); | ||
855 | nfs_request_add_commit_list(req, list); | ||
856 | } | ||
857 | |||
765 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 858 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) |
766 | { | 859 | { |
767 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); | 860 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); |
@@ -797,11 +890,12 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how) | |||
797 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); | 890 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); |
798 | ds = nfs4_fl_prepare_ds(lseg, idx); | 891 | ds = nfs4_fl_prepare_ds(lseg, idx); |
799 | if (!ds) { | 892 | if (!ds) { |
800 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | 893 | printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n", |
894 | __func__); | ||
801 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | 895 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); |
802 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | 896 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); |
803 | prepare_to_resend_writes(data); | 897 | prepare_to_resend_writes(data); |
804 | data->mds_ops->rpc_release(data); | 898 | filelayout_commit_release(data); |
805 | return -EAGAIN; | 899 | return -EAGAIN; |
806 | } | 900 | } |
807 | dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); | 901 | dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); |
@@ -817,24 +911,87 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how) | |||
817 | /* | 911 | /* |
818 | * This is only useful while we are using whole file layouts. | 912 | * This is only useful while we are using whole file layouts. |
819 | */ | 913 | */ |
820 | static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | 914 | static struct pnfs_layout_segment * |
915 | find_only_write_lseg_locked(struct inode *inode) | ||
821 | { | 916 | { |
822 | struct pnfs_layout_segment *lseg, *rv = NULL; | 917 | struct pnfs_layout_segment *lseg; |
823 | 918 | ||
824 | spin_lock(&inode->i_lock); | ||
825 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) | 919 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) |
826 | if (lseg->pls_range.iomode == IOMODE_RW) | 920 | if (lseg->pls_range.iomode == IOMODE_RW) |
827 | rv = get_lseg(lseg); | 921 | return lseg; |
922 | return NULL; | ||
923 | } | ||
924 | |||
925 | static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | ||
926 | { | ||
927 | struct pnfs_layout_segment *rv; | ||
928 | |||
929 | spin_lock(&inode->i_lock); | ||
930 | rv = find_only_write_lseg_locked(inode); | ||
931 | if (rv) | ||
932 | get_lseg(rv); | ||
828 | spin_unlock(&inode->i_lock); | 933 | spin_unlock(&inode->i_lock); |
829 | return rv; | 934 | return rv; |
830 | } | 935 | } |
831 | 936 | ||
832 | static int alloc_ds_commits(struct inode *inode, struct list_head *list) | 937 | static int |
938 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | ||
939 | spinlock_t *lock) | ||
940 | { | ||
941 | struct list_head *src = &bucket->written; | ||
942 | struct list_head *dst = &bucket->committing; | ||
943 | struct nfs_page *req, *tmp; | ||
944 | int ret = 0; | ||
945 | |||
946 | list_for_each_entry_safe(req, tmp, src, wb_list) { | ||
947 | if (!nfs_lock_request(req)) | ||
948 | continue; | ||
949 | if (cond_resched_lock(lock)) | ||
950 | list_safe_reset_next(req, tmp, wb_list); | ||
951 | nfs_request_remove_commit_list(req); | ||
952 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
953 | nfs_list_add_request(req, dst); | ||
954 | ret++; | ||
955 | if (ret == max) | ||
956 | break; | ||
957 | } | ||
958 | return ret; | ||
959 | } | ||
960 | |||
961 | /* Move reqs from written to committing lists, returning count of number moved. | ||
962 | * Note called with i_lock held. | ||
963 | */ | ||
964 | static int filelayout_scan_commit_lists(struct inode *inode, int max, | ||
965 | spinlock_t *lock) | ||
966 | { | ||
967 | struct pnfs_layout_segment *lseg; | ||
968 | struct nfs4_filelayout_segment *fl; | ||
969 | int i, rv = 0, cnt; | ||
970 | |||
971 | lseg = find_only_write_lseg_locked(inode); | ||
972 | if (!lseg) | ||
973 | goto out_done; | ||
974 | fl = FILELAYOUT_LSEG(lseg); | ||
975 | if (fl->commit_through_mds) | ||
976 | goto out_done; | ||
977 | for (i = 0; i < fl->number_of_buckets && max != 0; i++) { | ||
978 | cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], | ||
979 | max, lock); | ||
980 | max -= cnt; | ||
981 | rv += cnt; | ||
982 | } | ||
983 | out_done: | ||
984 | return rv; | ||
985 | } | ||
986 | |||
987 | static unsigned int | ||
988 | alloc_ds_commits(struct inode *inode, struct list_head *list) | ||
833 | { | 989 | { |
834 | struct pnfs_layout_segment *lseg; | 990 | struct pnfs_layout_segment *lseg; |
835 | struct nfs4_filelayout_segment *fl; | 991 | struct nfs4_filelayout_segment *fl; |
836 | struct nfs_write_data *data; | 992 | struct nfs_write_data *data; |
837 | int i, j; | 993 | int i, j; |
994 | unsigned int nreq = 0; | ||
838 | 995 | ||
839 | /* Won't need this when non-whole file layout segments are supported | 996 | /* Won't need this when non-whole file layout segments are supported |
840 | * instead we will use a pnfs_layout_hdr structure */ | 997 | * instead we will use a pnfs_layout_hdr structure */ |
@@ -843,28 +1000,27 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list) | |||
843 | return 0; | 1000 | return 0; |
844 | fl = FILELAYOUT_LSEG(lseg); | 1001 | fl = FILELAYOUT_LSEG(lseg); |
845 | for (i = 0; i < fl->number_of_buckets; i++) { | 1002 | for (i = 0; i < fl->number_of_buckets; i++) { |
846 | if (list_empty(&fl->commit_buckets[i])) | 1003 | if (list_empty(&fl->commit_buckets[i].committing)) |
847 | continue; | 1004 | continue; |
848 | data = nfs_commitdata_alloc(); | 1005 | data = nfs_commitdata_alloc(); |
849 | if (!data) | 1006 | if (!data) |
850 | goto out_bad; | 1007 | break; |
851 | data->ds_commit_index = i; | 1008 | data->ds_commit_index = i; |
852 | data->lseg = lseg; | 1009 | data->lseg = lseg; |
853 | list_add(&data->pages, list); | 1010 | list_add(&data->pages, list); |
1011 | nreq++; | ||
854 | } | 1012 | } |
855 | put_lseg(lseg); | ||
856 | return 0; | ||
857 | 1013 | ||
858 | out_bad: | 1014 | /* Clean up on error */ |
859 | for (j = i; j < fl->number_of_buckets; j++) { | 1015 | for (j = i; j < fl->number_of_buckets; j++) { |
860 | if (list_empty(&fl->commit_buckets[i])) | 1016 | if (list_empty(&fl->commit_buckets[i].committing)) |
861 | continue; | 1017 | continue; |
862 | nfs_retry_commit(&fl->commit_buckets[i], lseg); | 1018 | nfs_retry_commit(&fl->commit_buckets[i].committing, lseg); |
863 | put_lseg(lseg); /* associated with emptying bucket */ | 1019 | put_lseg(lseg); /* associated with emptying bucket */ |
864 | } | 1020 | } |
865 | put_lseg(lseg); | 1021 | put_lseg(lseg); |
866 | /* Caller will clean up entries put on list */ | 1022 | /* Caller will clean up entries put on list */ |
867 | return -ENOMEM; | 1023 | return nreq; |
868 | } | 1024 | } |
869 | 1025 | ||
870 | /* This follows nfs_commit_list pretty closely */ | 1026 | /* This follows nfs_commit_list pretty closely */ |
@@ -874,40 +1030,40 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
874 | { | 1030 | { |
875 | struct nfs_write_data *data, *tmp; | 1031 | struct nfs_write_data *data, *tmp; |
876 | LIST_HEAD(list); | 1032 | LIST_HEAD(list); |
1033 | unsigned int nreq = 0; | ||
877 | 1034 | ||
878 | if (!list_empty(mds_pages)) { | 1035 | if (!list_empty(mds_pages)) { |
879 | data = nfs_commitdata_alloc(); | 1036 | data = nfs_commitdata_alloc(); |
880 | if (!data) | 1037 | if (data != NULL) { |
881 | goto out_bad; | 1038 | data->lseg = NULL; |
882 | data->lseg = NULL; | 1039 | list_add(&data->pages, &list); |
883 | list_add(&data->pages, &list); | 1040 | nreq++; |
1041 | } else | ||
1042 | nfs_retry_commit(mds_pages, NULL); | ||
884 | } | 1043 | } |
885 | 1044 | ||
886 | if (alloc_ds_commits(inode, &list)) | 1045 | nreq += alloc_ds_commits(inode, &list); |
887 | goto out_bad; | 1046 | |
1047 | if (nreq == 0) { | ||
1048 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1049 | goto out; | ||
1050 | } | ||
1051 | |||
1052 | atomic_add(nreq, &NFS_I(inode)->commits_outstanding); | ||
888 | 1053 | ||
889 | list_for_each_entry_safe(data, tmp, &list, pages) { | 1054 | list_for_each_entry_safe(data, tmp, &list, pages) { |
890 | list_del_init(&data->pages); | 1055 | list_del_init(&data->pages); |
891 | atomic_inc(&NFS_I(inode)->commits_outstanding); | ||
892 | if (!data->lseg) { | 1056 | if (!data->lseg) { |
893 | nfs_init_commit(data, mds_pages, NULL); | 1057 | nfs_init_commit(data, mds_pages, NULL); |
894 | nfs_initiate_commit(data, NFS_CLIENT(inode), | 1058 | nfs_initiate_commit(data, NFS_CLIENT(inode), |
895 | data->mds_ops, how); | 1059 | data->mds_ops, how); |
896 | } else { | 1060 | } else { |
897 | nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg); | 1061 | nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg); |
898 | filelayout_initiate_commit(data, how); | 1062 | filelayout_initiate_commit(data, how); |
899 | } | 1063 | } |
900 | } | 1064 | } |
901 | return 0; | 1065 | out: |
902 | out_bad: | 1066 | return PNFS_ATTEMPTED; |
903 | list_for_each_entry_safe(data, tmp, &list, pages) { | ||
904 | nfs_retry_commit(&data->pages, data->lseg); | ||
905 | list_del_init(&data->pages); | ||
906 | nfs_commit_free(data); | ||
907 | } | ||
908 | nfs_retry_commit(mds_pages, NULL); | ||
909 | nfs_commit_clear_lock(NFS_I(inode)); | ||
910 | return -ENOMEM; | ||
911 | } | 1067 | } |
912 | 1068 | ||
913 | static void | 1069 | static void |
@@ -924,8 +1080,9 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
924 | .free_lseg = filelayout_free_lseg, | 1080 | .free_lseg = filelayout_free_lseg, |
925 | .pg_read_ops = &filelayout_pg_read_ops, | 1081 | .pg_read_ops = &filelayout_pg_read_ops, |
926 | .pg_write_ops = &filelayout_pg_write_ops, | 1082 | .pg_write_ops = &filelayout_pg_write_ops, |
927 | .mark_pnfs_commit = filelayout_mark_pnfs_commit, | 1083 | .mark_request_commit = filelayout_mark_request_commit, |
928 | .choose_commit_list = filelayout_choose_commit_list, | 1084 | .clear_request_commit = filelayout_clear_request_commit, |
1085 | .scan_commit_lists = filelayout_scan_commit_lists, | ||
929 | .commit_pagelist = filelayout_commit_pagelist, | 1086 | .commit_pagelist = filelayout_commit_pagelist, |
930 | .read_pagelist = filelayout_read_pagelist, | 1087 | .read_pagelist = filelayout_read_pagelist, |
931 | .write_pagelist = filelayout_write_pagelist, | 1088 | .write_pagelist = filelayout_write_pagelist, |