blob: fbfbb701159d7969fb3be9fb264b6cc8c4d58f9c [file] [log] [blame]
Andy Adamson16b374c2010-10-20 00:18:04 -04001/*
2 * Device operations for the pnfs nfs4 file layout driver.
3 *
4 * Copyright (c) 2002
5 * The Regents of the University of Michigan
6 * All Rights Reserved
7 *
8 * Dean Hildebrand <dhildebz@umich.edu>
9 * Garth Goodson <Garth.Goodson@netapp.com>
10 *
11 * Permission is granted to use, copy, create derivative works, and
12 * redistribute this software and such derivative works for any purpose,
13 * so long as the name of the University of Michigan is not used in
14 * any advertising or publicity pertaining to the use or distribution
15 * of this software without specific, written prior authorization. If
16 * the above copyright notice or any other identification of the
17 * University of Michigan is included in any copy of any portion of
18 * this software, then the disclaimer below must also be included.
19 *
20 * This software is provided as is, without representation or warranty
21 * of any kind either express or implied, including without limitation
22 * the implied warranties of merchantability, fitness for a particular
23 * purpose, or noninfringement. The Regents of the University of
24 * Michigan shall not be liable for any damages, including special,
25 * indirect, incidental, or consequential damages, with respect to any
26 * claim arising out of or in connection with the use of the software,
27 * even if it has been or is hereafter advised of the possibility of
28 * such damages.
29 */
30
31#include <linux/nfs_fs.h>
32#include <linux/vmalloc.h>
Andy Adamson98fc6852012-04-27 17:53:45 -040033#include <linux/module.h>
Jeff Layton59766872013-02-04 12:50:00 -050034#include <linux/sunrpc/addr.h>
Andy Adamson16b374c2010-10-20 00:18:04 -040035
Tom Haynesb5968722014-05-12 14:35:52 -070036#include "../internal.h"
37#include "../nfs4session.h"
38#include "filelayout.h"
Andy Adamson16b374c2010-10-20 00:18:04 -040039
40#define NFSDBG_FACILITY NFSDBG_PNFS_LD
41
Andy Adamson98fc6852012-04-27 17:53:45 -040042static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO;
43static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS;
44
Andy Adamson16b374c2010-10-20 00:18:04 -040045/*
Andy Adamsond83217c2011-03-01 01:34:17 +000046 * Create an rpc connection to the nfs4_pnfs_ds data server
Weston Andros Adamson35dbbc92011-06-01 16:32:21 -040047 * Currently only supports IPv4 and IPv6 addresses
Andy Adamsond83217c2011-03-01 01:34:17 +000048 */
49static int
50nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
51{
Weston Andros Adamson7e574f02011-05-31 18:48:58 -040052 struct nfs_client *clp = ERR_PTR(-EIO);
Weston Andros Adamson14f9a602011-05-31 18:48:57 -040053 struct nfs4_pnfs_ds_addr *da;
Andy Adamsond83217c2011-03-01 01:34:17 +000054 int status = 0;
55
Weston Andros Adamson14f9a602011-05-31 18:48:57 -040056 dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
Andy Adamsond83217c2011-03-01 01:34:17 +000057 mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
58
Weston Andros Adamson7e574f02011-05-31 18:48:58 -040059 list_for_each_entry(da, &ds->ds_addrs, da_node) {
60 dprintk("%s: DS %s: trying address %s\n",
61 __func__, ds->ds_remotestr, da->da_remotestr);
Weston Andros Adamson14f9a602011-05-31 18:48:57 -040062
Weston Andros Adamson7e574f02011-05-31 18:48:58 -040063 clp = nfs4_set_ds_client(mds_srv->nfs_client,
Andy Adamson98fc6852012-04-27 17:53:45 -040064 (struct sockaddr *)&da->da_addr,
65 da->da_addrlen, IPPROTO_TCP,
66 dataserver_timeo, dataserver_retrans);
Weston Andros Adamson7e574f02011-05-31 18:48:58 -040067 if (!IS_ERR(clp))
68 break;
69 }
70
Andy Adamsond83217c2011-03-01 01:34:17 +000071 if (IS_ERR(clp)) {
72 status = PTR_ERR(clp);
73 goto out;
74 }
75
Trond Myklebust7b38c362012-05-23 13:23:31 -040076 status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
Andy Adamsond83217c2011-03-01 01:34:17 +000077 if (status)
78 goto out_put;
79
Trond Myklebustacd65e52013-09-26 14:32:56 -040080 smp_wmb();
Andy Adamsond83217c2011-03-01 01:34:17 +000081 ds->ds_clp = clp;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -040082 dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
Andy Adamsond83217c2011-03-01 01:34:17 +000083out:
84 return status;
85out_put:
86 nfs_put_client(clp);
87 goto out;
88}
89
Benny Halevy1775bc32011-05-20 13:47:33 +020090void
Andy Adamson16b374c2010-10-20 00:18:04 -040091nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
92{
93 struct nfs4_pnfs_ds *ds;
94 int i;
95
Benny Halevya1eaecb2011-05-19 22:14:47 -040096 nfs4_print_deviceid(&dsaddr->id_node.deviceid);
Andy Adamson16b374c2010-10-20 00:18:04 -040097
98 for (i = 0; i < dsaddr->ds_num; i++) {
99 ds = dsaddr->ds_list[i];
Peng Tao875ae062014-05-29 21:06:57 +0800100 if (ds != NULL)
101 nfs4_pnfs_ds_put(ds);
Andy Adamson16b374c2010-10-20 00:18:04 -0400102 }
103 kfree(dsaddr->stripe_indices);
104 kfree(dsaddr);
105}
106
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400107/*
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400108 * Currently only supports ipv4, ipv6 and one multi-path address.
Andy Adamson16b374c2010-10-20 00:18:04 -0400109 */
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400110static struct nfs4_pnfs_ds_addr *
Stanislav Kinsbursky17094272012-01-19 19:05:57 +0400111decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
Andy Adamson16b374c2010-10-20 00:18:04 -0400112{
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400113 struct nfs4_pnfs_ds_addr *da = NULL;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400114 char *buf, *portstr;
Dan Carpenter13fff2f2012-01-12 10:07:35 +0300115 __be16 port;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400116 int nlen, rlen;
Andy Adamson16b374c2010-10-20 00:18:04 -0400117 int tmp[2];
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400118 __be32 *p;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400119 char *netid, *match_netid;
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400120 size_t len, match_netid_len;
121 char *startsep = "";
122 char *endsep = "";
123
Andy Adamson16b374c2010-10-20 00:18:04 -0400124
125 /* r_netid */
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400126 p = xdr_inline_decode(streamp, 4);
127 if (unlikely(!p))
128 goto out_err;
Andy Adamson16b374c2010-10-20 00:18:04 -0400129 nlen = be32_to_cpup(p++);
Andy Adamson16b374c2010-10-20 00:18:04 -0400130
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400131 p = xdr_inline_decode(streamp, nlen);
132 if (unlikely(!p))
133 goto out_err;
Andy Adamson16b374c2010-10-20 00:18:04 -0400134
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400135 netid = kmalloc(nlen+1, gfp_flags);
136 if (unlikely(!netid))
Andy Adamson16b374c2010-10-20 00:18:04 -0400137 goto out_err;
Andy Adamson16b374c2010-10-20 00:18:04 -0400138
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400139 netid[nlen] = '\0';
140 memcpy(netid, p, nlen);
141
142 /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400143 p = xdr_inline_decode(streamp, 4);
144 if (unlikely(!p))
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400145 goto out_free_netid;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400146 rlen = be32_to_cpup(p);
147
148 p = xdr_inline_decode(streamp, rlen);
149 if (unlikely(!p))
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400150 goto out_free_netid;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400151
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400152 /* port is ".ABC.DEF", 8 chars max */
153 if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
Jesper Juhlad3d2ee2011-01-17 18:41:50 +0000154 dprintk("%s: Invalid address, length %d\n", __func__,
Andy Adamson16b374c2010-10-20 00:18:04 -0400155 rlen);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400156 goto out_free_netid;
Andy Adamson16b374c2010-10-20 00:18:04 -0400157 }
Trond Myklebusta75b9df2011-05-11 18:00:51 -0400158 buf = kmalloc(rlen + 1, gfp_flags);
Stanislav Fomichevb9f81052011-02-05 23:13:01 +0000159 if (!buf) {
160 dprintk("%s: Not enough memory\n", __func__);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400161 goto out_free_netid;
Stanislav Fomichevb9f81052011-02-05 23:13:01 +0000162 }
Andy Adamson16b374c2010-10-20 00:18:04 -0400163 buf[rlen] = '\0';
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400164 memcpy(buf, p, rlen);
Andy Adamson16b374c2010-10-20 00:18:04 -0400165
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400166 /* replace port '.' with '-' */
167 portstr = strrchr(buf, '.');
168 if (!portstr) {
169 dprintk("%s: Failed finding expected dot in port\n",
170 __func__);
171 goto out_free_buf;
172 }
173 *portstr = '-';
174
175 /* find '.' between address and port */
176 portstr = strrchr(buf, '.');
177 if (!portstr) {
178 dprintk("%s: Failed finding expected dot between address and "
179 "port\n", __func__);
180 goto out_free_buf;
181 }
182 *portstr = '\0';
183
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400184 da = kzalloc(sizeof(*da), gfp_flags);
185 if (unlikely(!da))
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400186 goto out_free_buf;
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400187
188 INIT_LIST_HEAD(&da->da_node);
189
Stanislav Kinsbursky17094272012-01-19 19:05:57 +0400190 if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400191 sizeof(da->da_addr))) {
192 dprintk("%s: error parsing address %s\n", __func__, buf);
193 goto out_free_da;
Andy Adamson16b374c2010-10-20 00:18:04 -0400194 }
195
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400196 portstr++;
197 sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
Andy Adamson16b374c2010-10-20 00:18:04 -0400198 port = htons((tmp[0] << 8) | (tmp[1]));
199
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400200 switch (da->da_addr.ss_family) {
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400201 case AF_INET:
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400202 ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
203 da->da_addrlen = sizeof(struct sockaddr_in);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400204 match_netid = "tcp";
205 match_netid_len = 3;
206 break;
207
208 case AF_INET6:
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400209 ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
210 da->da_addrlen = sizeof(struct sockaddr_in6);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400211 match_netid = "tcp6";
212 match_netid_len = 4;
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400213 startsep = "[";
214 endsep = "]";
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400215 break;
216
217 default:
218 dprintk("%s: unsupported address family: %u\n",
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400219 __func__, da->da_addr.ss_family);
220 goto out_free_da;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400221 }
222
223 if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
224 dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
225 __func__, netid, match_netid);
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400226 goto out_free_da;
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400227 }
228
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400229 /* save human readable address */
230 len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
231 da->da_remotestr = kzalloc(len, gfp_flags);
232
233 /* NULL is ok, only used for dprintk */
234 if (da->da_remotestr)
235 snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
236 buf, endsep, ntohs(port));
237
238 dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
239 kfree(buf);
240 kfree(netid);
241 return da;
242
243out_free_da:
244 kfree(da);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400245out_free_buf:
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400246 dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
Andy Adamson16b374c2010-10-20 00:18:04 -0400247 kfree(buf);
Weston Andros Adamsonc9895cb2011-05-31 18:48:56 -0400248out_free_netid:
249 kfree(netid);
Andy Adamson16b374c2010-10-20 00:18:04 -0400250out_err:
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400251 return NULL;
Andy Adamson16b374c2010-10-20 00:18:04 -0400252}
253
254/* Decode opaque device data and return the result */
Christoph Hellwig661373b2014-09-02 21:27:57 -0700255struct nfs4_file_layout_dsaddr *
256nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
257 gfp_t gfp_flags)
Andy Adamson16b374c2010-10-20 00:18:04 -0400258{
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400259 int i;
Andy Adamson16b374c2010-10-20 00:18:04 -0400260 u32 cnt, num;
261 u8 *indexp;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400262 __be32 *p;
263 u8 *stripe_indices;
264 u8 max_stripe_index;
265 struct nfs4_file_layout_dsaddr *dsaddr = NULL;
266 struct xdr_stream stream;
Benny Halevyf7da7a12011-05-19 14:16:47 -0400267 struct xdr_buf buf;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400268 struct page *scratch;
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400269 struct list_head dsaddrs;
270 struct nfs4_pnfs_ds_addr *da;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400271
272 /* set up xdr stream */
Trond Myklebusta75b9df2011-05-11 18:00:51 -0400273 scratch = alloc_page(gfp_flags);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400274 if (!scratch)
275 goto out_err;
276
Benny Halevyf7da7a12011-05-19 14:16:47 -0400277 xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400278 xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
Andy Adamson16b374c2010-10-20 00:18:04 -0400279
280 /* Get the stripe count (number of stripe index) */
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400281 p = xdr_inline_decode(&stream, 4);
282 if (unlikely(!p))
283 goto out_err_free_scratch;
284
285 cnt = be32_to_cpup(p);
Andy Adamson16b374c2010-10-20 00:18:04 -0400286 dprintk("%s stripe count %d\n", __func__, cnt);
287 if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
Weston Andros Adamsona0308892012-01-26 13:32:23 -0500288 printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
Andy Adamson16b374c2010-10-20 00:18:04 -0400289 "supported maximum %d\n", __func__,
290 cnt, NFS4_PNFS_MAX_STRIPE_CNT);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400291 goto out_err_free_scratch;
292 }
293
294 /* read stripe indices */
Trond Myklebusta75b9df2011-05-11 18:00:51 -0400295 stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400296 if (!stripe_indices)
297 goto out_err_free_scratch;
298
299 p = xdr_inline_decode(&stream, cnt << 2);
300 if (unlikely(!p))
301 goto out_err_free_stripe_indices;
302
303 indexp = &stripe_indices[0];
304 max_stripe_index = 0;
305 for (i = 0; i < cnt; i++) {
306 *indexp = be32_to_cpup(p++);
307 max_stripe_index = max(max_stripe_index, *indexp);
308 indexp++;
Andy Adamson16b374c2010-10-20 00:18:04 -0400309 }
310
311 /* Check the multipath list count */
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400312 p = xdr_inline_decode(&stream, 4);
313 if (unlikely(!p))
314 goto out_err_free_stripe_indices;
315
316 num = be32_to_cpup(p);
Andy Adamson16b374c2010-10-20 00:18:04 -0400317 dprintk("%s ds_num %u\n", __func__, num);
318 if (num > NFS4_PNFS_MAX_MULTI_CNT) {
Weston Andros Adamsona0308892012-01-26 13:32:23 -0500319 printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
Andy Adamson16b374c2010-10-20 00:18:04 -0400320 "supported maximum %d\n", __func__,
321 num, NFS4_PNFS_MAX_MULTI_CNT);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400322 goto out_err_free_stripe_indices;
Andy Adamson16b374c2010-10-20 00:18:04 -0400323 }
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400324
325 /* validate stripe indices are all < num */
326 if (max_stripe_index >= num) {
Weston Andros Adamsona0308892012-01-26 13:32:23 -0500327 printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400328 __func__, max_stripe_index, num);
329 goto out_err_free_stripe_indices;
330 }
331
Andy Adamson16b374c2010-10-20 00:18:04 -0400332 dsaddr = kzalloc(sizeof(*dsaddr) +
333 (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
Trond Myklebusta75b9df2011-05-11 18:00:51 -0400334 gfp_flags);
Andy Adamson16b374c2010-10-20 00:18:04 -0400335 if (!dsaddr)
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400336 goto out_err_free_stripe_indices;
Andy Adamson16b374c2010-10-20 00:18:04 -0400337
338 dsaddr->stripe_count = cnt;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400339 dsaddr->stripe_indices = stripe_indices;
340 stripe_indices = NULL;
Andy Adamson16b374c2010-10-20 00:18:04 -0400341 dsaddr->ds_num = num;
Christoph Hellwig661373b2014-09-02 21:27:57 -0700342 nfs4_init_deviceid_node(&dsaddr->id_node, server, &pdev->dev_id);
Andy Adamson16b374c2010-10-20 00:18:04 -0400343
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400344 INIT_LIST_HEAD(&dsaddrs);
345
Andy Adamson16b374c2010-10-20 00:18:04 -0400346 for (i = 0; i < dsaddr->ds_num; i++) {
347 int j;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400348 u32 mp_count;
Andy Adamson16b374c2010-10-20 00:18:04 -0400349
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400350 p = xdr_inline_decode(&stream, 4);
351 if (unlikely(!p))
352 goto out_err_free_deviceid;
353
354 mp_count = be32_to_cpup(p); /* multipath count */
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400355 for (j = 0; j < mp_count; j++) {
Christoph Hellwig661373b2014-09-02 21:27:57 -0700356 da = decode_ds_addr(server->nfs_client->cl_net,
Stanislav Kinsbursky17094272012-01-19 19:05:57 +0400357 &stream, gfp_flags);
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400358 if (da)
359 list_add_tail(&da->da_node, &dsaddrs);
360 }
361 if (list_empty(&dsaddrs)) {
362 dprintk("%s: no suitable DS addresses found\n",
363 __func__);
364 goto out_err_free_deviceid;
365 }
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400366
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400367 dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
368 if (!dsaddr->ds_list[i])
369 goto out_err_drain_dsaddrs;
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400370
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400371 /* If DS was already in cache, free ds addrs */
372 while (!list_empty(&dsaddrs)) {
373 da = list_first_entry(&dsaddrs,
374 struct nfs4_pnfs_ds_addr,
375 da_node);
376 list_del_init(&da->da_node);
377 kfree(da->da_remotestr);
378 kfree(da);
Andy Adamson16b374c2010-10-20 00:18:04 -0400379 }
380 }
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400381
382 __free_page(scratch);
Andy Adamson16b374c2010-10-20 00:18:04 -0400383 return dsaddr;
384
Weston Andros Adamson14f9a602011-05-31 18:48:57 -0400385out_err_drain_dsaddrs:
386 while (!list_empty(&dsaddrs)) {
387 da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
388 da_node);
389 list_del_init(&da->da_node);
390 kfree(da->da_remotestr);
391 kfree(da);
392 }
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400393out_err_free_deviceid:
Andy Adamson16b374c2010-10-20 00:18:04 -0400394 nfs4_fl_free_deviceid(dsaddr);
Weston Andros Adamson35124a02011-03-24 16:48:21 -0400395 /* stripe_indicies was part of dsaddr */
396 goto out_err_free_scratch;
397out_err_free_stripe_indices:
398 kfree(stripe_indices);
399out_err_free_scratch:
400 __free_page(scratch);
Andy Adamson16b374c2010-10-20 00:18:04 -0400401out_err:
402 dprintk("%s ERROR: returning NULL\n", __func__);
403 return NULL;
404}
405
Christoph Hellwigea8eecd2011-03-01 01:34:21 +0000406void
407nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
Andy Adamson16b374c2010-10-20 00:18:04 -0400408{
Benny Halevy1775bc32011-05-20 13:47:33 +0200409 nfs4_put_deviceid_node(&dsaddr->id_node);
Andy Adamson16b374c2010-10-20 00:18:04 -0400410}
Fred Isamancfe7f412011-03-01 01:34:18 +0000411
412/*
413 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
414 * Then: ((res + fsi) % dsaddr->stripe_count)
415 */
416u32
417nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset)
418{
419 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
420 u64 tmp;
421
422 tmp = offset - flseg->pattern_offset;
423 do_div(tmp, flseg->stripe_unit);
424 tmp += flseg->first_stripe_index;
425 return do_div(tmp, flseg->dsaddr->stripe_count);
426}
427
428u32
429nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j)
430{
431 return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j];
432}
433
434struct nfs_fh *
435nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
436{
437 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
438 u32 i;
439
440 if (flseg->stripe_type == STRIPE_SPARSE) {
441 if (flseg->num_fh == 1)
442 i = 0;
443 else if (flseg->num_fh == 0)
444 /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
445 return NULL;
446 else
447 i = nfs4_fl_calc_ds_index(lseg, j);
448 } else
449 i = j;
450 return flseg->fh_array[i];
451}
452
Andy Adamsonc23266d2013-05-08 16:21:18 -0400453static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
454{
455 might_sleep();
NeilBrown74316202014-07-07 15:16:04 +1000456 wait_on_bit_action(&ds->ds_state, NFS4DS_CONNECTING,
457 nfs_wait_bit_killable, TASK_KILLABLE);
Andy Adamsonc23266d2013-05-08 16:21:18 -0400458}
459
460static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
461{
Peter Zijlstra4e857c52014-03-17 18:06:10 +0100462 smp_mb__before_atomic();
Andy Adamsonc23266d2013-05-08 16:21:18 -0400463 clear_bit(NFS4DS_CONNECTING, &ds->ds_state);
Peter Zijlstra4e857c52014-03-17 18:06:10 +0100464 smp_mb__after_atomic();
Andy Adamsonc23266d2013-05-08 16:21:18 -0400465 wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
466}
467
468
Fred Isamancfe7f412011-03-01 01:34:18 +0000469struct nfs4_pnfs_ds *
470nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
471{
472 struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
473 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
Andy Adamson554d4582012-04-27 17:53:42 -0400474 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
Trond Myklebust52b26a32013-09-26 14:08:36 -0400475 struct nfs4_pnfs_ds *ret = ds;
Fred Isamancfe7f412011-03-01 01:34:18 +0000476
477 if (ds == NULL) {
Weston Andros Adamsona0308892012-01-26 13:32:23 -0500478 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
Fred Isamancfe7f412011-03-01 01:34:18 +0000479 __func__, ds_idx);
Tom Haynesf54bcf22014-12-11 15:34:59 -0500480 pnfs_generic_mark_devid_invalid(devid);
Trond Myklebust52b26a32013-09-26 14:08:36 -0400481 goto out;
Fred Isamancfe7f412011-03-01 01:34:18 +0000482 }
Trond Myklebustacd65e52013-09-26 14:32:56 -0400483 smp_rmb();
Andy Adamsonc23266d2013-05-08 16:21:18 -0400484 if (ds->ds_clp)
Trond Myklebust52b26a32013-09-26 14:08:36 -0400485 goto out_test_devid;
Fred Isamancfe7f412011-03-01 01:34:18 +0000486
Andy Adamsonc23266d2013-05-08 16:21:18 -0400487 if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
Andy Adamson568e8c42011-03-01 01:34:22 +0000488 struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
Fred Isamancfe7f412011-03-01 01:34:18 +0000489 int err;
490
Andy Adamson568e8c42011-03-01 01:34:22 +0000491 err = nfs4_ds_connect(s, ds);
Trond Myklebust52b26a32013-09-26 14:08:36 -0400492 if (err)
Trond Myklebust1dfed272012-09-18 19:51:12 -0400493 nfs4_mark_deviceid_unavailable(devid);
Andy Adamsonc23266d2013-05-08 16:21:18 -0400494 nfs4_clear_ds_conn_bit(ds);
495 } else {
496 /* Either ds is connected, or ds is NULL */
497 nfs4_wait_ds_connect(ds);
Fred Isamancfe7f412011-03-01 01:34:18 +0000498 }
Trond Myklebust52b26a32013-09-26 14:08:36 -0400499out_test_devid:
500 if (filelayout_test_devid_unavailable(devid))
501 ret = NULL;
502out:
503 return ret;
Fred Isamancfe7f412011-03-01 01:34:18 +0000504}
Andy Adamson98fc6852012-04-27 17:53:45 -0400505
506module_param(dataserver_retrans, uint, 0644);
507MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client "
508 "retries a request before it attempts further "
509 " recovery action.");
510module_param(dataserver_timeo, uint, 0644);
511MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
512 "NFSv4.1 client waits for a response from a "
513 " data server before it retries an NFS request.");