2 * Device operations for the pnfs nfs4 file layout driver.
5 * The Regents of the University of Michigan
8 * Dean Hildebrand <dhildebz@umich.edu>
9 * Garth Goodson <Garth.Goodson@netapp.com>
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.
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
31 #include <linux/nfs_fs.h>
32 #include <linux/vmalloc.h>
33 #include <linux/module.h>
35 #include "../internal.h"
36 #include "../nfs4session.h"
37 #include "filelayout.h"
39 #define NFSDBG_FACILITY NFSDBG_PNFS_LD
41 static unsigned int dataserver_timeo
= NFS4_DEF_DS_TIMEO
;
42 static unsigned int dataserver_retrans
= NFS4_DEF_DS_RETRANS
;
45 nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr
*dsaddr
)
47 struct nfs4_pnfs_ds
*ds
;
50 nfs4_print_deviceid(&dsaddr
->id_node
.deviceid
);
52 for (i
= 0; i
< dsaddr
->ds_num
; i
++) {
53 ds
= dsaddr
->ds_list
[i
];
57 kfree(dsaddr
->stripe_indices
);
58 kfree_rcu(dsaddr
, id_node
.rcu
);
61 /* Decode opaque device data and return the result */
62 struct nfs4_file_layout_dsaddr
*
63 nfs4_fl_alloc_deviceid_node(struct nfs_server
*server
, struct pnfs_device
*pdev
,
72 struct nfs4_file_layout_dsaddr
*dsaddr
= NULL
;
73 struct xdr_stream stream
;
76 struct list_head dsaddrs
;
77 struct nfs4_pnfs_ds_addr
*da
;
79 /* set up xdr stream */
80 scratch
= alloc_page(gfp_flags
);
84 xdr_init_decode_pages(&stream
, &buf
, pdev
->pages
, pdev
->pglen
);
85 xdr_set_scratch_buffer(&stream
, page_address(scratch
), PAGE_SIZE
);
87 /* Get the stripe count (number of stripe index) */
88 p
= xdr_inline_decode(&stream
, 4);
90 goto out_err_free_scratch
;
92 cnt
= be32_to_cpup(p
);
93 dprintk("%s stripe count %d\n", __func__
, cnt
);
94 if (cnt
> NFS4_PNFS_MAX_STRIPE_CNT
) {
95 printk(KERN_WARNING
"NFS: %s: stripe count %d greater than "
96 "supported maximum %d\n", __func__
,
97 cnt
, NFS4_PNFS_MAX_STRIPE_CNT
);
98 goto out_err_free_scratch
;
101 /* read stripe indices */
102 stripe_indices
= kcalloc(cnt
, sizeof(u8
), gfp_flags
);
104 goto out_err_free_scratch
;
106 p
= xdr_inline_decode(&stream
, cnt
<< 2);
108 goto out_err_free_stripe_indices
;
110 indexp
= &stripe_indices
[0];
111 max_stripe_index
= 0;
112 for (i
= 0; i
< cnt
; i
++) {
113 *indexp
= be32_to_cpup(p
++);
114 max_stripe_index
= max(max_stripe_index
, *indexp
);
118 /* Check the multipath list count */
119 p
= xdr_inline_decode(&stream
, 4);
121 goto out_err_free_stripe_indices
;
123 num
= be32_to_cpup(p
);
124 dprintk("%s ds_num %u\n", __func__
, num
);
125 if (num
> NFS4_PNFS_MAX_MULTI_CNT
) {
126 printk(KERN_WARNING
"NFS: %s: multipath count %d greater than "
127 "supported maximum %d\n", __func__
,
128 num
, NFS4_PNFS_MAX_MULTI_CNT
);
129 goto out_err_free_stripe_indices
;
132 /* validate stripe indices are all < num */
133 if (max_stripe_index
>= num
) {
134 printk(KERN_WARNING
"NFS: %s: stripe index %u >= num ds %u\n",
135 __func__
, max_stripe_index
, num
);
136 goto out_err_free_stripe_indices
;
139 dsaddr
= kzalloc(sizeof(*dsaddr
) +
140 (sizeof(struct nfs4_pnfs_ds
*) * (num
- 1)),
143 goto out_err_free_stripe_indices
;
145 dsaddr
->stripe_count
= cnt
;
146 dsaddr
->stripe_indices
= stripe_indices
;
147 stripe_indices
= NULL
;
148 dsaddr
->ds_num
= num
;
149 nfs4_init_deviceid_node(&dsaddr
->id_node
, server
, &pdev
->dev_id
);
151 INIT_LIST_HEAD(&dsaddrs
);
153 for (i
= 0; i
< dsaddr
->ds_num
; i
++) {
157 p
= xdr_inline_decode(&stream
, 4);
159 goto out_err_free_deviceid
;
161 mp_count
= be32_to_cpup(p
); /* multipath count */
162 for (j
= 0; j
< mp_count
; j
++) {
163 da
= nfs4_decode_mp_ds_addr(server
->nfs_client
->cl_net
,
166 list_add_tail(&da
->da_node
, &dsaddrs
);
168 if (list_empty(&dsaddrs
)) {
169 dprintk("%s: no suitable DS addresses found\n",
171 goto out_err_free_deviceid
;
174 dsaddr
->ds_list
[i
] = nfs4_pnfs_ds_add(&dsaddrs
, gfp_flags
);
175 if (!dsaddr
->ds_list
[i
])
176 goto out_err_drain_dsaddrs
;
178 /* If DS was already in cache, free ds addrs */
179 while (!list_empty(&dsaddrs
)) {
180 da
= list_first_entry(&dsaddrs
,
181 struct nfs4_pnfs_ds_addr
,
183 list_del_init(&da
->da_node
);
184 kfree(da
->da_remotestr
);
189 __free_page(scratch
);
192 out_err_drain_dsaddrs
:
193 while (!list_empty(&dsaddrs
)) {
194 da
= list_first_entry(&dsaddrs
, struct nfs4_pnfs_ds_addr
,
196 list_del_init(&da
->da_node
);
197 kfree(da
->da_remotestr
);
200 out_err_free_deviceid
:
201 nfs4_fl_free_deviceid(dsaddr
);
202 /* stripe_indicies was part of dsaddr */
203 goto out_err_free_scratch
;
204 out_err_free_stripe_indices
:
205 kfree(stripe_indices
);
206 out_err_free_scratch
:
207 __free_page(scratch
);
209 dprintk("%s ERROR: returning NULL\n", __func__
);
214 nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr
*dsaddr
)
216 nfs4_put_deviceid_node(&dsaddr
->id_node
);
220 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
221 * Then: ((res + fsi) % dsaddr->stripe_count)
224 nfs4_fl_calc_j_index(struct pnfs_layout_segment
*lseg
, loff_t offset
)
226 struct nfs4_filelayout_segment
*flseg
= FILELAYOUT_LSEG(lseg
);
229 tmp
= offset
- flseg
->pattern_offset
;
230 do_div(tmp
, flseg
->stripe_unit
);
231 tmp
+= flseg
->first_stripe_index
;
232 return do_div(tmp
, flseg
->dsaddr
->stripe_count
);
236 nfs4_fl_calc_ds_index(struct pnfs_layout_segment
*lseg
, u32 j
)
238 return FILELAYOUT_LSEG(lseg
)->dsaddr
->stripe_indices
[j
];
242 nfs4_fl_select_ds_fh(struct pnfs_layout_segment
*lseg
, u32 j
)
244 struct nfs4_filelayout_segment
*flseg
= FILELAYOUT_LSEG(lseg
);
247 if (flseg
->stripe_type
== STRIPE_SPARSE
) {
248 if (flseg
->num_fh
== 1)
250 else if (flseg
->num_fh
== 0)
251 /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
254 i
= nfs4_fl_calc_ds_index(lseg
, j
);
257 return flseg
->fh_array
[i
];
260 /* Upon return, either ds is connected, or ds is NULL */
261 struct nfs4_pnfs_ds
*
262 nfs4_fl_prepare_ds(struct pnfs_layout_segment
*lseg
, u32 ds_idx
)
264 struct nfs4_file_layout_dsaddr
*dsaddr
= FILELAYOUT_LSEG(lseg
)->dsaddr
;
265 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 struct nfs_server
*s
= NFS_SERVER(lseg
->pls_layout
->plh_inode
);
272 printk(KERN_ERR
"NFS: %s: No data server for offset index %d\n",
274 pnfs_generic_mark_devid_invalid(devid
);
281 status
= nfs4_pnfs_ds_connect(s
, ds
, devid
, dataserver_timeo
,
282 dataserver_retrans
, 4,
283 s
->nfs_client
->cl_minorversion
);
285 nfs4_mark_deviceid_unavailable(devid
);
291 if (ret
->ds_clp
== NULL
||
292 filelayout_test_devid_unavailable(devid
))
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.");