Blame view

fs/nfs/nfs4filelayoutdev.c 20.7 KB
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  /*
   *  Device operations for the pnfs nfs4 file layout driver.
   *
   *  Copyright (c) 2002
   *  The Regents of the University of Michigan
   *  All Rights Reserved
   *
   *  Dean Hildebrand <dhildebz@umich.edu>
   *  Garth Goodson   <Garth.Goodson@netapp.com>
   *
   *  Permission is granted to use, copy, create derivative works, and
   *  redistribute this software and such derivative works for any purpose,
   *  so long as the name of the University of Michigan is not used in
   *  any advertising or publicity pertaining to the use or distribution
   *  of this software without specific, written prior authorization. If
   *  the above copyright notice or any other identification of the
   *  University of Michigan is included in any copy of any portion of
   *  this software, then the disclaimer below must also be included.
   *
   *  This software is provided as is, without representation or warranty
   *  of any kind either express or implied, including without limitation
   *  the implied warranties of merchantability, fitness for a particular
   *  purpose, or noninfringement.  The Regents of the University of
   *  Michigan shall not be liable for any damages, including special,
   *  indirect, incidental, or consequential damages, with respect to any
   *  claim arising out of or in connection with the use of the software,
   *  even if it has been or is hereafter advised of the possibility of
   *  such damages.
   */
  
  #include <linux/nfs_fs.h>
  #include <linux/vmalloc.h>
  
  #include "internal.h"
  #include "nfs4filelayout.h"
  
  #define NFSDBG_FACILITY		NFSDBG_PNFS_LD
  
  /*
   * Data server cache
   *
   * Data servers can be mapped to different device ids.
   * nfs4_pnfs_ds reference counting
   *   - set to 1 on allocation
   *   - incremented when a device id maps a data server already in the cache.
   *   - decremented when deviceid is removed from the cache.
   */
  DEFINE_SPINLOCK(nfs4_ds_cache_lock);
  static LIST_HEAD(nfs4_data_server_cache);
  
  /* Debug routines */
  void
  print_ds(struct nfs4_pnfs_ds *ds)
  {
  	if (ds == NULL) {
  		printk("%s NULL device
  ", __func__);
  		return;
  	}
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
60
61
  	printk("        ds %s
  "
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
62
63
64
65
66
67
  		"        ref count %d
  "
  		"        client %p
  "
  		"        cl_exchange_flags %x
  ",
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
68
  		ds->ds_remotestr,
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
69
70
71
  		atomic_read(&ds->ds_count), ds->ds_clp,
  		ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
  }
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
72
73
  static bool
  same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
74
  {
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
75
76
  	struct sockaddr_in *a, *b;
  	struct sockaddr_in6 *a6, *b6;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
77

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  	if (addr1->sa_family != addr2->sa_family)
  		return false;
  
  	switch (addr1->sa_family) {
  	case AF_INET:
  		a = (struct sockaddr_in *)addr1;
  		b = (struct sockaddr_in *)addr2;
  
  		if (a->sin_addr.s_addr == b->sin_addr.s_addr &&
  		    a->sin_port == b->sin_port)
  			return true;
  		break;
  
  	case AF_INET6:
  		a6 = (struct sockaddr_in6 *)addr1;
  		b6 = (struct sockaddr_in6 *)addr2;
  
  		/* LINKLOCAL addresses must have matching scope_id */
  		if (ipv6_addr_scope(&a6->sin6_addr) ==
  		    IPV6_ADDR_SCOPE_LINKLOCAL &&
  		    a6->sin6_scope_id != b6->sin6_scope_id)
  			return false;
  
  		if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) &&
  		    a6->sin6_port == b6->sin6_port)
  			return true;
  		break;
  
  	default:
  		dprintk("%s: unhandled address family: %u
  ",
  			__func__, addr1->sa_family);
  		return false;
  	}
  
  	return false;
  }
  
  /*
   * Lookup DS by addresses.  The first matching address returns true.
   * nfs4_ds_cache_lock is held
   */
  static struct nfs4_pnfs_ds *
  _data_server_lookup_locked(struct list_head *dsaddrs)
  {
  	struct nfs4_pnfs_ds *ds;
  	struct nfs4_pnfs_ds_addr *da1, *da2;
  
  	list_for_each_entry(da1, dsaddrs, da_node) {
  		list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
  			list_for_each_entry(da2, &ds->ds_addrs, da_node) {
  				if (same_sockaddr(
  					(struct sockaddr *)&da1->da_addr,
  					(struct sockaddr *)&da2->da_addr))
  					return ds;
  			}
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
134
135
136
137
  		}
  	}
  	return NULL;
  }
