linux/fs/nfs/objlayout/pnfs_osd_xdr_cli.c
<<
>>
Prefs
   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