diff options
author | Weston Andros Adamson <dros@primarydata.com> | 2014-05-15 11:56:54 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-05-29 11:11:48 -0400 |
commit | 5002c58639d41b93e800c8a4b7eca49c40d57822 (patch) | |
tree | b9d9981b3396f4f7a5f518f905d8a1199e087509 | |
parent | 7f714720fac03383d687dbe39494cc96b845bd46 (diff) |
pnfs: support multiple verfs per direct req
Support direct requests that span multiple pnfs data servers by
comparing nfs_pgio_header->verf to a cached verf in pnfs_commit_bucket.
Continue to use dreq->verf if the MDS is used / non-pNFS.
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/direct.c | 102 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 6 | ||||
-rw-r--r-- | include/linux/nfs.h | 5 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 2 |
4 files changed, 109 insertions, 6 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 2c0e08f4cf71..4ad7bc388679 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -108,6 +108,97 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
108 | return atomic_dec_and_test(&dreq->io_count); | 108 | return atomic_dec_and_test(&dreq->io_count); |
109 | } | 109 | } |
110 | 110 | ||
111 | /* | ||
112 | * nfs_direct_select_verf - select the right verifier | ||
113 | * @dreq - direct request possibly spanning multiple servers | ||
114 | * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs | ||
115 | * @ds_idx - index of data server in data server list, only valid if ds_clp set | ||
116 | * | ||
117 | * returns the correct verifier to use given the role of the server | ||
118 | */ | ||
119 | static struct nfs_writeverf * | ||
120 | nfs_direct_select_verf(struct nfs_direct_req *dreq, | ||
121 | struct nfs_client *ds_clp, | ||
122 | int ds_idx) | ||
123 | { | ||
124 | struct nfs_writeverf *verfp = &dreq->verf; | ||
125 | |||
126 | #ifdef CONFIG_NFS_V4_1 | ||
127 | if (ds_clp) { | ||
128 | /* pNFS is in use, use the DS verf */ | ||
129 | if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets) | ||
130 | verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf; | ||
131 | else | ||
132 | WARN_ON_ONCE(1); | ||
133 | } | ||
134 | #endif | ||
135 | return verfp; | ||
136 | } | ||
137 | |||
138 | |||
139 | /* | ||
140 | * nfs_direct_set_hdr_verf - set the write/commit verifier | ||
141 | * @dreq - direct request possibly spanning multiple servers | ||
142 | * @hdr - pageio header to validate against previously seen verfs | ||
143 | * | ||
144 | * Set the server's (MDS or DS) "seen" verifier | ||
145 | */ | ||
146 | static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, | ||
147 | struct nfs_pgio_header *hdr) | ||
148 | { | ||
149 | struct nfs_writeverf *verfp; | ||
150 | |||
151 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | ||
152 | hdr->data->ds_idx); | ||
153 | WARN_ON_ONCE(verfp->committed >= 0); | ||
154 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | ||
155 | WARN_ON_ONCE(verfp->committed < 0); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * nfs_direct_cmp_hdr_verf - compare verifier for pgio header | ||
160 | * @dreq - direct request possibly spanning multiple servers | ||
161 | * @hdr - pageio header to validate against previously seen verf | ||
162 | * | ||
163 | * set the server's "seen" verf if not initialized. | ||
164 | * returns result of comparison between @hdr->verf and the "seen" | ||
165 | * verf of the server used by @hdr (DS or MDS) | ||
166 | */ | ||
167 | static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, | ||
168 | struct nfs_pgio_header *hdr) | ||
169 | { | ||
170 | struct nfs_writeverf *verfp; | ||
171 | |||
172 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | ||
173 | hdr->data->ds_idx); | ||
174 | if (verfp->committed < 0) { | ||
175 | nfs_direct_set_hdr_verf(dreq, hdr); | ||
176 | return 0; | ||
177 | } | ||
178 | return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | ||
179 | } | ||
180 | |||
181 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | ||
182 | /* | ||
183 | * nfs_direct_cmp_commit_data_verf - compare verifier for commit data | ||
184 | * @dreq - direct request possibly spanning multiple servers | ||
185 | * @data - commit data to validate against previously seen verf | ||
186 | * | ||
187 | * returns result of comparison between @data->verf and the verf of | ||
188 | * the server used by @data (DS or MDS) | ||
189 | */ | ||
190 | static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, | ||
191 | struct nfs_commit_data *data) | ||
192 | { | ||
193 | struct nfs_writeverf *verfp; | ||
194 | |||
195 | verfp = nfs_direct_select_verf(dreq, data->ds_clp, | ||
196 | data->ds_commit_index); | ||
197 | WARN_ON_ONCE(verfp->committed < 0); | ||
198 | return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); | ||
199 | } | ||
200 | #endif | ||
201 | |||
111 | /** | 202 | /** |
112 | * nfs_direct_IO - NFS address space operation for direct I/O | 203 | * nfs_direct_IO - NFS address space operation for direct I/O |
113 | * @rw: direction (read or write) | 204 | * @rw: direction (read or write) |
@@ -168,6 +259,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
168 | kref_get(&dreq->kref); | 259 | kref_get(&dreq->kref); |
169 | init_completion(&dreq->completion); | 260 | init_completion(&dreq->completion); |
170 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); | 261 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); |
262 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ | ||
171 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); | 263 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); |
172 | spin_lock_init(&dreq->lock); | 264 | spin_lock_init(&dreq->lock); |
173 | 265 | ||
@@ -602,7 +694,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) | |||
602 | dprintk("NFS: %5u commit failed with error %d.\n", | 694 | dprintk("NFS: %5u commit failed with error %d.\n", |
603 | data->task.tk_pid, status); | 695 | data->task.tk_pid, status); |
604 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 696 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
605 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 697 | } else if (nfs_direct_cmp_commit_data_verf(dreq, data)) { |
606 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); | 698 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
607 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 699 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
608 | } | 700 | } |
@@ -811,13 +903,13 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
811 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) | 903 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) |
812 | bit = NFS_IOHDR_NEED_RESCHED; | 904 | bit = NFS_IOHDR_NEED_RESCHED; |
813 | else if (dreq->flags == 0) { | 905 | else if (dreq->flags == 0) { |
814 | memcpy(&dreq->verf, &hdr->verf, | 906 | nfs_direct_set_hdr_verf(dreq, hdr); |
815 | sizeof(dreq->verf)); | ||
816 | bit = NFS_IOHDR_NEED_COMMIT; | 907 | bit = NFS_IOHDR_NEED_COMMIT; |
817 | dreq->flags = NFS_ODIRECT_DO_COMMIT; | 908 | dreq->flags = NFS_ODIRECT_DO_COMMIT; |
818 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { | 909 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { |
819 | if (memcmp(&dreq->verf, &hdr->verf, sizeof(dreq->verf))) { | 910 | if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) { |
820 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 911 | dreq->flags = |
912 | NFS_ODIRECT_RESCHED_WRITES; | ||
821 | bit = NFS_IOHDR_NEED_RESCHED; | 913 | bit = NFS_IOHDR_NEED_RESCHED; |
822 | } else | 914 | } else |
823 | bit = NFS_IOHDR_NEED_COMMIT; | 915 | bit = NFS_IOHDR_NEED_COMMIT; |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 7a665e0f35b7..0ebc521ea6fc 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -560,6 +560,7 @@ filelayout_read_pagelist(struct nfs_pgio_data *data) | |||
560 | /* No multipath support. Use first DS */ | 560 | /* No multipath support. Use first DS */ |
561 | atomic_inc(&ds->ds_clp->cl_count); | 561 | atomic_inc(&ds->ds_clp->cl_count); |
562 | data->ds_clp = ds->ds_clp; | 562 | data->ds_clp = ds->ds_clp; |
563 | data->ds_idx = idx; | ||
563 | fh = nfs4_fl_select_ds_fh(lseg, j); | 564 | fh = nfs4_fl_select_ds_fh(lseg, j); |
564 | if (fh) | 565 | if (fh) |
565 | data->args.fh = fh; | 566 | data->args.fh = fh; |
@@ -603,6 +604,7 @@ filelayout_write_pagelist(struct nfs_pgio_data *data, int sync) | |||
603 | data->pgio_done_cb = filelayout_write_done_cb; | 604 | data->pgio_done_cb = filelayout_write_done_cb; |
604 | atomic_inc(&ds->ds_clp->cl_count); | 605 | atomic_inc(&ds->ds_clp->cl_count); |
605 | data->ds_clp = ds->ds_clp; | 606 | data->ds_clp = ds->ds_clp; |
607 | data->ds_idx = idx; | ||
606 | fh = nfs4_fl_select_ds_fh(lseg, j); | 608 | fh = nfs4_fl_select_ds_fh(lseg, j); |
607 | if (fh) | 609 | if (fh) |
608 | data->args.fh = fh; | 610 | data->args.fh = fh; |
@@ -875,6 +877,8 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, | |||
875 | for (i = 0; i < size; i++) { | 877 | for (i = 0; i < size; i++) { |
876 | INIT_LIST_HEAD(&buckets[i].written); | 878 | INIT_LIST_HEAD(&buckets[i].written); |
877 | INIT_LIST_HEAD(&buckets[i].committing); | 879 | INIT_LIST_HEAD(&buckets[i].committing); |
880 | /* mark direct verifier as unset */ | ||
881 | buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW; | ||
878 | } | 882 | } |
879 | 883 | ||
880 | spin_lock(cinfo->lock); | 884 | spin_lock(cinfo->lock); |
@@ -885,6 +889,8 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, | |||
885 | &buckets[i].written); | 889 | &buckets[i].written); |
886 | list_splice(&cinfo->ds->buckets[i].committing, | 890 | list_splice(&cinfo->ds->buckets[i].committing, |
887 | &buckets[i].committing); | 891 | &buckets[i].committing); |
892 | buckets[i].direct_verf.committed = | ||
893 | cinfo->ds->buckets[i].direct_verf.committed; | ||
888 | buckets[i].wlseg = cinfo->ds->buckets[i].wlseg; | 894 | buckets[i].wlseg = cinfo->ds->buckets[i].wlseg; |
889 | buckets[i].clseg = cinfo->ds->buckets[i].clseg; | 895 | buckets[i].clseg = cinfo->ds->buckets[i].clseg; |
890 | } | 896 | } |
diff --git a/include/linux/nfs.h b/include/linux/nfs.h index 3e794c12e90a..610af5155ef2 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h | |||
@@ -46,6 +46,9 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc | |||
46 | enum nfs3_stable_how { | 46 | enum nfs3_stable_how { |
47 | NFS_UNSTABLE = 0, | 47 | NFS_UNSTABLE = 0, |
48 | NFS_DATA_SYNC = 1, | 48 | NFS_DATA_SYNC = 1, |
49 | NFS_FILE_SYNC = 2 | 49 | NFS_FILE_SYNC = 2, |
50 | |||
51 | /* used by direct.c to mark verf as invalid */ | ||
52 | NFS_INVALID_STABLE_HOW = -1 | ||
50 | }; | 53 | }; |
51 | #endif /* _LINUX_NFS_H */ | 54 | #endif /* _LINUX_NFS_H */ |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ae636013fb1f..9a1396e70310 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1112,6 +1112,7 @@ struct pnfs_commit_bucket { | |||
1112 | struct list_head committing; | 1112 | struct list_head committing; |
1113 | struct pnfs_layout_segment *wlseg; | 1113 | struct pnfs_layout_segment *wlseg; |
1114 | struct pnfs_layout_segment *clseg; | 1114 | struct pnfs_layout_segment *clseg; |
1115 | struct nfs_writeverf direct_verf; | ||
1115 | }; | 1116 | }; |
1116 | 1117 | ||
1117 | struct pnfs_ds_commit_info { | 1118 | struct pnfs_ds_commit_info { |
@@ -1294,6 +1295,7 @@ struct nfs_pgio_data { | |||
1294 | __u64 mds_offset; /* Filelayout dense stripe */ | 1295 | __u64 mds_offset; /* Filelayout dense stripe */ |
1295 | struct nfs_page_array pages; | 1296 | struct nfs_page_array pages; |
1296 | struct nfs_client *ds_clp; /* pNFS data server */ | 1297 | struct nfs_client *ds_clp; /* pNFS data server */ |
1298 | int ds_idx; /* ds index if ds_clp is set */ | ||
1297 | }; | 1299 | }; |
1298 | 1300 | ||
1299 | struct nfs_rw_header { | 1301 | struct nfs_rw_header { |