d83217c13   Andy Adamson   NFSv4.1: data ser...
138
  /*
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
   * Compare two lists of addresses.
   */
  static bool
  _data_server_match_all_addrs_locked(struct list_head *dsaddrs1,
  				    struct list_head *dsaddrs2)
  {
  	struct nfs4_pnfs_ds_addr *da1, *da2;
  	size_t count1 = 0,
  	       count2 = 0;
  
  	list_for_each_entry(da1, dsaddrs1, da_node)
  		count1++;
  
  	list_for_each_entry(da2, dsaddrs2, da_node) {
  		bool found = false;
  		count2++;
  		list_for_each_entry(da1, dsaddrs1, da_node) {
  			if (same_sockaddr((struct sockaddr *)&da1->da_addr,
  				(struct sockaddr *)&da2->da_addr)) {
  				found = true;
  				break;
  			}
  		}
  		if (!found)
  			return false;
  	}
  
  	return (count1 == count2);
  }
  
  /*
d83217c13   Andy Adamson   NFSv4.1: data ser...
170
   * Create an rpc connection to the nfs4_pnfs_ds data server
35dbbc99e   Weston Andros Adamson   NFS: fix comment
171
   * Currently only supports IPv4 and IPv6 addresses
d83217c13   Andy Adamson   NFSv4.1: data ser...
172
173
174
175
   */
  static int
  nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
  {
7e574f0d3   Weston Andros Adamson   NFS: pnfs: loop o...
176
  	struct nfs_client *clp = ERR_PTR(-EIO);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
177
  	struct nfs4_pnfs_ds_addr *da;
d83217c13   Andy Adamson   NFSv4.1: data ser...
178
  	int status = 0;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
179
180
  	dprintk("--> %s DS %s au_flavor %d
  ", __func__, ds->ds_remotestr,
d83217c13   Andy Adamson   NFSv4.1: data ser...
181
  		mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
182
  	BUG_ON(list_empty(&ds->ds_addrs));
7e574f0d3   Weston Andros Adamson   NFS: pnfs: loop o...
183
184
185
186
  	list_for_each_entry(da, &ds->ds_addrs, da_node) {
  		dprintk("%s: DS %s: trying address %s
  ",
  			__func__, ds->ds_remotestr, da->da_remotestr);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
187

7e574f0d3   Weston Andros Adamson   NFS: pnfs: loop o...
188
  		clp = nfs4_set_ds_client(mds_srv->nfs_client,
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
189
190
  				 (struct sockaddr *)&da->da_addr,
  				 da->da_addrlen, IPPROTO_TCP);
7e574f0d3   Weston Andros Adamson   NFS: pnfs: loop o...
191
192
193
  		if (!IS_ERR(clp))
  			break;
  	}
d83217c13   Andy Adamson   NFSv4.1: data ser...
194
195
196
197
198
199
200
201
202
203
204
  	if (IS_ERR(clp)) {
  		status = PTR_ERR(clp);
  		goto out;
  	}
  
  	if ((clp->cl_exchange_flags & EXCHGID4_FLAG_MASK_PNFS) != 0) {
  		if (!is_ds_client(clp)) {
  			status = -ENODEV;
  			goto out_put;
  		}
  		ds->ds_clp = clp;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
205
206
207
  		dprintk("%s [existing] server=%s
  ", __func__,
  			ds->ds_remotestr);
d83217c13   Andy Adamson   NFSv4.1: data ser...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  		goto out;
  	}
  
  	/*
  	 * Do not set NFS_CS_CHECK_LEASE_TIME instead set the DS lease to
  	 * be equal to the MDS lease. Renewal is scheduled in create_session.
  	 */
  	spin_lock(&mds_srv->nfs_client->cl_lock);
  	clp->cl_lease_time = mds_srv->nfs_client->cl_lease_time;
  	spin_unlock(&mds_srv->nfs_client->cl_lock);
  	clp->cl_last_renewal = jiffies;
  
  	/* New nfs_client */
  	status = nfs4_init_ds_session(clp);
  	if (status)
  		goto out_put;
  
  	ds->ds_clp = clp;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
226
227
  	dprintk("%s [new] addr: %s
  ", __func__, ds->ds_remotestr);
d83217c13   Andy Adamson   NFSv4.1: data ser...
228
229
230
231
232
233
  out:
  	return status;
  out_put:
  	nfs_put_client(clp);
  	goto out;
  }
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
234
235
236
  static void
  destroy_ds(struct nfs4_pnfs_ds *ds)
  {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
237
  	struct nfs4_pnfs_ds_addr *da;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
238
239
240
241
242
243
244
  	dprintk("--> %s
  ", __func__);
  	ifdebug(FACILITY)
  		print_ds(ds);
  
  	if (ds->ds_clp)
  		nfs_put_client(ds->ds_clp);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
245
246
247
248
249
250
251
252
253
  
  	while (!list_empty(&ds->ds_addrs)) {
  		da = list_first_entry(&ds->ds_addrs,
  				      struct nfs4_pnfs_ds_addr,
  				      da_node);
  		list_del_init(&da->da_node);
  		kfree(da->da_remotestr);
  		kfree(da);
  	}
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
254
  	kfree(ds->ds_remotestr);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
255
256
  	kfree(ds);
  }
1775bc342   Benny Halevy   NFSv4.1: purge de...
257
  void
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
258
259
260
261
  nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
  {
  	struct nfs4_pnfs_ds *ds;
  	int i;
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
262
  	nfs4_print_deviceid(&dsaddr->id_node.deviceid);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  
  	for (i = 0; i < dsaddr->ds_num; i++) {
  		ds = dsaddr->ds_list[i];
  		if (ds != NULL) {
  			if (atomic_dec_and_lock(&ds->ds_count,
  						&nfs4_ds_cache_lock)) {
  				list_del_init(&ds->ds_node);
  				spin_unlock(&nfs4_ds_cache_lock);
  				destroy_ds(ds);
  			}
  		}
  	}
  	kfree(dsaddr->stripe_indices);
  	kfree(dsaddr);
  }
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
278
279
280
281
282
  /*
   * Create a string with a human readable address and port to avoid
   * complicated setup around many dprinks.
   */
  static char *
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
283
  nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
284
  {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
285
  	struct nfs4_pnfs_ds_addr *da;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
286
  	char *remotestr;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
287
  	size_t len;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
288
  	char *p;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
289

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
290
291
292
  	len = 3;        /* '{', '}' and eol */
  	list_for_each_entry(da, dsaddrs, da_node) {
  		len += strlen(da->da_remotestr) + 1;    /* string plus comma */
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
293
  	}
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
294
295
  	remotestr = kzalloc(len, gfp_flags);
  	if (!remotestr)
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
296
  		return NULL;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
297

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
298
299
300
301
302
  	p = remotestr;
  	*(p++) = '{';
  	len--;
  	list_for_each_entry(da, dsaddrs, da_node) {
  		size_t ll = strlen(da->da_remotestr);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
303

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
304
305
  		if (ll > len)
  			goto out_err;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
306

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
307
308
309
  		memcpy(p, da->da_remotestr, ll);
  		p += ll;
  		len -= ll;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
310

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
311
312
313
314
315
316
317
318
319
  		if (len < 1)
  			goto out_err;
  		(*p++) = ',';
  		len--;
  	}
  	if (len < 2)
  		goto out_err;
  	*(p++) = '}';
  	*p = '\0';
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
320
  	return remotestr;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
321
322
323
  out_err:
  	kfree(remotestr);
  	return NULL;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
324
  }
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
325
  static struct nfs4_pnfs_ds *
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
326
  nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
327
  {
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
328
329
  	struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
  	char *remotestr;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
330

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
331
332
333
334
335
336
337
  	if (list_empty(dsaddrs)) {
  		dprintk("%s: no addresses defined
  ", __func__);
  		goto out;
  	}
  
  	ds = kzalloc(sizeof(*ds), gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
338
339
  	if (!ds)
  		goto out;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
340
  	/* this is only used for debugging, so it's ok if its NULL */
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
341
  	remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
342

16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
343
  	spin_lock(&nfs4_ds_cache_lock);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
344
  	tmp_ds = _data_server_lookup_locked(dsaddrs);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
345
  	if (tmp_ds == NULL) {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
346
347
  		INIT_LIST_HEAD(&ds->ds_addrs);
  		list_splice_init(dsaddrs, &ds->ds_addrs);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
348
  		ds->ds_remotestr = remotestr;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
349
350
351
352
  		atomic_set(&ds->ds_count, 1);
  		INIT_LIST_HEAD(&ds->ds_node);
  		ds->ds_clp = NULL;
  		list_add(&ds->ds_node, &nfs4_data_server_cache);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
353
354
355
  		dprintk("%s add new data server %s
  ", __func__,
  			ds->ds_remotestr);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
356
  	} else {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
357
358
359
360
361
  		if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
  							 dsaddrs)) {
  			dprintk("%s:  multipath address mismatch: %s != %s",
  				__func__, tmp_ds->ds_remotestr, remotestr);
  		}
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
362
  		kfree(remotestr);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
363
364
  		kfree(ds);
  		atomic_inc(&tmp_ds->ds_count);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
365
366
367
  		dprintk("%s data server %s found, inc'ed ds_count to %d
  ",
  			__func__, tmp_ds->ds_remotestr,
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
368
369
370
371
372
373
374
375
376
  			atomic_read(&tmp_ds->ds_count));
  		ds = tmp_ds;
  	}
  	spin_unlock(&nfs4_ds_cache_lock);
  out:
  	return ds;
  }
  
  /*
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
377
   * Currently only supports ipv4, ipv6 and one multi-path address.
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
378
   */
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
379
380
  static struct nfs4_pnfs_ds_addr *
  decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
381
  {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
382
  	struct nfs4_pnfs_ds_addr *da = NULL;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
383
  	char *buf, *portstr;
13fff2f35   Dan Carpenter   NFS: cleanup endi...
384
  	__be16 port;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
385
  	int nlen, rlen;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
386
  	int tmp[2];
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
387
  	__be32 *p;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
388
  	char *netid, *match_netid;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
389
390
391
  	size_t len, match_netid_len;
  	char *startsep = "";
  	char *endsep = "";
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
392
393
  
  	/* r_netid */
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
394
395
396
  	p = xdr_inline_decode(streamp, 4);
  	if (unlikely(!p))
  		goto out_err;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
397
  	nlen = be32_to_cpup(p++);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
398

35124a099   Weston Andros Adamson   Cleanup XDR parsi...
399
400
401
  	p = xdr_inline_decode(streamp, nlen);
  	if (unlikely(!p))
  		goto out_err;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
402

c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
403
404
  	netid = kmalloc(nlen+1, gfp_flags);
  	if (unlikely(!netid))
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
405
  		goto out_err;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
406

c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
407
408
409
410
  	netid[nlen] = '\0';
  	memcpy(netid, p, nlen);
  
  	/* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
411
412
  	p = xdr_inline_decode(streamp, 4);
  	if (unlikely(!p))
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
413
  		goto out_free_netid;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
414
415
416
417
  	rlen = be32_to_cpup(p);
  
  	p = xdr_inline_decode(streamp, rlen);
  	if (unlikely(!p))
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
418
  		goto out_free_netid;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
419

c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
420
421
  	/* port is ".ABC.DEF", 8 chars max */
  	if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
ad3d2eedf   Jesper Juhl   NFS4: Avoid poten...
422
423
  		dprintk("%s: Invalid address, length %d
  ", __func__,
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
424
  			rlen);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
425
  		goto out_free_netid;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
426
  	}
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
427
  	buf = kmalloc(rlen + 1, gfp_flags);
b9f810570   Stanislav Fomichev   nfs: add kmalloc ...
428
429
430
  	if (!buf) {
  		dprintk("%s: Not enough memory
  ", __func__);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
431
  		goto out_free_netid;
b9f810570   Stanislav Fomichev   nfs: add kmalloc ...
432
  	}
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
433
  	buf[rlen] = '\0';
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
434
  	memcpy(buf, p, rlen);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
435

c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  	/* replace port '.' with '-' */
  	portstr = strrchr(buf, '.');
  	if (!portstr) {
  		dprintk("%s: Failed finding expected dot in port
  ",
  			__func__);
  		goto out_free_buf;
  	}
  	*portstr = '-';
  
  	/* find '.' between address and port */
  	portstr = strrchr(buf, '.');
  	if (!portstr) {
  		dprintk("%s: Failed finding expected dot between address and "
  			"port
  ", __func__);
  		goto out_free_buf;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
453
  	}
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
454
  	*portstr = '\0';
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
455

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
456
457
  	da = kzalloc(sizeof(*da), gfp_flags);
  	if (unlikely(!da))
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
458
  		goto out_free_buf;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
459
460
461
462
463
464
465
466
  
  	INIT_LIST_HEAD(&da->da_node);
  
  	if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr,
  		      sizeof(da->da_addr))) {
  		dprintk("%s: error parsing address %s
  ", __func__, buf);
  		goto out_free_da;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
467
  	}
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
468
469
  	portstr++;
  	sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
470
  	port = htons((tmp[0] << 8) | (tmp[1]));
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
471
  	switch (da->da_addr.ss_family) {
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
472
  	case AF_INET:
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
473
474
  		((struct sockaddr_in *)&da->da_addr)->sin_port = port;
  		da->da_addrlen = sizeof(struct sockaddr_in);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
475
476
477
478
479
  		match_netid = "tcp";
  		match_netid_len = 3;
  		break;
  
  	case AF_INET6:
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
480
481
  		((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
  		da->da_addrlen = sizeof(struct sockaddr_in6);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
482
483
  		match_netid = "tcp6";
  		match_netid_len = 4;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
484
485
  		startsep = "[";
  		endsep = "]";
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
486
487
488
489
490
  		break;
  
  	default:
  		dprintk("%s: unsupported address family: %u
  ",
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
491
492
  			__func__, da->da_addr.ss_family);
  		goto out_free_da;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
493
494
495
496
497
498
  	}
  
  	if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
  		dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"
  ",
  			__func__, netid, match_netid);
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
499
  		goto out_free_da;
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
500
  	}
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  	/* save human readable address */
  	len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
  	da->da_remotestr = kzalloc(len, gfp_flags);
  
  	/* NULL is ok, only used for dprintk */
  	if (da->da_remotestr)
  		snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
  			 buf, endsep, ntohs(port));
  
  	dprintk("%s: Parsed DS addr %s
  ", __func__, da->da_remotestr);
  	kfree(buf);
  	kfree(netid);
  	return da;
  
  out_free_da:
  	kfree(da);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
518
  out_free_buf:
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
519
520
  	dprintk("%s: Error parsing DS addr: %s
  ", __func__, buf);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
521
  	kfree(buf);
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
522
523
  out_free_netid:
  	kfree(netid);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
524
  out_err:
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
525
  	return NULL;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
526
527
528
529
  }
  
  /* Decode opaque device data and return the result */
  static struct nfs4_file_layout_dsaddr*
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
530
  decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
531
  {
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
532
  	int i;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
533
534
  	u32 cnt, num;
  	u8 *indexp;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
535
536
537
538
539
  	__be32 *p;
  	u8 *stripe_indices;
  	u8 max_stripe_index;
  	struct nfs4_file_layout_dsaddr *dsaddr = NULL;
  	struct xdr_stream stream;
f7da7a129   Benny Halevy   SUNRPC: introduce...
540
  	struct xdr_buf buf;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
541
  	struct page *scratch;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
542
543
  	struct list_head dsaddrs;
  	struct nfs4_pnfs_ds_addr *da;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
544
545
  
  	/* set up xdr stream */
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
546
  	scratch = alloc_page(gfp_flags);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
547
548
  	if (!scratch)
  		goto out_err;
f7da7a129   Benny Halevy   SUNRPC: introduce...
549
  	xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
550
  	xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
551
552
  
  	/* Get the stripe count (number of stripe index) */
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
553
554
555
556
557
  	p = xdr_inline_decode(&stream, 4);
  	if (unlikely(!p))
  		goto out_err_free_scratch;
  
  	cnt = be32_to_cpup(p);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
558
559
560
561
562
563
564
  	dprintk("%s stripe count  %d
  ", __func__, cnt);
  	if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
  		printk(KERN_WARNING "%s: stripe count %d greater than "
  		       "supported maximum %d
  ", __func__,
  			cnt, NFS4_PNFS_MAX_STRIPE_CNT);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
565
566
567
568
  		goto out_err_free_scratch;
  	}
  
  	/* read stripe indices */
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
569
  	stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
570
571
572
573
574
575
576
577
578
579
580
581
582
  	if (!stripe_indices)
  		goto out_err_free_scratch;
  
  	p = xdr_inline_decode(&stream, cnt << 2);
  	if (unlikely(!p))
  		goto out_err_free_stripe_indices;
  
  	indexp = &stripe_indices[0];
  	max_stripe_index = 0;
  	for (i = 0; i < cnt; i++) {
  		*indexp = be32_to_cpup(p++);
  		max_stripe_index = max(max_stripe_index, *indexp);
  		indexp++;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
583
584
585
  	}
  
  	/* Check the multipath list count */
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
586
587
588
589
590
  	p = xdr_inline_decode(&stream, 4);
  	if (unlikely(!p))
  		goto out_err_free_stripe_indices;
  
  	num = be32_to_cpup(p);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
591
592
593
594
595
596
597
  	dprintk("%s ds_num %u
  ", __func__, num);
  	if (num > NFS4_PNFS_MAX_MULTI_CNT) {
  		printk(KERN_WARNING "%s: multipath count %d greater than "
  			"supported maximum %d
  ", __func__,
  			num, NFS4_PNFS_MAX_MULTI_CNT);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
598
  		goto out_err_free_stripe_indices;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
599
  	}
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
600
601
602
603
604
605
606
607
  
  	/* validate stripe indices are all < num */
  	if (max_stripe_index >= num) {
  		printk(KERN_WARNING "%s: stripe index %u >= num ds %u
  ",
  			__func__, max_stripe_index, num);
  		goto out_err_free_stripe_indices;
  	}
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
608
609
  	dsaddr = kzalloc(sizeof(*dsaddr) +
  			(sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
610
  			gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
611
  	if (!dsaddr)
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
612
  		goto out_err_free_stripe_indices;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
613
614
  
  	dsaddr->stripe_count = cnt;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
615
616
  	dsaddr->stripe_indices = stripe_indices;
  	stripe_indices = NULL;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
617
  	dsaddr->ds_num = num;
1775bc342   Benny Halevy   NFSv4.1: purge de...
618
619
620
  	nfs4_init_deviceid_node(&dsaddr->id_node,
  				NFS_SERVER(ino)->pnfs_curr_ld,
  				NFS_SERVER(ino)->nfs_client,
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
621
  				&pdev->dev_id);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
622

14f9a6076   Weston Andros Adamson   NFS: Parse and st...
623
  	INIT_LIST_HEAD(&dsaddrs);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
624
625
  	for (i = 0; i < dsaddr->ds_num; i++) {
  		int j;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
626
627
628
629
630
  		u32 mp_count;
  
  		p = xdr_inline_decode(&stream, 4);
  		if (unlikely(!p))
  			goto out_err_free_deviceid;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
631

35124a099   Weston Andros Adamson   Cleanup XDR parsi...
632
  		mp_count = be32_to_cpup(p); /* multipath count */
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
633
  		for (j = 0; j < mp_count; j++) {
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  			da = decode_ds_addr(&stream, gfp_flags);
  			if (da)
  				list_add_tail(&da->da_node, &dsaddrs);
  		}
  		if (list_empty(&dsaddrs)) {
  			dprintk("%s: no suitable DS addresses found
  ",
  				__func__);
  			goto out_err_free_deviceid;
  		}
  
  		dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
  		if (!dsaddr->ds_list[i])
  			goto out_err_drain_dsaddrs;
  
  		/* If DS was already in cache, free ds addrs */
  		while (!list_empty(&dsaddrs)) {
  			da = list_first_entry(&dsaddrs,
  					      struct nfs4_pnfs_ds_addr,
  					      da_node);
  			list_del_init(&da->da_node);
  			kfree(da->da_remotestr);
  			kfree(da);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
657
658
  		}
  	}
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
659
660
  
  	__free_page(scratch);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
661
  	return dsaddr;
14f9a6076   Weston Andros Adamson   NFS: Parse and st...
662
663
664
665
666
667
668
669
  out_err_drain_dsaddrs:
  	while (!list_empty(&dsaddrs)) {
  		da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
  				      da_node);
  		list_del_init(&da->da_node);
  		kfree(da->da_remotestr);
  		kfree(da);
  	}
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
670
  out_err_free_deviceid:
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
671
  	nfs4_fl_free_deviceid(dsaddr);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
672
673
674
675
676
677
  	/* stripe_indicies was part of dsaddr */
  	goto out_err_free_scratch;
  out_err_free_stripe_indices:
  	kfree(stripe_indices);
  out_err_free_scratch:
  	__free_page(scratch);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
678
679
680
681
682
683
684
  out_err:
  	dprintk("%s ERROR: returning NULL
  ", __func__);
  	return NULL;
  }
  
  /*
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
685
686
   * Decode the opaque device specified in 'dev' and add it to the cache of
   * available devices.
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
687
   */
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
688
  static struct nfs4_file_layout_dsaddr *
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
689
  decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
690
  {
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
691
692
  	struct nfs4_deviceid_node *d;
  	struct nfs4_file_layout_dsaddr *n, *new;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
693

a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
694
  	new = decode_device(inode, dev, gfp_flags);
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
695
  	if (!new) {
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
696
697
698
699
700
  		printk(KERN_WARNING "%s: Could not decode or add device
  ",
  			__func__);
  		return NULL;
  	}
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
701
702
703
  	d = nfs4_insert_deviceid_node(&new->id_node);
  	n = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
  	if (n != new) {
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
704
  		nfs4_fl_free_deviceid(new);
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
705
  		return n;
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
706
  	}
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
707
  	return new;
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
708
709
710
711
712
713
714
  }
  
  /*
   * Retrieve the information for dev_id, add it to the list
   * of available devices, and return it.
   */
  struct nfs4_file_layout_dsaddr *
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
715
  get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  {
  	struct pnfs_device *pdev = NULL;
  	u32 max_resp_sz;
  	int max_pages;
  	struct page **pages = NULL;
  	struct nfs4_file_layout_dsaddr *dsaddr = NULL;
  	int rc, i;
  	struct nfs_server *server = NFS_SERVER(inode);
  
  	/*
  	 * Use the session max response size as the basis for setting
  	 * GETDEVICEINFO's maxcount
  	 */
  	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
  	max_pages = max_resp_sz >> PAGE_SHIFT;
  	dprintk("%s inode %p max_resp_sz %u max_pages %d
  ",
  		__func__, inode, max_resp_sz, max_pages);
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
734
  	pdev = kzalloc(sizeof(struct pnfs_device), gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
735
736
  	if (pdev == NULL)
  		return NULL;
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
737
  	pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
738
739
740
741
742
  	if (pages == NULL) {
  		kfree(pdev);
  		return NULL;
  	}
  	for (i = 0; i < max_pages; i++) {
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
743
  		pages[i] = alloc_page(gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
744
745
746
  		if (!pages[i])
  			goto out_free;
  	}
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  	memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
  	pdev->layout_type = LAYOUT_NFSV4_1_FILES;
  	pdev->pages = pages;
  	pdev->pgbase = 0;
  	pdev->pglen = PAGE_SIZE * max_pages;
  	pdev->mincount = 0;
  
  	rc = nfs4_proc_getdeviceinfo(server, pdev);
  	dprintk("%s getdevice info returns %d
  ", __func__, rc);
  	if (rc)
  		goto out_free;
  
  	/*
  	 * Found new device, need to decode it and then add it to the
  	 * list of known devices for this mountpoint.
  	 */
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
764
  	dsaddr = decode_and_add_device(inode, pdev, gfp_flags);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
765
  out_free:
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
766
767
768
769
770
771
772
773
  	for (i = 0; i < max_pages; i++)
  		__free_page(pages[i]);
  	kfree(pages);
  	kfree(pdev);
  	dprintk("<-- %s dsaddr %p
  ", __func__, dsaddr);
  	return dsaddr;
  }
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
774
775
  void
  nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
776
  {
1775bc342   Benny Halevy   NFSv4.1: purge de...
777
  	nfs4_put_deviceid_node(&dsaddr->id_node);
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
778
  }
cfe7f4120   Fred Isaman   NFSv4.1: filelayo...
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  
  /*
   * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
   * Then: ((res + fsi) % dsaddr->stripe_count)
   */
  u32
  nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset)
  {
  	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
  	u64 tmp;
  
  	tmp = offset - flseg->pattern_offset;
  	do_div(tmp, flseg->stripe_unit);
  	tmp += flseg->first_stripe_index;
  	return do_div(tmp, flseg->dsaddr->stripe_count);
  }
  
  u32
  nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j)
  {
  	return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j];
  }
  
  struct nfs_fh *
  nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
  {
  	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
  	u32 i;
  
  	if (flseg->stripe_type == STRIPE_SPARSE) {
  		if (flseg->num_fh == 1)
  			i = 0;
  		else if (flseg->num_fh == 0)
  			/* Use the MDS OPEN fh set in nfs_read_rpcsetup */
  			return NULL;
  		else
  			i = nfs4_fl_calc_ds_index(lseg, j);
  	} else
  		i = j;
  	return flseg->fh_array[i];
  }
568e8c494   Andy Adamson   NFSv4.1: turn off...
820
821
  static void
  filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr,
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
822
  			       int err, const char *ds_remotestr)
568e8c494   Andy Adamson   NFSv4.1: turn off...
823
  {
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
824
  	u32 *p = (u32 *)&dsaddr->id_node.deviceid;
568e8c494   Andy Adamson   NFSv4.1: turn off...
825

c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
826
  	printk(KERN_ERR "NFS: data server %s connection error %d."
568e8c494   Andy Adamson   NFSv4.1: turn off...
827
828
  		" Deviceid [%x%x%x%x] marked out of use.
  ",
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
829
  		ds_remotestr, err, p[0], p[1], p[2], p[3]);
568e8c494   Andy Adamson   NFSv4.1: turn off...
830

a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
831
  	spin_lock(&nfs4_ds_cache_lock);
568e8c494   Andy Adamson   NFSv4.1: turn off...
832
  	dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY;
a1eaecbc4   Benny Halevy   NFSv4.1: make dev...
833
  	spin_unlock(&nfs4_ds_cache_lock);
568e8c494   Andy Adamson   NFSv4.1: turn off...
834
  }
cfe7f4120   Fred Isaman   NFSv4.1: filelayo...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
  struct nfs4_pnfs_ds *
  nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
  {
  	struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
  	struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
  
  	if (ds == NULL) {
  		printk(KERN_ERR "%s: No data server for offset index %d
  ",
  			__func__, ds_idx);
  		return NULL;
  	}
  
  	if (!ds->ds_clp) {
568e8c494   Andy Adamson   NFSv4.1: turn off...
849
  		struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
cfe7f4120   Fred Isaman   NFSv4.1: filelayo...
850
  		int err;
568e8c494   Andy Adamson   NFSv4.1: turn off...
851
852
853
854
855
856
857
  		if (dsaddr->flags & NFS4_DEVICE_ID_NEG_ENTRY) {
  			/* Already tried to connect, don't try again */
  			dprintk("%s Deviceid marked out of use
  ", __func__);
  			return NULL;
  		}
  		err = nfs4_ds_connect(s, ds);
cfe7f4120   Fred Isaman   NFSv4.1: filelayo...
858
  		if (err) {
568e8c494   Andy Adamson   NFSv4.1: turn off...
859
  			filelayout_mark_devid_negative(dsaddr, err,
c9895cb69   Weston Andros Adamson   NFS: pnfs IPv6 su...
860
  						       ds->ds_remotestr);
cfe7f4120   Fred Isaman   NFSv4.1: filelayo...
861
862
863
864
865
  			return NULL;
  		}
  	}
  	return ds;
  }