Commit 06b5fc3a authored by Trond Myklebust's avatar Trond Myklebust

Merge tag 'nfs-rdma-for-5.1-1' of git://git.linux-nfs.org/projects/anna/linux-nfs

NFSoRDMA client updates for 5.1

New features:
- Convert rpc auth layer to use xdr_streams
- Config option to disable insecure enctypes
- Reduce size of RPC receive buffers

Bugfixes and cleanups:
- Fix sparse warnings
- Check inline size before providing a write chunk
- Reduce the receive doorbell rate
- Various tracepoint improvements

[Trond: Fix up merge conflicts]
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parents 5085607d 2c94b8ec
...@@ -74,17 +74,6 @@ static void nlm4_compute_offsets(const struct nlm_lock *lock, ...@@ -74,17 +74,6 @@ static void nlm4_compute_offsets(const struct nlm_lock *lock,
*l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
} }
/*
* Handle decode buffer overflows out-of-line.
*/
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
{
dprintk("lockd: %s prematurely hit the end of our receive buffer. "
"Remaining buffer length is %tu words.\n",
func, xdr->end - xdr->p);
}
/* /*
* Encode/decode NLMv4 basic data types * Encode/decode NLMv4 basic data types
* *
...@@ -176,7 +165,6 @@ static int decode_cookie(struct xdr_stream *xdr, ...@@ -176,7 +165,6 @@ static int decode_cookie(struct xdr_stream *xdr,
dprintk("NFS: returned cookie was too long: %u\n", length); dprintk("NFS: returned cookie was too long: %u\n", length);
return -EIO; return -EIO;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
...@@ -236,7 +224,6 @@ static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) ...@@ -236,7 +224,6 @@ static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat)
__func__, be32_to_cpup(p)); __func__, be32_to_cpup(p));
return -EIO; return -EIO;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
...@@ -309,7 +296,6 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) ...@@ -309,7 +296,6 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
out: out:
return error; return error;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
......
...@@ -70,17 +70,6 @@ static void nlm_compute_offsets(const struct nlm_lock *lock, ...@@ -70,17 +70,6 @@ static void nlm_compute_offsets(const struct nlm_lock *lock,
*l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
} }
/*
* Handle decode buffer overflows out-of-line.
*/
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
{
dprintk("lockd: %s prematurely hit the end of our receive buffer. "
"Remaining buffer length is %tu words.\n",
func, xdr->end - xdr->p);
}
/* /*
* Encode/decode NLMv3 basic data types * Encode/decode NLMv3 basic data types
* *
...@@ -173,7 +162,6 @@ static int decode_cookie(struct xdr_stream *xdr, ...@@ -173,7 +162,6 @@ static int decode_cookie(struct xdr_stream *xdr,
dprintk("NFS: returned cookie was too long: %u\n", length); dprintk("NFS: returned cookie was too long: %u\n", length);
return -EIO; return -EIO;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
...@@ -231,7 +219,6 @@ static int decode_nlm_stat(struct xdr_stream *xdr, ...@@ -231,7 +219,6 @@ static int decode_nlm_stat(struct xdr_stream *xdr,
__func__, be32_to_cpup(p)); __func__, be32_to_cpup(p));
return -EIO; return -EIO;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
...@@ -303,7 +290,6 @@ static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result) ...@@ -303,7 +290,6 @@ static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
out: out:
return error; return error;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
......
...@@ -72,16 +72,6 @@ static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p) ...@@ -72,16 +72,6 @@ static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p)
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
static __be32 *read_buf(struct xdr_stream *xdr, size_t nbytes)
{
__be32 *p;
p = xdr_inline_decode(xdr, nbytes);
if (unlikely(p == NULL))
printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
return p;
}
static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len,
const char **str, size_t maxlen) const char **str, size_t maxlen)
{ {
...@@ -98,13 +88,13 @@ static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) ...@@ -98,13 +88,13 @@ static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
{ {
__be32 *p; __be32 *p;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
fh->size = ntohl(*p); fh->size = ntohl(*p);
if (fh->size > NFS4_FHSIZE) if (fh->size > NFS4_FHSIZE)
return htonl(NFS4ERR_BADHANDLE); return htonl(NFS4ERR_BADHANDLE);
p = read_buf(xdr, fh->size); p = xdr_inline_decode(xdr, fh->size);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
memcpy(&fh->data[0], p, fh->size); memcpy(&fh->data[0], p, fh->size);
...@@ -117,11 +107,11 @@ static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) ...@@ -117,11 +107,11 @@ static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
__be32 *p; __be32 *p;
unsigned int attrlen; unsigned int attrlen;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
attrlen = ntohl(*p); attrlen = ntohl(*p);
p = read_buf(xdr, attrlen << 2); p = xdr_inline_decode(xdr, attrlen << 2);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
if (likely(attrlen > 0)) if (likely(attrlen > 0))
...@@ -135,7 +125,7 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) ...@@ -135,7 +125,7 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{ {
__be32 *p; __be32 *p;
p = read_buf(xdr, NFS4_STATEID_SIZE); p = xdr_inline_decode(xdr, NFS4_STATEID_SIZE);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
memcpy(stateid->data, p, NFS4_STATEID_SIZE); memcpy(stateid->data, p, NFS4_STATEID_SIZE);
...@@ -156,7 +146,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound ...@@ -156,7 +146,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
status = decode_string(xdr, &hdr->taglen, &hdr->tag, CB_OP_TAGLEN_MAXSZ); status = decode_string(xdr, &hdr->taglen, &hdr->tag, CB_OP_TAGLEN_MAXSZ);
if (unlikely(status != 0)) if (unlikely(status != 0))
return status; return status;
p = read_buf(xdr, 12); p = xdr_inline_decode(xdr, 12);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
hdr->minorversion = ntohl(*p++); hdr->minorversion = ntohl(*p++);
...@@ -176,7 +166,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound ...@@ -176,7 +166,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
{ {
__be32 *p; __be32 *p;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE_HDR); return htonl(NFS4ERR_RESOURCE_HDR);
*op = ntohl(*p); *op = ntohl(*p);
...@@ -205,7 +195,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, ...@@ -205,7 +195,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp,
status = decode_delegation_stateid(xdr, &args->stateid); status = decode_delegation_stateid(xdr, &args->stateid);
if (unlikely(status != 0)) if (unlikely(status != 0))
return status; return status;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
args->truncate = ntohl(*p); args->truncate = ntohl(*p);
...@@ -227,7 +217,7 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, ...@@ -227,7 +217,7 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
__be32 status = 0; __be32 status = 0;
uint32_t iomode; uint32_t iomode;
p = read_buf(xdr, 4 * sizeof(uint32_t)); p = xdr_inline_decode(xdr, 4 * sizeof(uint32_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
...@@ -245,14 +235,14 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, ...@@ -245,14 +235,14 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
if (unlikely(status != 0)) if (unlikely(status != 0))
return status; return status;
p = read_buf(xdr, 2 * sizeof(uint64_t)); p = xdr_inline_decode(xdr, 2 * sizeof(uint64_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
p = xdr_decode_hyper(p, &args->cbl_range.offset); p = xdr_decode_hyper(p, &args->cbl_range.offset);
p = xdr_decode_hyper(p, &args->cbl_range.length); p = xdr_decode_hyper(p, &args->cbl_range.length);
return decode_layout_stateid(xdr, &args->cbl_stateid); return decode_layout_stateid(xdr, &args->cbl_stateid);
} else if (args->cbl_recall_type == RETURN_FSID) { } else if (args->cbl_recall_type == RETURN_FSID) {
p = read_buf(xdr, 2 * sizeof(uint64_t)); p = xdr_inline_decode(xdr, 2 * sizeof(uint64_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
p = xdr_decode_hyper(p, &args->cbl_fsid.major); p = xdr_decode_hyper(p, &args->cbl_fsid.major);
...@@ -275,7 +265,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, ...@@ -275,7 +265,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
args->ndevs = 0; args->ndevs = 0;
/* Num of device notifications */ /* Num of device notifications */
p = read_buf(xdr, sizeof(uint32_t)); p = xdr_inline_decode(xdr, sizeof(uint32_t));
if (unlikely(p == NULL)) { if (unlikely(p == NULL)) {
status = htonl(NFS4ERR_BADXDR); status = htonl(NFS4ERR_BADXDR);
goto out; goto out;
...@@ -298,7 +288,8 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, ...@@ -298,7 +288,8 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
struct cb_devicenotifyitem *dev = &args->devs[i]; struct cb_devicenotifyitem *dev = &args->devs[i];
p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE); p = xdr_inline_decode(xdr, (4 * sizeof(uint32_t)) +
NFS4_DEVICEID4_SIZE);
if (unlikely(p == NULL)) { if (unlikely(p == NULL)) {
status = htonl(NFS4ERR_BADXDR); status = htonl(NFS4ERR_BADXDR);
goto err; goto err;
...@@ -329,7 +320,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, ...@@ -329,7 +320,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) { if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
p = read_buf(xdr, sizeof(uint32_t)); p = xdr_inline_decode(xdr, sizeof(uint32_t));
if (unlikely(p == NULL)) { if (unlikely(p == NULL)) {
status = htonl(NFS4ERR_BADXDR); status = htonl(NFS4ERR_BADXDR);
goto err; goto err;
...@@ -359,7 +350,7 @@ static __be32 decode_sessionid(struct xdr_stream *xdr, ...@@ -359,7 +350,7 @@ static __be32 decode_sessionid(struct xdr_stream *xdr,
{ {
__be32 *p; __be32 *p;
p = read_buf(xdr, NFS4_MAX_SESSIONID_LEN); p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
...@@ -379,13 +370,13 @@ static __be32 decode_rc_list(struct xdr_stream *xdr, ...@@ -379,13 +370,13 @@ static __be32 decode_rc_list(struct xdr_stream *xdr,
goto out; goto out;
status = htonl(NFS4ERR_RESOURCE); status = htonl(NFS4ERR_RESOURCE);
p = read_buf(xdr, sizeof(uint32_t)); p = xdr_inline_decode(xdr, sizeof(uint32_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
goto out; goto out;
rc_list->rcl_nrefcalls = ntohl(*p++); rc_list->rcl_nrefcalls = ntohl(*p++);
if (rc_list->rcl_nrefcalls) { if (rc_list->rcl_nrefcalls) {
p = read_buf(xdr, p = xdr_inline_decode(xdr,
rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
goto out; goto out;
...@@ -418,7 +409,7 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, ...@@ -418,7 +409,7 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
if (status) if (status)
return status; return status;
p = read_buf(xdr, 5 * sizeof(uint32_t)); p = xdr_inline_decode(xdr, 5 * sizeof(uint32_t));
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
...@@ -461,7 +452,7 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp, ...@@ -461,7 +452,7 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp,
uint32_t bitmap[2]; uint32_t bitmap[2];
__be32 *p, status; __be32 *p, status;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
args->craa_objs_to_keep = ntohl(*p++); args->craa_objs_to_keep = ntohl(*p++);
...@@ -480,7 +471,7 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp, ...@@ -480,7 +471,7 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
struct cb_recallslotargs *args = argp; struct cb_recallslotargs *args = argp;
__be32 *p; __be32 *p;
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
args->crsa_target_highest_slotid = ntohl(*p++); args->crsa_target_highest_slotid = ntohl(*p++);
...@@ -492,14 +483,14 @@ static __be32 decode_lockowner(struct xdr_stream *xdr, struct cb_notify_lock_arg ...@@ -492,14 +483,14 @@ static __be32 decode_lockowner(struct xdr_stream *xdr, struct cb_notify_lock_arg
__be32 *p; __be32 *p;
unsigned int len; unsigned int len;
p = read_buf(xdr, 12); p = xdr_inline_decode(xdr, 12);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
p = xdr_decode_hyper(p, &args->cbnl_owner.clientid); p = xdr_decode_hyper(p, &args->cbnl_owner.clientid);
len = be32_to_cpu(*p); len = be32_to_cpu(*p);
p = read_buf(xdr, len); p = xdr_inline_decode(xdr, len);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_BADXDR); return htonl(NFS4ERR_BADXDR);
...@@ -537,7 +528,7 @@ static __be32 decode_write_response(struct xdr_stream *xdr, ...@@ -537,7 +528,7 @@ static __be32 decode_write_response(struct xdr_stream *xdr,
__be32 *p; __be32 *p;
/* skip the always zero field */ /* skip the always zero field */
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out; goto out;
p++; p++;
...@@ -577,7 +568,7 @@ static __be32 decode_offload_args(struct svc_rqst *rqstp, ...@@ -577,7 +568,7 @@ static __be32 decode_offload_args(struct svc_rqst *rqstp,
return status; return status;
/* decode status */ /* decode status */
p = read_buf(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out; goto out;
args->error = ntohl(*p++); args->error = ntohl(*p++);
...@@ -943,10 +934,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) ...@@ -943,10 +934,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
}; };
unsigned int nops = 0; unsigned int nops = 0;
xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); xdr_init_decode(&xdr_in, &rqstp->rq_arg,
rqstp->rq_arg.head[0].iov_base, NULL);
p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
xdr_init_encode(&xdr_out, &rqstp->rq_res, p); xdr_init_encode(&xdr_out, &rqstp->rq_res, p, NULL);
status = decode_compound_hdr_arg(&xdr_in, &hdr_arg); status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
if (status == htonl(NFS4ERR_RESOURCE)) if (status == htonl(NFS4ERR_RESOURCE))
......
...@@ -2036,7 +2036,7 @@ ff_layout_encode_layoutreturn(struct xdr_stream *xdr, ...@@ -2036,7 +2036,7 @@ ff_layout_encode_layoutreturn(struct xdr_stream *xdr,
dprintk("%s: Begin\n", __func__); dprintk("%s: Begin\n", __func__);
xdr_init_encode(&tmp_xdr, &tmp_buf, NULL); xdr_init_encode(&tmp_xdr, &tmp_buf, NULL, NULL);
ff_layout_encode_ioerr(&tmp_xdr, args, ff_args); ff_layout_encode_ioerr(&tmp_xdr, args, ff_args);
ff_layout_encode_iostats_array(&tmp_xdr, args, ff_args); ff_layout_encode_iostats_array(&tmp_xdr, args, ff_args);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/nfs.h> #include <linux/nfs.h>
#include <linux/nfs2.h> #include <linux/nfs2.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include "nfstrace.h"
#include "internal.h" #include "internal.h"
#define NFSDBG_FACILITY NFSDBG_XDR #define NFSDBG_FACILITY NFSDBG_XDR
...@@ -55,41 +56,15 @@ ...@@ -55,41 +56,15 @@
#define NFS_attrstat_sz (1+NFS_fattr_sz) #define NFS_attrstat_sz (1+NFS_fattr_sz)
#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
#define NFS_readlinkres_sz (2) #define NFS_readlinkres_sz (2+1)
#define NFS_readres_sz (1+NFS_fattr_sz+1) #define NFS_readres_sz (1+NFS_fattr_sz+1+1)
#define NFS_writeres_sz (NFS_attrstat_sz) #define NFS_writeres_sz (NFS_attrstat_sz)
#define NFS_stat_sz (1) #define NFS_stat_sz (1)
#define NFS_readdirres_sz (1) #define NFS_readdirres_sz (1+1)
#define NFS_statfsres_sz (1+NFS_info_sz) #define NFS_statfsres_sz (1+NFS_info_sz)
static int nfs_stat_to_errno(enum nfs_stat); static int nfs_stat_to_errno(enum nfs_stat);
/*
* While encoding arguments, set up the reply buffer in advance to
* receive reply data directly into the page cache.
*/
static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
unsigned int base, unsigned int len,
unsigned int bufsize)
{
struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
}
/*
* Handle decode buffer overflows out-of-line.
*/
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
{
dprintk("NFS: %s prematurely hit the end of our receive buffer. "
"Remaining buffer length is %tu words.\n",
func, xdr->end - xdr->p);
}
/* /*
* Encode/decode NFSv2 basic data types * Encode/decode NFSv2 basic data types
* *
...@@ -110,8 +85,8 @@ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result) ...@@ -110,8 +85,8 @@ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
count = be32_to_cpup(p); count = be32_to_cpup(p);
recvd = xdr_read_pages(xdr, count); recvd = xdr_read_pages(xdr, count);
if (unlikely(count > recvd)) if (unlikely(count > recvd))
...@@ -125,9 +100,6 @@ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result) ...@@ -125,9 +100,6 @@ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
"count %u > recvd %u\n", count, recvd); "count %u > recvd %u\n", count, recvd);
count = recvd; count = recvd;
goto out; goto out;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -157,13 +129,16 @@ static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) ...@@ -157,13 +129,16 @@ static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
if (unlikely(*p != cpu_to_be32(NFS_OK)))
goto out_status;
*status = 0;
return 0;
out_status:
*status = be32_to_cpup(p); *status = be32_to_cpup(p);
trace_nfs_xdr_status((int)*status);
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -205,14 +180,11 @@ static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) ...@@ -205,14 +180,11 @@ static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, NFS2_FHSIZE); p = xdr_inline_decode(xdr, NFS2_FHSIZE);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
fh->size = NFS2_FHSIZE; fh->size = NFS2_FHSIZE;
memcpy(fh->data, p, NFS2_FHSIZE); memcpy(fh->data, p, NFS2_FHSIZE);
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -282,8 +254,8 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) ...@@ -282,8 +254,8 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, NFS_fattr_sz << 2); p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
fattr->valid |= NFS_ATTR_FATTR_V2; fattr->valid |= NFS_ATTR_FATTR_V2;
...@@ -325,9 +297,6 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) ...@@ -325,9 +297,6 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
out_gid: out_gid:
dprintk("NFS: returned invalid gid\n"); dprintk("NFS: returned invalid gid\n");
return -EINVAL; return -EINVAL;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -416,23 +385,20 @@ static int decode_filename_inline(struct xdr_stream *xdr, ...@@ -416,23 +385,20 @@ static int decode_filename_inline(struct xdr_stream *xdr,
u32 count; u32 count;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
count = be32_to_cpup(p); count = be32_to_cpup(p);
if (count > NFS3_MAXNAMLEN) if (count > NFS3_MAXNAMLEN)
goto out_nametoolong; goto out_nametoolong;
p = xdr_inline_decode(xdr, count); p = xdr_inline_decode(xdr, count);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
*name = (const char *)p; *name = (const char *)p;
*length = count; *length = count;
return 0; return 0;
out_nametoolong: out_nametoolong:
dprintk("NFS: returned filename too long: %u\n", count); dprintk("NFS: returned filename too long: %u\n", count);
return -ENAMETOOLONG; return -ENAMETOOLONG;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -455,8 +421,8 @@ static int decode_path(struct xdr_stream *xdr) ...@@ -455,8 +421,8 @@ static int decode_path(struct xdr_stream *xdr)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
length = be32_to_cpup(p); length = be32_to_cpup(p);
if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
goto out_size; goto out_size;
...@@ -472,9 +438,6 @@ static int decode_path(struct xdr_stream *xdr) ...@@ -472,9 +438,6 @@ static int decode_path(struct xdr_stream *xdr)
dprintk("NFS: server cheating in pathname result: " dprintk("NFS: server cheating in pathname result: "
"length %u > received %u\n", length, recvd); "length %u > received %u\n", length, recvd);
return -EIO; return -EIO;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
/* /*
...@@ -615,8 +578,8 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, ...@@ -615,8 +578,8 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
const struct nfs_readlinkargs *args = data; const struct nfs_readlinkargs *args = data;
encode_fhandle(xdr, args->fh); encode_fhandle(xdr, args->fh);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pglen, NFS_readlinkres_sz); args->pglen, NFS_readlinkres_sz);
} }
/* /*
...@@ -651,8 +614,8 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req, ...@@ -651,8 +614,8 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
const struct nfs_pgio_args *args = data; const struct nfs_pgio_args *args = data;
encode_readargs(xdr, args); encode_readargs(xdr, args);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->count, NFS_readres_sz); args->count, NFS_readres_sz);
req->rq_rcv_buf.flags |= XDRBUF_READ; req->rq_rcv_buf.flags |= XDRBUF_READ;
} }
...@@ -809,8 +772,8 @@ static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, ...@@ -809,8 +772,8 @@ static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
const struct nfs_readdirargs *args = data; const struct nfs_readdirargs *args = data;
encode_readdirargs(xdr, args); encode_readdirargs(xdr, args);
prepare_reply_buffer(req, args->pages, 0, rpc_prepare_reply_pages(req, args->pages, 0,
args->count, NFS_readdirres_sz); args->count, NFS_readdirres_sz);
} }
/* /*
...@@ -951,12 +914,12 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -951,12 +914,12 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
int error; int error;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EAGAIN;
if (*p++ == xdr_zero) { if (*p++ == xdr_zero) {
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EAGAIN;
if (*p++ == xdr_zero) if (*p++ == xdr_zero)
return -EAGAIN; return -EAGAIN;
entry->eof = 1; entry->eof = 1;
...@@ -964,8 +927,8 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -964,8 +927,8 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
} }
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EAGAIN;
entry->ino = be32_to_cpup(p); entry->ino = be32_to_cpup(p);
error = decode_filename_inline(xdr, &entry->name, &entry->len); error = decode_filename_inline(xdr, &entry->name, &entry->len);
...@@ -978,17 +941,13 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -978,17 +941,13 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
*/ */
entry->prev_cookie = entry->cookie; entry->prev_cookie = entry->cookie;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EAGAIN;
entry->cookie = be32_to_cpup(p); entry->cookie = be32_to_cpup(p);
entry->d_type = DT_UNKNOWN; entry->d_type = DT_UNKNOWN;
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EAGAIN;
} }
/* /*
...@@ -1052,17 +1011,14 @@ static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result) ...@@ -1052,17 +1011,14 @@ static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
__be32 *p; __be32 *p;
p = xdr_inline_decode(xdr, NFS_info_sz << 2); p = xdr_inline_decode(xdr, NFS_info_sz << 2);
if (unlikely(p == NULL)) if (unlikely(!p))
goto out_overflow; return -EIO;
result->tsize = be32_to_cpup(p++); result->tsize = be32_to_cpup(p++);
result->bsize = be32_to_cpup(p++); result->bsize = be32_to_cpup(p++);
result->blocks = be32_to_cpup(p++); result->blocks = be32_to_cpup(p++);
result->bfree = be32_to_cpup(p++); result->bfree = be32_to_cpup(p++);
result->bavail = be32_to_cpup(p); result->bavail = be32_to_cpup(p);
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr, static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
......
This diff is collapsed.
...@@ -394,7 +394,7 @@ static int decode_write_response(struct xdr_stream *xdr, ...@@ -394,7 +394,7 @@ static int decode_write_response(struct xdr_stream *xdr,
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; return -EIO;
count = be32_to_cpup(p); count = be32_to_cpup(p);
if (count > 1) if (count > 1)
return -EREMOTEIO; return -EREMOTEIO;
...@@ -402,18 +402,14 @@ static int decode_write_response(struct xdr_stream *xdr, ...@@ -402,18 +402,14 @@ static int decode_write_response(struct xdr_stream *xdr,
status = decode_opaque_fixed(xdr, &res->stateid, status = decode_opaque_fixed(xdr, &res->stateid,
NFS4_STATEID_SIZE); NFS4_STATEID_SIZE);
if (unlikely(status)) if (unlikely(status))
goto out_overflow; return -EIO;
} }
p = xdr_inline_decode(xdr, 8 + 4); p = xdr_inline_decode(xdr, 8 + 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; return -EIO;
p = xdr_decode_hyper(p, &res->count); p = xdr_decode_hyper(p, &res->count);
res->verifier.committed = be32_to_cpup(p); res->verifier.committed = be32_to_cpup(p);
return decode_verifier(xdr, &res->verifier.verifier); return decode_verifier(xdr, &res->verifier.verifier);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
static int decode_copy_requirements(struct xdr_stream *xdr, static int decode_copy_requirements(struct xdr_stream *xdr,
...@@ -422,14 +418,11 @@ static int decode_copy_requirements(struct xdr_stream *xdr, ...@@ -422,14 +418,11 @@ static int decode_copy_requirements(struct xdr_stream *xdr,
p = xdr_inline_decode(xdr, 4 + 4); p = xdr_inline_decode(xdr, 4 + 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; return -EIO;
res->consecutive = be32_to_cpup(p++); res->consecutive = be32_to_cpup(p++);
res->synchronous = be32_to_cpup(p++); res->synchronous = be32_to_cpup(p++);
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res) static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
...@@ -474,15 +467,11 @@ static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res) ...@@ -474,15 +467,11 @@ static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
p = xdr_inline_decode(xdr, 4 + 8); p = xdr_inline_decode(xdr, 4 + 8);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; return -EIO;
res->sr_eof = be32_to_cpup(p++); res->sr_eof = be32_to_cpup(p++);
p = xdr_decode_hyper(p, &res->sr_offset); p = xdr_decode_hyper(p, &res->sr_offset);
return 0; return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
} }
static int decode_layoutstats(struct xdr_stream *xdr) static int decode_layoutstats(struct xdr_stream *xdr)
......
...@@ -524,6 +524,31 @@ TRACE_EVENT(nfs4_setup_sequence, ...@@ -524,6 +524,31 @@ TRACE_EVENT(nfs4_setup_sequence,
) )
); );
TRACE_EVENT(nfs4_xdr_status,
TP_PROTO(
u32 op,
int error
),
TP_ARGS(op, error),
TP_STRUCT__entry(
__field(u32, op)
__field(int, error)
),
TP_fast_assign(
__entry->op = op;
__entry->error = -error;
),
TP_printk(
"operation %d: nfs status %d (%s)",
__entry->op,
__entry->error, show_nfsv4_errors(__entry->error)
)
);
DECLARE_EVENT_CLASS(nfs4_open_event, DECLARE_EVENT_CLASS(nfs4_open_event,
TP_PROTO( TP_PROTO(
const struct nfs_open_context *ctx, const struct nfs_open_context *ctx,
......
This diff is collapsed.
...@@ -11,3 +11,4 @@ ...@@ -11,3 +11,4 @@
EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_enter); EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_enter);
EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_exit); EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_fsync_exit);
EXPORT_TRACEPOINT_SYMBOL_GPL(nfs_xdr_status);
...@@ -969,6 +969,91 @@ TRACE_EVENT(nfs_commit_done, ...@@ -969,6 +969,91 @@ TRACE_EVENT(nfs_commit_done,
) )
); );
TRACE_DEFINE_ENUM(NFS_OK);
TRACE_DEFINE_ENUM(NFSERR_PERM);
TRACE_DEFINE_ENUM(NFSERR_NOENT);
TRACE_DEFINE_ENUM(NFSERR_IO);
TRACE_DEFINE_ENUM(NFSERR_NXIO);
TRACE_DEFINE_ENUM(NFSERR_ACCES);
TRACE_DEFINE_ENUM(NFSERR_EXIST);
TRACE_DEFINE_ENUM(NFSERR_XDEV);
TRACE_DEFINE_ENUM(NFSERR_NODEV);
TRACE_DEFINE_ENUM(NFSERR_NOTDIR);
TRACE_DEFINE_ENUM(NFSERR_ISDIR);
TRACE_DEFINE_ENUM(NFSERR_INVAL);
TRACE_DEFINE_ENUM(NFSERR_FBIG);
TRACE_DEFINE_ENUM(NFSERR_NOSPC);
TRACE_DEFINE_ENUM(NFSERR_ROFS);
TRACE_DEFINE_ENUM(NFSERR_MLINK);
TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG);
TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY);
TRACE_DEFINE_ENUM(NFSERR_DQUOT);
TRACE_DEFINE_ENUM(NFSERR_STALE);
TRACE_DEFINE_ENUM(NFSERR_REMOTE);
TRACE_DEFINE_ENUM(NFSERR_WFLUSH);
TRACE_DEFINE_ENUM(NFSERR_BADHANDLE);
TRACE_DEFINE_ENUM(NFSERR_NOT_SYNC);
TRACE_DEFINE_ENUM(NFSERR_BAD_COOKIE);
TRACE_DEFINE_ENUM(NFSERR_NOTSUPP);
TRACE_DEFINE_ENUM(NFSERR_TOOSMALL);
TRACE_DEFINE_ENUM(NFSERR_SERVERFAULT);
TRACE_DEFINE_ENUM(NFSERR_BADTYPE);
TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
#define nfs_show_status(x) \
__print_symbolic(x, \
{ NFS_OK, "OK" }, \
{ NFSERR_PERM, "PERM" }, \
{ NFSERR_NOENT, "NOENT" }, \
{ NFSERR_IO, "IO" }, \
{ NFSERR_NXIO, "NXIO" }, \
{ NFSERR_ACCES, "ACCES" }, \
{ NFSERR_EXIST, "EXIST" }, \
{ NFSERR_XDEV, "XDEV" }, \
{ NFSERR_NODEV, "NODEV" }, \
{ NFSERR_NOTDIR, "NOTDIR" }, \
{ NFSERR_ISDIR, "ISDIR" }, \
{ NFSERR_INVAL, "INVAL" }, \
{ NFSERR_FBIG, "FBIG" }, \
{ NFSERR_NOSPC, "NOSPC" }, \
{ NFSERR_ROFS, "ROFS" }, \
{ NFSERR_MLINK, "MLINK" }, \
{ NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \
{ NFSERR_NOTEMPTY, "NOTEMPTY" }, \
{ NFSERR_DQUOT, "DQUOT" }, \
{ NFSERR_STALE, "STALE" }, \
{ NFSERR_REMOTE, "REMOTE" }, \
{ NFSERR_WFLUSH, "WFLUSH" }, \
{ NFSERR_BADHANDLE, "BADHANDLE" }, \
{ NFSERR_NOT_SYNC, "NOTSYNC" }, \
{ NFSERR_BAD_COOKIE, "BADCOOKIE" }, \
{ NFSERR_NOTSUPP, "NOTSUPP" }, \
{ NFSERR_TOOSMALL, "TOOSMALL" }, \
{ NFSERR_SERVERFAULT, "REMOTEIO" }, \
{ NFSERR_BADTYPE, "BADTYPE" }, \
{ NFSERR_JUKEBOX, "JUKEBOX" })
TRACE_EVENT(nfs_xdr_status,
TP_PROTO(
int error
),
TP_ARGS(error),
TP_STRUCT__entry(
__field(int, error)
),
TP_fast_assign(
__entry->error = error;
),
TP_printk(
"error=%d (%s)",
__entry->error, nfs_show_status(__entry->error)
)
);
#endif /* _TRACE_NFS_H */ #endif /* _TRACE_NFS_H */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
......
...@@ -60,16 +60,6 @@ struct nfs4_cb_compound_hdr { ...@@ -60,16 +60,6 @@ struct nfs4_cb_compound_hdr {
int status; int status;
}; };
/*
* Handle decode buffer overflows out-of-line.
*/
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
{
dprintk("NFS: %s prematurely hit the end of our receive buffer. "
"Remaining buffer length is %tu words.\n",
func, xdr->end - xdr->p);
}
static __be32 *xdr_encode_empty_array(__be32 *p) static __be32 *xdr_encode_empty_array(__be32 *p)
{ {
*p++ = xdr_zero; *p++ = xdr_zero;
...@@ -240,7 +230,6 @@ static int decode_cb_op_status(struct xdr_stream *xdr, ...@@ -240,7 +230,6 @@ static int decode_cb_op_status(struct xdr_stream *xdr,
*status = nfs_cb_stat_to_errno(be32_to_cpup(p)); *status = nfs_cb_stat_to_errno(be32_to_cpup(p));
return 0; return 0;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
out_unexpected: out_unexpected:
dprintk("NFSD: Callback server returned operation %d but " dprintk("NFSD: Callback server returned operation %d but "
...@@ -309,7 +298,6 @@ static int decode_cb_compound4res(struct xdr_stream *xdr, ...@@ -309,7 +298,6 @@ static int decode_cb_compound4res(struct xdr_stream *xdr,
hdr->nops = be32_to_cpup(p); hdr->nops = be32_to_cpup(p);
return 0; return 0;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
} }
...@@ -437,7 +425,6 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr, ...@@ -437,7 +425,6 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr,
cb->cb_seq_status = status; cb->cb_seq_status = status;
return status; return status;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr);
status = -EIO; status = -EIO;
goto out; goto out;
} }
......
...@@ -74,14 +74,12 @@ struct rpc_cred_cache; ...@@ -74,14 +74,12 @@ struct rpc_cred_cache;
struct rpc_authops; struct rpc_authops;
struct rpc_auth { struct rpc_auth {
unsigned int au_cslack; /* call cred size estimate */ unsigned int au_cslack; /* call cred size estimate */
/* guess at number of u32's auth adds before unsigned int au_rslack; /* reply cred size estimate */
* reply data; normally the verifier size: */ unsigned int au_verfsize; /* size of reply verifier */
unsigned int au_rslack; unsigned int au_ralign; /* words before UL header */
/* for gss, used to calculate au_rslack: */
unsigned int au_verfsize; unsigned int au_flags;
const struct rpc_authops *au_ops;
unsigned int au_flags; /* various flags */
const struct rpc_authops *au_ops; /* operations */
rpc_authflavor_t au_flavor; /* pseudoflavor (note may rpc_authflavor_t au_flavor; /* pseudoflavor (note may
* differ from the flavor in * differ from the flavor in
* au_ops->au_flavor in gss * au_ops->au_flavor in gss
...@@ -131,13 +129,15 @@ struct rpc_credops { ...@@ -131,13 +129,15 @@ struct rpc_credops {
void (*crdestroy)(struct rpc_cred *); void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
__be32 * (*crmarshal)(struct rpc_task *, __be32 *); int (*crmarshal)(struct rpc_task *task,
struct xdr_stream *xdr);
int (*crrefresh)(struct rpc_task *); int (*crrefresh)(struct rpc_task *);
__be32 * (*crvalidate)(struct rpc_task *, __be32 *); int (*crvalidate)(struct rpc_task *task,
int (*crwrap_req)(struct rpc_task *, kxdreproc_t, struct xdr_stream *xdr);
void *, __be32 *, void *); int (*crwrap_req)(struct rpc_task *task,
int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, struct xdr_stream *xdr);
void *, __be32 *, void *); int (*crunwrap_resp)(struct rpc_task *task,
struct xdr_stream *xdr);
int (*crkey_timeout)(struct rpc_cred *); int (*crkey_timeout)(struct rpc_cred *);
char * (*crstringify_acceptor)(struct rpc_cred *); char * (*crstringify_acceptor)(struct rpc_cred *);
bool (*crneed_reencode)(struct rpc_task *); bool (*crneed_reencode)(struct rpc_task *);
...@@ -165,10 +165,18 @@ struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred * ...@@ -165,10 +165,18 @@ struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int);
void put_rpccred(struct rpc_cred *); void put_rpccred(struct rpc_cred *);
__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); int rpcauth_marshcred(struct rpc_task *task,
__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); struct xdr_stream *xdr);
int rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj); int rpcauth_checkverf(struct rpc_task *task,
int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj); struct xdr_stream *xdr);
int rpcauth_wrap_req_encode(struct rpc_task *task,
struct xdr_stream *xdr);
int rpcauth_wrap_req(struct rpc_task *task,
struct xdr_stream *xdr);
int rpcauth_unwrap_resp_decode(struct rpc_task *task,
struct xdr_stream *xdr);
int rpcauth_unwrap_resp(struct rpc_task *task,
struct xdr_stream *xdr);
bool rpcauth_xmit_need_reencode(struct rpc_task *task); bool rpcauth_xmit_need_reencode(struct rpc_task *task);
int rpcauth_refreshcred(struct rpc_task *); int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *);
......
...@@ -169,6 +169,9 @@ int rpcb_v4_register(struct net *net, const u32 program, ...@@ -169,6 +169,9 @@ int rpcb_v4_register(struct net *net, const u32 program,
const char *netid); const char *netid);
void rpcb_getport_async(struct rpc_task *); void rpcb_getport_async(struct rpc_task *);
void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
unsigned int base, unsigned int len,
unsigned int hdrsize);
void rpc_call_start(struct rpc_task *); void rpc_call_start(struct rpc_task *);
int rpc_call_async(struct rpc_clnt *clnt, int rpc_call_async(struct rpc_clnt *clnt,
const struct rpc_message *msg, int flags, const struct rpc_message *msg, int flags,
......
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Dumb way to share this static piece of information with nfsd * Define the string that exports the set of kernel-supported
* Kerberos enctypes. This list is sent via upcall to gssd, and
* is also exposed via the nfsd /proc API. The consumers generally
* treat this as an ordered list, where the first item in the list
* is the most preferred.
*/
#ifndef _LINUX_SUNRPC_GSS_KRB5_ENCTYPES_H
#define _LINUX_SUNRPC_GSS_KRB5_ENCTYPES_H
#ifdef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES
/*
* NB: This list includes encryption types that were deprecated
* by RFC 8429 (DES3_CBC_SHA1 and ARCFOUR_HMAC).
*
* ENCTYPE_AES256_CTS_HMAC_SHA1_96
* ENCTYPE_AES128_CTS_HMAC_SHA1_96
* ENCTYPE_DES3_CBC_SHA1
* ENCTYPE_ARCFOUR_HMAC
*/
#define KRB5_SUPPORTED_ENCTYPES "18,17,16,23"
#else /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
/*
* NB: This list includes encryption types that were deprecated
* by RFC 8429 and RFC 6649.
*
* ENCTYPE_AES256_CTS_HMAC_SHA1_96
* ENCTYPE_AES128_CTS_HMAC_SHA1_96
* ENCTYPE_DES3_CBC_SHA1
* ENCTYPE_ARCFOUR_HMAC
* ENCTYPE_DES_CBC_MD5
* ENCTYPE_DES_CBC_CRC
* ENCTYPE_DES_CBC_MD4
*/ */
#define KRB5_SUPPORTED_ENCTYPES "18,17,16,23,3,1,2" #define KRB5_SUPPORTED_ENCTYPES "18,17,16,23,3,1,2"
#endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
#endif /* _LINUX_SUNRPC_GSS_KRB5_ENCTYPES_H */
...@@ -87,6 +87,16 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) ...@@ -87,6 +87,16 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define xdr_one cpu_to_be32(1) #define xdr_one cpu_to_be32(1)
#define xdr_two cpu_to_be32(2) #define xdr_two cpu_to_be32(2)
#define rpc_auth_null cpu_to_be32(RPC_AUTH_NULL)
#define rpc_auth_unix cpu_to_be32(RPC_AUTH_UNIX)
#define rpc_auth_short cpu_to_be32(RPC_AUTH_SHORT)
#define rpc_auth_gss cpu_to_be32(RPC_AUTH_GSS)
#define rpc_call cpu_to_be32(RPC_CALL)
#define rpc_reply cpu_to_be32(RPC_REPLY)
#define rpc_msg_accepted cpu_to_be32(RPC_MSG_ACCEPTED)
#define rpc_success cpu_to_be32(RPC_SUCCESS) #define rpc_success cpu_to_be32(RPC_SUCCESS)
#define rpc_prog_unavail cpu_to_be32(RPC_PROG_UNAVAIL) #define rpc_prog_unavail cpu_to_be32(RPC_PROG_UNAVAIL)
#define rpc_prog_mismatch cpu_to_be32(RPC_PROG_MISMATCH) #define rpc_prog_mismatch cpu_to_be32(RPC_PROG_MISMATCH)
...@@ -95,6 +105,9 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) ...@@ -95,6 +105,9 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define rpc_system_err cpu_to_be32(RPC_SYSTEM_ERR) #define rpc_system_err cpu_to_be32(RPC_SYSTEM_ERR)
#define rpc_drop_reply cpu_to_be32(RPC_DROP_REPLY) #define rpc_drop_reply cpu_to_be32(RPC_DROP_REPLY)
#define rpc_mismatch cpu_to_be32(RPC_MISMATCH)
#define rpc_auth_error cpu_to_be32(RPC_AUTH_ERROR)
#define rpc_auth_ok cpu_to_be32(RPC_AUTH_OK) #define rpc_auth_ok cpu_to_be32(RPC_AUTH_OK)
#define rpc_autherr_badcred cpu_to_be32(RPC_AUTH_BADCRED) #define rpc_autherr_badcred cpu_to_be32(RPC_AUTH_BADCRED)
#define rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED) #define rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED)
...@@ -103,7 +116,6 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) ...@@ -103,7 +116,6 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
#define rpc_autherr_tooweak cpu_to_be32(RPC_AUTH_TOOWEAK) #define rpc_autherr_tooweak cpu_to_be32(RPC_AUTH_TOOWEAK)
#define rpcsec_gsserr_credproblem cpu_to_be32(RPCSEC_GSS_CREDPROBLEM) #define rpcsec_gsserr_credproblem cpu_to_be32(RPCSEC_GSS_CREDPROBLEM)
#define rpcsec_gsserr_ctxproblem cpu_to_be32(RPCSEC_GSS_CTXPROBLEM) #define rpcsec_gsserr_ctxproblem cpu_to_be32(RPCSEC_GSS_CTXPROBLEM)
#define rpc_autherr_oldseqnum cpu_to_be32(101)
/* /*
* Miscellaneous XDR helper functions * Miscellaneous XDR helper functions
...@@ -167,7 +179,6 @@ xdr_adjust_iovec(struct kvec *iov, __be32 *p) ...@@ -167,7 +179,6 @@ xdr_adjust_iovec(struct kvec *iov, __be32 *p)
extern void xdr_shift_buf(struct xdr_buf *, size_t); extern void xdr_shift_buf(struct xdr_buf *, size_t);
extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *);
extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int); extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int);
extern void xdr_buf_trim(struct xdr_buf *, unsigned int);
extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, unsigned int); extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, unsigned int);
extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int);
extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int);
...@@ -217,6 +228,8 @@ struct xdr_stream { ...@@ -217,6 +228,8 @@ struct xdr_stream {
struct kvec scratch; /* Scratch buffer */ struct kvec scratch; /* Scratch buffer */
struct page **page_ptr; /* pointer to the current page */ struct page **page_ptr; /* pointer to the current page */
unsigned int nwords; /* Remaining decode buffer length */ unsigned int nwords; /* Remaining decode buffer length */
struct rpc_rqst *rqst; /* For debugging */
}; };
/* /*
...@@ -227,7 +240,8 @@ typedef void (*kxdreproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -227,7 +240,8 @@ typedef void (*kxdreproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr, typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
void *obj); void *obj);
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
__be32 *p, struct rpc_rqst *rqst);
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_commit_encode(struct xdr_stream *xdr); extern void xdr_commit_encode(struct xdr_stream *xdr);
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len); extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
...@@ -235,7 +249,8 @@ extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen); ...@@ -235,7 +249,8 @@ extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len); unsigned int base, unsigned int len);
extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr); extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr);
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf,
__be32 *p, struct rpc_rqst *rqst);
extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
struct page **pages, unsigned int len); struct page **pages, unsigned int len);
extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen); extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
......
...@@ -196,8 +196,6 @@ struct rpc_xprt { ...@@ -196,8 +196,6 @@ struct rpc_xprt {
size_t max_payload; /* largest RPC payload size, size_t max_payload; /* largest RPC payload size,
in bytes */ in bytes */
unsigned int tsh_size; /* size of transport specific
header */
struct rpc_wait_queue binding; /* requests waiting on rpcbind */ struct rpc_wait_queue binding; /* requests waiting on rpcbind */
struct rpc_wait_queue sending; /* requests waiting to send */ struct rpc_wait_queue sending; /* requests waiting to send */
...@@ -362,11 +360,6 @@ struct rpc_xprt * xprt_alloc(struct net *net, size_t size, ...@@ -362,11 +360,6 @@ struct rpc_xprt * xprt_alloc(struct net *net, size_t size,
unsigned int max_req); unsigned int max_req);
void xprt_free(struct rpc_xprt *); void xprt_free(struct rpc_xprt *);
static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
{
return p + xprt->tsh_size;
}
static inline int static inline int
xprt_enable_swap(struct rpc_xprt *xprt) xprt_enable_swap(struct rpc_xprt *xprt)
{ {
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 Oracle. All rights reserved.
*
* Trace point definitions for the "rpcgss" subsystem.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM rpcgss
#if !defined(_TRACE_RPCRDMA_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_RPCGSS_H
#include <linux/tracepoint.h>
/**
** GSS-API related trace events
**/
TRACE_DEFINE_ENUM(GSS_S_BAD_MECH);
TRACE_DEFINE_ENUM(GSS_S_BAD_NAME);
TRACE_DEFINE_ENUM(GSS_S_BAD_NAMETYPE);
TRACE_DEFINE_ENUM(GSS_S_BAD_BINDINGS);
TRACE_DEFINE_ENUM(GSS_S_BAD_STATUS);
TRACE_DEFINE_ENUM(GSS_S_BAD_SIG);
TRACE_DEFINE_ENUM(GSS_S_NO_CRED);
TRACE_DEFINE_ENUM(GSS_S_NO_CONTEXT);
TRACE_DEFINE_ENUM(GSS_S_DEFECTIVE_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_DEFECTIVE_CREDENTIAL);
TRACE_DEFINE_ENUM(GSS_S_CREDENTIALS_EXPIRED);
TRACE_DEFINE_ENUM(GSS_S_CONTEXT_EXPIRED);
TRACE_DEFINE_ENUM(GSS_S_FAILURE);
TRACE_DEFINE_ENUM(GSS_S_BAD_QOP);
TRACE_DEFINE_ENUM(GSS_S_UNAUTHORIZED);
TRACE_DEFINE_ENUM(GSS_S_UNAVAILABLE);
TRACE_DEFINE_ENUM(GSS_S_DUPLICATE_ELEMENT);
TRACE_DEFINE_ENUM(GSS_S_NAME_NOT_MN);
TRACE_DEFINE_ENUM(GSS_S_CONTINUE_NEEDED);
TRACE_DEFINE_ENUM(GSS_S_DUPLICATE_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_OLD_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_UNSEQ_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_GAP_TOKEN);
#define show_gss_status(x) \
__print_flags(x, "|", \
{ GSS_S_BAD_MECH, "GSS_S_BAD_MECH" }, \
{ GSS_S_BAD_NAME, "GSS_S_BAD_NAME" }, \
{ GSS_S_BAD_NAMETYPE, "GSS_S_BAD_NAMETYPE" }, \
{ GSS_S_BAD_BINDINGS, "GSS_S_BAD_BINDINGS" }, \
{ GSS_S_BAD_STATUS, "GSS_S_BAD_STATUS" }, \
{ GSS_S_BAD_SIG, "GSS_S_BAD_SIG" }, \
{ GSS_S_NO_CRED, "GSS_S_NO_CRED" }, \
{ GSS_S_NO_CONTEXT, "GSS_S_NO_CONTEXT" }, \
{ GSS_S_DEFECTIVE_TOKEN, "GSS_S_DEFECTIVE_TOKEN" }, \
{ GSS_S_DEFECTIVE_CREDENTIAL, "GSS_S_DEFECTIVE_CREDENTIAL" }, \
{ GSS_S_CREDENTIALS_EXPIRED, "GSS_S_CREDENTIALS_EXPIRED" }, \
{ GSS_S_CONTEXT_EXPIRED, "GSS_S_CONTEXT_EXPIRED" }, \
{ GSS_S_FAILURE, "GSS_S_FAILURE" }, \
{ GSS_S_BAD_QOP, "GSS_S_BAD_QOP" }, \
{ GSS_S_UNAUTHORIZED, "GSS_S_UNAUTHORIZED" }, \
{ GSS_S_UNAVAILABLE, "GSS_S_UNAVAILABLE" }, \
{ GSS_S_DUPLICATE_ELEMENT, "GSS_S_DUPLICATE_ELEMENT" }, \
{ GSS_S_NAME_NOT_MN, "GSS_S_NAME_NOT_MN" }, \
{ GSS_S_CONTINUE_NEEDED, "GSS_S_CONTINUE_NEEDED" }, \
{ GSS_S_DUPLICATE_TOKEN, "GSS_S_DUPLICATE_TOKEN" }, \
{ GSS_S_OLD_TOKEN, "GSS_S_OLD_TOKEN" }, \
{ GSS_S_UNSEQ_TOKEN, "GSS_S_UNSEQ_TOKEN" }, \
{ GSS_S_GAP_TOKEN, "GSS_S_GAP_TOKEN" })
DECLARE_EVENT_CLASS(rpcgss_gssapi_event,
TP_PROTO(
const struct rpc_task *task,
u32 maj_stat
),
TP_ARGS(task, maj_stat),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(u32, maj_stat)
),
TP_fast_assign(
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
__entry->maj_stat = maj_stat;
),
TP_printk("task:%u@%u maj_stat=%s",
__entry->task_id, __entry->client_id,
__entry->maj_stat == 0 ?
"GSS_S_COMPLETE" : show_gss_status(__entry->maj_stat))
);
#define DEFINE_GSSAPI_EVENT(name) \
DEFINE_EVENT(rpcgss_gssapi_event, rpcgss_##name, \
TP_PROTO( \
const struct rpc_task *task, \
u32 maj_stat \
), \
TP_ARGS(task, maj_stat))
TRACE_EVENT(rpcgss_import_ctx,
TP_PROTO(
int status
),
TP_ARGS(status),
TP_STRUCT__entry(
__field(int, status)
),
TP_fast_assign(
__entry->status = status;
),
TP_printk("status=%d", __entry->status)
);
DEFINE_GSSAPI_EVENT(get_mic);
DEFINE_GSSAPI_EVENT(verify_mic);
DEFINE_GSSAPI_EVENT(wrap);
DEFINE_GSSAPI_EVENT(unwrap);
/**
** GSS auth unwrap failures
**/
TRACE_EVENT(rpcgss_unwrap_failed,
TP_PROTO(
const struct rpc_task *task
),
TP_ARGS(task),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
),
TP_fast_assign(
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
),
TP_printk("task:%u@%u", __entry->task_id, __entry->client_id)
);
TRACE_EVENT(rpcgss_bad_seqno,
TP_PROTO(
const struct rpc_task *task,
u32 expected,
u32 received
),
TP_ARGS(task, expected, received),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(u32, expected)
__field(u32, received)
),
TP_fast_assign(
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
__entry->expected = expected;
__entry->received = received;
),
TP_printk("task:%u@%u expected seqno %u, received seqno %u",
__entry->task_id, __entry->client_id,
__entry->expected, __entry->received)
);
TRACE_EVENT(rpcgss_seqno,
TP_PROTO(
const struct rpc_task *task
),
TP_ARGS(task),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(u32, xid)
__field(u32, seqno)
),
TP_fast_assign(
const struct rpc_rqst *rqst = task->tk_rqstp;
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
__entry->xid = be32_to_cpu(rqst->rq_xid);
__entry->seqno = rqst->rq_seqno;
),
TP_printk("task:%u@%u xid=0x%08x seqno=%u",
__entry->task_id, __entry->client_id,
__entry->xid, __entry->seqno)
);
TRACE_EVENT(rpcgss_need_reencode,
TP_PROTO(
const struct rpc_task *task,
u32 seq_xmit,
bool ret
),
TP_ARGS(task, seq_xmit, ret),
TP_STRUCT__entry(
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(u32, xid)
__field(u32, seq_xmit)
__field(u32, seqno)
__field(bool, ret)
),
TP_fast_assign(
__entry->task_id = task->tk_pid;
__entry->client_id = task->tk_client->cl_clid;
__entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid);
__entry->seq_xmit = seq_xmit;
__entry->seqno = task->tk_rqstp->rq_seqno;
__entry->ret = ret;
),
TP_printk("task:%u@%u xid=0x%08x rq_seqno=%u seq_xmit=%u reencode %sneeded",
__entry->task_id, __entry->client_id,
__entry->xid, __entry->seqno, __entry->seq_xmit,
__entry->ret ? "" : "un")
);
/**
** gssd upcall related trace events
**/
TRACE_EVENT(rpcgss_upcall_msg,
TP_PROTO(
const char *buf
),
TP_ARGS(buf),
TP_STRUCT__entry(
__string(msg, buf)
),
TP_fast_assign(
__assign_str(msg, buf)
),
TP_printk("msg='%s'", __get_str(msg))
);
TRACE_EVENT(rpcgss_upcall_result,
TP_PROTO(
u32 uid,
int result
),
TP_ARGS(uid, result),
TP_STRUCT__entry(
__field(u32, uid)
__field(int, result)
),
TP_fast_assign(
__entry->uid = uid;
__entry->result = result;
),
TP_printk("for uid %u, result=%d", __entry->uid, __entry->result)
);
TRACE_EVENT(rpcgss_context,
TP_PROTO(
unsigned long expiry,
unsigned long now,
unsigned int timeout,
unsigned int len,
const u8 *data
),
TP_ARGS(expiry, now, timeout, len, data),
TP_STRUCT__entry(
__field(unsigned long, expiry)
__field(unsigned long, now)
__field(unsigned int, timeout)
__field(int, len)
__string(acceptor, data)
),
TP_fast_assign(
__entry->expiry = expiry;
__entry->now = now;
__entry->timeout = timeout;
__entry->len = len;
strncpy(__get_str(acceptor), data, len);
),
TP_printk("gc_expiry=%lu now=%lu timeout=%u acceptor=%.*s",
__entry->expiry, __entry->now, __entry->timeout,
__entry->len, __get_str(acceptor))
);
/**
** Miscellaneous events
*/
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5);
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I);
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P);
#define show_pseudoflavor(x) \
__print_symbolic(x, \
{ RPC_AUTH_GSS_KRB5, "RPC_AUTH_GSS_KRB5" }, \
{ RPC_AUTH_GSS_KRB5I, "RPC_AUTH_GSS_KRB5I" }, \
{ RPC_AUTH_GSS_KRB5P, "RPC_AUTH_GSS_KRB5P" })
TRACE_EVENT(rpcgss_createauth,
TP_PROTO(
unsigned int flavor,
int error
),
TP_ARGS(flavor, error),
TP_STRUCT__entry(
__field(unsigned int, flavor)
__field(int, error)
),
TP_fast_assign(
__entry->flavor = flavor;
__entry->error = error;
),
TP_printk("flavor=%s error=%d",
show_pseudoflavor(__entry->flavor), __entry->error)
);
#endif /* _TRACE_RPCGSS_H */
#include <trace/define_trace.h>
...@@ -521,12 +521,18 @@ TRACE_EVENT(xprtrdma_post_send, ...@@ -521,12 +521,18 @@ TRACE_EVENT(xprtrdma_post_send,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(const void *, req) __field(const void *, req)
__field(unsigned int, task_id)
__field(unsigned int, client_id)
__field(int, num_sge) __field(int, num_sge)
__field(int, signaled) __field(int, signaled)
__field(int, status) __field(int, status)
), ),
TP_fast_assign( TP_fast_assign(
const struct rpc_rqst *rqst = &req->rl_slot;
__entry->task_id = rqst->rq_task->tk_pid;
__entry->client_id = rqst->rq_task->tk_client->cl_clid;
__entry->req = req; __entry->req = req;
__entry->num_sge = req->rl_sendctx->sc_wr.num_sge; __entry->num_sge = req->rl_sendctx->sc_wr.num_sge;
__entry->signaled = req->rl_sendctx->sc_wr.send_flags & __entry->signaled = req->rl_sendctx->sc_wr.send_flags &
...@@ -534,9 +540,11 @@ TRACE_EVENT(xprtrdma_post_send, ...@@ -534,9 +540,11 @@ TRACE_EVENT(xprtrdma_post_send,
__entry->status = status; __entry->status = status;
), ),
TP_printk("req=%p, %d SGEs%s, status=%d", TP_printk("task:%u@%u req=%p (%d SGE%s) %sstatus=%d",
__entry->task_id, __entry->client_id,
__entry->req, __entry->num_sge, __entry->req, __entry->num_sge,
(__entry->signaled ? ", signaled" : ""), (__entry->num_sge == 1 ? "" : "s"),
(__entry->signaled ? "signaled " : ""),
__entry->status __entry->status
) )
); );
......
This diff is collapsed.
...@@ -34,6 +34,22 @@ config RPCSEC_GSS_KRB5 ...@@ -34,6 +34,22 @@ config RPCSEC_GSS_KRB5
If unsure, say Y. If unsure, say Y.
config CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES
bool "Secure RPC: Disable insecure Kerberos encryption types"
depends on RPCSEC_GSS_KRB5
default n
help
Choose Y here to disable the use of deprecated encryption types
with the Kerberos version 5 GSS-API mechanism (RFC 1964). The
deprecated encryption types include DES-CBC-MD5, DES-CBC-CRC,
and DES-CBC-MD4. These types were deprecated by RFC 6649 because
they were found to be insecure.
N is the default because many sites have deployed KDCs and
keytabs that contain only these deprecated encryption types.
Choosing Y prevents the use of known-insecure encryption types
but might result in compatibility problems.
config SUNRPC_DEBUG config SUNRPC_DEBUG
bool "RPC: Enable dprintk debugging" bool "RPC: Enable dprintk debugging"
depends on SUNRPC && SYSCTL depends on SUNRPC && SYSCTL
......
...@@ -17,9 +17,7 @@ ...@@ -17,9 +17,7 @@
#include <linux/sunrpc/gss_api.h> #include <linux/sunrpc/gss_api.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) #include <trace/events/sunrpc.h>
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
#define RPC_CREDCACHE_DEFAULT_HASHBITS (4) #define RPC_CREDCACHE_DEFAULT_HASHBITS (4)
struct rpc_cred_cache { struct rpc_cred_cache {
...@@ -267,8 +265,6 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size) ...@@ -267,8 +265,6 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size)
} }
} }
rcu_read_unlock(); rcu_read_unlock();
dprintk("RPC: %s returns %d\n", __func__, result);
return result; return result;
} }
EXPORT_SYMBOL_GPL(rpcauth_list_flavors); EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
...@@ -636,9 +632,6 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) ...@@ -636,9 +632,6 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
struct rpc_cred *ret; struct rpc_cred *ret;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
dprintk("RPC: looking up %s cred\n",
auth->au_ops->au_name);
memset(&acred, 0, sizeof(acred)); memset(&acred, 0, sizeof(acred));
acred.cred = cred; acred.cred = cred;
ret = auth->au_ops->lookup_cred(auth, &acred, flags); ret = auth->au_ops->lookup_cred(auth, &acred, flags);
...@@ -670,8 +663,6 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) ...@@ -670,8 +663,6 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
}; };
struct rpc_cred *ret; struct rpc_cred *ret;
dprintk("RPC: %5u looking up %s cred\n",
task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
put_cred(acred.cred); put_cred(acred.cred);
return ret; return ret;
...@@ -688,8 +679,6 @@ rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags) ...@@ -688,8 +679,6 @@ rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags)
if (!acred.principal) if (!acred.principal)
return NULL; return NULL;
dprintk("RPC: %5u looking up %s machine cred\n",
task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
return auth->au_ops->lookup_cred(auth, &acred, lookupflags); return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
} }
...@@ -698,8 +687,6 @@ rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) ...@@ -698,8 +687,6 @@ rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
{ {
struct rpc_auth *auth = task->tk_client->cl_auth; struct rpc_auth *auth = task->tk_client->cl_auth;
dprintk("RPC: %5u looking up %s cred\n",
task->tk_pid, auth->au_ops->au_name);
return rpcauth_lookupcred(auth, lookupflags); return rpcauth_lookupcred(auth, lookupflags);
} }
...@@ -771,75 +758,102 @@ put_rpccred(struct rpc_cred *cred) ...@@ -771,75 +758,102 @@ put_rpccred(struct rpc_cred *cred)
} }
EXPORT_SYMBOL_GPL(put_rpccred); EXPORT_SYMBOL_GPL(put_rpccred);
__be32 * /**
rpcauth_marshcred(struct rpc_task *task, __be32 *p) * rpcauth_marshcred - Append RPC credential to end of @xdr
* @task: controlling RPC task
* @xdr: xdr_stream containing initial portion of RPC Call header
*
* On success, an appropriate verifier is added to @xdr, @xdr is
* updated to point past the verifier, and zero is returned.
* Otherwise, @xdr is in an undefined state and a negative errno
* is returned.
*/
int rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr)
{ {
struct rpc_cred *cred = task->tk_rqstp->rq_cred; const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
dprintk("RPC: %5u marshaling %s cred %p\n", return ops->crmarshal(task, xdr);
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
return cred->cr_ops->crmarshal(task, p);
} }
__be32 * /**
rpcauth_checkverf(struct rpc_task *task, __be32 *p) * rpcauth_wrap_req_encode - XDR encode the RPC procedure
* @task: controlling RPC task
* @xdr: stream where on-the-wire bytes are to be marshalled
*
* On success, @xdr contains the encoded and wrapped message.
* Otherwise, @xdr is in an undefined state.
*/
int rpcauth_wrap_req_encode(struct rpc_task *task, struct xdr_stream *xdr)
{ {
struct rpc_cred *cred = task->tk_rqstp->rq_cred; kxdreproc_t encode = task->tk_msg.rpc_proc->p_encode;
dprintk("RPC: %5u validating %s cred %p\n", encode(task->tk_rqstp, xdr, task->tk_msg.rpc_argp);
task->tk_pid, cred->cr_auth->au_ops->au_name, cred); return 0;
return cred->cr_ops->crvalidate(task, p);
} }
EXPORT_SYMBOL_GPL(rpcauth_wrap_req_encode);
static void rpcauth_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp, /**
__be32 *data, void *obj) * rpcauth_wrap_req - XDR encode and wrap the RPC procedure
* @task: controlling RPC task
* @xdr: stream where on-the-wire bytes are to be marshalled
*
* On success, @xdr contains the encoded and wrapped message,
* and zero is returned. Otherwise, @xdr is in an undefined
* state and a negative errno is returned.
*/
int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
{ {
struct xdr_stream xdr; const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
xdr_init_encode(&xdr, &rqstp->rq_snd_buf, data); return ops->crwrap_req(task, xdr);
encode(rqstp, &xdr, obj);
} }
/**
* rpcauth_checkverf - Validate verifier in RPC Reply header
* @task: controlling RPC task
* @xdr: xdr_stream containing RPC Reply header
*
* On success, @xdr is updated to point past the verifier and
* zero is returned. Otherwise, @xdr is in an undefined state
* and a negative errno is returned.
*/
int int
rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr)
__be32 *data, void *obj)
{ {
struct rpc_cred *cred = task->tk_rqstp->rq_cred; const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", return ops->crvalidate(task, xdr);
task->tk_pid, cred->cr_ops->cr_name, cred);
if (cred->cr_ops->crwrap_req)
return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
/* By default, we encode the arguments normally. */
rpcauth_wrap_req_encode(encode, rqstp, data, obj);
return 0;
} }
static int /**
rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp, * rpcauth_unwrap_resp_decode - Invoke XDR decode function
__be32 *data, void *obj) * @task: controlling RPC task
* @xdr: stream where the Reply message resides
*
* Returns zero on success; otherwise a negative errno is returned.
*/
int
rpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr)
{ {
struct xdr_stream xdr; kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data); return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp);
return decode(rqstp, &xdr, obj);
} }
EXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode);
/**
* rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred
* @task: controlling RPC task
* @xdr: stream where the Reply message resides
*
* Returns zero on success; otherwise a negative errno is returned.
*/
int int
rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, rpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
__be32 *data, void *obj)
{ {
struct rpc_cred *cred = task->tk_rqstp->rq_cred; const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", return ops->crunwrap_resp(task, xdr);
task->tk_pid, cred->cr_ops->cr_name, cred);
if (cred->cr_ops->crunwrap_resp)
return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
data, obj);
/* By default, we decode the arguments normally. */
return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
} }
bool bool
...@@ -865,8 +879,6 @@ rpcauth_refreshcred(struct rpc_task *task) ...@@ -865,8 +879,6 @@ rpcauth_refreshcred(struct rpc_task *task)
goto out; goto out;
cred = task->tk_rqstp->rq_cred; cred = task->tk_rqstp->rq_cred;
} }
dprintk("RPC: %5u refreshing %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
err = cred->cr_ops->crrefresh(task); err = cred->cr_ops->crrefresh(task);
out: out:
...@@ -880,8 +892,6 @@ rpcauth_invalcred(struct rpc_task *task) ...@@ -880,8 +892,6 @@ rpcauth_invalcred(struct rpc_task *task)
{ {
struct rpc_cred *cred = task->tk_rqstp->rq_cred; struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u invalidating %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
if (cred) if (cred)
clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
} }
......
...@@ -7,7 +7,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o ...@@ -7,7 +7,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
auth_rpcgss-y := auth_gss.o gss_generic_token.o \ auth_rpcgss-y := auth_gss.o gss_generic_token.o \
gss_mech_switch.o svcauth_gss.o \ gss_mech_switch.o svcauth_gss.o \
gss_rpc_upcall.o gss_rpc_xdr.o gss_rpc_upcall.o gss_rpc_xdr.o trace.o
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
......
This diff is collapsed.
// SPDX-License-Identifier: BSD-3-Clause
/* /*
* linux/net/sunrpc/gss_krb5_mech.c * linux/net/sunrpc/gss_krb5_mech.c
* *
...@@ -6,32 +7,6 @@ ...@@ -6,32 +7,6 @@
* *
* Andy Adamson <andros@umich.edu> * Andy Adamson <andros@umich.edu>
* J. Bruce Fields <bfields@umich.edu> * J. Bruce Fields <bfields@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/ */
#include <crypto/hash.h> #include <crypto/hash.h>
...@@ -53,6 +28,7 @@ ...@@ -53,6 +28,7 @@
static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ static struct gss_api_mech gss_kerberos_mech; /* forward declaration */
static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
#ifndef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES
/* /*
* DES (All DES enctypes are mapped to the same gss functionality) * DES (All DES enctypes are mapped to the same gss functionality)
*/ */
...@@ -74,6 +50,7 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { ...@@ -74,6 +50,7 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.cksumlength = 8, .cksumlength = 8,
.keyed_cksum = 0, .keyed_cksum = 0,
}, },
#endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
/* /*
* RC4-HMAC * RC4-HMAC
*/ */
......
...@@ -570,14 +570,16 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) ...@@ -570,14 +570,16 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
*/ */
movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len); movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len);
movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip; movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip;
BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen > if (offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
buf->head[0].iov_len); buf->head[0].iov_len)
return GSS_S_FAILURE;
memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen); memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen);
buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip; buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip; buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
/* Trim off the trailing "extra count" and checksum blob */ /* Trim off the trailing "extra count" and checksum blob */
xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip); buf->len -= ec + GSS_KRB5_TOK_HDR_LEN + tailskip;
return GSS_S_COMPLETE; return GSS_S_COMPLETE;
} }
......
// SPDX-License-Identifier: BSD-3-Clause
/* /*
* linux/net/sunrpc/gss_mech_switch.c * linux/net/sunrpc/gss_mech_switch.c
* *
...@@ -5,32 +6,6 @@ ...@@ -5,32 +6,6 @@
* All rights reserved. * All rights reserved.
* *
* J. Bruce Fields <bfields@umich.edu> * J. Bruce Fields <bfields@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/ */
#include <linux/types.h> #include <linux/types.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* linux/net/sunrpc/gss_rpc_upcall.c * linux/net/sunrpc/gss_rpc_upcall.c
* *
* Copyright (C) 2012 Simo Sorce <simo@redhat.com> * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/types.h> #include <linux/types.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* /*
* linux/net/sunrpc/gss_rpc_upcall.h * linux/net/sunrpc/gss_rpc_upcall.h
* *
* Copyright (C) 2012 Simo Sorce <simo@redhat.com> * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#ifndef _GSS_RPC_UPCALL_H #ifndef _GSS_RPC_UPCALL_H
...@@ -45,4 +32,5 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data); ...@@ -45,4 +32,5 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data);
void init_gssp_clnt(struct sunrpc_net *); void init_gssp_clnt(struct sunrpc_net *);
int set_gssp_clnt(struct net *); int set_gssp_clnt(struct net *);
void clear_gssp_clnt(struct sunrpc_net *); void clear_gssp_clnt(struct sunrpc_net *);
#endif /* _GSS_RPC_UPCALL_H */ #endif /* _GSS_RPC_UPCALL_H */
// SPDX-License-Identifier: GPL-2.0+
/* /*
* GSS Proxy upcall module * GSS Proxy upcall module
* *
* Copyright (C) 2012 Simo Sorce <simo@redhat.com> * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/sunrpc/svcauth.h> #include <linux/sunrpc/svcauth.h>
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* /*
* GSS Proxy upcall module * GSS Proxy upcall module
* *
* Copyright (C) 2012 Simo Sorce <simo@redhat.com> * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#ifndef _LINUX_GSS_RPC_XDR_H #ifndef _LINUX_GSS_RPC_XDR_H
...@@ -262,6 +249,4 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, ...@@ -262,6 +249,4 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
#define GSSX_ARG_wrap_size_limit_sz 0 #define GSSX_ARG_wrap_size_limit_sz 0
#define GSSX_RES_wrap_size_limit_sz 0 #define GSSX_RES_wrap_size_limit_sz 0
#endif /* _LINUX_GSS_RPC_XDR_H */ #endif /* _LINUX_GSS_RPC_XDR_H */
// SPDX-License-Identifier: GPL-2.0
/* /*
* Neil Brown <neilb@cse.unsw.edu.au> * Neil Brown <neilb@cse.unsw.edu.au>
* J. Bruce Fields <bfields@umich.edu> * J. Bruce Fields <bfields@umich.edu>
...@@ -896,7 +897,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g ...@@ -896,7 +897,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
if (svc_getnl(&buf->head[0]) != seq) if (svc_getnl(&buf->head[0]) != seq)
goto out; goto out;
/* trim off the mic and padding at the end before returning */ /* trim off the mic and padding at the end before returning */
xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4); buf->len -= 4 + round_up_to_quad(mic.len);
stat = 0; stat = 0;
out: out:
kfree(mic.data); kfree(mic.data);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, 2019 Oracle. All rights reserved.
*/
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/gss_err.h>
#define CREATE_TRACE_POINTS
#include <trace/events/rpcgss.h>
...@@ -59,15 +59,21 @@ nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags) ...@@ -59,15 +59,21 @@ nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags)
/* /*
* Marshal credential. * Marshal credential.
*/ */
static __be32 * static int
nul_marshal(struct rpc_task *task, __be32 *p) nul_marshal(struct rpc_task *task, struct xdr_stream *xdr)
{ {
*p++ = htonl(RPC_AUTH_NULL); __be32 *p;
*p++ = 0;
*p++ = htonl(RPC_AUTH_NULL); p = xdr_reserve_space(xdr, 4 * sizeof(*p));
*p++ = 0; if (!p)
return -EMSGSIZE;
return p; /* Credential */
*p++ = rpc_auth_null;
*p++ = xdr_zero;
/* Verifier */
*p++ = rpc_auth_null;
*p = xdr_zero;
return 0;
} }
/* /*
...@@ -80,25 +86,19 @@ nul_refresh(struct rpc_task *task) ...@@ -80,25 +86,19 @@ nul_refresh(struct rpc_task *task)
return 0; return 0;
} }
static __be32 * static int
nul_validate(struct rpc_task *task, __be32 *p) nul_validate(struct rpc_task *task, struct xdr_stream *xdr)
{ {
rpc_authflavor_t flavor; __be32 *p;
u32 size;
p = xdr_inline_decode(xdr, 2 * sizeof(*p));
flavor = ntohl(*p++); if (!p)
if (flavor != RPC_AUTH_NULL) { return -EIO;
printk("RPC: bad verf flavor: %u\n", flavor); if (*p++ != rpc_auth_null)
return ERR_PTR(-EIO); return -EIO;
} if (*p != xdr_zero)
return -EIO;
size = ntohl(*p++); return 0;
if (size != 0) {
printk("RPC: bad verf size: %u\n", size);
return ERR_PTR(-EIO);
}
return p;
} }
const struct rpc_authops authnull_ops = { const struct rpc_authops authnull_ops = {
...@@ -114,6 +114,8 @@ static ...@@ -114,6 +114,8 @@ static
struct rpc_auth null_auth = { struct rpc_auth null_auth = {
.au_cslack = NUL_CALLSLACK, .au_cslack = NUL_CALLSLACK,
.au_rslack = NUL_REPLYSLACK, .au_rslack = NUL_REPLYSLACK,
.au_verfsize = NUL_REPLYSLACK,
.au_ralign = NUL_REPLYSLACK,
.au_ops = &authnull_ops, .au_ops = &authnull_ops,
.au_flavor = RPC_AUTH_NULL, .au_flavor = RPC_AUTH_NULL,
.au_count = REFCOUNT_INIT(1), .au_count = REFCOUNT_INIT(1),
...@@ -125,8 +127,10 @@ const struct rpc_credops null_credops = { ...@@ -125,8 +127,10 @@ const struct rpc_credops null_credops = {
.crdestroy = nul_destroy_cred, .crdestroy = nul_destroy_cred,
.crmatch = nul_match, .crmatch = nul_match,
.crmarshal = nul_marshal, .crmarshal = nul_marshal,
.crwrap_req = rpcauth_wrap_req_encode,
.crrefresh = nul_refresh, .crrefresh = nul_refresh,
.crvalidate = nul_validate, .crvalidate = nul_validate,
.crunwrap_resp = rpcauth_unwrap_resp_decode,
}; };
static static
......
...@@ -28,8 +28,6 @@ static mempool_t *unix_pool; ...@@ -28,8 +28,6 @@ static mempool_t *unix_pool;
static struct rpc_auth * static struct rpc_auth *
unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{ {
dprintk("RPC: creating UNIX authenticator for client %p\n",
clnt);
refcount_inc(&unix_auth.au_count); refcount_inc(&unix_auth.au_count);
return &unix_auth; return &unix_auth;
} }
...@@ -37,7 +35,6 @@ unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) ...@@ -37,7 +35,6 @@ unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
static void static void
unx_destroy(struct rpc_auth *auth) unx_destroy(struct rpc_auth *auth)
{ {
dprintk("RPC: destroying UNIX authenticator %p\n", auth);
} }
/* /*
...@@ -48,10 +45,6 @@ unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) ...@@ -48,10 +45,6 @@ unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{ {
struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS); struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS);
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
from_kuid(&init_user_ns, acred->cred->fsuid),
from_kgid(&init_user_ns, acred->cred->fsgid));
rpcauth_init_cred(ret, acred, auth, &unix_credops); rpcauth_init_cred(ret, acred, auth, &unix_credops);
ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
return ret; return ret;
...@@ -61,7 +54,7 @@ static void ...@@ -61,7 +54,7 @@ static void
unx_free_cred_callback(struct rcu_head *head) unx_free_cred_callback(struct rcu_head *head)
{ {
struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu); struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
dprintk("RPC: unx_free_cred %p\n", rpc_cred);
put_cred(rpc_cred->cr_cred); put_cred(rpc_cred->cr_cred);
mempool_free(rpc_cred, unix_pool); mempool_free(rpc_cred, unix_pool);
} }
...@@ -106,37 +99,55 @@ unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) ...@@ -106,37 +99,55 @@ unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
* Marshal credentials. * Marshal credentials.
* Maybe we should keep a cached credential for performance reasons. * Maybe we should keep a cached credential for performance reasons.
*/ */
static __be32 * static int
unx_marshal(struct rpc_task *task, __be32 *p) unx_marshal(struct rpc_task *task, struct xdr_stream *xdr)
{ {
struct rpc_clnt *clnt = task->tk_client; struct rpc_clnt *clnt = task->tk_client;
struct rpc_cred *cred = task->tk_rqstp->rq_cred; struct rpc_cred *cred = task->tk_rqstp->rq_cred;
__be32 *base, *hold; __be32 *p, *cred_len, *gidarr_len;
int i; int i;
struct group_info *gi = cred->cr_cred->group_info; struct group_info *gi = cred->cr_cred->group_info;
*p++ = htonl(RPC_AUTH_UNIX); /* Credential */
base = p++;
*p++ = htonl(jiffies/HZ); p = xdr_reserve_space(xdr, 3 * sizeof(*p));
if (!p)
/* goto marshal_failed;
* Copy the UTS nodename captured when the client was created. *p++ = rpc_auth_unix;
*/ cred_len = p++;
p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); *p++ = xdr_zero; /* stamp */
if (xdr_stream_encode_opaque(xdr, clnt->cl_nodename,
*p++ = htonl((u32) from_kuid(&init_user_ns, cred->cr_cred->fsuid)); clnt->cl_nodelen) < 0)
*p++ = htonl((u32) from_kgid(&init_user_ns, cred->cr_cred->fsgid)); goto marshal_failed;
hold = p++; p = xdr_reserve_space(xdr, 3 * sizeof(*p));
if (!p)
goto marshal_failed;
*p++ = cpu_to_be32(from_kuid(&init_user_ns, cred->cr_cred->fsuid));
*p++ = cpu_to_be32(from_kgid(&init_user_ns, cred->cr_cred->fsgid));
gidarr_len = p++;
if (gi) if (gi)
for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++) for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
*p++ = htonl((u32) from_kgid(&init_user_ns, gi->gid[i])); *p++ = cpu_to_be32(from_kgid(&init_user_ns,
*hold = htonl(p - hold - 1); /* gid array length */ gi->gid[i]));
*base = htonl((p - base - 1) << 2); /* cred length */ *gidarr_len = cpu_to_be32(p - gidarr_len - 1);
*cred_len = cpu_to_be32((p - cred_len - 1) << 2);
p = xdr_reserve_space(xdr, (p - gidarr_len - 1) << 2);
if (!p)
goto marshal_failed;
/* Verifier */
p = xdr_reserve_space(xdr, 2 * sizeof(*p));
if (!p)
goto marshal_failed;
*p++ = rpc_auth_null;
*p = xdr_zero;
*p++ = htonl(RPC_AUTH_NULL); return 0;
*p++ = htonl(0);
return p; marshal_failed:
return -EMSGSIZE;
} }
/* /*
...@@ -149,29 +160,35 @@ unx_refresh(struct rpc_task *task) ...@@ -149,29 +160,35 @@ unx_refresh(struct rpc_task *task)
return 0; return 0;
} }
static __be32 * static int
unx_validate(struct rpc_task *task, __be32 *p) unx_validate(struct rpc_task *task, struct xdr_stream *xdr)
{ {
rpc_authflavor_t flavor; struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
u32 size; __be32 *p;
u32 size;
flavor = ntohl(*p++);
if (flavor != RPC_AUTH_NULL && p = xdr_inline_decode(xdr, 2 * sizeof(*p));
flavor != RPC_AUTH_UNIX && if (!p)
flavor != RPC_AUTH_SHORT) { return -EIO;
printk("RPC: bad verf flavor: %u\n", flavor); switch (*p++) {
return ERR_PTR(-EIO); case rpc_auth_null:
} case rpc_auth_unix:
case rpc_auth_short:
size = ntohl(*p++); break;
if (size > RPC_MAX_AUTH_SIZE) { default:
printk("RPC: giant verf size: %u\n", size); return -EIO;
return ERR_PTR(-EIO);
} }
task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; size = be32_to_cpup(p);
p += (size >> 2); if (size > RPC_MAX_AUTH_SIZE)
return -EIO;
return p; p = xdr_inline_decode(xdr, size);
if (!p)
return -EIO;
auth->au_verfsize = XDR_QUADLEN(size) + 2;
auth->au_rslack = XDR_QUADLEN(size) + 2;
auth->au_ralign = XDR_QUADLEN(size) + 2;
return 0;
} }
int __init rpc_init_authunix(void) int __init rpc_init_authunix(void)
...@@ -198,6 +215,7 @@ static ...@@ -198,6 +215,7 @@ static
struct rpc_auth unix_auth = { struct rpc_auth unix_auth = {
.au_cslack = UNX_CALLSLACK, .au_cslack = UNX_CALLSLACK,
.au_rslack = NUL_REPLYSLACK, .au_rslack = NUL_REPLYSLACK,
.au_verfsize = NUL_REPLYSLACK,
.au_ops = &authunix_ops, .au_ops = &authunix_ops,
.au_flavor = RPC_AUTH_UNIX, .au_flavor = RPC_AUTH_UNIX,
.au_count = REFCOUNT_INIT(1), .au_count = REFCOUNT_INIT(1),
...@@ -209,6 +227,8 @@ const struct rpc_credops unix_credops = { ...@@ -209,6 +227,8 @@ const struct rpc_credops unix_credops = {
.crdestroy = unx_destroy_cred, .crdestroy = unx_destroy_cred,
.crmatch = unx_match, .crmatch = unx_match,
.crmarshal = unx_marshal, .crmarshal = unx_marshal,
.crwrap_req = rpcauth_wrap_req_encode,
.crrefresh = unx_refresh, .crrefresh = unx_refresh,
.crvalidate = unx_validate, .crvalidate = unx_validate,
.crunwrap_resp = rpcauth_unwrap_resp_decode,
}; };
This diff is collapsed.
...@@ -1144,17 +1144,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) ...@@ -1144,17 +1144,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
#endif #endif
/*
* Setup response header for TCP, it has a 4B record length field.
*/
static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
{
struct kvec *resv = &rqstp->rq_res.head[0];
/* tcp needs a space for the record length... */
svc_putnl(resv, 0);
}
/* /*
* Common routine for processing the RPC request. * Common routine for processing the RPC request.
*/ */
...@@ -1182,10 +1171,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1182,10 +1171,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
clear_bit(RQ_DROPME, &rqstp->rq_flags); clear_bit(RQ_DROPME, &rqstp->rq_flags);
/* Setup reply header */
if (rqstp->rq_prot == IPPROTO_TCP)
svc_tcp_prep_reply_hdr(rqstp);
svc_putu32(resv, rqstp->rq_xid); svc_putu32(resv, rqstp->rq_xid);
vers = svc_getnl(argv); vers = svc_getnl(argv);
...@@ -1443,6 +1428,10 @@ svc_process(struct svc_rqst *rqstp) ...@@ -1443,6 +1428,10 @@ svc_process(struct svc_rqst *rqstp)
goto out_drop; goto out_drop;
} }
/* Reserve space for the record marker */
if (rqstp->rq_prot == IPPROTO_TCP)
svc_putnl(resv, 0);
/* Returns 1 for send, 0 for drop */ /* Returns 1 for send, 0 for drop */
if (likely(svc_process_common(rqstp, argv, resv))) if (likely(svc_process_common(rqstp, argv, resv)))
return svc_send(rqstp); return svc_send(rqstp);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/sunrpc/xdr.h> #include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/msg_prot.h>
#include <linux/bvec.h> #include <linux/bvec.h>
#include <trace/events/sunrpc.h>
/* /*
* XDR functions for basic NFS types * XDR functions for basic NFS types
...@@ -162,6 +163,15 @@ xdr_free_bvec(struct xdr_buf *buf) ...@@ -162,6 +163,15 @@ xdr_free_bvec(struct xdr_buf *buf)
buf->bvec = NULL; buf->bvec = NULL;
} }
/**
* xdr_inline_pages - Prepare receive buffer for a large reply
* @xdr: xdr_buf into which reply will be placed
* @offset: expected offset where data payload will start, in bytes
* @pages: vector of struct page pointers
* @base: offset in first page where receive should start, in bytes
* @len: expected size of the upper layer data payload, in bytes
*
*/
void void
xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
struct page **pages, unsigned int base, unsigned int len) struct page **pages, unsigned int base, unsigned int len)
...@@ -179,6 +189,8 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, ...@@ -179,6 +189,8 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
tail->iov_base = buf + offset; tail->iov_base = buf + offset;
tail->iov_len = buflen - offset; tail->iov_len = buflen - offset;
if ((xdr->page_len & 3) == 0)
tail->iov_len -= sizeof(__be32);
xdr->buflen += len; xdr->buflen += len;
} }
...@@ -346,13 +358,15 @@ EXPORT_SYMBOL_GPL(_copy_from_pages); ...@@ -346,13 +358,15 @@ EXPORT_SYMBOL_GPL(_copy_from_pages);
* 'len' bytes. The extra data is not lost, but is instead * 'len' bytes. The extra data is not lost, but is instead
* moved into the inlined pages and/or the tail. * moved into the inlined pages and/or the tail.
*/ */
static void static unsigned int
xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
{ {
struct kvec *head, *tail; struct kvec *head, *tail;
size_t copy, offs; size_t copy, offs;
unsigned int pglen = buf->page_len; unsigned int pglen = buf->page_len;
unsigned int result;
result = 0;
tail = buf->tail; tail = buf->tail;
head = buf->head; head = buf->head;
...@@ -366,6 +380,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) ...@@ -366,6 +380,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
copy = tail->iov_len - len; copy = tail->iov_len - len;
memmove((char *)tail->iov_base + len, memmove((char *)tail->iov_base + len,
tail->iov_base, copy); tail->iov_base, copy);
result += copy;
} }
/* Copy from the inlined pages into the tail */ /* Copy from the inlined pages into the tail */
copy = len; copy = len;
...@@ -376,11 +391,13 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) ...@@ -376,11 +391,13 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
copy = 0; copy = 0;
else if (copy > tail->iov_len - offs) else if (copy > tail->iov_len - offs)
copy = tail->iov_len - offs; copy = tail->iov_len - offs;
if (copy != 0) if (copy != 0) {
_copy_from_pages((char *)tail->iov_base + offs, _copy_from_pages((char *)tail->iov_base + offs,
buf->pages, buf->pages,
buf->page_base + pglen + offs - len, buf->page_base + pglen + offs - len,
copy); copy);
result += copy;
}
/* Do we also need to copy data from the head into the tail ? */ /* Do we also need to copy data from the head into the tail ? */
if (len > pglen) { if (len > pglen) {
offs = copy = len - pglen; offs = copy = len - pglen;
...@@ -390,6 +407,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) ...@@ -390,6 +407,7 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
(char *)head->iov_base + (char *)head->iov_base +
head->iov_len - offs, head->iov_len - offs,
copy); copy);
result += copy;
} }
} }
/* Now handle pages */ /* Now handle pages */
...@@ -405,12 +423,15 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) ...@@ -405,12 +423,15 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
_copy_to_pages(buf->pages, buf->page_base, _copy_to_pages(buf->pages, buf->page_base,
(char *)head->iov_base + head->iov_len - len, (char *)head->iov_base + head->iov_len - len,
copy); copy);
result += copy;
} }
head->iov_len -= len; head->iov_len -= len;
buf->buflen -= len; buf->buflen -= len;
/* Have we truncated the message? */ /* Have we truncated the message? */
if (buf->len > buf->buflen) if (buf->len > buf->buflen)
buf->len = buf->buflen; buf->len = buf->buflen;
return result;
} }
/** /**
...@@ -422,14 +443,16 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) ...@@ -422,14 +443,16 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
* 'len' bytes. The extra data is not lost, but is instead * 'len' bytes. The extra data is not lost, but is instead
* moved into the tail. * moved into the tail.
*/ */
static void static unsigned int
xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
{ {
struct kvec *tail; struct kvec *tail;
size_t copy; size_t copy;
unsigned int pglen = buf->page_len; unsigned int pglen = buf->page_len;
unsigned int tailbuf_len; unsigned int tailbuf_len;
unsigned int result;
result = 0;
tail = buf->tail; tail = buf->tail;
BUG_ON (len > pglen); BUG_ON (len > pglen);
...@@ -447,18 +470,22 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) ...@@ -447,18 +470,22 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
if (tail->iov_len > len) { if (tail->iov_len > len) {
char *p = (char *)tail->iov_base + len; char *p = (char *)tail->iov_base + len;
memmove(p, tail->iov_base, tail->iov_len - len); memmove(p, tail->iov_base, tail->iov_len - len);
result += tail->iov_len - len;
} else } else
copy = tail->iov_len; copy = tail->iov_len;
/* Copy from the inlined pages into the tail */ /* Copy from the inlined pages into the tail */
_copy_from_pages((char *)tail->iov_base, _copy_from_pages((char *)tail->iov_base,
buf->pages, buf->page_base + pglen - len, buf->pages, buf->page_base + pglen - len,
copy); copy);
result += copy;
} }
buf->page_len -= len; buf->page_len -= len;
buf->buflen -= len; buf->buflen -= len;
/* Have we truncated the message? */ /* Have we truncated the message? */
if (buf->len > buf->buflen) if (buf->len > buf->buflen)
buf->len = buf->buflen; buf->len = buf->buflen;
return result;
} }
void void
...@@ -483,6 +510,7 @@ EXPORT_SYMBOL_GPL(xdr_stream_pos); ...@@ -483,6 +510,7 @@ EXPORT_SYMBOL_GPL(xdr_stream_pos);
* @xdr: pointer to xdr_stream struct * @xdr: pointer to xdr_stream struct
* @buf: pointer to XDR buffer in which to encode data * @buf: pointer to XDR buffer in which to encode data
* @p: current pointer inside XDR buffer * @p: current pointer inside XDR buffer
* @rqst: pointer to controlling rpc_rqst, for debugging
* *
* Note: at the moment the RPC client only passes the length of our * Note: at the moment the RPC client only passes the length of our
* scratch buffer in the xdr_buf's header kvec. Previously this * scratch buffer in the xdr_buf's header kvec. Previously this
...@@ -491,7 +519,8 @@ EXPORT_SYMBOL_GPL(xdr_stream_pos); ...@@ -491,7 +519,8 @@ EXPORT_SYMBOL_GPL(xdr_stream_pos);
* of the buffer length, and takes care of adjusting the kvec * of the buffer length, and takes care of adjusting the kvec
* length for us. * length for us.
*/ */
void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
struct rpc_rqst *rqst)
{ {
struct kvec *iov = buf->head; struct kvec *iov = buf->head;
int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
...@@ -513,6 +542,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) ...@@ -513,6 +542,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
buf->len += len; buf->len += len;
iov->iov_len += len; iov->iov_len += len;
} }
xdr->rqst = rqst;
} }
EXPORT_SYMBOL_GPL(xdr_init_encode); EXPORT_SYMBOL_GPL(xdr_init_encode);
...@@ -551,9 +581,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, ...@@ -551,9 +581,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
int frag1bytes, frag2bytes; int frag1bytes, frag2bytes;
if (nbytes > PAGE_SIZE) if (nbytes > PAGE_SIZE)
return NULL; /* Bigger buffers require special handling */ goto out_overflow; /* Bigger buffers require special handling */
if (xdr->buf->len + nbytes > xdr->buf->buflen) if (xdr->buf->len + nbytes > xdr->buf->buflen)
return NULL; /* Sorry, we're totally out of space */ goto out_overflow; /* Sorry, we're totally out of space */
frag1bytes = (xdr->end - xdr->p) << 2; frag1bytes = (xdr->end - xdr->p) << 2;
frag2bytes = nbytes - frag1bytes; frag2bytes = nbytes - frag1bytes;
if (xdr->iov) if (xdr->iov)
...@@ -582,6 +612,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, ...@@ -582,6 +612,9 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
xdr->buf->page_len += frag2bytes; xdr->buf->page_len += frag2bytes;
xdr->buf->len += nbytes; xdr->buf->len += nbytes;
return p; return p;
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
/** /**
...@@ -819,8 +852,10 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr) ...@@ -819,8 +852,10 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr)
* @xdr: pointer to xdr_stream struct * @xdr: pointer to xdr_stream struct
* @buf: pointer to XDR buffer from which to decode data * @buf: pointer to XDR buffer from which to decode data
* @p: current pointer inside XDR buffer * @p: current pointer inside XDR buffer
* @rqst: pointer to controlling rpc_rqst, for debugging
*/ */
void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
struct rpc_rqst *rqst)
{ {
xdr->buf = buf; xdr->buf = buf;
xdr->scratch.iov_base = NULL; xdr->scratch.iov_base = NULL;
...@@ -836,6 +871,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) ...@@ -836,6 +871,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
xdr->nwords -= p - xdr->p; xdr->nwords -= p - xdr->p;
xdr->p = p; xdr->p = p;
} }
xdr->rqst = rqst;
} }
EXPORT_SYMBOL_GPL(xdr_init_decode); EXPORT_SYMBOL_GPL(xdr_init_decode);
...@@ -854,7 +890,7 @@ void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, ...@@ -854,7 +890,7 @@ void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
buf->page_len = len; buf->page_len = len;
buf->buflen = len; buf->buflen = len;
buf->len = len; buf->len = len;
xdr_init_decode(xdr, buf, NULL); xdr_init_decode(xdr, buf, NULL, NULL);
} }
EXPORT_SYMBOL_GPL(xdr_init_decode_pages); EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
...@@ -896,20 +932,23 @@ static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes) ...@@ -896,20 +932,23 @@ static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
size_t cplen = (char *)xdr->end - (char *)xdr->p; size_t cplen = (char *)xdr->end - (char *)xdr->p;
if (nbytes > xdr->scratch.iov_len) if (nbytes > xdr->scratch.iov_len)
return NULL; goto out_overflow;
p = __xdr_inline_decode(xdr, cplen); p = __xdr_inline_decode(xdr, cplen);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
memcpy(cpdest, p, cplen); memcpy(cpdest, p, cplen);
if (!xdr_set_next_buffer(xdr))
goto out_overflow;
cpdest += cplen; cpdest += cplen;
nbytes -= cplen; nbytes -= cplen;
if (!xdr_set_next_buffer(xdr))
return NULL;
p = __xdr_inline_decode(xdr, nbytes); p = __xdr_inline_decode(xdr, nbytes);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
memcpy(cpdest, p, nbytes); memcpy(cpdest, p, nbytes);
return xdr->scratch.iov_base; return xdr->scratch.iov_base;
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
/** /**
...@@ -926,14 +965,17 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) ...@@ -926,14 +965,17 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{ {
__be32 *p; __be32 *p;
if (nbytes == 0) if (unlikely(nbytes == 0))
return xdr->p; return xdr->p;
if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr)) if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
return NULL; goto out_overflow;
p = __xdr_inline_decode(xdr, nbytes); p = __xdr_inline_decode(xdr, nbytes);
if (p != NULL) if (p != NULL)
return p; return p;
return xdr_copy_to_scratch(xdr, nbytes); return xdr_copy_to_scratch(xdr, nbytes);
out_overflow:
trace_rpc_xdr_overflow(xdr, nbytes);
return NULL;
} }
EXPORT_SYMBOL_GPL(xdr_inline_decode); EXPORT_SYMBOL_GPL(xdr_inline_decode);
...@@ -943,13 +985,17 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len) ...@@ -943,13 +985,17 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
struct kvec *iov; struct kvec *iov;
unsigned int nwords = XDR_QUADLEN(len); unsigned int nwords = XDR_QUADLEN(len);
unsigned int cur = xdr_stream_pos(xdr); unsigned int cur = xdr_stream_pos(xdr);
unsigned int copied, offset;
if (xdr->nwords == 0) if (xdr->nwords == 0)
return 0; return 0;
/* Realign pages to current pointer position */ /* Realign pages to current pointer position */
iov = buf->head; iov = buf->head;
if (iov->iov_len > cur) { if (iov->iov_len > cur) {
xdr_shrink_bufhead(buf, iov->iov_len - cur); offset = iov->iov_len - cur;
copied = xdr_shrink_bufhead(buf, offset);
trace_rpc_xdr_alignment(xdr, offset, copied);
xdr->nwords = XDR_QUADLEN(buf->len - cur); xdr->nwords = XDR_QUADLEN(buf->len - cur);
} }
...@@ -961,7 +1007,9 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len) ...@@ -961,7 +1007,9 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
len = buf->page_len; len = buf->page_len;
else if (nwords < xdr->nwords) { else if (nwords < xdr->nwords) {
/* Truncate page data and move it into the tail */ /* Truncate page data and move it into the tail */
xdr_shrink_pagelen(buf, buf->page_len - len); offset = buf->page_len - len;
copied = xdr_shrink_pagelen(buf, offset);
trace_rpc_xdr_alignment(xdr, offset, copied);
xdr->nwords = XDR_QUADLEN(buf->len - cur); xdr->nwords = XDR_QUADLEN(buf->len - cur);
} }
return len; return len;
...@@ -1102,47 +1150,6 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, ...@@ -1102,47 +1150,6 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
} }
EXPORT_SYMBOL_GPL(xdr_buf_subsegment); EXPORT_SYMBOL_GPL(xdr_buf_subsegment);
/**
* xdr_buf_trim - lop at most "len" bytes off the end of "buf"
* @buf: buf to be trimmed
* @len: number of bytes to reduce "buf" by
*
* Trim an xdr_buf by the given number of bytes by fixing up the lengths. Note
* that it's possible that we'll trim less than that amount if the xdr_buf is
* too small, or if (for instance) it's all in the head and the parser has
* already read too far into it.
*/
void xdr_buf_trim(struct xdr_buf *buf, unsigned int len)
{
size_t cur;
unsigned int trim = len;
if (buf->tail[0].iov_len) {
cur = min_t(size_t, buf->tail[0].iov_len, trim);
buf->tail[0].iov_len -= cur;
trim -= cur;
if (!trim)
goto fix_len;
}
if (buf->page_len) {
cur = min_t(unsigned int, buf->page_len, trim);
buf->page_len -= cur;
trim -= cur;
if (!trim)
goto fix_len;
}
if (buf->head[0].iov_len) {
cur = min_t(size_t, buf->head[0].iov_len, trim);
buf->head[0].iov_len -= cur;
trim -= cur;
}
fix_len:
buf->len -= (len - trim);
}
EXPORT_SYMBOL_GPL(xdr_buf_trim);
static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len) static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
{ {
unsigned int this_len; unsigned int this_len;
......
This diff is collapsed.
...@@ -123,7 +123,7 @@ static int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst) ...@@ -123,7 +123,7 @@ static int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
rpcrdma_set_xdrlen(&req->rl_hdrbuf, 0); rpcrdma_set_xdrlen(&req->rl_hdrbuf, 0);
xdr_init_encode(&req->rl_stream, &req->rl_hdrbuf, xdr_init_encode(&req->rl_stream, &req->rl_hdrbuf,
req->rl_rdmabuf->rg_base); req->rl_rdmabuf->rg_base, rqst);
p = xdr_reserve_space(&req->rl_stream, 28); p = xdr_reserve_space(&req->rl_stream, 28);
if (unlikely(!p)) if (unlikely(!p))
......
...@@ -391,7 +391,7 @@ frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc) ...@@ -391,7 +391,7 @@ frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
*/ */
struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
struct rpcrdma_mr_seg *seg, struct rpcrdma_mr_seg *seg,
int nsegs, bool writing, u32 xid, int nsegs, bool writing, __be32 xid,
struct rpcrdma_mr **out) struct rpcrdma_mr **out)
{ {
struct rpcrdma_ia *ia = &r_xprt->rx_ia; struct rpcrdma_ia *ia = &r_xprt->rx_ia;
...@@ -446,7 +446,7 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt, ...@@ -446,7 +446,7 @@ struct rpcrdma_mr_seg *frwr_map(struct rpcrdma_xprt *r_xprt,
goto out_mapmr_err; goto out_mapmr_err;
ibmr->iova &= 0x00000000ffffffff; ibmr->iova &= 0x00000000ffffffff;
ibmr->iova |= ((u64)cpu_to_be32(xid)) << 32; ibmr->iova |= ((u64)be32_to_cpu(xid)) << 32;
key = (u8)(ibmr->rkey & 0x000000FF); key = (u8)(ibmr->rkey & 0x000000FF);
ib_update_fast_reg_key(ibmr, ++key); ib_update_fast_reg_key(ibmr, ++key);
......
This diff is collapsed.
...@@ -304,7 +304,6 @@ xprt_setup_rdma_bc(struct xprt_create *args) ...@@ -304,7 +304,6 @@ xprt_setup_rdma_bc(struct xprt_create *args)
xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO; xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
xprt->prot = XPRT_TRANSPORT_BC_RDMA; xprt->prot = XPRT_TRANSPORT_BC_RDMA;
xprt->tsh_size = 0;
xprt->ops = &xprt_rdma_bc_procs; xprt->ops = &xprt_rdma_bc_procs;
memcpy(&xprt->addr, args->dstaddr, args->addrlen); memcpy(&xprt->addr, args->dstaddr, args->addrlen);
......
...@@ -332,7 +332,6 @@ xprt_setup_rdma(struct xprt_create *args) ...@@ -332,7 +332,6 @@ xprt_setup_rdma(struct xprt_create *args)
xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO; xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
xprt->resvport = 0; /* privileged port not needed */ xprt->resvport = 0; /* privileged port not needed */
xprt->tsh_size = 0; /* RPC-RDMA handles framing */
xprt->ops = &xprt_rdma_procs; xprt->ops = &xprt_rdma_procs;
/* /*
......
...@@ -1481,6 +1481,8 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp) ...@@ -1481,6 +1481,8 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
if (ep->rep_receive_count > needed) if (ep->rep_receive_count > needed)
goto out; goto out;
needed -= ep->rep_receive_count; needed -= ep->rep_receive_count;
if (!temp)
needed += RPCRDMA_MAX_RECV_BATCH;
count = 0; count = 0;
wr = NULL; wr = NULL;
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment