1b5968725STom Haynes /*
2b5968725STom Haynes * Module for the pnfs nfs4 file layout driver.
3b5968725STom Haynes * Defines all I/O and Policy interface operations, plus code
4b5968725STom Haynes * to register itself with the pNFS client.
5b5968725STom Haynes *
6b5968725STom Haynes * Copyright (c) 2002
7b5968725STom Haynes * The Regents of the University of Michigan
8b5968725STom Haynes * All Rights Reserved
9b5968725STom Haynes *
10b5968725STom Haynes * Dean Hildebrand <dhildebz@umich.edu>
11b5968725STom Haynes *
12b5968725STom Haynes * Permission is granted to use, copy, create derivative works, and
13b5968725STom Haynes * redistribute this software and such derivative works for any purpose,
14b5968725STom Haynes * so long as the name of the University of Michigan is not used in
15b5968725STom Haynes * any advertising or publicity pertaining to the use or distribution
16b5968725STom Haynes * of this software without specific, written prior authorization. If
17b5968725STom Haynes * the above copyright notice or any other identification of the
18b5968725STom Haynes * University of Michigan is included in any copy of any portion of
19b5968725STom Haynes * this software, then the disclaimer below must also be included.
20b5968725STom Haynes *
21b5968725STom Haynes * This software is provided as is, without representation or warranty
22b5968725STom Haynes * of any kind either express or implied, including without limitation
23b5968725STom Haynes * the implied warranties of merchantability, fitness for a particular
24b5968725STom Haynes * purpose, or noninfringement. The Regents of the University of
25b5968725STom Haynes * Michigan shall not be liable for any damages, including special,
26b5968725STom Haynes * indirect, incidental, or consequential damages, with respect to any
27b5968725STom Haynes * claim arising out of or in connection with the use of the software,
28b5968725STom Haynes * even if it has been or is hereafter advised of the possibility of
29b5968725STom Haynes * such damages.
30b5968725STom Haynes */
31b5968725STom Haynes
32b5968725STom Haynes #include <linux/nfs_fs.h>
33b5968725STom Haynes #include <linux/nfs_page.h>
34b5968725STom Haynes #include <linux/module.h>
3566114cadSTejun Heo #include <linux/backing-dev.h>
36b5968725STom Haynes
37b5968725STom Haynes #include <linux/sunrpc/metrics.h>
38b5968725STom Haynes
39b5968725STom Haynes #include "../nfs4session.h"
40b5968725STom Haynes #include "../internal.h"
41b5968725STom Haynes #include "../delegation.h"
42b5968725STom Haynes #include "filelayout.h"
43b5968725STom Haynes #include "../nfs4trace.h"
44b5968725STom Haynes
45b5968725STom Haynes #define NFSDBG_FACILITY NFSDBG_PNFS_LD
46b5968725STom Haynes
47b5968725STom Haynes MODULE_LICENSE("GPL");
48b5968725STom Haynes MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
49b5968725STom Haynes MODULE_DESCRIPTION("The NFSv4 file layout driver");
50b5968725STom Haynes
51b5968725STom Haynes #define FILELAYOUT_POLL_RETRY_MAX (15*HZ)
529c455a8cSTrond Myklebust static const struct pnfs_commit_ops filelayout_commit_ops;
53b5968725STom Haynes
54b5968725STom Haynes static loff_t
filelayout_get_dense_offset(struct nfs4_filelayout_segment * flseg,loff_t offset)55b5968725STom Haynes filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
56b5968725STom Haynes loff_t offset)
57b5968725STom Haynes {
58b5968725STom Haynes u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
59b5968725STom Haynes u64 stripe_no;
60b5968725STom Haynes u32 rem;
61b5968725STom Haynes
62b5968725STom Haynes offset -= flseg->pattern_offset;
63b5968725STom Haynes stripe_no = div_u64(offset, stripe_width);
64b5968725STom Haynes div_u64_rem(offset, flseg->stripe_unit, &rem);
65b5968725STom Haynes
66b5968725STom Haynes return stripe_no * flseg->stripe_unit + rem;
67b5968725STom Haynes }
68b5968725STom Haynes
69b5968725STom Haynes /* This function is used by the layout driver to calculate the
70b5968725STom Haynes * offset of the file on the dserver based on whether the
71b5968725STom Haynes * layout type is STRIPE_DENSE or STRIPE_SPARSE
72b5968725STom Haynes */
73b5968725STom Haynes static loff_t
filelayout_get_dserver_offset(struct pnfs_layout_segment * lseg,loff_t offset)74b5968725STom Haynes filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
75b5968725STom Haynes {
76b5968725STom Haynes struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
77b5968725STom Haynes
78b5968725STom Haynes switch (flseg->stripe_type) {
79b5968725STom Haynes case STRIPE_SPARSE:
80b5968725STom Haynes return offset;
81b5968725STom Haynes
82b5968725STom Haynes case STRIPE_DENSE:
83b5968725STom Haynes return filelayout_get_dense_offset(flseg, offset);
84b5968725STom Haynes }
85b5968725STom Haynes
86b5968725STom Haynes BUG();
87b5968725STom Haynes }
88b5968725STom Haynes
filelayout_reset_write(struct nfs_pgio_header * hdr)89d45f60c6SWeston Andros Adamson static void filelayout_reset_write(struct nfs_pgio_header *hdr)
90b5968725STom Haynes {
91d45f60c6SWeston Andros Adamson struct rpc_task *task = &hdr->task;
92b5968725STom Haynes
93b5968725STom Haynes if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
94b5968725STom Haynes dprintk("%s Reset task %5u for i/o through MDS "
95b5968725STom Haynes "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
96d45f60c6SWeston Andros Adamson hdr->task.tk_pid,
97b5968725STom Haynes hdr->inode->i_sb->s_id,
98b5968725STom Haynes (unsigned long long)NFS_FILEID(hdr->inode),
99d45f60c6SWeston Andros Adamson hdr->args.count,
100d45f60c6SWeston Andros Adamson (unsigned long long)hdr->args.offset);
101b5968725STom Haynes
10253113ad3SWeston Andros Adamson task->tk_status = pnfs_write_done_resend_to_mds(hdr);
103b5968725STom Haynes }
104b5968725STom Haynes }
105b5968725STom Haynes
filelayout_reset_read(struct nfs_pgio_header * hdr)106d45f60c6SWeston Andros Adamson static void filelayout_reset_read(struct nfs_pgio_header *hdr)
107b5968725STom Haynes {
108d45f60c6SWeston Andros Adamson struct rpc_task *task = &hdr->task;
109b5968725STom Haynes
110b5968725STom Haynes if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
111b5968725STom Haynes dprintk("%s Reset task %5u for i/o through MDS "
112b5968725STom Haynes "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
113d45f60c6SWeston Andros Adamson hdr->task.tk_pid,
114b5968725STom Haynes hdr->inode->i_sb->s_id,
115b5968725STom Haynes (unsigned long long)NFS_FILEID(hdr->inode),
116d45f60c6SWeston Andros Adamson hdr->args.count,
117d45f60c6SWeston Andros Adamson (unsigned long long)hdr->args.offset);
118b5968725STom Haynes
11953113ad3SWeston Andros Adamson task->tk_status = pnfs_read_done_resend_to_mds(hdr);
120b5968725STom Haynes }
121b5968725STom Haynes }
122b5968725STom Haynes
filelayout_async_handle_error(struct rpc_task * task,struct nfs4_state * state,struct nfs_client * clp,struct pnfs_layout_segment * lseg)123b5968725STom Haynes static int filelayout_async_handle_error(struct rpc_task *task,
124b5968725STom Haynes struct nfs4_state *state,
125b5968725STom Haynes struct nfs_client *clp,
126b5968725STom Haynes struct pnfs_layout_segment *lseg)
127b5968725STom Haynes {
128b5968725STom Haynes struct pnfs_layout_hdr *lo = lseg->pls_layout;
129b5968725STom Haynes struct inode *inode = lo->plh_inode;
130b5968725STom Haynes struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
131b5968725STom Haynes struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
132b5968725STom Haynes
133b5968725STom Haynes if (task->tk_status >= 0)
134b5968725STom Haynes return 0;
135b5968725STom Haynes
136b5968725STom Haynes switch (task->tk_status) {
137b5968725STom Haynes /* DS session errors */
138b5968725STom Haynes case -NFS4ERR_BADSESSION:
139b5968725STom Haynes case -NFS4ERR_BADSLOT:
140b5968725STom Haynes case -NFS4ERR_BAD_HIGH_SLOT:
141b5968725STom Haynes case -NFS4ERR_DEADSESSION:
142b5968725STom Haynes case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
143b5968725STom Haynes case -NFS4ERR_SEQ_FALSE_RETRY:
144b5968725STom Haynes case -NFS4ERR_SEQ_MISORDERED:
145b5968725STom Haynes dprintk("%s ERROR %d, Reset session. Exchangeid "
146b5968725STom Haynes "flags 0x%x\n", __func__, task->tk_status,
147b5968725STom Haynes clp->cl_exchange_flags);
148b5968725STom Haynes nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
149b5968725STom Haynes break;
150b5968725STom Haynes case -NFS4ERR_DELAY:
151b5968725STom Haynes case -NFS4ERR_GRACE:
152b5968725STom Haynes rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
153b5968725STom Haynes break;
154b5968725STom Haynes case -NFS4ERR_RETRY_UNCACHED_REP:
155b5968725STom Haynes break;
156b5968725STom Haynes /* Invalidate Layout errors */
157a0bc01e0SOlga Kornievskaia case -NFS4ERR_ACCESS:
158b5968725STom Haynes case -NFS4ERR_PNFS_NO_LAYOUT:
159b5968725STom Haynes case -ESTALE: /* mapped NFS4ERR_STALE */
160b5968725STom Haynes case -EBADHANDLE: /* mapped NFS4ERR_BADHANDLE */
161b5968725STom Haynes case -EISDIR: /* mapped NFS4ERR_ISDIR */
162b5968725STom Haynes case -NFS4ERR_FHEXPIRED:
163b5968725STom Haynes case -NFS4ERR_WRONG_TYPE:
164b5968725STom Haynes dprintk("%s Invalid layout error %d\n", __func__,
165b5968725STom Haynes task->tk_status);
166b5968725STom Haynes /*
167b5968725STom Haynes * Destroy layout so new i/o will get a new layout.
168b5968725STom Haynes * Layout will not be destroyed until all current lseg
169b5968725STom Haynes * references are put. Mark layout as invalid to resend failed
170b5968725STom Haynes * i/o and all i/o waiting on the slot table to the MDS until
171b5968725STom Haynes * layout is destroyed and a new valid layout is obtained.
172b5968725STom Haynes */
173b5968725STom Haynes pnfs_destroy_layout(NFS_I(inode));
174b5968725STom Haynes rpc_wake_up(&tbl->slot_tbl_waitq);
175b5968725STom Haynes goto reset;
176b5968725STom Haynes /* RPC connection errors */
177b5968725STom Haynes case -ECONNREFUSED:
178b5968725STom Haynes case -EHOSTDOWN:
179b5968725STom Haynes case -EHOSTUNREACH:
180b5968725STom Haynes case -ENETUNREACH:
181b5968725STom Haynes case -EIO:
182b5968725STom Haynes case -ETIMEDOUT:
183b5968725STom Haynes case -EPIPE:
184431794e6STrond Myklebust case -EPROTO:
185431794e6STrond Myklebust case -ENODEV:
186b5968725STom Haynes dprintk("%s DS connection error %d\n", __func__,
187b5968725STom Haynes task->tk_status);
188b5968725STom Haynes nfs4_mark_deviceid_unavailable(devid);
189c220106fSPeng Tao pnfs_error_mark_layout_for_return(inode, lseg);
190a0bc01e0SOlga Kornievskaia pnfs_set_lo_fail(lseg);
191b5968725STom Haynes rpc_wake_up(&tbl->slot_tbl_waitq);
192df561f66SGustavo A. R. Silva fallthrough;
193b5968725STom Haynes default:
194b5968725STom Haynes reset:
195b5968725STom Haynes dprintk("%s Retry through MDS. Error %d\n", __func__,
196b5968725STom Haynes task->tk_status);
197b5968725STom Haynes return -NFS4ERR_RESET_TO_MDS;
198b5968725STom Haynes }
199b5968725STom Haynes task->tk_status = 0;
200b5968725STom Haynes return -EAGAIN;
201b5968725STom Haynes }
202b5968725STom Haynes
203b5968725STom Haynes /* NFS_PROTO call done callback routines */
204b5968725STom Haynes
filelayout_read_done_cb(struct rpc_task * task,struct nfs_pgio_header * hdr)205b5968725STom Haynes static int filelayout_read_done_cb(struct rpc_task *task,
206d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr)
207b5968725STom Haynes {
208b5968725STom Haynes int err;
209b5968725STom Haynes
210d45f60c6SWeston Andros Adamson trace_nfs4_pnfs_read(hdr, task->tk_status);
211d45f60c6SWeston Andros Adamson err = filelayout_async_handle_error(task, hdr->args.context->state,
212d45f60c6SWeston Andros Adamson hdr->ds_clp, hdr->lseg);
213b5968725STom Haynes
214b5968725STom Haynes switch (err) {
215b5968725STom Haynes case -NFS4ERR_RESET_TO_MDS:
216d45f60c6SWeston Andros Adamson filelayout_reset_read(hdr);
217b5968725STom Haynes return task->tk_status;
218b5968725STom Haynes case -EAGAIN:
219b5968725STom Haynes rpc_restart_call_prepare(task);
220b5968725STom Haynes return -EAGAIN;
221b5968725STom Haynes }
222b5968725STom Haynes
223b5968725STom Haynes return 0;
224b5968725STom Haynes }
225b5968725STom Haynes
226b5968725STom Haynes /*
227b5968725STom Haynes * We reference the rpc_cred of the first WRITE that triggers the need for
228b5968725STom Haynes * a LAYOUTCOMMIT, and use it to send the layoutcommit compound.
229b5968725STom Haynes * rfc5661 is not clear about which credential should be used.
230b5968725STom Haynes */
231b5968725STom Haynes static void
filelayout_set_layoutcommit(struct nfs_pgio_header * hdr)232d45f60c6SWeston Andros Adamson filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
233b5968725STom Haynes {
2342e18d4d8STrond Myklebust loff_t end_offs = 0;
235b5968725STom Haynes
236b5968725STom Haynes if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
2372e18d4d8STrond Myklebust hdr->res.verf->committed == NFS_FILE_SYNC)
238b5968725STom Haynes return;
2392e18d4d8STrond Myklebust if (hdr->res.verf->committed == NFS_DATA_SYNC)
2402e18d4d8STrond Myklebust end_offs = hdr->mds_offset + (loff_t)hdr->res.count;
241b5968725STom Haynes
2422e18d4d8STrond Myklebust /* Note: if the write is unstable, don't set end_offs until commit */
2432e18d4d8STrond Myklebust pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs);
244f383b7e8STom Haynes dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
245b5968725STom Haynes (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
246b5968725STom Haynes }
247b5968725STom Haynes
248b5968725STom Haynes bool
filelayout_test_devid_unavailable(struct nfs4_deviceid_node * node)249b5968725STom Haynes filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
250b5968725STom Haynes {
251b5968725STom Haynes return filelayout_test_devid_invalid(node) ||
252b5968725STom Haynes nfs4_test_deviceid_unavailable(node);
253b5968725STom Haynes }
254b5968725STom Haynes
255b5968725STom Haynes static bool
filelayout_reset_to_mds(struct pnfs_layout_segment * lseg)256b5968725STom Haynes filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
257b5968725STom Haynes {
258b5968725STom Haynes struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);
259b5968725STom Haynes
260b5968725STom Haynes return filelayout_test_devid_unavailable(node);
261b5968725STom Haynes }
262b5968725STom Haynes
263b5968725STom Haynes /*
264b5968725STom Haynes * Call ops for the async read/write cases
265b5968725STom Haynes * In the case of dense layouts, the offset needs to be reset to its
266b5968725STom Haynes * original value.
267b5968725STom Haynes */
filelayout_read_prepare(struct rpc_task * task,void * data)268b5968725STom Haynes static void filelayout_read_prepare(struct rpc_task *task, void *data)
269b5968725STom Haynes {
270d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
271b5968725STom Haynes
272d45f60c6SWeston Andros Adamson if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
273b5968725STom Haynes rpc_exit(task, -EIO);
274b5968725STom Haynes return;
275b5968725STom Haynes }
276d45f60c6SWeston Andros Adamson if (filelayout_reset_to_mds(hdr->lseg)) {
277b5968725STom Haynes dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
278d45f60c6SWeston Andros Adamson filelayout_reset_read(hdr);
279b5968725STom Haynes rpc_exit(task, 0);
280b5968725STom Haynes return;
281b5968725STom Haynes }
282d45f60c6SWeston Andros Adamson hdr->pgio_done_cb = filelayout_read_done_cb;
283b5968725STom Haynes
2846de7e12fSAnna Schumaker if (nfs4_setup_sequence(hdr->ds_clp,
285d45f60c6SWeston Andros Adamson &hdr->args.seq_args,
286d45f60c6SWeston Andros Adamson &hdr->res.seq_res,
287b5968725STom Haynes task))
288b5968725STom Haynes return;
289d45f60c6SWeston Andros Adamson if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
290d45f60c6SWeston Andros Adamson hdr->args.lock_context, FMODE_READ) == -EIO)
291b5968725STom Haynes rpc_exit(task, -EIO); /* lost lock, terminate I/O */
292b5968725STom Haynes }
293b5968725STom Haynes
filelayout_read_call_done(struct rpc_task * task,void * data)294b5968725STom Haynes static void filelayout_read_call_done(struct rpc_task *task, void *data)
295b5968725STom Haynes {
296d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
297b5968725STom Haynes
298d45f60c6SWeston Andros Adamson if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
299b5968725STom Haynes task->tk_status == 0) {
300d45f60c6SWeston Andros Adamson nfs41_sequence_done(task, &hdr->res.seq_res);
301b5968725STom Haynes return;
302b5968725STom Haynes }
303b5968725STom Haynes
304b5968725STom Haynes /* Note this may cause RPC to be resent */
305d45f60c6SWeston Andros Adamson hdr->mds_ops->rpc_call_done(task, data);
306b5968725STom Haynes }
307b5968725STom Haynes
filelayout_read_count_stats(struct rpc_task * task,void * data)308b5968725STom Haynes static void filelayout_read_count_stats(struct rpc_task *task, void *data)
309b5968725STom Haynes {
310d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
311b5968725STom Haynes
312d45f60c6SWeston Andros Adamson rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
313b5968725STom Haynes }
314b5968725STom Haynes
filelayout_write_done_cb(struct rpc_task * task,struct nfs_pgio_header * hdr)315b5968725STom Haynes static int filelayout_write_done_cb(struct rpc_task *task,
316d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr)
317b5968725STom Haynes {
318b5968725STom Haynes int err;
319b5968725STom Haynes
320d45f60c6SWeston Andros Adamson trace_nfs4_pnfs_write(hdr, task->tk_status);
321d45f60c6SWeston Andros Adamson err = filelayout_async_handle_error(task, hdr->args.context->state,
322d45f60c6SWeston Andros Adamson hdr->ds_clp, hdr->lseg);
323b5968725STom Haynes
324b5968725STom Haynes switch (err) {
325b5968725STom Haynes case -NFS4ERR_RESET_TO_MDS:
326d45f60c6SWeston Andros Adamson filelayout_reset_write(hdr);
327b5968725STom Haynes return task->tk_status;
328b5968725STom Haynes case -EAGAIN:
329b5968725STom Haynes rpc_restart_call_prepare(task);
330b5968725STom Haynes return -EAGAIN;
331b5968725STom Haynes }
332b5968725STom Haynes
333d45f60c6SWeston Andros Adamson filelayout_set_layoutcommit(hdr);
334e033fb51STrond Myklebust
335e033fb51STrond Myklebust /* zero out the fattr */
336e033fb51STrond Myklebust hdr->fattr.valid = 0;
337e033fb51STrond Myklebust if (task->tk_status >= 0)
338e033fb51STrond Myklebust nfs_writeback_update_inode(hdr);
339e033fb51STrond Myklebust
340b5968725STom Haynes return 0;
341b5968725STom Haynes }
342b5968725STom Haynes
filelayout_commit_done_cb(struct rpc_task * task,struct nfs_commit_data * data)343b5968725STom Haynes static int filelayout_commit_done_cb(struct rpc_task *task,
344b5968725STom Haynes struct nfs_commit_data *data)
345b5968725STom Haynes {
346b5968725STom Haynes int err;
347b5968725STom Haynes
348b5968725STom Haynes trace_nfs4_pnfs_commit_ds(data, task->tk_status);
349b5968725STom Haynes err = filelayout_async_handle_error(task, NULL, data->ds_clp,
350b5968725STom Haynes data->lseg);
351b5968725STom Haynes
352b5968725STom Haynes switch (err) {
353b5968725STom Haynes case -NFS4ERR_RESET_TO_MDS:
354f54bcf2eSTom Haynes pnfs_generic_prepare_to_resend_writes(data);
355b5968725STom Haynes return -EAGAIN;
356b5968725STom Haynes case -EAGAIN:
357b5968725STom Haynes rpc_restart_call_prepare(task);
358b5968725STom Haynes return -EAGAIN;
359b5968725STom Haynes }
360b5968725STom Haynes
36167af7611STrond Myklebust pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
362bc7d4b8fSPeng Tao
363b5968725STom Haynes return 0;
364b5968725STom Haynes }
365b5968725STom Haynes
filelayout_write_prepare(struct rpc_task * task,void * data)366b5968725STom Haynes static void filelayout_write_prepare(struct rpc_task *task, void *data)
367b5968725STom Haynes {
368d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
369b5968725STom Haynes
370d45f60c6SWeston Andros Adamson if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
371b5968725STom Haynes rpc_exit(task, -EIO);
372b5968725STom Haynes return;
373b5968725STom Haynes }
374d45f60c6SWeston Andros Adamson if (filelayout_reset_to_mds(hdr->lseg)) {
375b5968725STom Haynes dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
376d45f60c6SWeston Andros Adamson filelayout_reset_write(hdr);
377b5968725STom Haynes rpc_exit(task, 0);
378b5968725STom Haynes return;
379b5968725STom Haynes }
3806de7e12fSAnna Schumaker if (nfs4_setup_sequence(hdr->ds_clp,
381d45f60c6SWeston Andros Adamson &hdr->args.seq_args,
382d45f60c6SWeston Andros Adamson &hdr->res.seq_res,
383b5968725STom Haynes task))
384b5968725STom Haynes return;
385d45f60c6SWeston Andros Adamson if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
386d45f60c6SWeston Andros Adamson hdr->args.lock_context, FMODE_WRITE) == -EIO)
387b5968725STom Haynes rpc_exit(task, -EIO); /* lost lock, terminate I/O */
388b5968725STom Haynes }
389b5968725STom Haynes
filelayout_write_call_done(struct rpc_task * task,void * data)390b5968725STom Haynes static void filelayout_write_call_done(struct rpc_task *task, void *data)
391b5968725STom Haynes {
392d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
393b5968725STom Haynes
394d45f60c6SWeston Andros Adamson if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
395b5968725STom Haynes task->tk_status == 0) {
396d45f60c6SWeston Andros Adamson nfs41_sequence_done(task, &hdr->res.seq_res);
397b5968725STom Haynes return;
398b5968725STom Haynes }
399b5968725STom Haynes
400b5968725STom Haynes /* Note this may cause RPC to be resent */
401d45f60c6SWeston Andros Adamson hdr->mds_ops->rpc_call_done(task, data);
402b5968725STom Haynes }
403b5968725STom Haynes
filelayout_write_count_stats(struct rpc_task * task,void * data)404b5968725STom Haynes static void filelayout_write_count_stats(struct rpc_task *task, void *data)
405b5968725STom Haynes {
406d45f60c6SWeston Andros Adamson struct nfs_pgio_header *hdr = data;
407b5968725STom Haynes
408d45f60c6SWeston Andros Adamson rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
409b5968725STom Haynes }
410b5968725STom Haynes
filelayout_commit_prepare(struct rpc_task * task,void * data)411b5968725STom Haynes static void filelayout_commit_prepare(struct rpc_task *task, void *data)
412b5968725STom Haynes {
413b5968725STom Haynes struct nfs_commit_data *wdata = data;
414b5968725STom Haynes
4156de7e12fSAnna Schumaker nfs4_setup_sequence(wdata->ds_clp,
416b5968725STom Haynes &wdata->args.seq_args,
417b5968725STom Haynes &wdata->res.seq_res,
418b5968725STom Haynes task);
419b5968725STom Haynes }
420b5968725STom Haynes
filelayout_commit_count_stats(struct rpc_task * task,void * data)421b5968725STom Haynes static void filelayout_commit_count_stats(struct rpc_task *task, void *data)
422b5968725STom Haynes {
423b5968725STom Haynes struct nfs_commit_data *cdata = data;
424b5968725STom Haynes
425b5968725STom Haynes rpc_count_iostats(task, NFS_SERVER(cdata->inode)->client->cl_metrics);
426b5968725STom Haynes }
427b5968725STom Haynes
428b5968725STom Haynes static const struct rpc_call_ops filelayout_read_call_ops = {
429b5968725STom Haynes .rpc_call_prepare = filelayout_read_prepare,
430b5968725STom Haynes .rpc_call_done = filelayout_read_call_done,
431b5968725STom Haynes .rpc_count_stats = filelayout_read_count_stats,
432f54bcf2eSTom Haynes .rpc_release = pnfs_generic_rw_release,
433b5968725STom Haynes };
434b5968725STom Haynes
435b5968725STom Haynes static const struct rpc_call_ops filelayout_write_call_ops = {
436b5968725STom Haynes .rpc_call_prepare = filelayout_write_prepare,
437b5968725STom Haynes .rpc_call_done = filelayout_write_call_done,
438b5968725STom Haynes .rpc_count_stats = filelayout_write_count_stats,
439f54bcf2eSTom Haynes .rpc_release = pnfs_generic_rw_release,
440b5968725STom Haynes };
441b5968725STom Haynes
442b5968725STom Haynes static const struct rpc_call_ops filelayout_commit_call_ops = {
443b5968725STom Haynes .rpc_call_prepare = filelayout_commit_prepare,
444f54bcf2eSTom Haynes .rpc_call_done = pnfs_generic_write_commit_done,
445b5968725STom Haynes .rpc_count_stats = filelayout_commit_count_stats,
446f54bcf2eSTom Haynes .rpc_release = pnfs_generic_commit_release,
447b5968725STom Haynes };
448b5968725STom Haynes
449b5968725STom Haynes static enum pnfs_try_status
filelayout_read_pagelist(struct nfs_pgio_header * hdr)450d45f60c6SWeston Andros Adamson filelayout_read_pagelist(struct nfs_pgio_header *hdr)
451b5968725STom Haynes {
452b5968725STom Haynes struct pnfs_layout_segment *lseg = hdr->lseg;
453b5968725STom Haynes struct nfs4_pnfs_ds *ds;
454b5968725STom Haynes struct rpc_clnt *ds_clnt;
455d45f60c6SWeston Andros Adamson loff_t offset = hdr->args.offset;
456b5968725STom Haynes u32 j, idx;
457b5968725STom Haynes struct nfs_fh *fh;
458b5968725STom Haynes
4595b5e0928SAlexey Dobriyan dprintk("--> %s ino %lu pgbase %u req %zu@%llu\n",
460b5968725STom Haynes __func__, hdr->inode->i_ino,
461d45f60c6SWeston Andros Adamson hdr->args.pgbase, (size_t)hdr->args.count, offset);
462b5968725STom Haynes
463b5968725STom Haynes /* Retrieve the correct rpc_client for the byte range */
464b5968725STom Haynes j = nfs4_fl_calc_j_index(lseg, offset);
465b5968725STom Haynes idx = nfs4_fl_calc_ds_index(lseg, j);
466b5968725STom Haynes ds = nfs4_fl_prepare_ds(lseg, idx);
467b5968725STom Haynes if (!ds)
468b5968725STom Haynes return PNFS_NOT_ATTEMPTED;
469b5968725STom Haynes
470b5968725STom Haynes ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
471b5968725STom Haynes if (IS_ERR(ds_clnt))
472b5968725STom Haynes return PNFS_NOT_ATTEMPTED;
473b5968725STom Haynes
474b5968725STom Haynes dprintk("%s USE DS: %s cl_count %d\n", __func__,
475212bf41dSElena Reshetova ds->ds_remotestr, refcount_read(&ds->ds_clp->cl_count));
476b5968725STom Haynes
477b5968725STom Haynes /* No multipath support. Use first DS */
478212bf41dSElena Reshetova refcount_inc(&ds->ds_clp->cl_count);
479d45f60c6SWeston Andros Adamson hdr->ds_clp = ds->ds_clp;
4806cccbb6fSWeston Andros Adamson hdr->ds_commit_idx = idx;
481b5968725STom Haynes fh = nfs4_fl_select_ds_fh(lseg, j);
482b5968725STom Haynes if (fh)
483d45f60c6SWeston Andros Adamson hdr->args.fh = fh;
484b5968725STom Haynes
485d45f60c6SWeston Andros Adamson hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
486d45f60c6SWeston Andros Adamson hdr->mds_offset = offset;
487b5968725STom Haynes
488b5968725STom Haynes /* Perform an asynchronous read to ds */
48946a5ab47SPeng Tao nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
49046a5ab47SPeng Tao NFS_PROTO(hdr->inode), &filelayout_read_call_ops,
491*df24c483SMike Snitzer 0, RPC_TASK_SOFTCONN, NULL);
492b5968725STom Haynes return PNFS_ATTEMPTED;
493b5968725STom Haynes }
494b5968725STom Haynes
495b5968725STom Haynes /* Perform async writes. */
496b5968725STom Haynes static enum pnfs_try_status
filelayout_write_pagelist(struct nfs_pgio_header * hdr,int sync)497d45f60c6SWeston Andros Adamson filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
498b5968725STom Haynes {
499b5968725STom Haynes struct pnfs_layout_segment *lseg = hdr->lseg;
500b5968725STom Haynes struct nfs4_pnfs_ds *ds;
501b5968725STom Haynes struct rpc_clnt *ds_clnt;
502d45f60c6SWeston Andros Adamson loff_t offset = hdr->args.offset;
503b5968725STom Haynes u32 j, idx;
504b5968725STom Haynes struct nfs_fh *fh;
505b5968725STom Haynes
506b5968725STom Haynes /* Retrieve the correct rpc_client for the byte range */
507b5968725STom Haynes j = nfs4_fl_calc_j_index(lseg, offset);
508b5968725STom Haynes idx = nfs4_fl_calc_ds_index(lseg, j);
509b5968725STom Haynes ds = nfs4_fl_prepare_ds(lseg, idx);
510b5968725STom Haynes if (!ds)
511b5968725STom Haynes return PNFS_NOT_ATTEMPTED;
512b5968725STom Haynes
513b5968725STom Haynes ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
514b5968725STom Haynes if (IS_ERR(ds_clnt))
515b5968725STom Haynes return PNFS_NOT_ATTEMPTED;
516b5968725STom Haynes
5175b5e0928SAlexey Dobriyan dprintk("%s ino %lu sync %d req %zu@%llu DS: %s cl_count %d\n",
518d45f60c6SWeston Andros Adamson __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count,
519212bf41dSElena Reshetova offset, ds->ds_remotestr, refcount_read(&ds->ds_clp->cl_count));
520b5968725STom Haynes
521d45f60c6SWeston Andros Adamson hdr->pgio_done_cb = filelayout_write_done_cb;
522212bf41dSElena Reshetova refcount_inc(&ds->ds_clp->cl_count);
523d45f60c6SWeston Andros Adamson hdr->ds_clp = ds->ds_clp;
5246cccbb6fSWeston Andros Adamson hdr->ds_commit_idx = idx;
525b5968725STom Haynes fh = nfs4_fl_select_ds_fh(lseg, j);
526b5968725STom Haynes if (fh)
527d45f60c6SWeston Andros Adamson hdr->args.fh = fh;
528d45f60c6SWeston Andros Adamson hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
529b5968725STom Haynes
530b5968725STom Haynes /* Perform an asynchronous write */
53146a5ab47SPeng Tao nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
53246a5ab47SPeng Tao NFS_PROTO(hdr->inode), &filelayout_write_call_ops,
533*df24c483SMike Snitzer sync, RPC_TASK_SOFTCONN, NULL);
534b5968725STom Haynes return PNFS_ATTEMPTED;
535b5968725STom Haynes }
536b5968725STom Haynes
537b5968725STom Haynes static int
filelayout_check_deviceid(struct pnfs_layout_hdr * lo,struct nfs4_filelayout_segment * fl,gfp_t gfp_flags)5388d40b0f1SAndy Adamson filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
539b5968725STom Haynes struct nfs4_filelayout_segment *fl,
540b5968725STom Haynes gfp_t gfp_flags)
541b5968725STom Haynes {
542b5968725STom Haynes struct nfs4_deviceid_node *d;
543b5968725STom Haynes struct nfs4_file_layout_dsaddr *dsaddr;
544b5968725STom Haynes int status = -EINVAL;
545b5968725STom Haynes
5461ebf9801STrond Myklebust /* Is the deviceid already set? If so, we're good. */
5471ebf9801STrond Myklebust if (fl->dsaddr != NULL)
5481ebf9801STrond Myklebust return 0;
5491ebf9801STrond Myklebust
550b5968725STom Haynes /* find and reference the deviceid */
551629dc870SAndy Adamson d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
552b5968725STom Haynes lo->plh_lc_cred, gfp_flags);
553661373b1SChristoph Hellwig if (d == NULL)
554b5968725STom Haynes goto out;
555661373b1SChristoph Hellwig
556b5968725STom Haynes dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
557b5968725STom Haynes /* Found deviceid is unavailable */
558b5968725STom Haynes if (filelayout_test_devid_unavailable(&dsaddr->id_node))
559b5968725STom Haynes goto out_put;
560b5968725STom Haynes
561b5968725STom Haynes if (fl->first_stripe_index >= dsaddr->stripe_count) {
562b5968725STom Haynes dprintk("%s Bad first_stripe_index %u\n",
563b5968725STom Haynes __func__, fl->first_stripe_index);
564b5968725STom Haynes goto out_put;
565b5968725STom Haynes }
566b5968725STom Haynes
567b5968725STom Haynes if ((fl->stripe_type == STRIPE_SPARSE &&
568b5968725STom Haynes fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
569b5968725STom Haynes (fl->stripe_type == STRIPE_DENSE &&
570b5968725STom Haynes fl->num_fh != dsaddr->stripe_count)) {
571b5968725STom Haynes dprintk("%s num_fh %u not valid for given packing\n",
572b5968725STom Haynes __func__, fl->num_fh);
573b5968725STom Haynes goto out_put;
574b5968725STom Haynes }
5758d40b0f1SAndy Adamson status = 0;
5761ebf9801STrond Myklebust
5771ebf9801STrond Myklebust /*
5781ebf9801STrond Myklebust * Atomic compare and xchange to ensure we don't scribble
5791ebf9801STrond Myklebust * over a non-NULL pointer.
5801ebf9801STrond Myklebust */
5811ebf9801STrond Myklebust if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
5821ebf9801STrond Myklebust goto out_put;
5838d40b0f1SAndy Adamson out:
5848d40b0f1SAndy Adamson return status;
5858d40b0f1SAndy Adamson out_put:
5868d40b0f1SAndy Adamson nfs4_fl_put_deviceid(dsaddr);
5878d40b0f1SAndy Adamson goto out;
5888d40b0f1SAndy Adamson }
5898d40b0f1SAndy Adamson
5908d40b0f1SAndy Adamson /*
5918d40b0f1SAndy Adamson * filelayout_check_layout()
5928d40b0f1SAndy Adamson *
5938d40b0f1SAndy Adamson * Make sure layout segment parameters are sane WRT the device.
5948d40b0f1SAndy Adamson * At this point no generic layer initialization of the lseg has occurred,
5958d40b0f1SAndy Adamson * and nothing has been added to the layout_hdr cache.
5968d40b0f1SAndy Adamson *
5978d40b0f1SAndy Adamson */
5988d40b0f1SAndy Adamson static int
filelayout_check_layout(struct pnfs_layout_hdr * lo,struct nfs4_filelayout_segment * fl,struct nfs4_layoutget_res * lgr,gfp_t gfp_flags)5998d40b0f1SAndy Adamson filelayout_check_layout(struct pnfs_layout_hdr *lo,
6008d40b0f1SAndy Adamson struct nfs4_filelayout_segment *fl,
6018d40b0f1SAndy Adamson struct nfs4_layoutget_res *lgr,
6028d40b0f1SAndy Adamson gfp_t gfp_flags)
6038d40b0f1SAndy Adamson {
6048d40b0f1SAndy Adamson int status = -EINVAL;
6058d40b0f1SAndy Adamson
6068d40b0f1SAndy Adamson dprintk("--> %s\n", __func__);
6078d40b0f1SAndy Adamson
6088d40b0f1SAndy Adamson if (fl->pattern_offset > lgr->range.offset) {
6098d40b0f1SAndy Adamson dprintk("%s pattern_offset %lld too large\n",
6108d40b0f1SAndy Adamson __func__, fl->pattern_offset);
6118d40b0f1SAndy Adamson goto out;
6128d40b0f1SAndy Adamson }
6138d40b0f1SAndy Adamson
6148d40b0f1SAndy Adamson if (!fl->stripe_unit) {
6158d40b0f1SAndy Adamson dprintk("%s Invalid stripe unit (%u)\n",
6168d40b0f1SAndy Adamson __func__, fl->stripe_unit);
6178d40b0f1SAndy Adamson goto out;
6188d40b0f1SAndy Adamson }
619b5968725STom Haynes
620b5968725STom Haynes status = 0;
621b5968725STom Haynes out:
622b5968725STom Haynes dprintk("--> %s returns %d\n", __func__, status);
623b5968725STom Haynes return status;
624b5968725STom Haynes }
625b5968725STom Haynes
_filelayout_free_lseg(struct nfs4_filelayout_segment * fl)6263ec0c979SKinglong Mee static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
627b5968725STom Haynes {
628b5968725STom Haynes int i;
629b5968725STom Haynes
6303ec0c979SKinglong Mee if (fl->fh_array) {
631b5968725STom Haynes for (i = 0; i < fl->num_fh; i++) {
632b5968725STom Haynes if (!fl->fh_array[i])
633b5968725STom Haynes break;
634b5968725STom Haynes kfree(fl->fh_array[i]);
635b5968725STom Haynes }
636b5968725STom Haynes kfree(fl->fh_array);
637b5968725STom Haynes }
638b5968725STom Haynes kfree(fl);
639b5968725STom Haynes }
640b5968725STom Haynes
641b5968725STom Haynes static int
filelayout_decode_layout(struct pnfs_layout_hdr * flo,struct nfs4_filelayout_segment * fl,struct nfs4_layoutget_res * lgr,gfp_t gfp_flags)642b5968725STom Haynes filelayout_decode_layout(struct pnfs_layout_hdr *flo,
643b5968725STom Haynes struct nfs4_filelayout_segment *fl,
644b5968725STom Haynes struct nfs4_layoutget_res *lgr,
645b5968725STom Haynes gfp_t gfp_flags)
646b5968725STom Haynes {
647b5968725STom Haynes struct xdr_stream stream;
648b5968725STom Haynes struct xdr_buf buf;
649b5968725STom Haynes struct page *scratch;
650b5968725STom Haynes __be32 *p;
651b5968725STom Haynes uint32_t nfl_util;
652b5968725STom Haynes int i;
653b5968725STom Haynes
654b5968725STom Haynes dprintk("%s: set_layout_map Begin\n", __func__);
655b5968725STom Haynes
656b5968725STom Haynes scratch = alloc_page(gfp_flags);
657b5968725STom Haynes if (!scratch)
658b5968725STom Haynes return -ENOMEM;
659b5968725STom Haynes
660b5968725STom Haynes xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
6610ae4c3e8SChuck Lever xdr_set_scratch_page(&stream, scratch);
662b5968725STom Haynes
663b5968725STom Haynes /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
664b5968725STom Haynes * num_fh (4) */
665b5968725STom Haynes p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20);
666b5968725STom Haynes if (unlikely(!p))
667b5968725STom Haynes goto out_err;
668b5968725STom Haynes
669629dc870SAndy Adamson memcpy(&fl->deviceid, p, sizeof(fl->deviceid));
670b5968725STom Haynes p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
671629dc870SAndy Adamson nfs4_print_deviceid(&fl->deviceid);
672b5968725STom Haynes
673b5968725STom Haynes nfl_util = be32_to_cpup(p++);
674b5968725STom Haynes if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
675b5968725STom Haynes fl->commit_through_mds = 1;
676b5968725STom Haynes if (nfl_util & NFL4_UFLG_DENSE)
677b5968725STom Haynes fl->stripe_type = STRIPE_DENSE;
678b5968725STom Haynes else
679b5968725STom Haynes fl->stripe_type = STRIPE_SPARSE;
680b5968725STom Haynes fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
681b5968725STom Haynes
682b5968725STom Haynes fl->first_stripe_index = be32_to_cpup(p++);
683b5968725STom Haynes p = xdr_decode_hyper(p, &fl->pattern_offset);
684b5968725STom Haynes fl->num_fh = be32_to_cpup(p++);
685b5968725STom Haynes
686b5968725STom Haynes dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
687b5968725STom Haynes __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
688b5968725STom Haynes fl->pattern_offset);
689b5968725STom Haynes
690b5968725STom Haynes /* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
691b5968725STom Haynes * Futher checking is done in filelayout_check_layout */
692b5968725STom Haynes if (fl->num_fh >
693b5968725STom Haynes max(NFS4_PNFS_MAX_STRIPE_CNT, NFS4_PNFS_MAX_MULTI_CNT))
694b5968725STom Haynes goto out_err;
695b5968725STom Haynes
696b5968725STom Haynes if (fl->num_fh > 0) {
697b5968725STom Haynes fl->fh_array = kcalloc(fl->num_fh, sizeof(fl->fh_array[0]),
698b5968725STom Haynes gfp_flags);
699b5968725STom Haynes if (!fl->fh_array)
700b5968725STom Haynes goto out_err;
701b5968725STom Haynes }
702b5968725STom Haynes
703b5968725STom Haynes for (i = 0; i < fl->num_fh; i++) {
704b5968725STom Haynes /* Do we want to use a mempool here? */
705b5968725STom Haynes fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
706b5968725STom Haynes if (!fl->fh_array[i])
7073ec0c979SKinglong Mee goto out_err;
708b5968725STom Haynes
709b5968725STom Haynes p = xdr_inline_decode(&stream, 4);
710b5968725STom Haynes if (unlikely(!p))
7113ec0c979SKinglong Mee goto out_err;
712b5968725STom Haynes fl->fh_array[i]->size = be32_to_cpup(p++);
713769b01eaSDan Carpenter if (fl->fh_array[i]->size > NFS_MAXFHSIZE) {
714b5968725STom Haynes printk(KERN_ERR "NFS: Too big fh %d received %d\n",
715b5968725STom Haynes i, fl->fh_array[i]->size);
7163ec0c979SKinglong Mee goto out_err;
717b5968725STom Haynes }
718b5968725STom Haynes
719b5968725STom Haynes p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
720b5968725STom Haynes if (unlikely(!p))
7213ec0c979SKinglong Mee goto out_err;
722b5968725STom Haynes memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
723b5968725STom Haynes dprintk("DEBUG: %s: fh len %d\n", __func__,
724b5968725STom Haynes fl->fh_array[i]->size);
725b5968725STom Haynes }
726b5968725STom Haynes
727b5968725STom Haynes __free_page(scratch);
728b5968725STom Haynes return 0;
729b5968725STom Haynes
730b5968725STom Haynes out_err:
731b5968725STom Haynes __free_page(scratch);
732b5968725STom Haynes return -EIO;
733b5968725STom Haynes }
734b5968725STom Haynes
735b5968725STom Haynes static void
filelayout_free_lseg(struct pnfs_layout_segment * lseg)736b5968725STom Haynes filelayout_free_lseg(struct pnfs_layout_segment *lseg)
737b5968725STom Haynes {
738b5968725STom Haynes struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
739b5968725STom Haynes
740b5968725STom Haynes dprintk("--> %s\n", __func__);
7410a47df11SScott Mayhew if (fl->dsaddr != NULL)
742b5968725STom Haynes nfs4_fl_put_deviceid(fl->dsaddr);
743b5968725STom Haynes /* This assumes a single RW lseg */
744b5968725STom Haynes if (lseg->pls_range.iomode == IOMODE_RW) {
745b5968725STom Haynes struct nfs4_filelayout *flo;
746a9901899STrond Myklebust struct inode *inode;
747b5968725STom Haynes
748b5968725STom Haynes flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
749a9901899STrond Myklebust inode = flo->generic_hdr.plh_inode;
750a9901899STrond Myklebust spin_lock(&inode->i_lock);
751a9901899STrond Myklebust pnfs_generic_ds_cinfo_release_lseg(&flo->commit_info, lseg);
752a9901899STrond Myklebust spin_unlock(&inode->i_lock);
753b5968725STom Haynes }
754b5968725STom Haynes _filelayout_free_lseg(fl);
755b5968725STom Haynes }
756b5968725STom Haynes
757b5968725STom Haynes static struct pnfs_layout_segment *
filelayout_alloc_lseg(struct pnfs_layout_hdr * layoutid,struct nfs4_layoutget_res * lgr,gfp_t gfp_flags)758b5968725STom Haynes filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
759b5968725STom Haynes struct nfs4_layoutget_res *lgr,
760b5968725STom Haynes gfp_t gfp_flags)
761b5968725STom Haynes {
762b5968725STom Haynes struct nfs4_filelayout_segment *fl;
763b5968725STom Haynes int rc;
764b5968725STom Haynes
765b5968725STom Haynes dprintk("--> %s\n", __func__);
766b5968725STom Haynes fl = kzalloc(sizeof(*fl), gfp_flags);
767b5968725STom Haynes if (!fl)
768b5968725STom Haynes return NULL;
769b5968725STom Haynes
770629dc870SAndy Adamson rc = filelayout_decode_layout(layoutid, fl, lgr, gfp_flags);
771629dc870SAndy Adamson if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, gfp_flags)) {
772b5968725STom Haynes _filelayout_free_lseg(fl);
773b5968725STom Haynes return NULL;
774b5968725STom Haynes }
775b5968725STom Haynes return &fl->generic_hdr;
776b5968725STom Haynes }
777b5968725STom Haynes
778a6b9d2faSOlga Kornievskaia static bool
filelayout_lseg_is_striped(const struct nfs4_filelayout_segment * flseg)779a6b9d2faSOlga Kornievskaia filelayout_lseg_is_striped(const struct nfs4_filelayout_segment *flseg)
780a6b9d2faSOlga Kornievskaia {
781a6b9d2faSOlga Kornievskaia return flseg->num_fh > 1;
782a6b9d2faSOlga Kornievskaia }
783a6b9d2faSOlga Kornievskaia
784b5968725STom Haynes /*
785b5968725STom Haynes * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
786b5968725STom Haynes *
787b5968725STom Haynes * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
788b5968725STom Haynes * of bytes (maximum @req->wb_bytes) that can be coalesced.
789b5968725STom Haynes */
790b5968725STom Haynes static size_t
filelayout_pg_test(struct nfs_pageio_descriptor * pgio,struct nfs_page * prev,struct nfs_page * req)791b5968725STom Haynes filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
792b5968725STom Haynes struct nfs_page *req)
793b5968725STom Haynes {
794b5968725STom Haynes unsigned int size;
795b5968725STom Haynes u64 p_stripe, r_stripe;
796b5968725STom Haynes u32 stripe_offset;
797b5968725STom Haynes u64 segment_offset = pgio->pg_lseg->pls_range.offset;
798b5968725STom Haynes u32 stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
799b5968725STom Haynes
800b5968725STom Haynes /* calls nfs_generic_pg_test */
801b5968725STom Haynes size = pnfs_generic_pg_test(pgio, prev, req);
802b5968725STom Haynes if (!size)
803b5968725STom Haynes return 0;
804a6b9d2faSOlga Kornievskaia else if (!filelayout_lseg_is_striped(FILELAYOUT_LSEG(pgio->pg_lseg)))
805a6b9d2faSOlga Kornievskaia return size;
806b5968725STom Haynes
807b5968725STom Haynes /* see if req and prev are in the same stripe */
808b5968725STom Haynes if (prev) {
809b5968725STom Haynes p_stripe = (u64)req_offset(prev) - segment_offset;
810b5968725STom Haynes r_stripe = (u64)req_offset(req) - segment_offset;
811b5968725STom Haynes do_div(p_stripe, stripe_unit);
812b5968725STom Haynes do_div(r_stripe, stripe_unit);
813b5968725STom Haynes
814b5968725STom Haynes if (p_stripe != r_stripe)
815b5968725STom Haynes return 0;
816b5968725STom Haynes }
817b5968725STom Haynes
818b5968725STom Haynes /* calculate remaining bytes in the current stripe */
819b5968725STom Haynes div_u64_rem((u64)req_offset(req) - segment_offset,
820b5968725STom Haynes stripe_unit,
821b5968725STom Haynes &stripe_offset);
822b5968725STom Haynes WARN_ON_ONCE(stripe_offset > stripe_unit);
823b5968725STom Haynes if (stripe_offset >= stripe_unit)
824b5968725STom Haynes return 0;
825b5968725STom Haynes return min(stripe_unit - (unsigned int)stripe_offset, size);
826b5968725STom Haynes }
827b5968725STom Haynes
8288d40b0f1SAndy Adamson static struct pnfs_layout_segment *
fl_pnfs_update_layout(struct inode * ino,struct nfs_open_context * ctx,loff_t pos,u64 count,enum pnfs_iomode iomode,bool strict_iomode,gfp_t gfp_flags)8298d40b0f1SAndy Adamson fl_pnfs_update_layout(struct inode *ino,
8308d40b0f1SAndy Adamson struct nfs_open_context *ctx,
8318d40b0f1SAndy Adamson loff_t pos,
8328d40b0f1SAndy Adamson u64 count,
8338d40b0f1SAndy Adamson enum pnfs_iomode iomode,
8348d40b0f1SAndy Adamson bool strict_iomode,
8358d40b0f1SAndy Adamson gfp_t gfp_flags)
8368d40b0f1SAndy Adamson {
8378d40b0f1SAndy Adamson struct pnfs_layout_segment *lseg = NULL;
8388d40b0f1SAndy Adamson struct pnfs_layout_hdr *lo;
8398d40b0f1SAndy Adamson struct nfs4_filelayout_segment *fl;
8408d40b0f1SAndy Adamson int status;
8418d40b0f1SAndy Adamson
8428d40b0f1SAndy Adamson lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
8438d40b0f1SAndy Adamson gfp_flags);
844126966ddSTrond Myklebust if (IS_ERR(lseg)) {
845126966ddSTrond Myklebust /* Fall back to MDS on recoverable errors */
846126966ddSTrond Myklebust if (!nfs_error_is_fatal_on_server(PTR_ERR(lseg)))
847126966ddSTrond Myklebust lseg = NULL;
848126966ddSTrond Myklebust goto out;
849126966ddSTrond Myklebust } else if (!lseg)
8508d40b0f1SAndy Adamson goto out;
8518d40b0f1SAndy Adamson
8528d40b0f1SAndy Adamson lo = NFS_I(ino)->layout;
8538d40b0f1SAndy Adamson fl = FILELAYOUT_LSEG(lseg);
8548d40b0f1SAndy Adamson
8558d40b0f1SAndy Adamson status = filelayout_check_deviceid(lo, fl, gfp_flags);
856209aa230SArtem Savkov if (status) {
85728d4411fSOlga Kornievskaia pnfs_error_mark_layout_for_return(ino, lseg);
85828d4411fSOlga Kornievskaia pnfs_set_lo_fail(lseg);
8598d40b0f1SAndy Adamson pnfs_put_lseg(lseg);
860b1029c9bSOlga Kornievskaia lseg = NULL;
861209aa230SArtem Savkov }
862209aa230SArtem Savkov out:
8638d40b0f1SAndy Adamson return lseg;
8648d40b0f1SAndy Adamson }
8658d40b0f1SAndy Adamson
866b5968725STom Haynes static void
filelayout_pg_init_read(struct nfs_pageio_descriptor * pgio,struct nfs_page * req)867b5968725STom Haynes filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
868b5968725STom Haynes struct nfs_page *req)
869b5968725STom Haynes {
870a01b077aSOlga Kornievskaia pnfs_generic_pg_check_layout(pgio, req);
871d600ad1fSPeng Tao if (!pgio->pg_lseg) {
8728d40b0f1SAndy Adamson pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
8739fcd5960STrond Myklebust nfs_req_openctx(req),
874464b424fSAnna Schumaker req_offset(req),
875464b424fSAnna Schumaker req->wb_bytes,
876b5968725STom Haynes IOMODE_READ,
877c7d73af2STom Haynes false,
8783ebcb246SOlga Kornievskaia nfs_io_gfp_mask());
879d600ad1fSPeng Tao if (IS_ERR(pgio->pg_lseg)) {
880d600ad1fSPeng Tao pgio->pg_error = PTR_ERR(pgio->pg_lseg);
881d600ad1fSPeng Tao pgio->pg_lseg = NULL;
882d600ad1fSPeng Tao return;
883d600ad1fSPeng Tao }
884d600ad1fSPeng Tao }
885b5968725STom Haynes /* If no lseg, fall back to read through mds */
886b5968725STom Haynes if (pgio->pg_lseg == NULL)
887b5968725STom Haynes nfs_pageio_reset_read_mds(pgio);
888b5968725STom Haynes }
889b5968725STom Haynes
890b5968725STom Haynes static void
filelayout_pg_init_write(struct nfs_pageio_descriptor * pgio,struct nfs_page * req)891b5968725STom Haynes filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
892b5968725STom Haynes struct nfs_page *req)
893b5968725STom Haynes {
894a01b077aSOlga Kornievskaia pnfs_generic_pg_check_layout(pgio, req);
895d600ad1fSPeng Tao if (!pgio->pg_lseg) {
8968d40b0f1SAndy Adamson pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
8979fcd5960STrond Myklebust nfs_req_openctx(req),
898464b424fSAnna Schumaker req_offset(req),
899464b424fSAnna Schumaker req->wb_bytes,
900b5968725STom Haynes IOMODE_RW,
901c7d73af2STom Haynes false,
9023ebcb246SOlga Kornievskaia nfs_io_gfp_mask());
903d600ad1fSPeng Tao if (IS_ERR(pgio->pg_lseg)) {
904d600ad1fSPeng Tao pgio->pg_error = PTR_ERR(pgio->pg_lseg);
905d600ad1fSPeng Tao pgio->pg_lseg = NULL;
906d600ad1fSPeng Tao return;
907d600ad1fSPeng Tao }
908d600ad1fSPeng Tao }
909d600ad1fSPeng Tao
910b5968725STom Haynes /* If no lseg, fall back to write through mds */
911b5968725STom Haynes if (pgio->pg_lseg == NULL)
912b5968725STom Haynes nfs_pageio_reset_write_mds(pgio);
913b5968725STom Haynes }
914b5968725STom Haynes
915b5968725STom Haynes static const struct nfs_pageio_ops filelayout_pg_read_ops = {
916b5968725STom Haynes .pg_init = filelayout_pg_init_read,
917b5968725STom Haynes .pg_test = filelayout_pg_test,
918b5968725STom Haynes .pg_doio = pnfs_generic_pg_readpages,
919180bb5ecSWeston Andros Adamson .pg_cleanup = pnfs_generic_pg_cleanup,
920b5968725STom Haynes };
921b5968725STom Haynes
922b5968725STom Haynes static const struct nfs_pageio_ops filelayout_pg_write_ops = {
923b5968725STom Haynes .pg_init = filelayout_pg_init_write,
924b5968725STom Haynes .pg_test = filelayout_pg_test,
925b5968725STom Haynes .pg_doio = pnfs_generic_pg_writepages,
926180bb5ecSWeston Andros Adamson .pg_cleanup = pnfs_generic_pg_cleanup,
927b5968725STom Haynes };
928b5968725STom Haynes
select_bucket_index(struct nfs4_filelayout_segment * fl,u32 j)929b5968725STom Haynes static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
930b5968725STom Haynes {
931b5968725STom Haynes if (fl->stripe_type == STRIPE_SPARSE)
932b5968725STom Haynes return nfs4_fl_calc_ds_index(&fl->generic_hdr, j);
933b5968725STom Haynes else
934b5968725STom Haynes return j;
935b5968725STom Haynes }
936b5968725STom Haynes
937c8a3292dSPeng Tao static void
filelayout_mark_request_commit(struct nfs_page * req,struct pnfs_layout_segment * lseg,struct nfs_commit_info * cinfo,u32 ds_commit_idx)938c8a3292dSPeng Tao filelayout_mark_request_commit(struct nfs_page *req,
939b5968725STom Haynes struct pnfs_layout_segment *lseg,
940b57ff130SWeston Andros Adamson struct nfs_commit_info *cinfo,
941b57ff130SWeston Andros Adamson u32 ds_commit_idx)
942c8a3292dSPeng Tao
943b5968725STom Haynes {
944b5968725STom Haynes struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
945b5968725STom Haynes u32 i, j;
946b5968725STom Haynes
947c8a3292dSPeng Tao if (fl->commit_through_mds) {
9486272dcc6SAnna Schumaker nfs_request_add_commit_list(req, cinfo);
949338d00cfSTom Haynes } else {
950b5968725STom Haynes /* Note that we are calling nfs4_fl_calc_j_index on each page
951b5968725STom Haynes * that ends up being committed to a data server. An attractive
952b5968725STom Haynes * alternative is to add a field to nfs_write_data and nfs_page
953b5968725STom Haynes * to store the value calculated in filelayout_write_pagelist
954b5968725STom Haynes * and just use that here.
955b5968725STom Haynes */
956b5968725STom Haynes j = nfs4_fl_calc_j_index(lseg, req_offset(req));
957b5968725STom Haynes i = select_bucket_index(fl, j);
958338d00cfSTom Haynes pnfs_layout_mark_request_commit(req, lseg, cinfo, i);
959b5968725STom Haynes }
960b5968725STom Haynes }
961b5968725STom Haynes
calc_ds_index_from_commit(struct pnfs_layout_segment * lseg,u32 i)962b5968725STom Haynes static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
963b5968725STom Haynes {
964b5968725STom Haynes struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
965b5968725STom Haynes
966b5968725STom Haynes if (flseg->stripe_type == STRIPE_SPARSE)
967b5968725STom Haynes return i;
968b5968725STom Haynes else
969b5968725STom Haynes return nfs4_fl_calc_ds_index(lseg, i);
970b5968725STom Haynes }
971b5968725STom Haynes
972b5968725STom Haynes static struct nfs_fh *
select_ds_fh_from_commit(struct pnfs_layout_segment * lseg,u32 i)973b5968725STom Haynes select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
974b5968725STom Haynes {
975b5968725STom Haynes struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
976b5968725STom Haynes
977b5968725STom Haynes if (flseg->stripe_type == STRIPE_SPARSE) {
978b5968725STom Haynes if (flseg->num_fh == 1)
979b5968725STom Haynes i = 0;
980b5968725STom Haynes else if (flseg->num_fh == 0)
981b5968725STom Haynes /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
982b5968725STom Haynes return NULL;
983b5968725STom Haynes }
984b5968725STom Haynes return flseg->fh_array[i];
985b5968725STom Haynes }
986b5968725STom Haynes
filelayout_initiate_commit(struct nfs_commit_data * data,int how)987b5968725STom Haynes static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
988b5968725STom Haynes {
989b5968725STom Haynes struct pnfs_layout_segment *lseg = data->lseg;
990b5968725STom Haynes struct nfs4_pnfs_ds *ds;
991b5968725STom Haynes struct rpc_clnt *ds_clnt;
992b5968725STom Haynes u32 idx;
993b5968725STom Haynes struct nfs_fh *fh;
994b5968725STom Haynes
995b5968725STom Haynes idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
996b5968725STom Haynes ds = nfs4_fl_prepare_ds(lseg, idx);
997b5968725STom Haynes if (!ds)
998b5968725STom Haynes goto out_err;
999b5968725STom Haynes
1000b5968725STom Haynes ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, data->inode);
1001b5968725STom Haynes if (IS_ERR(ds_clnt))
1002b5968725STom Haynes goto out_err;
1003b5968725STom Haynes
1004b5968725STom Haynes dprintk("%s ino %lu, how %d cl_count %d\n", __func__,
1005212bf41dSElena Reshetova data->inode->i_ino, how, refcount_read(&ds->ds_clp->cl_count));
1006b5968725STom Haynes data->commit_done_cb = filelayout_commit_done_cb;
1007212bf41dSElena Reshetova refcount_inc(&ds->ds_clp->cl_count);
1008b5968725STom Haynes data->ds_clp = ds->ds_clp;
1009b5968725STom Haynes fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
1010b5968725STom Haynes if (fh)
1011b5968725STom Haynes data->args.fh = fh;
1012c36aae9aSPeng Tao return nfs_initiate_commit(ds_clnt, data, NFS_PROTO(data->inode),
1013b5968725STom Haynes &filelayout_commit_call_ops, how,
1014*df24c483SMike Snitzer RPC_TASK_SOFTCONN, NULL);
1015b5968725STom Haynes out_err:
1016f54bcf2eSTom Haynes pnfs_generic_prepare_to_resend_writes(data);
1017f54bcf2eSTom Haynes pnfs_generic_commit_release(data);
1018b5968725STom Haynes return -EAGAIN;
1019b5968725STom Haynes }
1020b5968725STom Haynes
1021b5968725STom Haynes static int
filelayout_commit_pagelist(struct inode * inode,struct list_head * mds_pages,int how,struct nfs_commit_info * cinfo)1022b5968725STom Haynes filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
1023b5968725STom Haynes int how, struct nfs_commit_info *cinfo)
1024b5968725STom Haynes {
1025f54bcf2eSTom Haynes return pnfs_generic_commit_pagelist(inode, mds_pages, how, cinfo,
1026f54bcf2eSTom Haynes filelayout_initiate_commit);
1027b5968725STom Haynes }
1028b5968725STom Haynes
1029661373b1SChristoph Hellwig static struct nfs4_deviceid_node *
filelayout_alloc_deviceid_node(struct nfs_server * server,struct pnfs_device * pdev,gfp_t gfp_flags)1030661373b1SChristoph Hellwig filelayout_alloc_deviceid_node(struct nfs_server *server,
1031661373b1SChristoph Hellwig struct pnfs_device *pdev, gfp_t gfp_flags)
1032661373b1SChristoph Hellwig {
1033661373b1SChristoph Hellwig struct nfs4_file_layout_dsaddr *dsaddr;
1034661373b1SChristoph Hellwig
1035661373b1SChristoph Hellwig dsaddr = nfs4_fl_alloc_deviceid_node(server, pdev, gfp_flags);
1036661373b1SChristoph Hellwig if (!dsaddr)
1037661373b1SChristoph Hellwig return NULL;
1038661373b1SChristoph Hellwig return &dsaddr->id_node;
1039661373b1SChristoph Hellwig }
1040b5968725STom Haynes
1041b5968725STom Haynes static void
filelayout_free_deviceid_node(struct nfs4_deviceid_node * d)1042fc87701bSTrond Myklebust filelayout_free_deviceid_node(struct nfs4_deviceid_node *d)
1043b5968725STom Haynes {
1044b5968725STom Haynes nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node));
1045b5968725STom Haynes }
1046b5968725STom Haynes
1047b5968725STom Haynes static struct pnfs_layout_hdr *
filelayout_alloc_layout_hdr(struct inode * inode,gfp_t gfp_flags)1048b5968725STom Haynes filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
1049b5968725STom Haynes {
1050b5968725STom Haynes struct nfs4_filelayout *flo;
1051b5968725STom Haynes
1052b5968725STom Haynes flo = kzalloc(sizeof(*flo), gfp_flags);
1053c21e7168STrond Myklebust if (flo == NULL)
1054c21e7168STrond Myklebust return NULL;
1055c21e7168STrond Myklebust pnfs_init_ds_commit_info(&flo->commit_info);
10569c455a8cSTrond Myklebust flo->commit_info.ops = &filelayout_commit_ops;
1057c21e7168STrond Myklebust return &flo->generic_hdr;
1058b5968725STom Haynes }
1059b5968725STom Haynes
1060b5968725STom Haynes static void
filelayout_free_layout_hdr(struct pnfs_layout_hdr * lo)1061b5968725STom Haynes filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo)
1062b5968725STom Haynes {
1063cf6605d1STrond Myklebust kfree_rcu(FILELAYOUT_FROM_HDR(lo), generic_hdr.plh_rcu);
1064b5968725STom Haynes }
1065b5968725STom Haynes
1066b5968725STom Haynes static struct pnfs_ds_commit_info *
filelayout_get_ds_info(struct inode * inode)1067b5968725STom Haynes filelayout_get_ds_info(struct inode *inode)
1068b5968725STom Haynes {
1069b5968725STom Haynes struct pnfs_layout_hdr *layout = NFS_I(inode)->layout;
1070b5968725STom Haynes
1071b5968725STom Haynes if (layout == NULL)
1072b5968725STom Haynes return NULL;
1073b5968725STom Haynes else
1074b5968725STom Haynes return &FILELAYOUT_FROM_HDR(layout)->commit_info;
1075b5968725STom Haynes }
1076b5968725STom Haynes
1077a9901899STrond Myklebust static void
filelayout_setup_ds_info(struct pnfs_ds_commit_info * fl_cinfo,struct pnfs_layout_segment * lseg)1078ba827c9aSTrond Myklebust filelayout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
1079ba827c9aSTrond Myklebust struct pnfs_layout_segment *lseg)
1080ba827c9aSTrond Myklebust {
1081ba827c9aSTrond Myklebust struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
1082ba827c9aSTrond Myklebust struct inode *inode = lseg->pls_layout->plh_inode;
1083ba827c9aSTrond Myklebust struct pnfs_commit_array *array, *new;
1084ba827c9aSTrond Myklebust unsigned int size = (fl->stripe_type == STRIPE_SPARSE) ?
1085ba827c9aSTrond Myklebust fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
1086ba827c9aSTrond Myklebust
1087a245832aSTrond Myklebust new = pnfs_alloc_commit_array(size, nfs_io_gfp_mask());
1088ba827c9aSTrond Myklebust if (new) {
1089ba827c9aSTrond Myklebust spin_lock(&inode->i_lock);
1090ba827c9aSTrond Myklebust array = pnfs_add_commit_array(fl_cinfo, new, lseg);
1091ba827c9aSTrond Myklebust spin_unlock(&inode->i_lock);
1092ba827c9aSTrond Myklebust if (array != new)
1093ba827c9aSTrond Myklebust pnfs_free_commit_array(new);
1094ba827c9aSTrond Myklebust }
1095ba827c9aSTrond Myklebust }
1096ba827c9aSTrond Myklebust
1097ba827c9aSTrond Myklebust static void
filelayout_release_ds_info(struct pnfs_ds_commit_info * fl_cinfo,struct inode * inode)1098a9901899STrond Myklebust filelayout_release_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
1099a9901899STrond Myklebust struct inode *inode)
1100a9901899STrond Myklebust {
1101a9901899STrond Myklebust spin_lock(&inode->i_lock);
1102a9901899STrond Myklebust pnfs_generic_ds_cinfo_destroy(fl_cinfo);
1103a9901899STrond Myklebust spin_unlock(&inode->i_lock);
1104a9901899STrond Myklebust }
1105a9901899STrond Myklebust
11069c455a8cSTrond Myklebust static const struct pnfs_commit_ops filelayout_commit_ops = {
11079c455a8cSTrond Myklebust .setup_ds_info = filelayout_setup_ds_info,
11089c455a8cSTrond Myklebust .release_ds_info = filelayout_release_ds_info,
11099c455a8cSTrond Myklebust .mark_request_commit = filelayout_mark_request_commit,
11109c455a8cSTrond Myklebust .clear_request_commit = pnfs_generic_clear_request_commit,
11119c455a8cSTrond Myklebust .scan_commit_lists = pnfs_generic_scan_commit_lists,
11129c455a8cSTrond Myklebust .recover_commit_reqs = pnfs_generic_recover_commit_reqs,
11139c455a8cSTrond Myklebust .commit_pagelist = filelayout_commit_pagelist,
11149c455a8cSTrond Myklebust };
1115a9901899STrond Myklebust
1116b5968725STom Haynes static struct pnfs_layoutdriver_type filelayout_type = {
1117b5968725STom Haynes .id = LAYOUT_NFSV4_1_FILES,
1118b5968725STom Haynes .name = "LAYOUT_NFSV4_1_FILES",
1119b5968725STom Haynes .owner = THIS_MODULE,
1120a8fd0feeSOlga Kornievskaia .flags = PNFS_LAYOUTGET_ON_OPEN,
112128ced9a8STrond Myklebust .max_layoutget_response = 4096, /* 1 page or so... */
1122b5968725STom Haynes .alloc_layout_hdr = filelayout_alloc_layout_hdr,
1123b5968725STom Haynes .free_layout_hdr = filelayout_free_layout_hdr,
1124b5968725STom Haynes .alloc_lseg = filelayout_alloc_lseg,
1125b5968725STom Haynes .free_lseg = filelayout_free_lseg,
1126b5968725STom Haynes .pg_read_ops = &filelayout_pg_read_ops,
1127b5968725STom Haynes .pg_write_ops = &filelayout_pg_write_ops,
1128b5968725STom Haynes .get_ds_info = &filelayout_get_ds_info,
1129b5968725STom Haynes .read_pagelist = filelayout_read_pagelist,
1130b5968725STom Haynes .write_pagelist = filelayout_write_pagelist,
1131661373b1SChristoph Hellwig .alloc_deviceid_node = filelayout_alloc_deviceid_node,
1132fc87701bSTrond Myklebust .free_deviceid_node = filelayout_free_deviceid_node,
11335bb89b47STrond Myklebust .sync = pnfs_nfs_generic_sync,
1134b5968725STom Haynes };
1135b5968725STom Haynes
nfs4filelayout_init(void)1136b5968725STom Haynes static int __init nfs4filelayout_init(void)
1137b5968725STom Haynes {
1138b5968725STom Haynes printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
1139b5968725STom Haynes __func__);
1140b5968725STom Haynes return pnfs_register_layoutdriver(&filelayout_type);
1141b5968725STom Haynes }
1142b5968725STom Haynes
nfs4filelayout_exit(void)1143b5968725STom Haynes static void __exit nfs4filelayout_exit(void)
1144b5968725STom Haynes {
1145b5968725STom Haynes printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
1146b5968725STom Haynes __func__);
1147b5968725STom Haynes pnfs_unregister_layoutdriver(&filelayout_type);
1148b5968725STom Haynes }
1149b5968725STom Haynes
1150b5968725STom Haynes MODULE_ALIAS("nfs-layouttype4-1");
1151b5968725STom Haynes
1152b5968725STom Haynes module_init(nfs4filelayout_init);
1153b5968725STom Haynes module_exit(nfs4filelayout_exit);
1154