summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorMarcel Telka <marcel.telka@nexenta.com>2015-09-03 19:47:20 +0200
committerDan McDonald <danmcd@omniti.com>2015-09-03 13:56:17 -0400
commitcf98b944cdc2063fc14f3fd525e284de3ed29fd0 (patch)
tree28df5e6ccce80e3e691e730096fac98ff788e25f /usr/src
parentfb01aed523c52aea9a7b48fe29a1b2624c7f21c5 (diff)
downloadillumos-joyent-cf98b944cdc2063fc14f3fd525e284de3ed29fd0.tar.gz
5907 xdrmblk_getpos() is unreliable
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com> Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_dump.c14
-rw-r--r--usr/src/uts/common/rpc/clnt_clts.c26
-rw-r--r--usr/src/uts/common/rpc/clnt_cots.c23
-rw-r--r--usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c5
-rw-r--r--usr/src/uts/common/rpc/svc_clts.c24
-rw-r--r--usr/src/uts/common/rpc/svc_cots.c24
-rw-r--r--usr/src/uts/common/rpc/xdr_mblk.c333
7 files changed, 327 insertions, 122 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs_dump.c b/usr/src/uts/common/fs/nfs/nfs_dump.c
index f49449fde8..afa50a7124 100644
--- a/usr/src/uts/common/fs/nfs/nfs_dump.c
+++ b/usr/src/uts/common/fs/nfs/nfs_dump.c
@@ -18,6 +18,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
/*
* Copyright 2014 Gary Mills
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
@@ -405,15 +410,18 @@ nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res;
break;
default:
+ XDR_DESTROY(xdrp);
return (EIO);
}
if (!xdr_replymsg(xdrp, &reply_msg)) {
+ XDR_DESTROY(xdrp);
cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed");
return (EIO);
}
if (reply_msg.rm_xid != call_xid) {
+ XDR_DESTROY(xdrp);
*badmsg = 1;
return (0);
}
@@ -421,6 +429,7 @@ nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
_seterr_reply(&reply_msg, &rpc_err);
if (rpc_err.re_status != RPC_SUCCESS) {
+ XDR_DESTROY(xdrp);
cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)",
rpc_err.re_status, clnt_sperrno(rpc_err.re_status));
return (EIO);
@@ -429,17 +438,20 @@ nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
switch (nfsdump_version) {
case NFS_VERSION:
if (na.ns_status) {
+ XDR_DESTROY(xdrp);
cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status);
return (EIO);
}
break;
case NFS_V3:
if (wres.status != NFS3_OK) {
+ XDR_DESTROY(xdrp);
cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status);
return (EIO);
}
break;
default:
+ XDR_DESTROY(xdrp);
return (EIO);
}
@@ -449,6 +461,8 @@ nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
(void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf));
}
+ XDR_DESTROY(xdrp);
+
freemsg(rudata.udata.udata_mp);
return (0);
diff --git a/usr/src/uts/common/rpc/clnt_clts.c b/usr/src/uts/common/rpc/clnt_clts.c
index 2c4bf03bf4..beab2b6a4b 100644
--- a/usr/src/uts/common/rpc/clnt_clts.c
+++ b/usr/src/uts/common/rpc/clnt_clts.c
@@ -18,6 +18,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -342,9 +347,11 @@ clnt_clts_kcreate(struct knetconfig *config, struct netbuf *addr,
/* pre-serialize call message header */
if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) {
+ XDR_DESTROY(&p->cku_outxdr);
error = EINVAL; /* XXX */
goto bad;
}
+ XDR_DESTROY(&p->cku_outxdr);
p->cku_config.knc_rdev = config->knc_rdev;
p->cku_config.knc_semantics = config->knc_semantics;
@@ -528,6 +535,7 @@ call_again:
if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) ||
(!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) ||
(!(*xdr_args)(xdrs, argsp))) {
+ XDR_DESTROY(xdrs);
freemsg(mp);
p->cku_err.re_status = RPC_CANTENCODEARGS;
p->cku_err.re_errno = EIO;
@@ -544,12 +552,15 @@ call_again:
/* Serialize the procedure number and the arguments. */
if (!AUTH_WRAP(h->cl_auth, (caddr_t)p->cku_rpchdr,
CKU_HDRSIZE+4, xdrs, xdr_args, argsp)) {
+ XDR_DESTROY(xdrs);
freemsg(mp);
p->cku_err.re_status = RPC_CANTENCODEARGS;
p->cku_err.re_errno = EIO;
goto done;
}
}
+
+ XDR_DESTROY(xdrs);
} else
mp = mpdup;
@@ -780,6 +791,7 @@ tryread:
p->cku_err.re_status = RPC_CANTDECODERES;
p->cku_err.re_errno = EIO;
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
goto done1;
}
@@ -796,6 +808,7 @@ tryread:
p->cku_err.re_why = AUTH_INVALIDRESP;
RCSTAT_INCR(p->cku_stats, rcbadverfs);
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
goto tryread;
}
if (!AUTH_UNWRAP(h->cl_auth, xdrs, xdr_results, resultsp)) {
@@ -803,6 +816,7 @@ tryread:
p->cku_err.re_errno = EIO;
}
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
goto done1;
}
/* set errno in case we can't recover */
@@ -820,11 +834,13 @@ tryread:
*/
if (re_status == RPC_PROCUNAVAIL && p->cku_bcast) {
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
goto tryread;
}
if (re_status == RPC_AUTHERROR) {
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
call_table_remove(call);
if (call->call_reply != NULL) {
freemsg(call->call_reply);
@@ -914,6 +930,7 @@ tryread:
}
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
done1:
call_table_remove(call);
@@ -1006,16 +1023,13 @@ clnt_clts_kerror(CLIENT *h, struct rpc_err *err)
*err = p->cku_err;
}
+/*ARGSUSED*/
static bool_t
clnt_clts_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr)
{
- /* LINTED pointer alignment */
- struct cku_private *p = htop(h);
- XDR *xdrs;
+ xdr_free(xdr_res, res_ptr);
- xdrs = &(p->cku_outxdr);
- xdrs->x_op = XDR_FREE;
- return ((*xdr_res)(xdrs, res_ptr));
+ return (TRUE);
}
/*ARGSUSED*/
diff --git a/usr/src/uts/common/rpc/clnt_cots.c b/usr/src/uts/common/rpc/clnt_cots.c
index f3b2c1946c..88fe0f86ff 100644
--- a/usr/src/uts/common/rpc/clnt_cots.c
+++ b/usr/src/uts/common/rpc/clnt_cots.c
@@ -18,6 +18,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -603,6 +608,7 @@ clnt_cots_kcreate(dev_t dev, struct netbuf *addr, int family, rpcprog_t prog,
xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, WIRE_HDR_SIZE, XDR_ENCODE);
if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) {
+ XDR_DESTROY(&p->cku_outxdr);
RPCLOG0(1, "clnt_cots_kcreate - Fatal header serialization "
"error\n");
auth_destroy(h->cl_auth);
@@ -610,6 +616,7 @@ clnt_cots_kcreate(dev_t dev, struct netbuf *addr, int family, rpcprog_t prog,
RPCLOG0(1, "clnt_cots_kcreate: create failed error EINVAL\n");
return (EINVAL); /* XXX */
}
+ XDR_DESTROY(&p->cku_outxdr);
/*
* The zalloc initialized the fields below.
@@ -651,16 +658,13 @@ clnt_cots_kerror(CLIENT *h, struct rpc_err *err)
*err = p->cku_err;
}
+/*ARGSUSED*/
static bool_t
clnt_cots_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr)
{
- /* LINTED pointer alignment */
- cku_private_t *p = htop(h);
- XDR *xdrs;
+ xdr_free(xdr_res, res_ptr);
- xdrs = &(p->cku_outxdr);
- xdrs->x_op = XDR_FREE;
- return ((*xdr_res)(xdrs, res_ptr));
+ return (TRUE);
}
static bool_t
@@ -1073,6 +1077,7 @@ call_again:
if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) ||
(!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) ||
(!(*xdr_args)(xdrs, argsp))) {
+ XDR_DESTROY(xdrs);
p->cku_err.re_status = RPC_CANTENCODEARGS;
p->cku_err.re_errno = EIO;
goto cots_done;
@@ -1091,12 +1096,15 @@ call_again:
/* Serialize the procedure number and the arguments. */
if (!AUTH_WRAP(h->cl_auth, p->cku_rpchdr, WIRE_HDR_SIZE+4,
xdrs, xdr_args, argsp)) {
+ XDR_DESTROY(xdrs);
p->cku_err.re_status = RPC_CANTENCODEARGS;
p->cku_err.re_errno = EIO;
goto cots_done;
}
}
+ XDR_DESTROY(xdrs);
+
RPCLOG(2, "clnt_cots_kcallit: connected, sending call, tidu_size %d\n",
tidu_size);
@@ -1365,6 +1373,7 @@ read_again:
"failure\n");
freemsg(mp);
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
mutex_enter(&call->call_lock);
if (call->call_reply == NULL)
call->call_status = RPC_TIMEDOUT;
@@ -1402,6 +1411,7 @@ read_again:
(void) xdr_rpc_free_verifier(xdrs,
&reply_msg);
+ XDR_DESTROY(xdrs);
if (p->cku_flags & CKU_ONQUEUE) {
call_table_remove(call);
@@ -1487,6 +1497,7 @@ read_again:
}
(void) xdr_rpc_free_verifier(xdrs, &reply_msg);
+ XDR_DESTROY(xdrs);
if (p->cku_flags & CKU_ONQUEUE) {
call_table_remove(call);
diff --git a/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c b/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c
index c83eec5f82..23f98b982c 100644
--- a/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c
+++ b/usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c
@@ -18,7 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
@@ -984,9 +986,6 @@ rpcsec_gss_init(
arg->cr_version = creds.version;
arg->cr_service = creds.service;
- /* We no longer need the xp_xdrin, destroy it all here. */
- XDR_DESTROY(&(rqst->rq_xprt->xp_xdrin));
-
/* should be ok to hold clm lock as taskq will have new thread(s) */
ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
diff --git a/usr/src/uts/common/rpc/svc_clts.c b/usr/src/uts/common/rpc/svc_clts.c
index acbaa7f3f6..45645ac541 100644
--- a/usr/src/uts/common/rpc/svc_clts.c
+++ b/usr/src/uts/common/rpc/svc_clts.c
@@ -18,7 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -382,6 +384,7 @@ svc_clts_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg)
TRACE_0(TR_FAC_KRPC, TR_XDR_CALLMSG_START,
"xdr_callmsg_start:");
if (! xdr_callmsg(xdrs, msg)) {
+ XDR_DESTROY(xdrs);
TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
"xdr_callmsg_end:(%S)", "bad");
RSSTAT_INCR(stats, rsxdrcall);
@@ -468,7 +471,7 @@ svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
}
/*
- * Initialize the XDR decode stream. Additional mblks
+ * Initialize the XDR encode stream. Additional mblks
* will be allocated if necessary. They will be UD_MAXSIZE
* sized.
*/
@@ -489,6 +492,7 @@ svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
if (!(xdr_replymsg(xdrs, msg) &&
(!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
xdr_results, xdr_location)))) {
+ XDR_DESTROY(xdrs);
TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
"xdr_replymsg_end:(%S)", "bad");
RPCLOG0(1, "xdr_replymsg/SVCAUTH_WRAP failed\n");
@@ -500,10 +504,13 @@ svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
} else if (!(xdr_replymsg_body(xdrs, msg) &&
(!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
xdr_results, xdr_location)))) {
+ XDR_DESTROY(xdrs);
RPCLOG0(1, "xdr_replymsg_body/SVCAUTH_WRAP failed\n");
goto out;
}
+ XDR_DESTROY(xdrs);
+
msgsz = (int)xmsgsize(ud->ud_resp->b_cont);
if (msgsz <= 0 || (clone_xprt->xp_msg_size != -1 &&
@@ -635,6 +642,8 @@ svc_clts_kfreeargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args,
} else
retval = TRUE;
+ XDR_DESTROY(xdrs);
+
if (ud->ud_inmp) {
freemsg(ud->ud_inmp);
ud->ud_inmp = NULL;
@@ -658,14 +667,14 @@ svc_clts_kgetres(SVCXPRT *clone_xprt, int size)
*/
while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) {
if (strwaitbuf(UD_INITSIZE, BPRI_LO)) {
- return (FALSE);
+ return (NULL);
}
}
mp->b_cont = NULL;
/*
- * Initialize the XDR decode stream. Additional mblks
+ * Initialize the XDR encode stream. Additional mblks
* will be allocated if necessary. They will be UD_MAXSIZE
* sized.
*/
@@ -687,16 +696,19 @@ svc_clts_kgetres(SVCXPRT *clone_xprt, int size)
rply.acpted_rply.ar_stat = SUCCESS;
if (!xdr_replymsg_hdr(xdrs, &rply)) {
+ XDR_DESTROY(xdrs);
freeb(mp);
return (NULL);
}
buf = XDR_INLINE(xdrs, size);
- if (buf == NULL)
+ if (buf == NULL) {
+ XDR_DESTROY(xdrs);
freeb(mp);
- else
+ } else {
ud->ud_resp->b_cont = mp;
+ }
return (buf);
}
@@ -710,6 +722,8 @@ svc_clts_kfreeres(SVCXPRT *clone_xprt)
if (ud->ud_resp == NULL || ud->ud_resp->b_cont == NULL)
return;
+ XDR_DESTROY(&clone_xprt->xp_xdrout);
+
/*
* SVC_FREERES() is called whenever the server decides not to
* send normal reply. Thus, we expect only one mblk to be allocated,
diff --git a/usr/src/uts/common/rpc/svc_cots.c b/usr/src/uts/common/rpc/svc_cots.c
index aa2740725f..944e7396e6 100644
--- a/usr/src/uts/common/rpc/svc_cots.c
+++ b/usr/src/uts/common/rpc/svc_cots.c
@@ -18,7 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -371,6 +373,7 @@ svc_cots_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg)
"xdr_callmsg_start:");
RPCLOG0(4, "xdr_callmsg_start:\n");
if (!xdr_callmsg(xdrs, msg)) {
+ XDR_DESTROY(xdrs);
TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
"xdr_callmsg_end:(%S)", "bad");
RPCLOG0(1, "svc_cots_krecv xdr_callmsg failure\n");
@@ -443,6 +446,7 @@ svc_cots_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
if (!(xdr_replymsg_body(xdrs, msg) &&
(!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
xdr_results, xdr_location)))) {
+ XDR_DESTROY(xdrs);
RPCLOG0(1, "svc_cots_ksend: "
"xdr_replymsg_body/SVCAUTH_WRAP failed\n");
freemsg(mp);
@@ -472,7 +476,7 @@ svc_cots_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
}
/*
- * Initialize the XDR decode stream. Additional mblks
+ * Initialize the XDR encode stream. Additional mblks
* will be allocated if necessary. They will be TIDU
* sized.
*/
@@ -517,6 +521,7 @@ svc_cots_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
if (!(xdr_replymsg(xdrs, msg) &&
(!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
xdr_results, xdr_location)))) {
+ XDR_DESTROY(xdrs);
TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
"xdr_replymsg_end:(%S)", "bad");
freemsg(mp);
@@ -528,6 +533,8 @@ svc_cots_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
"xdr_replymsg_end:(%S)", "good");
}
+ XDR_DESTROY(xdrs);
+
put(clone_xprt->xp_wq, mp);
retval = TRUE;
@@ -564,6 +571,8 @@ svc_cots_kfreeargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args,
caddr_t args_ptr)
{
cots_data_t *cd = (cots_data_t *)clone_xprt->xp_p2buf;
+ /* LINTED pointer alignment */
+ XDR *xdrs = &clone_xprt->xp_xdrin;
mblk_t *mp;
bool_t retval;
@@ -574,14 +583,13 @@ svc_cots_kfreeargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args,
* the memory be intact during the free routine.
*/
if (args_ptr) {
- /* LINTED pointer alignment */
- XDR *xdrs = &clone_xprt->xp_xdrin;
-
xdrs->x_op = XDR_FREE;
retval = (*xdr_args)(xdrs, args_ptr);
} else
retval = TRUE;
+ XDR_DESTROY(xdrs);
+
if ((mp = cd->cd_req_mp) != NULL) {
cd->cd_req_mp = (mblk_t *)0;
freemsg(mp);
@@ -612,11 +620,11 @@ svc_cots_kgetres(SVCXPRT *clone_xprt, int size)
*/
while ((mp = allocb(len, BPRI_LO)) == NULL) {
if (strwaitbuf(len, BPRI_LO))
- return (FALSE);
+ return (NULL);
}
/*
- * Initialize the XDR decode stream. Additional mblks
+ * Initialize the XDR encode stream. Additional mblks
* will be allocated if necessary. They will be TIDU
* sized.
*/
@@ -664,13 +672,14 @@ svc_cots_kgetres(SVCXPRT *clone_xprt, int size)
rply.acpted_rply.ar_stat = SUCCESS;
if (!xdr_replymsg_hdr(xdrs, &rply)) {
+ XDR_DESTROY(xdrs);
freeb(mp);
return (NULL);
}
-
buf = XDR_INLINE(xdrs, size);
if (buf == NULL) {
+ XDR_DESTROY(xdrs);
ASSERT(cd->cd_mp == NULL);
freemsg(mp);
} else {
@@ -687,6 +696,7 @@ svc_cots_kfreeres(SVCXPRT *clone_xprt)
cd = (cots_data_t *)clone_xprt->xp_p2buf;
if ((mp = cd->cd_mp) != NULL) {
+ XDR_DESTROY(&clone_xprt->xp_xdrout);
cd->cd_mp = (mblk_t *)NULL;
freemsg(mp);
}
diff --git a/usr/src/uts/common/rpc/xdr_mblk.c b/usr/src/uts/common/rpc/xdr_mblk.c
index 0b06b827e0..ac9b1f15ee 100644
--- a/usr/src/uts/common/rpc/xdr_mblk.c
+++ b/usr/src/uts/common/rpc/xdr_mblk.c
@@ -18,6 +18,11 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -59,6 +64,7 @@ static void xdrmblk_destroy(XDR *);
static bool_t xdrmblk_control(XDR *, int, void *);
static mblk_t *xdrmblk_alloc(int);
+static void xdrmblk_skip_fully_read_mblks(XDR *);
/*
* Xdr on mblks operations vector.
@@ -76,38 +82,77 @@ struct xdr_ops xdrmblk_ops = {
};
/*
+ * The xdrmblk_params structure holds the internal data for the XDR stream.
+ * The x_private member of the XDR points to this structure. The
+ * xdrmblk_params structure is dynamically allocated in xdrmblk_init() and
+ * freed in xdrmblk_destroy().
+ *
+ * The apos and rpos members of the xdrmblk_params structure are used to
+ * implement xdrmblk_getpos() and xdrmblk_setpos().
+ *
+ * In addition to the xdrmblk_params structure we store some additional
+ * internal data directly in the XDR stream structure:
+ *
+ * x_base A pointer to the current mblk (that one we are currently
+ * working with).
+ * x_handy The number of available bytes (either for read or for write) in
+ * the current mblk.
+ */
+struct xdrmblk_params {
+ int sz;
+ uint_t apos; /* Absolute position of the current mblk */
+ uint_t rpos; /* Relative position in the current mblk */
+};
+
+/*
* Initialize xdr stream.
*/
void
xdrmblk_init(XDR *xdrs, mblk_t *m, enum xdr_op op, int sz)
{
+ struct xdrmblk_params *p;
+
xdrs->x_op = op;
xdrs->x_ops = &xdrmblk_ops;
xdrs->x_base = (caddr_t)m;
xdrs->x_public = NULL;
- xdrs->x_private = (caddr_t)(uintptr_t)sz;
+ p = kmem_alloc(sizeof (struct xdrmblk_params), KM_SLEEP);
+ xdrs->x_private = (caddr_t)p;
- if (op == XDR_DECODE)
- xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
- else
- xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_datap->db_base);
+ p->sz = sz;
+ p->apos = 0;
+ p->rpos = 0;
+
+ if (op == XDR_DECODE) {
+ xdrs->x_handy = (int)MBLKL(m);
+ } else {
+ xdrs->x_handy = (int)MBLKTAIL(m);
+ if (p->sz < sizeof (int32_t))
+ p->sz = sizeof (int32_t);
+ }
}
-/* ARGSUSED */
static void
xdrmblk_destroy(XDR *xdrs)
{
+ kmem_free(xdrs->x_private, sizeof (struct xdrmblk_params));
}
static bool_t
xdrmblk_getint32(XDR *xdrs, int32_t *int32p)
{
mblk_t *m;
+ struct xdrmblk_params *p;
+
+ xdrmblk_skip_fully_read_mblks(xdrs);
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
if (m == NULL)
return (FALSE);
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
/*
* If the pointer is not aligned or there is not
* enough bytes, pullupmsg to get enough bytes and
@@ -124,23 +169,17 @@ xdrmblk_getint32(XDR *xdrs, int32_t *int32p)
return (FALSE);
delay(hz);
}
- xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
+ p->apos += p->rpos;
+ p->rpos = 0;
+ xdrs->x_handy = (int)MBLKL(m);
}
/* LINTED pointer alignment */
*int32p = ntohl(*((int32_t *)(m->b_rptr)));
m->b_rptr += sizeof (int32_t);
+ xdrs->x_handy -= sizeof (int32_t);
+ p->rpos += sizeof (int32_t);
- /*
- * Instead of leaving handy as 0 causing more pullupmsg's
- * simply move to the next mblk.
- */
- if ((xdrs->x_handy -= sizeof (int32_t)) == 0) {
- m = m->b_cont;
- xdrs->x_base = (caddr_t)m;
- if (m != NULL)
- xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
- }
return (TRUE);
}
@@ -148,24 +187,30 @@ static bool_t
xdrmblk_putint32(XDR *xdrs, int32_t *int32p)
{
mblk_t *m;
+ struct xdrmblk_params *p;
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
if (m == NULL)
return (FALSE);
- if ((xdrs->x_handy -= (int)sizeof (int32_t)) < 0) {
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
+ while (!IS_P2ALIGNED(m->b_wptr, sizeof (int32_t)) ||
+ xdrs->x_handy < sizeof (int32_t)) {
if (m->b_cont == NULL) {
- m->b_cont = xdrmblk_alloc((int)(uintptr_t)
- xdrs->x_private);
+ ASSERT(p->sz >= sizeof (int32_t));
+ m->b_cont = xdrmblk_alloc(p->sz);
}
m = m->b_cont;
xdrs->x_base = (caddr_t)m;
+ p->apos += p->rpos;
+ p->rpos = 0;
if (m == NULL) {
xdrs->x_handy = 0;
return (FALSE);
}
- xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_rptr -
- sizeof (int32_t));
+ xdrs->x_handy = (int)MBLKTAIL(m);
ASSERT(m->b_rptr == m->b_wptr);
ASSERT(m->b_rptr >= m->b_datap->db_base);
ASSERT(m->b_rptr < m->b_datap->db_lim);
@@ -173,6 +218,8 @@ xdrmblk_putint32(XDR *xdrs, int32_t *int32p)
/* LINTED pointer alignment */
*(int32_t *)m->b_wptr = htonl(*int32p);
m->b_wptr += sizeof (int32_t);
+ xdrs->x_handy -= sizeof (int32_t);
+ p->rpos += sizeof (int32_t);
ASSERT(m->b_wptr <= m->b_datap->db_lim);
return (TRUE);
}
@@ -186,12 +233,16 @@ static bool_t
xdrmblk_getbytes(XDR *xdrs, caddr_t addr, int len)
{
mblk_t *m;
+ struct xdrmblk_params *p;
int i;
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
if (m == NULL)
return (FALSE);
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
/*
* Performance tweak: converted explicit bcopy()
* call to simple in-line. This function is called
@@ -200,9 +251,9 @@ xdrmblk_getbytes(XDR *xdrs, caddr_t addr, int len)
* Overhead of calling bcopy() is obnoxious for such
* small copies.
*/
- while ((xdrs->x_handy -= len) < 0) {
- if ((xdrs->x_handy += len) > 0) {
- if (len < XDRMBLK_BCOPY_LIMIT) {
+ while (xdrs->x_handy < len) {
+ if (xdrs->x_handy > 0) {
+ if (xdrs->x_handy < XDRMBLK_BCOPY_LIMIT) {
for (i = 0; i < xdrs->x_handy; i++)
*addr++ = *m->b_rptr++;
} else {
@@ -211,15 +262,22 @@ xdrmblk_getbytes(XDR *xdrs, caddr_t addr, int len)
addr += xdrs->x_handy;
}
len -= xdrs->x_handy;
+ p->rpos += xdrs->x_handy;
}
m = m->b_cont;
xdrs->x_base = (caddr_t)m;
+ p->apos += p->rpos;
+ p->rpos = 0;
if (m == NULL) {
xdrs->x_handy = 0;
return (FALSE);
}
- xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
+ xdrs->x_handy = (int)MBLKL(m);
}
+
+ xdrs->x_handy -= len;
+ p->rpos += len;
+
if (len < XDRMBLK_BCOPY_LIMIT) {
for (i = 0; i < len; i++)
*addr++ = *m->b_rptr++;
@@ -227,6 +285,7 @@ xdrmblk_getbytes(XDR *xdrs, caddr_t addr, int len)
bcopy(m->b_rptr, addr, len);
m->b_rptr += len;
}
+
return (TRUE);
}
@@ -242,10 +301,11 @@ bool_t
xdrmblk_getmblk(XDR *xdrs, mblk_t **mm, uint_t *lenp)
{
mblk_t *m, *nextm;
+ struct xdrmblk_params *p;
int len;
- int32_t llen;
+ uint32_t llen;
- if (!xdrmblk_getint32(xdrs, &llen))
+ if (!xdrmblk_getint32(xdrs, (int32_t *)&llen))
return (FALSE);
*lenp = llen;
@@ -289,6 +349,11 @@ xdrmblk_getmblk(XDR *xdrs, mblk_t **mm, uint_t *lenp)
}
xdrs->x_base = (caddr_t)m;
xdrs->x_handy = m != NULL ? MBLKL(m) : 0;
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+ p->apos += p->rpos + llen;
+ p->rpos = 0;
+
return (TRUE);
}
@@ -296,12 +361,16 @@ static bool_t
xdrmblk_putbytes(XDR *xdrs, caddr_t addr, int len)
{
mblk_t *m;
- uint_t i;
+ struct xdrmblk_params *p;
+ int i;
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
if (m == NULL)
return (FALSE);
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
/*
* Performance tweak: converted explicit bcopy()
* call to simple in-line. This function is called
@@ -310,10 +379,10 @@ xdrmblk_putbytes(XDR *xdrs, caddr_t addr, int len)
* Overhead of calling bcopy() is obnoxious for such
* small copies.
*/
- while ((xdrs->x_handy -= len) < 0) {
- if ((xdrs->x_handy += len) > 0) {
+ while (xdrs->x_handy < len) {
+ if (xdrs->x_handy > 0) {
if (xdrs->x_handy < XDRMBLK_BCOPY_LIMIT) {
- for (i = 0; i < (uint_t)xdrs->x_handy; i++)
+ for (i = 0; i < xdrs->x_handy; i++)
*m->b_wptr++ = *addr++;
} else {
bcopy(addr, m->b_wptr, xdrs->x_handy);
@@ -321,29 +390,35 @@ xdrmblk_putbytes(XDR *xdrs, caddr_t addr, int len)
addr += xdrs->x_handy;
}
len -= xdrs->x_handy;
+ p->rpos += xdrs->x_handy;
}
/*
* We don't have enough space, so allocate the
- * amount we need, or x_private, whichever is larger.
+ * amount we need, or sz, whichever is larger.
* It is better to let the underlying transport divide
* large chunks than to try and guess what is best.
*/
if (m->b_cont == NULL)
- m->b_cont = xdrmblk_alloc(MAX(len,
- (int)(uintptr_t)xdrs->x_private));
+ m->b_cont = xdrmblk_alloc(MAX(len, p->sz));
m = m->b_cont;
xdrs->x_base = (caddr_t)m;
+ p->apos += p->rpos;
+ p->rpos = 0;
if (m == NULL) {
xdrs->x_handy = 0;
return (FALSE);
}
- xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_rptr);
+ xdrs->x_handy = (int)MBLKTAIL(m);
ASSERT(m->b_rptr == m->b_wptr);
ASSERT(m->b_rptr >= m->b_datap->db_base);
ASSERT(m->b_rptr < m->b_datap->db_lim);
}
+
+ xdrs->x_handy -= len;
+ p->rpos += len;
+
if (len < XDRMBLK_BCOPY_LIMIT) {
for (i = 0; i < len; i++)
*m->b_wptr++ = *addr++;
@@ -366,6 +441,7 @@ xdrmblk_putbytes(XDR *xdrs, caddr_t addr, int len)
bool_t
xdrmblk_putmblk(XDR *xdrs, mblk_t *m, uint_t len)
{
+ struct xdrmblk_params *p;
int32_t llen = (int32_t)len;
if ((DLEN(m) % BYTES_PER_XDR_UNIT) != 0)
@@ -373,59 +449,59 @@ xdrmblk_putmblk(XDR *xdrs, mblk_t *m, uint_t len)
if (!xdrmblk_putint32(xdrs, &llen))
return (FALSE);
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
/* LINTED pointer alignment */
((mblk_t *)xdrs->x_base)->b_cont = m;
+ p->apos += p->rpos;
/* base points to the last mblk */
- while (m->b_cont)
+ while (m->b_cont) {
+ p->apos += MBLKL(m);
m = m->b_cont;
+ }
xdrs->x_base = (caddr_t)m;
xdrs->x_handy = 0;
+ p->rpos = MBLKL(m);
return (TRUE);
}
static uint_t
xdrmblk_getpos(XDR *xdrs)
{
- uint_t tmp;
- mblk_t *m;
-
- /* LINTED pointer alignment */
- m = (mblk_t *)xdrs->x_base;
-
- if (xdrs->x_op == XDR_DECODE)
- tmp = (uint_t)(m->b_rptr - m->b_datap->db_base);
- else
- tmp = (uint_t)(m->b_wptr - m->b_datap->db_base);
- return (tmp);
+ struct xdrmblk_params *p = (struct xdrmblk_params *)xdrs->x_private;
+ return (p->apos + p->rpos);
}
static bool_t
xdrmblk_setpos(XDR *xdrs, uint_t pos)
{
mblk_t *m;
- unsigned char *newaddr;
+ struct xdrmblk_params *p;
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
+ if (pos < p->apos)
+ return (FALSE);
+
+ if (pos > p->apos + p->rpos + xdrs->x_handy)
+ return (FALSE);
+
+ if (pos == p->apos + p->rpos)
+ return (TRUE);
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
- if (m == NULL)
- return (FALSE);
+ ASSERT(m != NULL);
- /* calculate the new address from the base */
- newaddr = m->b_datap->db_base + pos;
+ if (xdrs->x_op == XDR_DECODE)
+ m->b_rptr = m->b_rptr - p->rpos + (pos - p->apos);
+ else
+ m->b_wptr = m->b_wptr - p->rpos + (pos - p->apos);
- if (xdrs->x_op == XDR_DECODE) {
- if (newaddr > m->b_wptr)
- return (FALSE);
- m->b_rptr = newaddr;
- xdrs->x_handy = (int)(m->b_wptr - newaddr);
- } else {
- if (newaddr > m->b_datap->db_lim)
- return (FALSE);
- m->b_wptr = newaddr;
- xdrs->x_handy = (int)(m->b_datap->db_lim - newaddr);
- }
+ xdrs->x_handy = p->rpos + xdrs->x_handy - (pos - p->apos);
+ p->rpos = pos - p->apos;
return (TRUE);
}
@@ -441,6 +517,8 @@ xdrmblk_inline(XDR *xdrs, int len)
{
rpc_inline_t *buf;
mblk_t *m;
+ unsigned char **mptr;
+ struct xdrmblk_params *p;
/*
* Can't inline XDR_FREE calls, doesn't make sense.
@@ -448,46 +526,65 @@ xdrmblk_inline(XDR *xdrs, int len)
if (xdrs->x_op == XDR_FREE)
return (NULL);
- /*
- * Can't inline if there isn't enough room, don't have an
- * mblk pointer, its not 4 byte aligned, or if there is more than
- * one reference to the data block associated with this mblk. This last
- * check is used because the caller may want to modified
- * the data in the inlined portion and someone else is
- * holding a reference to the data who may not want it
- * to be modified.
- */
- if (xdrs->x_handy < len ||
- /* LINTED pointer alignment */
- (m = (mblk_t *)xdrs->x_base) == NULL ||
- !IS_P2ALIGNED(m->b_rptr, sizeof (int32_t)) ||
- m->b_datap->db_ref != 1) {
#ifdef DEBUG
+ if (!do_xdrmblk_inline) {
xdrmblk_inline_misses++;
-#endif
return (NULL);
}
+#endif
+
+ if (xdrs->x_op == XDR_DECODE)
+ xdrmblk_skip_fully_read_mblks(xdrs);
+ /*
+ * Can't inline if there isn't enough room.
+ */
+ if (len <= 0 || xdrs->x_handy < len) {
#ifdef DEBUG
- if (!do_xdrmblk_inline) {
xdrmblk_inline_misses++;
+#endif
return (NULL);
}
-#endif
- xdrs->x_handy -= len;
+ /* LINTED pointer alignment */
+ m = (mblk_t *)xdrs->x_base;
+ ASSERT(m != NULL);
+
if (xdrs->x_op == XDR_DECODE) {
/* LINTED pointer alignment */
- buf = (rpc_inline_t *)m->b_rptr;
- m->b_rptr += len;
+ mptr = &m->b_rptr;
} else {
/* LINTED pointer alignment */
- buf = (rpc_inline_t *)m->b_wptr;
- m->b_wptr += len;
+ mptr = &m->b_wptr;
}
+
+ /*
+ * Can't inline if the buffer is not 4 byte aligned, or if there is
+ * more than one reference to the data block associated with this mblk.
+ * This last check is used because the caller may want to modify the
+ * data in the inlined portion and someone else is holding a reference
+ * to the data who may not want it to be modified.
+ */
+ if (!IS_P2ALIGNED(*mptr, sizeof (int32_t)) ||
+ m->b_datap->db_ref != 1) {
+#ifdef DEBUG
+ xdrmblk_inline_misses++;
+#endif
+ return (NULL);
+ }
+
+ buf = (rpc_inline_t *)*mptr;
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
+ *mptr += len;
+ xdrs->x_handy -= len;
+ p->rpos += len;
+
#ifdef DEBUG
xdrmblk_inline_hits++;
#endif
+
return (buf);
}
@@ -495,11 +592,14 @@ static bool_t
xdrmblk_control(XDR *xdrs, int request, void *info)
{
mblk_t *m;
+ struct xdrmblk_params *p;
int32_t *int32p;
int len;
switch (request) {
case XDR_PEEK:
+ xdrmblk_skip_fully_read_mblks(xdrs);
+
/*
* Return the next 4 byte unit in the XDR stream.
*/
@@ -508,8 +608,7 @@ xdrmblk_control(XDR *xdrs, int request, void *info)
/* LINTED pointer alignment */
m = (mblk_t *)xdrs->x_base;
- if (m == NULL)
- return (FALSE);
+ ASSERT(m != NULL);
/*
* If the pointer is not aligned, fail the peek
@@ -523,27 +622,39 @@ xdrmblk_control(XDR *xdrs, int request, void *info)
return (TRUE);
case XDR_SKIPBYTES:
- /* LINTED pointer alignment */
- m = (mblk_t *)xdrs->x_base;
- if (m == NULL)
- return (FALSE);
int32p = (int32_t *)info;
len = RNDUP((int)(*int32p));
if (len < 0)
return (FALSE);
- while ((xdrs->x_handy -= len) < 0) {
- if ((xdrs->x_handy += len) > 0) {
+ if (len == 0)
+ return (TRUE);
+
+ /* LINTED pointer alignment */
+ m = (mblk_t *)xdrs->x_base;
+ if (m == NULL)
+ return (FALSE);
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+
+ while (xdrs->x_handy < len) {
+ if (xdrs->x_handy > 0) {
m->b_rptr += xdrs->x_handy;
len -= xdrs->x_handy;
+ p->rpos += xdrs->x_handy;
}
m = m->b_cont;
xdrs->x_base = (caddr_t)m;
+ p->apos += p->rpos;
+ p->rpos = 0;
if (m == NULL) {
xdrs->x_handy = 0;
return (FALSE);
}
- xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
+ xdrs->x_handy = (int)MBLKL(m);
}
+
+ xdrs->x_handy -= len;
+ p->rpos += len;
m->b_rptr += len;
return (TRUE);
@@ -578,3 +689,35 @@ xdrmblk_alloc(int sz)
return (mp);
}
+
+/*
+ * Skip fully read or empty mblks
+ */
+static void
+xdrmblk_skip_fully_read_mblks(XDR *xdrs)
+{
+ mblk_t *m;
+ struct xdrmblk_params *p;
+
+ if (xdrs->x_handy != 0)
+ return;
+
+ /* LINTED pointer alignment */
+ m = (mblk_t *)xdrs->x_base;
+ if (m == NULL)
+ return;
+
+ p = (struct xdrmblk_params *)xdrs->x_private;
+ p->apos += p->rpos;
+ p->rpos = 0;
+
+ do {
+ m = m->b_cont;
+ if (m == NULL)
+ break;
+
+ xdrs->x_handy = (int)MBLKL(m);
+ } while (xdrs->x_handy == 0);
+
+ xdrs->x_base = (caddr_t)m;
+}