diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2011-05-22 12:49:57 -0400 |
---|---|---|
committer | Boaz Harrosh <bharrosh@panasas.com> | 2011-05-29 13:52:36 -0400 |
commit | f1bc893a89d012649e4e7f43575b2c290e08ee42 (patch) | |
tree | 2f06cc6c3232292b2dfae6e7e7f3770699f324b4 /fs | |
parent | 38b7c401f6ade50543f246c4bc2c971edf2b19dd (diff) |
pnfs-obj: pnfs_osd XDR client implementation
* Add the fs/nfs/objlayout/pnfs_osd_xdr_cli.c file, which will
include the XDR encode/decode implementations for the pNFS
client objlayout driver.
[Wrong type in comments]
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/objlayout/Kbuild | 2 | ||||
-rw-r--r-- | fs/nfs/objlayout/pnfs_osd_xdr_cli.c | 412 |
2 files changed, 413 insertions, 1 deletions
diff --git a/fs/nfs/objlayout/Kbuild b/fs/nfs/objlayout/Kbuild index 2e5b9a44773c..7b2a5a240657 100644 --- a/fs/nfs/objlayout/Kbuild +++ b/fs/nfs/objlayout/Kbuild | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the pNFS Objects Layout Driver kernel module | 2 | # Makefile for the pNFS Objects Layout Driver kernel module |
3 | # | 3 | # |
4 | objlayoutdriver-y := objio_osd.o | 4 | objlayoutdriver-y := objio_osd.o pnfs_osd_xdr_cli.o |
5 | obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayoutdriver.o | 5 | obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayoutdriver.o |
diff --git a/fs/nfs/objlayout/pnfs_osd_xdr_cli.c b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c new file mode 100644 index 000000000000..16fc758e9123 --- /dev/null +++ b/fs/nfs/objlayout/pnfs_osd_xdr_cli.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * Object-Based pNFS Layout XDR layer | ||
3 | * | ||
4 | * Copyright (C) 2007 Panasas Inc. [year of first publication] | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Benny Halevy <bhalevy@panasas.com> | ||
8 | * Boaz Harrosh <bharrosh@panasas.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 | ||
12 | * See the file COPYING included with this distribution for more details. | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or without | ||
15 | * modification, are permitted provided that the following conditions | ||
16 | * are met: | ||
17 | * | ||
18 | * 1. Redistributions of source code must retain the above copyright | ||
19 | * notice, this list of conditions and the following disclaimer. | ||
20 | * 2. Redistributions in binary form must reproduce the above copyright | ||
21 | * notice, this list of conditions and the following disclaimer in the | ||
22 | * documentation and/or other materials provided with the distribution. | ||
23 | * 3. Neither the name of the Panasas company nor the names of its | ||
24 | * contributors may be used to endorse or promote products derived | ||
25 | * from this software without specific prior written permission. | ||
26 | * | ||
27 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
28 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
29 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
30 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
34 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
35 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
36 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | #include <linux/pnfs_osd_xdr.h> | ||
41 | |||
42 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | ||
43 | |||
44 | /* | ||
45 | * The following implementation is based on RFC5664 | ||
46 | */ | ||
47 | |||
48 | /* | ||
49 | * struct pnfs_osd_objid { | ||
50 | * struct nfs4_deviceid oid_device_id; | ||
51 | * u64 oid_partition_id; | ||
52 | * u64 oid_object_id; | ||
53 | * }; // xdr size 32 bytes | ||
54 | */ | ||
55 | static __be32 * | ||
56 | _osd_xdr_decode_objid(__be32 *p, struct pnfs_osd_objid *objid) | ||
57 | { | ||
58 | p = xdr_decode_opaque_fixed(p, objid->oid_device_id.data, | ||
59 | sizeof(objid->oid_device_id.data)); | ||
60 | |||
61 | p = xdr_decode_hyper(p, &objid->oid_partition_id); | ||
62 | p = xdr_decode_hyper(p, &objid->oid_object_id); | ||
63 | return p; | ||
64 | } | ||
65 | /* | ||
66 | * struct pnfs_osd_opaque_cred { | ||
67 | * u32 cred_len; | ||
68 | * void *cred; | ||
69 | * }; // xdr size [variable] | ||
70 | * The return pointers are from the xdr buffer | ||
71 | */ | ||
72 | static int | ||
73 | _osd_xdr_decode_opaque_cred(struct pnfs_osd_opaque_cred *opaque_cred, | ||
74 | struct xdr_stream *xdr) | ||
75 | { | ||
76 | __be32 *p = xdr_inline_decode(xdr, 1); | ||
77 | |||
78 | if (!p) | ||
79 | return -EINVAL; | ||
80 | |||
81 | opaque_cred->cred_len = be32_to_cpu(*p++); | ||
82 | |||
83 | p = xdr_inline_decode(xdr, opaque_cred->cred_len); | ||
84 | if (!p) | ||
85 | return -EINVAL; | ||
86 | |||
87 | opaque_cred->cred = p; | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * struct pnfs_osd_object_cred { | ||
93 | * struct pnfs_osd_objid oc_object_id; | ||
94 | * u32 oc_osd_version; | ||
95 | * u32 oc_cap_key_sec; | ||
96 | * struct pnfs_osd_opaque_cred oc_cap_key | ||
97 | * struct pnfs_osd_opaque_cred oc_cap; | ||
98 | * }; // xdr size 32 + 4 + 4 + [variable] + [variable] | ||
99 | */ | ||
100 | static int | ||
101 | _osd_xdr_decode_object_cred(struct pnfs_osd_object_cred *comp, | ||
102 | struct xdr_stream *xdr) | ||
103 | { | ||
104 | __be32 *p = xdr_inline_decode(xdr, 32 + 4 + 4); | ||
105 | int ret; | ||
106 | |||
107 | if (!p) | ||
108 | return -EIO; | ||
109 | |||
110 | p = _osd_xdr_decode_objid(p, &comp->oc_object_id); | ||
111 | comp->oc_osd_version = be32_to_cpup(p++); | ||
112 | comp->oc_cap_key_sec = be32_to_cpup(p); | ||
113 | |||
114 | ret = _osd_xdr_decode_opaque_cred(&comp->oc_cap_key, xdr); | ||
115 | if (unlikely(ret)) | ||
116 | return ret; | ||
117 | |||
118 | ret = _osd_xdr_decode_opaque_cred(&comp->oc_cap, xdr); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * struct pnfs_osd_data_map { | ||
124 | * u32 odm_num_comps; | ||
125 | * u64 odm_stripe_unit; | ||
126 | * u32 odm_group_width; | ||
127 | * u32 odm_group_depth; | ||
128 | * u32 odm_mirror_cnt; | ||
129 | * u32 odm_raid_algorithm; | ||
130 | * }; // xdr size 4 + 8 + 4 + 4 + 4 + 4 | ||
131 | */ | ||
132 | static inline int | ||
133 | _osd_data_map_xdr_sz(void) | ||
134 | { | ||
135 | return 4 + 8 + 4 + 4 + 4 + 4; | ||
136 | } | ||
137 | |||
138 | static __be32 * | ||
139 | _osd_xdr_decode_data_map(__be32 *p, struct pnfs_osd_data_map *data_map) | ||
140 | { | ||
141 | data_map->odm_num_comps = be32_to_cpup(p++); | ||
142 | p = xdr_decode_hyper(p, &data_map->odm_stripe_unit); | ||
143 | data_map->odm_group_width = be32_to_cpup(p++); | ||
144 | data_map->odm_group_depth = be32_to_cpup(p++); | ||
145 | data_map->odm_mirror_cnt = be32_to_cpup(p++); | ||
146 | data_map->odm_raid_algorithm = be32_to_cpup(p++); | ||
147 | dprintk("%s: odm_num_comps=%u odm_stripe_unit=%llu odm_group_width=%u " | ||
148 | "odm_group_depth=%u odm_mirror_cnt=%u odm_raid_algorithm=%u\n", | ||
149 | __func__, | ||
150 | data_map->odm_num_comps, | ||
151 | (unsigned long long)data_map->odm_stripe_unit, | ||
152 | data_map->odm_group_width, | ||
153 | data_map->odm_group_depth, | ||
154 | data_map->odm_mirror_cnt, | ||
155 | data_map->odm_raid_algorithm); | ||
156 | return p; | ||
157 | } | ||
158 | |||
159 | int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout, | ||
160 | struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr) | ||
161 | { | ||
162 | __be32 *p; | ||
163 | |||
164 | memset(iter, 0, sizeof(*iter)); | ||
165 | |||
166 | p = xdr_inline_decode(xdr, _osd_data_map_xdr_sz() + 4 + 4); | ||
167 | if (unlikely(!p)) | ||
168 | return -EINVAL; | ||
169 | |||
170 | p = _osd_xdr_decode_data_map(p, &layout->olo_map); | ||
171 | layout->olo_comps_index = be32_to_cpup(p++); | ||
172 | layout->olo_num_comps = be32_to_cpup(p++); | ||
173 | iter->total_comps = layout->olo_num_comps; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | bool pnfs_osd_xdr_decode_layout_comp(struct pnfs_osd_object_cred *comp, | ||
178 | struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr, | ||
179 | int *err) | ||
180 | { | ||
181 | BUG_ON(iter->decoded_comps > iter->total_comps); | ||
182 | if (iter->decoded_comps == iter->total_comps) | ||
183 | return false; | ||
184 | |||
185 | *err = _osd_xdr_decode_object_cred(comp, xdr); | ||
186 | if (unlikely(*err)) { | ||
187 | dprintk("%s: _osd_xdr_decode_object_cred=>%d decoded_comps=%d " | ||
188 | "total_comps=%d\n", __func__, *err, | ||
189 | iter->decoded_comps, iter->total_comps); | ||
190 | return false; /* stop the loop */ | ||
191 | } | ||
192 | dprintk("%s: dev(%llx:%llx) par=0x%llx obj=0x%llx " | ||
193 | "key_len=%u cap_len=%u\n", | ||
194 | __func__, | ||
195 | _DEVID_LO(&comp->oc_object_id.oid_device_id), | ||
196 | _DEVID_HI(&comp->oc_object_id.oid_device_id), | ||
197 | comp->oc_object_id.oid_partition_id, | ||
198 | comp->oc_object_id.oid_object_id, | ||
199 | comp->oc_cap_key.cred_len, comp->oc_cap.cred_len); | ||
200 | |||
201 | iter->decoded_comps++; | ||
202 | return true; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Get Device Information Decoding | ||
207 | * | ||
208 | * Note: since Device Information is currently done synchronously, all | ||
209 | * variable strings fields are left inside the rpc buffer and are only | ||
210 | * pointed to by the pnfs_osd_deviceaddr members. So the read buffer | ||
211 | * should not be freed while the returned information is in use. | ||
212 | */ | ||
213 | /* | ||
214 | *struct nfs4_string { | ||
215 | * unsigned int len; | ||
216 | * char *data; | ||
217 | *}; // size [variable] | ||
218 | * NOTE: Returned string points to inside the XDR buffer | ||
219 | */ | ||
220 | static __be32 * | ||
221 | __read_u8_opaque(__be32 *p, struct nfs4_string *str) | ||
222 | { | ||
223 | str->len = be32_to_cpup(p++); | ||
224 | str->data = (char *)p; | ||
225 | |||
226 | p += XDR_QUADLEN(str->len); | ||
227 | return p; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * struct pnfs_osd_targetid { | ||
232 | * u32 oti_type; | ||
233 | * struct nfs4_string oti_scsi_device_id; | ||
234 | * };// size 4 + [variable] | ||
235 | */ | ||
236 | static __be32 * | ||
237 | __read_targetid(__be32 *p, struct pnfs_osd_targetid* targetid) | ||
238 | { | ||
239 | u32 oti_type; | ||
240 | |||
241 | oti_type = be32_to_cpup(p++); | ||
242 | targetid->oti_type = oti_type; | ||
243 | |||
244 | switch (oti_type) { | ||
245 | case OBJ_TARGET_SCSI_NAME: | ||
246 | case OBJ_TARGET_SCSI_DEVICE_ID: | ||
247 | p = __read_u8_opaque(p, &targetid->oti_scsi_device_id); | ||
248 | } | ||
249 | |||
250 | return p; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * struct pnfs_osd_net_addr { | ||
255 | * struct nfs4_string r_netid; | ||
256 | * struct nfs4_string r_addr; | ||
257 | * }; | ||
258 | */ | ||
259 | static __be32 * | ||
260 | __read_net_addr(__be32 *p, struct pnfs_osd_net_addr* netaddr) | ||
261 | { | ||
262 | p = __read_u8_opaque(p, &netaddr->r_netid); | ||
263 | p = __read_u8_opaque(p, &netaddr->r_addr); | ||
264 | |||
265 | return p; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * struct pnfs_osd_targetaddr { | ||
270 | * u32 ota_available; | ||
271 | * struct pnfs_osd_net_addr ota_netaddr; | ||
272 | * }; | ||
273 | */ | ||
274 | static __be32 * | ||
275 | __read_targetaddr(__be32 *p, struct pnfs_osd_targetaddr *targetaddr) | ||
276 | { | ||
277 | u32 ota_available; | ||
278 | |||
279 | ota_available = be32_to_cpup(p++); | ||
280 | targetaddr->ota_available = ota_available; | ||
281 | |||
282 | if (ota_available) | ||
283 | p = __read_net_addr(p, &targetaddr->ota_netaddr); | ||
284 | |||
285 | |||
286 | return p; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * struct pnfs_osd_deviceaddr { | ||
291 | * struct pnfs_osd_targetid oda_targetid; | ||
292 | * struct pnfs_osd_targetaddr oda_targetaddr; | ||
293 | * u8 oda_lun[8]; | ||
294 | * struct nfs4_string oda_systemid; | ||
295 | * struct pnfs_osd_object_cred oda_root_obj_cred; | ||
296 | * struct nfs4_string oda_osdname; | ||
297 | * }; | ||
298 | */ | ||
299 | |||
300 | /* We need this version for the pnfs_osd_xdr_decode_deviceaddr which does | ||
301 | * not have an xdr_stream | ||
302 | */ | ||
303 | static __be32 * | ||
304 | __read_opaque_cred(__be32 *p, | ||
305 | struct pnfs_osd_opaque_cred *opaque_cred) | ||
306 | { | ||
307 | opaque_cred->cred_len = be32_to_cpu(*p++); | ||
308 | opaque_cred->cred = p; | ||
309 | return p + XDR_QUADLEN(opaque_cred->cred_len); | ||
310 | } | ||
311 | |||
312 | static __be32 * | ||
313 | __read_object_cred(__be32 *p, struct pnfs_osd_object_cred *comp) | ||
314 | { | ||
315 | p = _osd_xdr_decode_objid(p, &comp->oc_object_id); | ||
316 | comp->oc_osd_version = be32_to_cpup(p++); | ||
317 | comp->oc_cap_key_sec = be32_to_cpup(p++); | ||
318 | |||
319 | p = __read_opaque_cred(p, &comp->oc_cap_key); | ||
320 | p = __read_opaque_cred(p, &comp->oc_cap); | ||
321 | return p; | ||
322 | } | ||
323 | |||
324 | void pnfs_osd_xdr_decode_deviceaddr( | ||
325 | struct pnfs_osd_deviceaddr *deviceaddr, __be32 *p) | ||
326 | { | ||
327 | p = __read_targetid(p, &deviceaddr->oda_targetid); | ||
328 | |||
329 | p = __read_targetaddr(p, &deviceaddr->oda_targetaddr); | ||
330 | |||
331 | p = xdr_decode_opaque_fixed(p, deviceaddr->oda_lun, | ||
332 | sizeof(deviceaddr->oda_lun)); | ||
333 | |||
334 | p = __read_u8_opaque(p, &deviceaddr->oda_systemid); | ||
335 | |||
336 | p = __read_object_cred(p, &deviceaddr->oda_root_obj_cred); | ||
337 | |||
338 | p = __read_u8_opaque(p, &deviceaddr->oda_osdname); | ||
339 | |||
340 | /* libosd likes this terminated in dbg. It's last, so no problems */ | ||
341 | deviceaddr->oda_osdname.data[deviceaddr->oda_osdname.len] = 0; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * struct pnfs_osd_layoutupdate { | ||
346 | * u32 dsu_valid; | ||
347 | * s64 dsu_delta; | ||
348 | * u32 olu_ioerr_flag; | ||
349 | * }; xdr size 4 + 8 + 4 | ||
350 | */ | ||
351 | int | ||
352 | pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr, | ||
353 | struct pnfs_osd_layoutupdate *lou) | ||
354 | { | ||
355 | __be32 *p = xdr_reserve_space(xdr, 4 + 8 + 4); | ||
356 | |||
357 | if (!p) | ||
358 | return -E2BIG; | ||
359 | |||
360 | *p++ = cpu_to_be32(lou->dsu_valid); | ||
361 | if (lou->dsu_valid) | ||
362 | p = xdr_encode_hyper(p, lou->dsu_delta); | ||
363 | *p++ = cpu_to_be32(lou->olu_ioerr_flag); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * struct pnfs_osd_objid { | ||
369 | * struct nfs4_deviceid oid_device_id; | ||
370 | * u64 oid_partition_id; | ||
371 | * u64 oid_object_id; | ||
372 | * }; // xdr size 32 bytes | ||
373 | */ | ||
374 | static inline __be32 * | ||
375 | pnfs_osd_xdr_encode_objid(__be32 *p, struct pnfs_osd_objid *object_id) | ||
376 | { | ||
377 | p = xdr_encode_opaque_fixed(p, &object_id->oid_device_id.data, | ||
378 | sizeof(object_id->oid_device_id.data)); | ||
379 | p = xdr_encode_hyper(p, object_id->oid_partition_id); | ||
380 | p = xdr_encode_hyper(p, object_id->oid_object_id); | ||
381 | |||
382 | return p; | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * struct pnfs_osd_ioerr { | ||
387 | * struct pnfs_osd_objid oer_component; | ||
388 | * u64 oer_comp_offset; | ||
389 | * u64 oer_comp_length; | ||
390 | * u32 oer_iswrite; | ||
391 | * u32 oer_errno; | ||
392 | * }; // xdr size 32 + 24 bytes | ||
393 | */ | ||
394 | void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr) | ||
395 | { | ||
396 | p = pnfs_osd_xdr_encode_objid(p, &ioerr->oer_component); | ||
397 | p = xdr_encode_hyper(p, ioerr->oer_comp_offset); | ||
398 | p = xdr_encode_hyper(p, ioerr->oer_comp_length); | ||
399 | *p++ = cpu_to_be32(ioerr->oer_iswrite); | ||
400 | *p = cpu_to_be32(ioerr->oer_errno); | ||
401 | } | ||
402 | |||
403 | __be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr) | ||
404 | { | ||
405 | __be32 *p; | ||
406 | |||
407 | p = xdr_reserve_space(xdr, 32 + 24); | ||
408 | if (unlikely(!p)) | ||
409 | dprintk("%s: out of xdr space\n", __func__); | ||
410 | |||
411 | return p; | ||
412 | } | ||