diff options
author | Marcel Telka <marcel.telka@nexenta.com> | 2015-09-03 19:47:20 +0200 |
---|---|---|
committer | Dan McDonald <danmcd@omniti.com> | 2015-09-03 13:56:17 -0400 |
commit | cf98b944cdc2063fc14f3fd525e284de3ed29fd0 (patch) | |
tree | 28df5e6ccce80e3e691e730096fac98ff788e25f /usr/src | |
parent | fb01aed523c52aea9a7b48fe29a1b2624c7f21c5 (diff) | |
download | illumos-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.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/clnt_clts.c | 26 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/clnt_cots.c | 23 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/sec_gss/svc_rpcsec_gss.c | 5 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/svc_clts.c | 24 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/svc_cots.c | 24 | ||||
-rw-r--r-- | usr/src/uts/common/rpc/xdr_mblk.c | 333 |
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; +} |