xref: /linux/fs/nfs/filelayout/filelayout.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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