Branch data Line data Source code
1 : : /*
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>
33 : : #include <linux/module.h>
34 : :
35 : : #include "../internal.h"
36 : : #include "../nfs4session.h"
37 : : #include "filelayout.h"
38 : :
39 : : #define NFSDBG_FACILITY NFSDBG_PNFS_LD
40 : :
41 : : static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO;
42 : : static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS;
43 : :
44 : : void
45 : 0 : nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
46 : : {
47 : : struct nfs4_pnfs_ds *ds;
48 : : int i;
49 : :
50 : : nfs4_print_deviceid(&dsaddr->id_node.deviceid);
51 : :
52 [ # # ]: 0 : for (i = 0; i < dsaddr->ds_num; i++) {
53 : 0 : ds = dsaddr->ds_list[i];
54 [ # # ]: 0 : if (ds != NULL)
55 : 0 : nfs4_pnfs_ds_put(ds);
56 : : }
57 : 0 : kfree(dsaddr->stripe_indices);
58 [ # # ]: 0 : kfree_rcu(dsaddr, id_node.rcu);
59 : 0 : }
60 : :
61 : : /* Decode opaque device data and return the result */
62 : : struct nfs4_file_layout_dsaddr *
63 : 0 : nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
64 : : gfp_t gfp_flags)
65 : : {
66 : : int i;
67 : : u32 cnt, num;
68 : : u8 *indexp;
69 : : __be32 *p;
70 : : u8 *stripe_indices;
71 : : u8 max_stripe_index;
72 : : struct nfs4_file_layout_dsaddr *dsaddr = NULL;
73 : : struct xdr_stream stream;
74 : : struct xdr_buf buf;
75 : : struct page *scratch;
76 : : struct list_head dsaddrs;
77 : : struct nfs4_pnfs_ds_addr *da;
78 : :
79 : : /* set up xdr stream */
80 : : scratch = alloc_page(gfp_flags);
81 [ # # ]: 0 : if (!scratch)
82 : : goto out_err;
83 : :
84 : 0 : xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
85 : 0 : xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
86 : :
87 : : /* Get the stripe count (number of stripe index) */
88 : 0 : p = xdr_inline_decode(&stream, 4);
89 [ # # ]: 0 : if (unlikely(!p))
90 : : goto out_err_free_scratch;
91 : :
92 : : cnt = be32_to_cpup(p);
93 : : dprintk("%s stripe count %d\n", __func__, cnt);
94 [ # # ]: 0 : if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
95 : 0 : printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
96 : : "supported maximum %d\n", __func__,
97 : : cnt, NFS4_PNFS_MAX_STRIPE_CNT);
98 : 0 : goto out_err_free_scratch;
99 : : }
100 : :
101 : : /* read stripe indices */
102 : : stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags);
103 [ # # ]: 0 : if (!stripe_indices)
104 : : goto out_err_free_scratch;
105 : :
106 : 0 : p = xdr_inline_decode(&stream, cnt << 2);
107 [ # # ]: 0 : if (unlikely(!p))
108 : : goto out_err_free_stripe_indices;
109 : :
110 : : indexp = &stripe_indices[0];
111 : : max_stripe_index = 0;
112 [ # # ]: 0 : for (i = 0; i < cnt; i++) {
113 : 0 : *indexp = be32_to_cpup(p++);
114 : 0 : max_stripe_index = max(max_stripe_index, *indexp);
115 : 0 : indexp++;
116 : : }
117 : :
118 : : /* Check the multipath list count */
119 : 0 : p = xdr_inline_decode(&stream, 4);
120 [ # # ]: 0 : if (unlikely(!p))
121 : : goto out_err_free_stripe_indices;
122 : :
123 : : num = be32_to_cpup(p);
124 : : dprintk("%s ds_num %u\n", __func__, num);
125 [ # # ]: 0 : if (num > NFS4_PNFS_MAX_MULTI_CNT) {
126 : 0 : printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
127 : : "supported maximum %d\n", __func__,
128 : : num, NFS4_PNFS_MAX_MULTI_CNT);
129 : 0 : goto out_err_free_stripe_indices;
130 : : }
131 : :
132 : : /* validate stripe indices are all < num */
133 [ # # ]: 0 : if (max_stripe_index >= num) {
134 : 0 : printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
135 : : __func__, max_stripe_index, num);
136 : 0 : goto out_err_free_stripe_indices;
137 : : }
138 : :
139 : 0 : dsaddr = kzalloc(sizeof(*dsaddr) +
140 : : (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
141 : : gfp_flags);
142 [ # # ]: 0 : if (!dsaddr)
143 : : goto out_err_free_stripe_indices;
144 : :
145 : 0 : dsaddr->stripe_count = cnt;
146 : 0 : dsaddr->stripe_indices = stripe_indices;
147 : : stripe_indices = NULL;
148 : 0 : dsaddr->ds_num = num;
149 : 0 : nfs4_init_deviceid_node(&dsaddr->id_node, server, &pdev->dev_id);
150 : :
151 : : INIT_LIST_HEAD(&dsaddrs);
152 : :
153 [ # # ]: 0 : for (i = 0; i < dsaddr->ds_num; i++) {
154 : : int j;
155 : : u32 mp_count;
156 : :
157 : 0 : p = xdr_inline_decode(&stream, 4);
158 [ # # ]: 0 : if (unlikely(!p))
159 : : goto out_err_free_deviceid;
160 : :
161 : : mp_count = be32_to_cpup(p); /* multipath count */
162 [ # # ]: 0 : for (j = 0; j < mp_count; j++) {
163 : 0 : da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net,
164 : : &stream, gfp_flags);
165 [ # # ]: 0 : if (da)
166 : 0 : list_add_tail(&da->da_node, &dsaddrs);
167 : : }
168 [ # # ]: 0 : if (list_empty(&dsaddrs)) {
169 : : dprintk("%s: no suitable DS addresses found\n",
170 : : __func__);
171 : : goto out_err_free_deviceid;
172 : : }
173 : :
174 : 0 : dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
175 [ # # ]: 0 : if (!dsaddr->ds_list[i])
176 : : goto out_err_drain_dsaddrs;
177 : :
178 : : /* If DS was already in cache, free ds addrs */
179 [ # # ]: 0 : while (!list_empty(&dsaddrs)) {
180 : 0 : da = list_first_entry(&dsaddrs,
181 : : struct nfs4_pnfs_ds_addr,
182 : : da_node);
183 : 0 : list_del_init(&da->da_node);
184 : 0 : kfree(da->da_remotestr);
185 : 0 : kfree(da);
186 : : }
187 : : }
188 : :
189 : 0 : __free_page(scratch);
190 : 0 : return dsaddr;
191 : :
192 : : out_err_drain_dsaddrs:
193 [ # # ]: 0 : while (!list_empty(&dsaddrs)) {
194 : 0 : da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
195 : : da_node);
196 : 0 : list_del_init(&da->da_node);
197 : 0 : kfree(da->da_remotestr);
198 : 0 : kfree(da);
199 : : }
200 : : out_err_free_deviceid:
201 : 0 : nfs4_fl_free_deviceid(dsaddr);
202 : : /* stripe_indicies was part of dsaddr */
203 : 0 : goto out_err_free_scratch;
204 : : out_err_free_stripe_indices:
205 : 0 : kfree(stripe_indices);
206 : : out_err_free_scratch:
207 : 0 : __free_page(scratch);
208 : : out_err:
209 : : dprintk("%s ERROR: returning NULL\n", __func__);
210 : : return NULL;
211 : : }
212 : :
213 : : void
214 : 0 : nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
215 : : {
216 : 0 : nfs4_put_deviceid_node(&dsaddr->id_node);
217 : 0 : }
218 : :
219 : : /*
220 : : * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
221 : : * Then: ((res + fsi) % dsaddr->stripe_count)
222 : : */
223 : : u32
224 : 0 : nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset)
225 : : {
226 : : struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
227 : : u64 tmp;
228 : :
229 : 0 : tmp = offset - flseg->pattern_offset;
230 [ # # # # : 0 : do_div(tmp, flseg->stripe_unit);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
231 : 0 : tmp += flseg->first_stripe_index;
232 [ # # # # : 0 : return do_div(tmp, flseg->dsaddr->stripe_count);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
233 : : }
234 : :
235 : : u32
236 : 0 : nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j)
237 : : {
238 : 0 : return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j];
239 : : }
240 : :
241 : : struct nfs_fh *
242 : 0 : nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
243 : : {
244 : : struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
245 : : u32 i;
246 : :
247 [ # # ]: 0 : if (flseg->stripe_type == STRIPE_SPARSE) {
248 [ # # ]: 0 : if (flseg->num_fh == 1)
249 : : i = 0;
250 [ # # ]: 0 : else if (flseg->num_fh == 0)
251 : : /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
252 : : return NULL;
253 : : else
254 : : i = nfs4_fl_calc_ds_index(lseg, j);
255 : : } else
256 : : i = j;
257 : 0 : return flseg->fh_array[i];
258 : : }
259 : :
260 : : /* Upon return, either ds is connected, or ds is NULL */
261 : : struct nfs4_pnfs_ds *
262 : 0 : nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
263 : : {
264 : 0 : struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
265 : 0 : struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
266 : : struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
267 : : struct nfs4_pnfs_ds *ret = ds;
268 : 0 : struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
269 : : int status;
270 : :
271 [ # # ]: 0 : if (ds == NULL) {
272 : 0 : printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
273 : : __func__, ds_idx);
274 : : pnfs_generic_mark_devid_invalid(devid);
275 : : goto out;
276 : : }
277 : 0 : smp_rmb();
278 [ # # ]: 0 : if (ds->ds_clp)
279 : : goto out_test_devid;
280 : :
281 : 0 : status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
282 : : dataserver_retrans, 4,
283 : 0 : s->nfs_client->cl_minorversion);
284 [ # # ]: 0 : if (status) {
285 : 0 : nfs4_mark_deviceid_unavailable(devid);
286 : : ret = NULL;
287 : 0 : goto out;
288 : : }
289 : :
290 : : out_test_devid:
291 [ # # # # ]: 0 : if (ret->ds_clp == NULL ||
292 : 0 : filelayout_test_devid_unavailable(devid))
293 : : ret = NULL;
294 : : out:
295 : 0 : return ret;
296 : : }
297 : :
298 : : module_param(dataserver_retrans, uint, 0644);
299 : : MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client "
300 : : "retries a request before it attempts further "
301 : : " recovery action.");
302 : : module_param(dataserver_timeo, uint, 0644);
303 : : MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
304 : : "NFSv4.1 client waits for a response from a "
305 : : " data server before it retries an NFS request.");
|