]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - fs/nfs/nfs4xdr.c
Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO
[linux-imx.git] / fs / nfs / nfs4xdr.c
index 207d399c8dee3458ed418b6862f141795bb1450d..40da65e8fa2aa91508b8a22b0ce5186fbb8c79f0 100644 (file)
@@ -2656,6 +2656,10 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, NFS_FH(args->inode), &hdr);
        encode_layoutget(xdr, args, &hdr);
+
+       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
+           args->layout.pages, 0, args->layout.pglen);
+
        encode_nops(&hdr);
 }
 
@@ -5022,6 +5026,9 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
        __be32 *p;
        int status;
        u32 layout_count;
+       struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+       struct kvec *iov = rcvbuf->head;
+       u32 hdrlen, recvd;
 
        status = decode_op_hdr(xdr, OP_LAYOUTGET);
        if (status)
@@ -5038,17 +5045,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                return -EINVAL;
        }
 
-       p = xdr_inline_decode(xdr, 24);
+       p = xdr_inline_decode(xdr, 28);
        if (unlikely(!p))
                goto out_overflow;
        p = xdr_decode_hyper(p, &res->range.offset);
        p = xdr_decode_hyper(p, &res->range.length);
        res->range.iomode = be32_to_cpup(p++);
        res->type = be32_to_cpup(p++);
-
-       status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p);
-       if (unlikely(status))
-               return status;
+       res->layoutp->len = be32_to_cpup(p);
 
        dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
                __func__,
@@ -5056,12 +5060,18 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                (unsigned long)res->range.length,
                res->range.iomode,
                res->type,
-               res->layout.len);
+               res->layoutp->len);
+
+       hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
+       recvd = req->rq_rcv_buf.len - hdrlen;
+       if (res->layoutp->len > recvd) {
+               dprintk("NFS: server cheating in layoutget reply: "
+                               "layout len %u > recvd %u\n",
+                               res->layoutp->len, recvd);
+               return -EINVAL;
+       }
 
-       /* nfs4_proc_layoutget allocated a single page */
-       if (res->layout.len > PAGE_SIZE)
-               return -ENOMEM;
-       memcpy(res->layout.buf, p, res->layout.len);
+       xdr_read_pages(xdr, res->layoutp->len);
 
        if (layout_count > 1) {
                /* We only handle a length one array at the moment.  Any