aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@primarydata.com>2014-05-15 11:56:54 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-05-29 11:11:48 -0400
commit5002c58639d41b93e800c8a4b7eca49c40d57822 (patch)
treeb9d9981b3396f4f7a5f518f905d8a1199e087509 /fs/nfs/direct.c
parent7f714720fac03383d687dbe39494cc96b845bd46 (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>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c102
1 files changed, 97 insertions, 5 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 */
119static struct nfs_writeverf *
120nfs_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 */
146static 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 */
167static 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 */
190static 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;