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 <ooo@electrozaur.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 */ 55static __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 */ 72static 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 */ 100static 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 */ 132static inline int 133_osd_data_map_xdr_sz(void) 134{ 135 return 4 + 8 + 4 + 4 + 4 + 4; 136} 137 138static __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 159int 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 dprintk("%s: olo_comps_index=%d olo_num_comps=%d\n", __func__, 174 layout->olo_comps_index, layout->olo_num_comps); 175 176 iter->total_comps = layout->olo_num_comps; 177 return 0; 178} 179 180bool pnfs_osd_xdr_decode_layout_comp(struct pnfs_osd_object_cred *comp, 181 struct pnfs_osd_xdr_decode_layout_iter *iter, struct xdr_stream *xdr, 182 int *err) 183{ 184 BUG_ON(iter->decoded_comps > iter->total_comps); 185 if (iter->decoded_comps == iter->total_comps) 186 return false; 187 188 *err = _osd_xdr_decode_object_cred(comp, xdr); 189 if (unlikely(*err)) { 190 dprintk("%s: _osd_xdr_decode_object_cred=>%d decoded_comps=%d " 191 "total_comps=%d\n", __func__, *err, 192 iter->decoded_comps, iter->total_comps); 193 return false; /* stop the loop */ 194 } 195 dprintk("%s: dev(%llx:%llx) par=0x%llx obj=0x%llx " 196 "key_len=%u cap_len=%u\n", 197 __func__, 198 _DEVID_LO(&comp->oc_object_id.oid_device_id), 199 _DEVID_HI(&comp->oc_object_id.oid_device_id), 200 comp->oc_object_id.oid_partition_id, 201 comp->oc_object_id.oid_object_id, 202 comp->oc_cap_key.cred_len, comp->oc_cap.cred_len); 203 204 iter->decoded_comps++; 205 return true; 206} 207 208/* 209 * Get Device Information Decoding 210 * 211 * Note: since Device Information is currently done synchronously, all 212 * variable strings fields are left inside the rpc buffer and are only 213 * pointed to by the pnfs_osd_deviceaddr members. So the read buffer 214 * should not be freed while the returned information is in use. 215 */ 216/* 217 *struct nfs4_string { 218 * unsigned int len; 219 * char *data; 220 *}; // size [variable] 221 * NOTE: Returned string points to inside the XDR buffer 222 */ 223static __be32 * 224__read_u8_opaque(__be32 *p, struct nfs4_string *str) 225{ 226 str->len = be32_to_cpup(p++); 227 str->data = (char *)p; 228 229 p += XDR_QUADLEN(str->len); 230 return p; 231} 232 233/* 234 * struct pnfs_osd_targetid { 235 * u32 oti_type; 236 * struct nfs4_string oti_scsi_device_id; 237 * };// size 4 + [variable] 238 */ 239static __be32 * 240__read_targetid(__be32 *p, struct pnfs_osd_targetid* targetid) 241{ 242 u32 oti_type; 243 244 oti_type = be32_to_cpup(p++); 245 targetid->oti_type = oti_type; 246 247 switch (oti_type) { 248 case OBJ_TARGET_SCSI_NAME: 249 case OBJ_TARGET_SCSI_DEVICE_ID: 250 p = __read_u8_opaque(p, &targetid->oti_scsi_device_id); 251 } 252 253 return p; 254} 255 256/* 257 * struct pnfs_osd_net_addr { 258 * struct nfs4_string r_netid; 259 * struct nfs4_string r_addr; 260 * }; 261 */ 262static __be32 * 263__read_net_addr(__be32 *p, struct pnfs_osd_net_addr* netaddr) 264{ 265 p = __read_u8_opaque(p, &netaddr->r_netid); 266 p = __read_u8_opaque(p, &netaddr->r_addr); 267 268 return p; 269} 270 271/* 272 * struct pnfs_osd_targetaddr { 273 * u32 ota_available; 274 * struct pnfs_osd_net_addr ota_netaddr; 275 * }; 276 */ 277static __be32 * 278__read_targetaddr(__be32 *p, struct pnfs_osd_targetaddr *targetaddr) 279{ 280 u32 ota_available; 281 282 ota_available = be32_to_cpup(p++); 283 targetaddr->ota_available = ota_available; 284 285 if (ota_available) 286 p = __read_net_addr(p, &targetaddr->ota_netaddr); 287 288 289 return p; 290} 291 292/* 293 * struct pnfs_osd_deviceaddr { 294 * struct pnfs_osd_targetid oda_targetid; 295 * struct pnfs_osd_targetaddr oda_targetaddr; 296 * u8 oda_lun[8]; 297 * struct nfs4_string oda_systemid; 298 * struct pnfs_osd_object_cred oda_root_obj_cred; 299 * struct nfs4_string oda_osdname; 300 * }; 301 */ 302 303/* We need this version for the pnfs_osd_xdr_decode_deviceaddr which does 304 * not have an xdr_stream 305 */ 306static __be32 * 307__read_opaque_cred(__be32 *p, 308 struct pnfs_osd_opaque_cred *opaque_cred) 309{ 310 opaque_cred->cred_len = be32_to_cpu(*p++); 311 opaque_cred->cred = p; 312 return p + XDR_QUADLEN(opaque_cred->cred_len); 313} 314 315static __be32 * 316__read_object_cred(__be32 *p, struct pnfs_osd_object_cred *comp) 317{ 318 p = _osd_xdr_decode_objid(p, &comp->oc_object_id); 319 comp->oc_osd_version = be32_to_cpup(p++); 320 comp->oc_cap_key_sec = be32_to_cpup(p++); 321 322 p = __read_opaque_cred(p, &comp->oc_cap_key); 323 p = __read_opaque_cred(p, &comp->oc_cap); 324 return p; 325} 326 327void pnfs_osd_xdr_decode_deviceaddr( 328 struct pnfs_osd_deviceaddr *deviceaddr, __be32 *p) 329{ 330 p = __read_targetid(p, &deviceaddr->oda_targetid); 331 332 p = __read_targetaddr(p, &deviceaddr->oda_targetaddr); 333 334 p = xdr_decode_opaque_fixed(p, deviceaddr->oda_lun, 335 sizeof(deviceaddr->oda_lun)); 336 337 p = __read_u8_opaque(p, &deviceaddr->oda_systemid); 338 339 p = __read_object_cred(p, &deviceaddr->oda_root_obj_cred); 340 341 p = __read_u8_opaque(p, &deviceaddr->oda_osdname); 342 343 /* libosd likes this terminated in dbg. It's last, so no problems */ 344 deviceaddr->oda_osdname.data[deviceaddr->oda_osdname.len] = 0; 345} 346 347/* 348 * struct pnfs_osd_layoutupdate { 349 * u32 dsu_valid; 350 * s64 dsu_delta; 351 * u32 olu_ioerr_flag; 352 * }; xdr size 4 + 8 + 4 353 */ 354int 355pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr, 356 struct pnfs_osd_layoutupdate *lou) 357{ 358 __be32 *p = xdr_reserve_space(xdr, 4 + 8 + 4); 359 360 if (!p) 361 return -E2BIG; 362 363 *p++ = cpu_to_be32(lou->dsu_valid); 364 if (lou->dsu_valid) 365 p = xdr_encode_hyper(p, lou->dsu_delta); 366 *p++ = cpu_to_be32(lou->olu_ioerr_flag); 367 return 0; 368} 369 370/* 371 * struct pnfs_osd_objid { 372 * struct nfs4_deviceid oid_device_id; 373 * u64 oid_partition_id; 374 * u64 oid_object_id; 375 * }; // xdr size 32 bytes 376 */ 377static inline __be32 * 378pnfs_osd_xdr_encode_objid(__be32 *p, struct pnfs_osd_objid *object_id) 379{ 380 p = xdr_encode_opaque_fixed(p, &object_id->oid_device_id.data, 381 sizeof(object_id->oid_device_id.data)); 382 p = xdr_encode_hyper(p, object_id->oid_partition_id); 383 p = xdr_encode_hyper(p, object_id->oid_object_id); 384 385 return p; 386} 387 388/* 389 * struct pnfs_osd_ioerr { 390 * struct pnfs_osd_objid oer_component; 391 * u64 oer_comp_offset; 392 * u64 oer_comp_length; 393 * u32 oer_iswrite; 394 * u32 oer_errno; 395 * }; // xdr size 32 + 24 bytes 396 */ 397void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr) 398{ 399 p = pnfs_osd_xdr_encode_objid(p, &ioerr->oer_component); 400 p = xdr_encode_hyper(p, ioerr->oer_comp_offset); 401 p = xdr_encode_hyper(p, ioerr->oer_comp_length); 402 *p++ = cpu_to_be32(ioerr->oer_iswrite); 403 *p = cpu_to_be32(ioerr->oer_errno); 404} 405 406__be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr) 407{ 408 __be32 *p; 409 410 p = xdr_reserve_space(xdr, 32 + 24); 411 if (unlikely(!p)) 412 dprintk("%s: out of xdr space\n", __func__); 413 414 return p; 415} 416