linux/net/sunrpc/xprtrdma/svc_rdma_marshal.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the BSD-type
   8 * license below:
   9 *
  10 * Redistribution and use in source and binary forms, with or without
  11 * modification, are permitted provided that the following conditions
  12 * are met:
  13 *
  14 *      Redistributions of source code must retain the above copyright
  15 *      notice, this list of conditions and the following disclaimer.
  16 *
  17 *      Redistributions in binary form must reproduce the above
  18 *      copyright notice, this list of conditions and the following
  19 *      disclaimer in the documentation and/or other materials provided
  20 *      with the distribution.
  21 *
  22 *      Neither the name of the Network Appliance, Inc. nor the names of
  23 *      its contributors may be used to endorse or promote products
  24 *      derived from this software without specific prior written
  25 *      permission.
  26 *
  27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 *
  39 * Author: Tom Tucker <tom@opengridcomputing.com>
  40 */
  41
  42#include <linux/sunrpc/xdr.h>
  43#include <linux/sunrpc/debug.h>
  44#include <asm/unaligned.h>
  45#include <linux/sunrpc/rpc_rdma.h>
  46#include <linux/sunrpc/svc_rdma.h>
  47
  48#define RPCDBG_FACILITY RPCDBG_SVCXPRT
  49
  50/*
  51 * Decodes a read chunk list. The expected format is as follows:
  52 *    descrim  : xdr_one
  53 *    position : __be32 offset into XDR stream
  54 *    handle   : __be32 RKEY
  55 *    . . .
  56 *  end-of-list: xdr_zero
  57 */
  58static __be32 *decode_read_list(__be32 *va, __be32 *vaend)
  59{
  60        struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
  61
  62        while (ch->rc_discrim != xdr_zero) {
  63                if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
  64                    (unsigned long)vaend) {
  65                        dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
  66                        return NULL;
  67                }
  68                ch++;
  69        }
  70        return &ch->rc_position;
  71}
  72
  73/*
  74 * Decodes a write chunk list. The expected format is as follows:
  75 *    descrim  : xdr_one
  76 *    nchunks  : <count>
  77 *       handle   : __be32 RKEY           ---+
  78 *       length   : __be32 <len of segment>  |
  79 *       offset   : remove va                + <count>
  80 *       . . .                               |
  81 *                                        ---+
  82 */
  83static __be32 *decode_write_list(__be32 *va, __be32 *vaend)
  84{
  85        unsigned long start, end;
  86        int nchunks;
  87
  88        struct rpcrdma_write_array *ary =
  89                (struct rpcrdma_write_array *)va;
  90
  91        /* Check for not write-array */
  92        if (ary->wc_discrim == xdr_zero)
  93                return &ary->wc_nchunks;
  94
  95        if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
  96            (unsigned long)vaend) {
  97                dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
  98                return NULL;
  99        }
 100        nchunks = be32_to_cpu(ary->wc_nchunks);
 101
 102        start = (unsigned long)&ary->wc_array[0];
 103        end = (unsigned long)vaend;
 104        if (nchunks < 0 ||
 105            nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
 106            (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
 107                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
 108                        ary, nchunks, vaend);
 109                return NULL;
 110        }
 111        /*
 112         * rs_length is the 2nd 4B field in wc_target and taking its
 113         * address skips the list terminator
 114         */
 115        return &ary->wc_array[nchunks].wc_target.rs_length;
 116}
 117
 118static __be32 *decode_reply_array(__be32 *va, __be32 *vaend)
 119{
 120        unsigned long start, end;
 121        int nchunks;
 122        struct rpcrdma_write_array *ary =
 123                (struct rpcrdma_write_array *)va;
 124
 125        /* Check for no reply-array */
 126        if (ary->wc_discrim == xdr_zero)
 127                return &ary->wc_nchunks;
 128
 129        if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
 130            (unsigned long)vaend) {
 131                dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
 132                return NULL;
 133        }
 134        nchunks = be32_to_cpu(ary->wc_nchunks);
 135
 136        start = (unsigned long)&ary->wc_array[0];
 137        end = (unsigned long)vaend;
 138        if (nchunks < 0 ||
 139            nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
 140            (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
 141                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
 142                        ary, nchunks, vaend);
 143                return NULL;
 144        }
 145        return (__be32 *)&ary->wc_array[nchunks];
 146}
 147
 148int svc_rdma_xdr_decode_req(struct rpcrdma_msg *rmsgp, struct svc_rqst *rqstp)
 149{
 150        __be32 *va, *vaend;
 151        unsigned int len;
 152        u32 hdr_len;
 153
 154        /* Verify that there's enough bytes for header + something */
 155        if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_ERR) {
 156                dprintk("svcrdma: header too short = %d\n",
 157                        rqstp->rq_arg.len);
 158                return -EINVAL;
 159        }
 160
 161        if (rmsgp->rm_vers != rpcrdma_version) {
 162                dprintk("%s: bad version %u\n", __func__,
 163                        be32_to_cpu(rmsgp->rm_vers));
 164                return -EPROTONOSUPPORT;
 165        }
 166
 167        switch (be32_to_cpu(rmsgp->rm_type)) {
 168        case RDMA_MSG:
 169        case RDMA_NOMSG:
 170                break;
 171
 172        case RDMA_DONE:
 173                /* Just drop it */
 174                dprintk("svcrdma: dropping RDMA_DONE message\n");
 175                return 0;
 176
 177        case RDMA_ERROR:
 178                /* Possible if this is a backchannel reply.
 179                 * XXX: We should cancel this XID, though.
 180                 */
 181                dprintk("svcrdma: dropping RDMA_ERROR message\n");
 182                return 0;
 183
 184        case RDMA_MSGP:
 185                /* Pull in the extra for the padded case, bump our pointer */
 186                rmsgp->rm_body.rm_padded.rm_align =
 187                        be32_to_cpu(rmsgp->rm_body.rm_padded.rm_align);
 188                rmsgp->rm_body.rm_padded.rm_thresh =
 189                        be32_to_cpu(rmsgp->rm_body.rm_padded.rm_thresh);
 190
 191                va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
 192                rqstp->rq_arg.head[0].iov_base = va;
 193                len = (u32)((unsigned long)va - (unsigned long)rmsgp);
 194                rqstp->rq_arg.head[0].iov_len -= len;
 195                if (len > rqstp->rq_arg.len)
 196                        return -EINVAL;
 197                return len;
 198        default:
 199                dprintk("svcrdma: bad rdma procedure (%u)\n",
 200                        be32_to_cpu(rmsgp->rm_type));
 201                return -EINVAL;
 202        }
 203
 204        /* The chunk list may contain either a read chunk list or a write
 205         * chunk list and a reply chunk list.
 206         */
 207        va = &rmsgp->rm_body.rm_chunks[0];
 208        vaend = (__be32 *)((unsigned long)rmsgp + rqstp->rq_arg.len);
 209        va = decode_read_list(va, vaend);
 210        if (!va) {
 211                dprintk("svcrdma: failed to decode read list\n");
 212                return -EINVAL;
 213        }
 214        va = decode_write_list(va, vaend);
 215        if (!va) {
 216                dprintk("svcrdma: failed to decode write list\n");
 217                return -EINVAL;
 218        }
 219        va = decode_reply_array(va, vaend);
 220        if (!va) {
 221                dprintk("svcrdma: failed to decode reply chunk\n");
 222                return -EINVAL;
 223        }
 224
 225        rqstp->rq_arg.head[0].iov_base = va;
 226        hdr_len = (unsigned long)va - (unsigned long)rmsgp;
 227        rqstp->rq_arg.head[0].iov_len -= hdr_len;
 228
 229        return hdr_len;
 230}
 231
 232int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,
 233                              struct rpcrdma_msg *rmsgp,
 234                              enum rpcrdma_errcode err, __be32 *va)
 235{
 236        __be32 *startp = va;
 237
 238        *va++ = rmsgp->rm_xid;
 239        *va++ = rmsgp->rm_vers;
 240        *va++ = cpu_to_be32(xprt->sc_max_requests);
 241        *va++ = rdma_error;
 242        *va++ = cpu_to_be32(err);
 243        if (err == ERR_VERS) {
 244                *va++ = rpcrdma_version;
 245                *va++ = rpcrdma_version;
 246        }
 247
 248        return (int)((unsigned long)va - (unsigned long)startp);
 249}
 250
 251int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *rmsgp)
 252{
 253        struct rpcrdma_write_array *wr_ary;
 254
 255        /* There is no read-list in a reply */
 256
 257        /* skip write list */
 258        wr_ary = (struct rpcrdma_write_array *)
 259                &rmsgp->rm_body.rm_chunks[1];
 260        if (wr_ary->wc_discrim)
 261                wr_ary = (struct rpcrdma_write_array *)
 262                        &wr_ary->wc_array[be32_to_cpu(wr_ary->wc_nchunks)].
 263                        wc_target.rs_length;
 264        else
 265                wr_ary = (struct rpcrdma_write_array *)
 266                        &wr_ary->wc_nchunks;
 267
 268        /* skip reply array */
 269        if (wr_ary->wc_discrim)
 270                wr_ary = (struct rpcrdma_write_array *)
 271                        &wr_ary->wc_array[be32_to_cpu(wr_ary->wc_nchunks)];
 272        else
 273                wr_ary = (struct rpcrdma_write_array *)
 274                        &wr_ary->wc_nchunks;
 275
 276        return (unsigned long) wr_ary - (unsigned long) rmsgp;
 277}
 278
 279void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *rmsgp, int chunks)
 280{
 281        struct rpcrdma_write_array *ary;
 282
 283        /* no read-list */
 284        rmsgp->rm_body.rm_chunks[0] = xdr_zero;
 285
 286        /* write-array discrim */
 287        ary = (struct rpcrdma_write_array *)
 288                &rmsgp->rm_body.rm_chunks[1];
 289        ary->wc_discrim = xdr_one;
 290        ary->wc_nchunks = cpu_to_be32(chunks);
 291
 292        /* write-list terminator */
 293        ary->wc_array[chunks].wc_target.rs_handle = xdr_zero;
 294
 295        /* reply-array discriminator */
 296        ary->wc_array[chunks].wc_target.rs_length = xdr_zero;
 297}
 298
 299void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
 300                                 int chunks)
 301{
 302        ary->wc_discrim = xdr_one;
 303        ary->wc_nchunks = cpu_to_be32(chunks);
 304}
 305
 306void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
 307                                     int chunk_no,
 308                                     __be32 rs_handle,
 309                                     __be64 rs_offset,
 310                                     u32 write_len)
 311{
 312        struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
 313        seg->rs_handle = rs_handle;
 314        seg->rs_offset = rs_offset;
 315        seg->rs_length = cpu_to_be32(write_len);
 316}
 317
 318void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
 319                                  struct rpcrdma_msg *rdma_argp,
 320                                  struct rpcrdma_msg *rdma_resp,
 321                                  enum rpcrdma_proc rdma_type)
 322{
 323        rdma_resp->rm_xid = rdma_argp->rm_xid;
 324        rdma_resp->rm_vers = rdma_argp->rm_vers;
 325        rdma_resp->rm_credit = cpu_to_be32(xprt->sc_max_requests);
 326        rdma_resp->rm_type = cpu_to_be32(rdma_type);
 327
 328        /* Encode <nul> chunks lists */
 329        rdma_resp->rm_body.rm_chunks[0] = xdr_zero;
 330        rdma_resp->rm_body.rm_chunks[1] = xdr_zero;
 331        rdma_resp->rm_body.rm_chunks[2] = xdr_zero;
 332}
 333