xref: /linux/fs/nfs/flexfilelayout/flexfilelayoutdev.c (revision 73e3f0710014fe6d4ed98cfc02292f6121db7558)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Device operations for the pnfs nfs4 file layout driver.
4  *
5  * Copyright (c) 2014, Primary Data, Inc. All rights reserved.
6  *
7  * Tao Peng <bergwolf@primarydata.com>
8  */
9 
10 #include <linux/nfs_fs.h>
11 #include <linux/vmalloc.h>
12 #include <linux/module.h>
13 #include <linux/sunrpc/addr.h>
14 
15 #include "../internal.h"
16 #include "../nfs4session.h"
17 #include "flexfilelayout.h"
18 
19 #define NFSDBG_FACILITY		NFSDBG_PNFS_LD
20 
21 static unsigned int dataserver_timeo = NFS_DEF_TCP_TIMEO;
22 static unsigned int dataserver_retrans;
23 
24 static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg);
25 
nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds * mirror_ds)26 void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds)
27 {
28 	if (!IS_ERR_OR_NULL(mirror_ds))
29 		nfs4_put_deviceid_node(&mirror_ds->id_node);
30 }
31 
nfs4_ff_layout_free_deviceid(struct nfs4_ff_layout_ds * mirror_ds)32 void nfs4_ff_layout_free_deviceid(struct nfs4_ff_layout_ds *mirror_ds)
33 {
34 	nfs4_print_deviceid(&mirror_ds->id_node.deviceid);
35 	nfs4_pnfs_ds_put(mirror_ds->ds);
36 	kfree(mirror_ds->ds_versions);
37 	kfree_rcu(mirror_ds, id_node.rcu);
38 }
39 
40 /* Decode opaque device data and construct new_ds using it */
41 struct nfs4_ff_layout_ds *
nfs4_ff_alloc_deviceid_node(struct nfs_server * server,struct pnfs_device * pdev,gfp_t gfp_flags)42 nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
43 			    gfp_t gfp_flags)
44 {
45 	struct xdr_stream stream;
46 	struct xdr_buf buf;
47 	struct folio *scratch;
48 	struct list_head dsaddrs;
49 	struct nfs4_pnfs_ds_addr *da;
50 	struct nfs4_ff_layout_ds *new_ds = NULL;
51 	struct nfs4_ff_ds_version *ds_versions = NULL;
52 	struct net *net = server->nfs_client->cl_net;
53 	u32 mp_count;
54 	u32 version_count;
55 	__be32 *p;
56 	int i, ret = -ENOMEM;
57 
58 	/* set up xdr stream */
59 	scratch = folio_alloc(gfp_flags, 0);
60 	if (!scratch)
61 		goto out_err;
62 
63 	new_ds = kzalloc_obj(struct nfs4_ff_layout_ds, gfp_flags);
64 	if (!new_ds)
65 		goto out_scratch;
66 
67 	nfs4_init_deviceid_node(&new_ds->id_node,
68 				server,
69 				&pdev->dev_id);
70 	INIT_LIST_HEAD(&dsaddrs);
71 
72 	xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
73 	xdr_set_scratch_folio(&stream, scratch);
74 
75 	/* multipath count */
76 	p = xdr_inline_decode(&stream, 4);
77 	if (unlikely(!p))
78 		goto out_err_drain_dsaddrs;
79 	mp_count = be32_to_cpup(p);
80 	dprintk("%s: multipath ds count %d\n", __func__, mp_count);
81 
82 	for (i = 0; i < mp_count; i++) {
83 		/* multipath ds */
84 		da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags);
85 		if (da)
86 			list_add_tail(&da->da_node, &dsaddrs);
87 	}
88 	if (list_empty(&dsaddrs)) {
89 		dprintk("%s: no suitable DS addresses found\n",
90 			__func__);
91 		ret = -ENOMEDIUM;
92 		goto out_err_drain_dsaddrs;
93 	}
94 
95 	/* version count */
96 	p = xdr_inline_decode(&stream, 4);
97 	if (unlikely(!p))
98 		goto out_err_drain_dsaddrs;
99 	version_count = be32_to_cpup(p);
100 
101 	if (version_count == 0) {
102 		ret = -EINVAL;
103 		goto out_err_drain_dsaddrs;
104 	}
105 	dprintk("%s: version count %d\n", __func__, version_count);
106 
107 	ds_versions = kzalloc_objs(struct nfs4_ff_ds_version, version_count,
108 				   gfp_flags);
109 	if (!ds_versions)
110 		goto out_err_drain_dsaddrs;
111 
112 	for (i = 0; i < version_count; i++) {
113 		/* 20 = version(4) + minor_version(4) + rsize(4) + wsize(4) +
114 		 * tightly_coupled(4) */
115 		p = xdr_inline_decode(&stream, 20);
116 		if (unlikely(!p))
117 			goto out_err_drain_dsaddrs;
118 		ds_versions[i].version = be32_to_cpup(p++);
119 		ds_versions[i].minor_version = be32_to_cpup(p++);
120 		ds_versions[i].rsize = nfs_io_size(be32_to_cpup(p++),
121 						   server->nfs_client->cl_proto);
122 		ds_versions[i].wsize = nfs_io_size(be32_to_cpup(p++),
123 						   server->nfs_client->cl_proto);
124 		ds_versions[i].tightly_coupled = be32_to_cpup(p);
125 
126 		if (ds_versions[i].rsize > NFS_MAX_FILE_IO_SIZE)
127 			ds_versions[i].rsize = NFS_MAX_FILE_IO_SIZE;
128 		if (ds_versions[i].wsize > NFS_MAX_FILE_IO_SIZE)
129 			ds_versions[i].wsize = NFS_MAX_FILE_IO_SIZE;
130 
131 		/*
132 		 * check for valid major/minor combination.
133 		 * currently we support dataserver which talk:
134 		 *   v3, v4.0, v4.1, v4.2
135 		 */
136 		if (!((ds_versions[i].version == 3 && ds_versions[i].minor_version == 0) ||
137 			(ds_versions[i].version == 4 && ds_versions[i].minor_version < 3))) {
138 			dprintk("%s: [%d] unsupported ds version %d-%d\n", __func__,
139 				i, ds_versions[i].version,
140 				ds_versions[i].minor_version);
141 			ret = -EPROTONOSUPPORT;
142 			goto out_err_drain_dsaddrs;
143 		}
144 
145 		dprintk("%s: [%d] vers %u minor_ver %u rsize %u wsize %u coupled %d\n",
146 			__func__, i, ds_versions[i].version,
147 			ds_versions[i].minor_version,
148 			ds_versions[i].rsize,
149 			ds_versions[i].wsize,
150 			ds_versions[i].tightly_coupled);
151 	}
152 
153 	new_ds->ds_versions = ds_versions;
154 	new_ds->ds_versions_cnt = version_count;
155 
156 	new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, ds_versions[0].version,
157 				      gfp_flags);
158 	if (!new_ds->ds)
159 		goto out_err_drain_dsaddrs;
160 
161 	/* If DS was already in cache, free ds addrs */
162 	while (!list_empty(&dsaddrs)) {
163 		da = list_first_entry(&dsaddrs,
164 				      struct nfs4_pnfs_ds_addr,
165 				      da_node);
166 		list_del_init(&da->da_node);
167 		kfree(da->da_remotestr);
168 		kfree(da);
169 	}
170 
171 	folio_put(scratch);
172 	return new_ds;
173 
174 out_err_drain_dsaddrs:
175 	while (!list_empty(&dsaddrs)) {
176 		da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
177 				      da_node);
178 		list_del_init(&da->da_node);
179 		kfree(da->da_remotestr);
180 		kfree(da);
181 	}
182 
183 	kfree(ds_versions);
184 out_scratch:
185 	folio_put(scratch);
186 out_err:
187 	kfree(new_ds);
188 
189 	dprintk("%s ERROR: returning %d\n", __func__, ret);
190 	return NULL;
191 }
192 
extend_ds_error(struct nfs4_ff_layout_ds_err * err,u64 offset,u64 length)193 static void extend_ds_error(struct nfs4_ff_layout_ds_err *err,
194 			    u64 offset, u64 length)
195 {
196 	u64 end;
197 
198 	end = max_t(u64, pnfs_end_offset(err->offset, err->length),
199 		    pnfs_end_offset(offset, length));
200 	err->offset = min_t(u64, err->offset, offset);
201 	err->length = end - err->offset;
202 }
203 
204 static int
ff_ds_error_match(const struct nfs4_ff_layout_ds_err * e1,const struct nfs4_ff_layout_ds_err * e2)205 ff_ds_error_match(const struct nfs4_ff_layout_ds_err *e1,
206 		const struct nfs4_ff_layout_ds_err *e2)
207 {
208 	int ret;
209 
210 	if (e1->opnum != e2->opnum)
211 		return e1->opnum < e2->opnum ? -1 : 1;
212 	if (e1->status != e2->status)
213 		return e1->status < e2->status ? -1 : 1;
214 	ret = memcmp(e1->stateid.data, e2->stateid.data,
215 			sizeof(e1->stateid.data));
216 	if (ret != 0)
217 		return ret;
218 	ret = memcmp(&e1->deviceid, &e2->deviceid, sizeof(e1->deviceid));
219 	if (ret != 0)
220 		return ret;
221 	if (pnfs_end_offset(e1->offset, e1->length) < e2->offset)
222 		return -1;
223 	if (e1->offset > pnfs_end_offset(e2->offset, e2->length))
224 		return 1;
225 	/* If ranges overlap or are contiguous, they are the same */
226 	return 0;
227 }
228 
229 static void
ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout * flo,struct nfs4_ff_layout_ds_err * dserr)230 ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout *flo,
231 			      struct nfs4_ff_layout_ds_err *dserr)
232 {
233 	struct nfs4_ff_layout_ds_err *err, *tmp;
234 	struct list_head *head = &flo->error_list;
235 	int match;
236 
237 	/* Do insertion sort w/ merges */
238 	list_for_each_entry_safe(err, tmp, &flo->error_list, list) {
239 		match = ff_ds_error_match(err, dserr);
240 		if (match < 0)
241 			continue;
242 		if (match > 0) {
243 			/* Add entry "dserr" _before_ entry "err" */
244 			head = &err->list;
245 			break;
246 		}
247 		/* Entries match, so merge "err" into "dserr" */
248 		extend_ds_error(dserr, err->offset, err->length);
249 		list_replace(&err->list, &dserr->list);
250 		kfree(err);
251 		return;
252 	}
253 
254 	list_add_tail(&dserr->list, head);
255 }
256 
ff_layout_track_ds_error(struct nfs4_flexfile_layout * flo,struct nfs4_ff_layout_mirror * mirror,u32 dss_id,u64 offset,u64 length,int status,enum nfs_opnum4 opnum,gfp_t gfp_flags)257 int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
258 			     struct nfs4_ff_layout_mirror *mirror,
259 			     u32 dss_id, u64 offset, u64 length, int status,
260 			     enum nfs_opnum4 opnum, gfp_t gfp_flags)
261 {
262 	struct nfs4_ff_layout_ds_err *dserr;
263 
264 	if (status == 0)
265 		return 0;
266 
267 	if (IS_ERR_OR_NULL(mirror->dss[dss_id].mirror_ds))
268 		return -EINVAL;
269 
270 	dserr = kmalloc_obj(*dserr, gfp_flags);
271 	if (!dserr)
272 		return -ENOMEM;
273 
274 	INIT_LIST_HEAD(&dserr->list);
275 	dserr->offset = offset;
276 	dserr->length = length;
277 	dserr->status = status;
278 	dserr->opnum = opnum;
279 	nfs4_stateid_copy(&dserr->stateid, &mirror->dss[dss_id].stateid);
280 	memcpy(&dserr->deviceid, &mirror->dss[dss_id].mirror_ds->id_node.deviceid,
281 	       NFS4_DEVICEID4_SIZE);
282 
283 	spin_lock(&flo->generic_hdr.plh_inode->i_lock);
284 	ff_layout_add_ds_error_locked(flo, dserr);
285 	spin_unlock(&flo->generic_hdr.plh_inode->i_lock);
286 	return 0;
287 }
288 
289 static const struct cred *
ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror * mirror,u32 iomode,u32 dss_id)290 ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode, u32 dss_id)
291 {
292 	const struct cred *cred, __rcu **pcred;
293 
294 	if (iomode == IOMODE_READ)
295 		pcred = &mirror->dss[dss_id].ro_cred;
296 	else
297 		pcred = &mirror->dss[dss_id].rw_cred;
298 
299 	rcu_read_lock();
300 	do {
301 		cred = rcu_dereference(*pcred);
302 		if (!cred)
303 			break;
304 
305 		cred = get_cred_rcu(cred);
306 	} while(!cred);
307 	rcu_read_unlock();
308 	return cred;
309 }
310 
311 struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror * mirror,u32 dss_id)312 nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror, u32 dss_id)
313 {
314 	/* FIXME: For now assume there is only 1 version available for the DS */
315 	return &mirror->dss[dss_id].fh_versions[0];
316 }
317 
318 void
nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror * mirror,u32 dss_id,nfs4_stateid * stateid)319 nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror *mirror,
320 				 u32 dss_id,
321 				 nfs4_stateid *stateid)
322 {
323 	if (nfs4_ff_layout_ds_version(mirror, dss_id) == 4)
324 		nfs4_stateid_copy(stateid, &mirror->dss[dss_id].stateid);
325 }
326 
327 static bool
ff_layout_init_mirror_ds(struct pnfs_layout_hdr * lo,struct nfs4_ff_layout_mirror * mirror,u32 dss_id)328 ff_layout_init_mirror_ds(struct pnfs_layout_hdr *lo,
329 			 struct nfs4_ff_layout_mirror *mirror,
330 			 u32 dss_id)
331 {
332 	if (mirror == NULL)
333 		goto outerr;
334 	if (mirror->dss[dss_id].mirror_ds == NULL) {
335 		struct nfs4_deviceid_node *node;
336 		struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV);
337 
338 		node = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode),
339 				&mirror->dss[dss_id].devid, lo->plh_lc_cred,
340 				GFP_KERNEL);
341 		if (node)
342 			mirror_ds = FF_LAYOUT_MIRROR_DS(node);
343 
344 		/* check for race with another call to this function */
345 		if (cmpxchg(&mirror->dss[dss_id].mirror_ds, NULL, mirror_ds) &&
346 		    mirror_ds != ERR_PTR(-ENODEV))
347 			nfs4_put_deviceid_node(node);
348 	}
349 
350 	if (IS_ERR(mirror->dss[dss_id].mirror_ds))
351 		goto outerr;
352 
353 	return true;
354 outerr:
355 	return false;
356 }
357 
358 /**
359  * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
360  * @lseg: the layout segment we're operating on
361  * @mirror: layout mirror describing the DS to use
362  * @dss_id: DS stripe id to select stripe to use
363  * @fail_return: return layout on connect failure?
364  *
365  * Try to prepare a DS connection to accept an RPC call. This involves
366  * selecting a mirror to use and connecting the client to it if it's not
367  * already connected.
368  *
369  * Since we only need a single functioning mirror to satisfy a read, we don't
370  * want to return the layout if there is one. For writes though, any down
371  * mirror should result in a LAYOUTRETURN. @fail_return is how we distinguish
372  * between the two cases.
373  *
374  * Returns a pointer to a connected DS object on success or NULL on failure.
375  */
376 struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment * lseg,struct nfs4_ff_layout_mirror * mirror,u32 dss_id,bool fail_return)377 nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
378 			  struct nfs4_ff_layout_mirror *mirror,
379 			  u32 dss_id,
380 			  bool fail_return)
381 {
382 	struct nfs4_pnfs_ds *ds;
383 	struct inode *ino = lseg->pls_layout->plh_inode;
384 	struct nfs_server *s = NFS_SERVER(ino);
385 	unsigned int max_payload;
386 	int status = -EAGAIN;
387 
388 	if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror, dss_id))
389 		goto noconnect;
390 
391 	ds = mirror->dss[dss_id].mirror_ds->ds;
392 	if (READ_ONCE(ds->ds_clp))
393 		goto out;
394 	/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
395 	smp_rmb();
396 
397 	/* FIXME: For now we assume the server sent only one version of NFS
398 	 * to use for the DS.
399 	 */
400 	status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[dss_id].mirror_ds->id_node,
401 			     dataserver_timeo, dataserver_retrans,
402 			     mirror->dss[dss_id].mirror_ds->ds_versions[0].version,
403 			     mirror->dss[dss_id].mirror_ds->ds_versions[0].minor_version,
404 			     mirror->dss[dss_id].mirror_ds->ds_versions[0].tightly_coupled);
405 
406 	/* connect success, check rsize/wsize limit */
407 	if (!status) {
408 		/*
409 		 * ds_clp is put in destroy_ds().
410 		 * keep ds_clp even if DS is local, so that if local IO cannot
411 		 * proceed somehow, we can fall back to NFS whenever we want.
412 		 */
413 		nfs_local_probe_async(ds->ds_clp);
414 		max_payload =
415 			nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
416 				       NULL);
417 		if (mirror->dss[dss_id].mirror_ds->ds_versions[0].rsize > max_payload)
418 			mirror->dss[dss_id].mirror_ds->ds_versions[0].rsize = max_payload;
419 		if (mirror->dss[dss_id].mirror_ds->ds_versions[0].wsize > max_payload)
420 			mirror->dss[dss_id].mirror_ds->ds_versions[0].wsize = max_payload;
421 		goto out;
422 	}
423 noconnect:
424 	ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
425 				 mirror, dss_id, lseg->pls_range.offset,
426 				 lseg->pls_range.length, NFS4ERR_NXIO,
427 				 OP_ILLEGAL, GFP_NOIO);
428 	ff_layout_send_layouterror(lseg);
429 	if (fail_return || !ff_layout_has_available_ds(lseg))
430 		pnfs_error_mark_layout_for_return(ino, lseg);
431 	ds = ERR_PTR(status);
432 out:
433 	return ds;
434 }
435 
436 const struct cred *
ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror * mirror,const struct pnfs_layout_range * range,const struct cred * mdscred,u32 dss_id)437 ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
438 		      const struct pnfs_layout_range *range,
439 		      const struct cred *mdscred,
440 		      u32 dss_id)
441 {
442 	const struct cred *cred;
443 
444 	if (mirror && !mirror->dss[dss_id].mirror_ds->ds_versions[0].tightly_coupled) {
445 		cred = ff_layout_get_mirror_cred(mirror, range->iomode, dss_id);
446 		if (!cred)
447 			cred = get_cred(mdscred);
448 	} else {
449 		cred = get_cred(mdscred);
450 	}
451 	return cred;
452 }
453 
454 /**
455  * nfs4_ff_find_or_create_ds_client - Find or create a DS rpc client
456  * @mirror: pointer to the mirror
457  * @ds_clp: nfs_client for the DS
458  * @inode: pointer to inode
459  * @dss_id: DS stripe id
460  *
461  * Find or create a DS rpc client with th MDS server rpc client auth flavor
462  * in the nfs_client cl_ds_clients list.
463  */
464 struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror * mirror,struct nfs_client * ds_clp,struct inode * inode,u32 dss_id)465 nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
466 				 struct nfs_client *ds_clp, struct inode *inode,
467 				 u32 dss_id)
468 {
469 	switch (mirror->dss[dss_id].mirror_ds->ds_versions[0].version) {
470 	case 3:
471 		/* For NFSv3 DS, flavor is set when creating DS connections */
472 		return ds_clp->cl_rpcclient;
473 	case 4:
474 		return nfs4_find_or_create_ds_client(ds_clp, inode);
475 	default:
476 		BUG();
477 	}
478 }
479 
ff_layout_free_ds_ioerr(struct list_head * head)480 void ff_layout_free_ds_ioerr(struct list_head *head)
481 {
482 	struct nfs4_ff_layout_ds_err *err;
483 
484 	while (!list_empty(head)) {
485 		err = list_first_entry(head,
486 				struct nfs4_ff_layout_ds_err,
487 				list);
488 		list_del(&err->list);
489 		kfree(err);
490 	}
491 }
492 
493 /* called with inode i_lock held */
ff_layout_encode_ds_ioerr(struct xdr_stream * xdr,const struct list_head * head)494 int ff_layout_encode_ds_ioerr(struct xdr_stream *xdr, const struct list_head *head)
495 {
496 	struct nfs4_ff_layout_ds_err *err;
497 	__be32 *p;
498 
499 	list_for_each_entry(err, head, list) {
500 		/* offset(8) + length(8) + stateid(NFS4_STATEID_SIZE)
501 		 * + array length + deviceid(NFS4_DEVICEID4_SIZE)
502 		 * + status(4) + opnum(4)
503 		 */
504 		p = xdr_reserve_space(xdr,
505 				28 + NFS4_STATEID_SIZE + NFS4_DEVICEID4_SIZE);
506 		if (unlikely(!p))
507 			return -ENOBUFS;
508 		p = xdr_encode_hyper(p, err->offset);
509 		p = xdr_encode_hyper(p, err->length);
510 		p = xdr_encode_opaque_fixed(p, &err->stateid,
511 					    NFS4_STATEID_SIZE);
512 		/* Encode 1 error */
513 		*p++ = cpu_to_be32(1);
514 		p = xdr_encode_opaque_fixed(p, &err->deviceid,
515 					    NFS4_DEVICEID4_SIZE);
516 		*p++ = cpu_to_be32(err->status);
517 		*p++ = cpu_to_be32(err->opnum);
518 		dprintk("%s: offset %llu length %llu status %d op %d\n",
519 			__func__, err->offset, err->length, err->status,
520 			err->opnum);
521 	}
522 
523 	return 0;
524 }
525 
526 static
do_layout_fetch_ds_ioerr(struct pnfs_layout_hdr * lo,const struct pnfs_layout_range * range,struct list_head * head,unsigned int maxnum)527 unsigned int do_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo,
528 				      const struct pnfs_layout_range *range,
529 				      struct list_head *head,
530 				      unsigned int maxnum)
531 {
532 	struct nfs4_flexfile_layout *flo = FF_LAYOUT_FROM_HDR(lo);
533 	struct inode *inode = lo->plh_inode;
534 	struct nfs4_ff_layout_ds_err *err, *n;
535 	unsigned int ret = 0;
536 
537 	spin_lock(&inode->i_lock);
538 	list_for_each_entry_safe(err, n, &flo->error_list, list) {
539 		if (!pnfs_is_range_intersecting(err->offset,
540 				pnfs_end_offset(err->offset, err->length),
541 				range->offset,
542 				pnfs_end_offset(range->offset, range->length)))
543 			continue;
544 		if (!maxnum)
545 			break;
546 		list_move(&err->list, head);
547 		maxnum--;
548 		ret++;
549 	}
550 	spin_unlock(&inode->i_lock);
551 	return ret;
552 }
553 
ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr * lo,const struct pnfs_layout_range * range,struct list_head * head,unsigned int maxnum)554 unsigned int ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo,
555 				      const struct pnfs_layout_range *range,
556 				      struct list_head *head,
557 				      unsigned int maxnum)
558 {
559 	unsigned int ret;
560 
561 	ret = do_layout_fetch_ds_ioerr(lo, range, head, maxnum);
562 	/* If we're over the max, discard all remaining entries */
563 	if (ret == maxnum) {
564 		LIST_HEAD(discard);
565 		do_layout_fetch_ds_ioerr(lo, range, &discard, -1);
566 		ff_layout_free_ds_ioerr(&discard);
567 	}
568 	return ret;
569 }
570 
ff_read_layout_has_available_ds(struct pnfs_layout_segment * lseg)571 static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg)
572 {
573 	struct nfs4_ff_layout_mirror *mirror;
574 	struct nfs4_deviceid_node *devid;
575 	u32 idx, dss_id;
576 
577 	for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
578 		mirror = FF_LAYOUT_COMP(lseg, idx);
579 		if (!mirror)
580 			continue;
581 		for (dss_id = 0; dss_id < mirror->dss_count; dss_id++) {
582 			if (!mirror->dss[dss_id].mirror_ds)
583 				return true;
584 			if (IS_ERR(mirror->dss[dss_id].mirror_ds))
585 				continue;
586 			devid = &mirror->dss[dss_id].mirror_ds->id_node;
587 			if (!nfs4_test_deviceid_unavailable(devid))
588 				return true;
589 		}
590 	}
591 
592 	return false;
593 }
594 
ff_rw_layout_has_available_ds(struct pnfs_layout_segment * lseg)595 static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg)
596 {
597 	struct nfs4_ff_layout_mirror *mirror;
598 	struct nfs4_deviceid_node *devid;
599 	u32 idx, dss_id;
600 
601 	for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
602 		mirror = FF_LAYOUT_COMP(lseg, idx);
603 		if (!mirror)
604 			return false;
605 		for (dss_id = 0; dss_id < mirror->dss_count; dss_id++) {
606 			if (IS_ERR(mirror->dss[dss_id].mirror_ds))
607 				return false;
608 			if (!mirror->dss[dss_id].mirror_ds)
609 				continue;
610 			devid = &mirror->dss[dss_id].mirror_ds->id_node;
611 			if (nfs4_test_deviceid_unavailable(devid))
612 				return false;
613 		}
614 	}
615 
616 	return FF_LAYOUT_MIRROR_COUNT(lseg) != 0;
617 }
618 
ff_layout_has_available_ds(struct pnfs_layout_segment * lseg)619 static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg)
620 {
621 	if (lseg->pls_range.iomode == IOMODE_READ)
622 		return  ff_read_layout_has_available_ds(lseg);
623 	/* Note: RW layout needs all mirrors available */
624 	return ff_rw_layout_has_available_ds(lseg);
625 }
626 
ff_layout_avoid_mds_available_ds(struct pnfs_layout_segment * lseg)627 bool ff_layout_avoid_mds_available_ds(struct pnfs_layout_segment *lseg)
628 {
629 	return ff_layout_no_fallback_to_mds(lseg) ||
630 	       ff_layout_has_available_ds(lseg);
631 }
632 
ff_layout_avoid_read_on_rw(struct pnfs_layout_segment * lseg)633 bool ff_layout_avoid_read_on_rw(struct pnfs_layout_segment *lseg)
634 {
635 	return lseg->pls_range.iomode == IOMODE_RW &&
636 	       ff_layout_no_read_on_rw(lseg);
637 }
638 
639 module_param(dataserver_retrans, uint, 0644);
640 MODULE_PARM_DESC(dataserver_retrans, "The  number of times the NFSv4.1 client "
641 			"retries a request before it attempts further "
642 			" recovery  action.");
643 module_param(dataserver_timeo, uint, 0644);
644 MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
645 			"NFSv4.1  client  waits for a response from a "
646 			" data server before it retries an NFS request.");
647