svc_cots.c revision 1a5e258f5471356ca102c7176637cdce45bac147
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
/*
* Server side for connection-oriented RPC in the kernel.
*
*/
#include <sys/sysmacros.h>
#define COTS_MAX_ALLOCSIZE 2048
/*
* Routines exported through ops vector.
*/
static void svc_cots_kdestroy(SVCMASTERXPRT *);
void (*)(), int, int);
static void svc_cots_kfreeres(SVCXPRT *);
static void svc_cots_kclone_destroy(SVCXPRT *);
static void svc_cots_kstart(SVCMASTERXPRT *);
static void svc_cots_ktattrs(SVCXPRT *, int, void **);
/*
* Server transport operations vector.
*/
struct svc_ops svc_cots_op = {
svc_cots_krecv, /* Get requests */
svc_cots_kgetargs, /* Deserialize arguments */
svc_cots_ksend, /* Send reply */
svc_cots_kfreeargs, /* Free argument data space */
svc_cots_kdestroy, /* Destroy transport handle */
svc_cots_kdup, /* Check entry in dup req cache */
svc_cots_kdupdone, /* Mark entry in dup req cache as done */
svc_cots_kgetres, /* Get pointer to response buffer */
svc_cots_kfreeres, /* Destroy pre-serialized response header */
svc_cots_kclone_destroy, /* Destroy a clone xprt */
svc_cots_kstart, /* Tell `ready-to-receive' to rpcmod */
NULL, /* Transport specific clone xprt */
svc_cots_ktattrs /* Transport Attributes */
};
/*
* Master transport private data.
* Kept in xprt->xp_p2.
*/
struct cots_master_data {
char *cmd_src_addr; /* client's address */
int cmd_xprt_started; /* flag for clone routine to call */
/* rpcmod's start routine. */
};
/*
* Transport private data.
* Kept in clone_xprt->xp_p2buf.
*/
typedef struct cots_data {
} cots_data_t;
/*
* Server statistics
* NOTE: This structure type is duplicated in the NFS fast path.
*/
static const struct rpc_cots_server {
} cots_rsstat_tmpl = {
{ "calls", KSTAT_DATA_UINT64 },
{ "badcalls", KSTAT_DATA_UINT64 },
{ "nullrecv", KSTAT_DATA_UINT64 },
{ "badlen", KSTAT_DATA_UINT64 },
{ "xdrcall", KSTAT_DATA_UINT64 },
{ "dupchecks", KSTAT_DATA_UINT64 },
{ "dupreqs", KSTAT_DATA_UINT64 }
};
#define CLONE2STATS(clone_xprt) \
#define RSSTAT_INCR(s, x) \
/*
* Pointer to a transport specific `ready to receive' function in rpcmod
* (set from rpcmod).
*/
/*
* the address size of the underlying transport can sometimes be
* unknown (tinfo->ADDR_size == -1). For this case, it is
* necessary to figure out what the size is so the correct amount
* of data is allocated. This is an itterative process:
* 1. take a good guess (use T_MINADDRSIZE)
* 2. try it.
* 3. if it works then everything is ok
* 4. if the error is ENAMETOLONG, double the guess
* 5. go back to step 2.
*/
#define T_UNKNOWNADDRSIZE (-1)
#define T_MINADDRSIZE 32
/*
* Create a transport record.
* The transport record, output buffer, and private data structure
* are allocated. The output buffer is serialized into using xdrmem.
* There is one transport record per user process which implements a
* set of services.
*/
static kmutex_t cots_kcreate_lock;
int
{
struct cots_master_data *cmd;
struct T_addr_ack *ack_p;
return (EINVAL);
else {
}
cmd->cmd_xprt_started = 0;
if (err) {
(2 * sizeof (sin6_t)));
return (err);
}
/*
* If the current sanity check size in rpcmod is smaller
* than the size needed for this xprt, then increase
* the sanity check.
*/
if (max_msgsize != 0 && svc_max_msg_sizep &&
max_msgsize > *svc_max_msg_sizep) {
/* This check needs a lock */
}
return (0);
}
/*
* Destroy a master transport record.
* Frees the space allocated for a transport record.
*/
static void
{
(2 * sizeof (sin6_t)));
}
/*
* svc_tli_kcreate() calls this function at the end to tell
* rpcmod that the transport is ready to receive requests.
*/
static void
{
if (cmd->cmd_xprt_started == 0) {
/*
* Acquire the xp_req_lock in order to use xp_wq
* safely (we don't want to qenable a queue that has
* already been closed).
*/
if (cmd->cmd_xprt_started == 0 &&
}
}
}
/*
* Transport-type specific part of svc_xprt_cleanup().
*/
static void
{
}
}
/*
* Transport Attributes.
*/
static void
{
switch (attrflag) {
case SVC_TATTR_ADDRMASK:
}
}
/*
* Receive rpc requests.
* Checks if the message is intact, and deserializes the call packet.
*/
static bool_t
{
"svc_cots_krecv_start:");
(void *)clone_xprt);
goto bad;
}
"xdr_callmsg_start:");
"xdr_callmsg_end:(%S)", "bad");
goto bad;
}
"xdr_callmsg_end:(%S)", "good");
"svc_cots_krecv_end:(%S)", "good");
return (TRUE);
bad:
if (mp)
"svc_cots_krecv_end:(%S)", "bad");
return (FALSE);
}
/*
* Send rpc reply.
*/
static bool_t
{
/* LINTED pointer alignment */
"svc_cots_ksend_start:");
/*
* If there is a result procedure specified in the reply message,
* it will be processed in the xdr_replymsg and SVCAUTH_WRAP.
* We need to make sure it won't be processed twice, so we null
* it for xdr_replymsg here.
*/
}
}
if (mp) {
/*
* The program above pre-allocated an mblk and put
* the data in place.
*/
xdr_results, xdr_location)))) {
"xdr_replymsg_body/SVCAUTH_WRAP failed\n");
goto out;
}
} else {
int len;
int mpsize;
/*
* Leave space for protocol headers.
*/
/*
* Allocate an initial mblk for the response data.
*/
"svc_cots_ksend_end:(%S)", "strwaitbuf");
RPCLOG0(1,
"svc_cots_ksend: strwaitbuf failed\n");
goto out;
}
}
/*
* Initialize the XDR decode stream. Additional mblks
* will be allocated if necessary. They will be TIDU
* sized.
*/
/*
* If the size of mblk is not appreciably larger than what we
* asked, then resize the mblk to exactly len bytes. Reason for
* this: suppose len is 1600 bytes, the tidu is 1460 bytes
* (from TCP over ethernet), and the arguments to RPC require
* 2800 bytes. Ideally we want the protocol to render two
* ~1400 byte segments over the wire. If allocb() gives us a 2k
* mblk, and we allocate a second mblk for the rest, the
* protocol module may generate 3 segments over the wire:
* 1460 bytes for the first, 448 (2048 - 1600) for the 2nd, and
* 892 for the 3rd. If we "waste" 448 bytes in the first mblk,
* the XDR encoding will generate two ~1400 byte mblks, and the
* protocol module is more likely to produce properly sized
* segments.
*/
}
/*
* Adjust b_rptr to reserve space for the non-data protocol
* headers that any downstream modules might like to add, and
* for the record marking header.
*/
"xdr_replymsg_start:");
xdr_results, xdr_location)))) {
"xdr_replymsg_end:(%S)", "bad");
"failed\n");
goto out;
}
"xdr_replymsg_end:(%S)", "good");
}
out:
/*
* This is completely disgusting. If public is set it is
* a pointer to a structure whose first field is the address
* of the function to free that structure and any related
* stuff. (see rrokfree in nfs_xdr.c).
*/
/* LINTED pointer alignment */
}
"svc_cots_ksend_end:(%S)", "done");
return (retval);
}
/*
* Deserialize arguments.
*/
static bool_t
{
}
static bool_t
{
/*
* It is important to call the XDR routine before
* freeing the request mblk. Structures in the
* XDR data may point into the mblk and require that
* the memory be intact during the free routine.
*/
if (args_ptr) {
/* LINTED pointer alignment */
} else
}
return (retval);
}
static int32_t *
{
/* LINTED pointer alignment */
int len;
int mpsize;
/*
* Leave space for protocol headers.
*/
/*
* Allocate an initial mblk for the response data.
*/
return (FALSE);
}
/*
* Initialize the XDR decode stream. Additional mblks
* will be allocated if necessary. They will be TIDU
* sized.
*/
/*
* If the size of mblk is not appreciably larger than what we
* asked, then resize the mblk to exactly len bytes. Reason for
* this: suppose len is 1600 bytes, the tidu is 1460 bytes
* (from TCP over ethernet), and the arguments to RPC require
* 2800 bytes. Ideally we want the protocol to render two
* ~1400 byte segments over the wire. If allocb() gives us a 2k
* mblk, and we allocate a second mblk for the rest, the
* protocol module may generate 3 segments over the wire:
* 1460 bytes for the first, 448 (2048 - 1600) for the 2nd, and
* 892 for the 3rd. If we "waste" 448 bytes in the first mblk,
* the XDR encoding will generate two ~1400 byte mblks, and the
* protocol module is more likely to produce properly sized
* segments.
*/
}
/*
* Adjust b_rptr to reserve space for the non-data protocol
* headers that any downstream modules might like to add, and
* for the record marking header.
*/
/*
* Assume a successful RPC since most of them are.
*/
return (NULL);
}
} else {
}
return (buf);
}
static void
{
}
}
/*
* the dup cacheing routines below provide a cache of non-failure
* transaction id's. rpc service routines can use this to detect
* retransmissions and re-send a non-failure response.
*/
/*
* MAXDUPREQS is the number of cached items. It should be adjusted
* to the service load so that there is likely to be a response entry
* when the first retransmission comes in.
*/
#define MAXDUPREQS 1024
/*
* This should be appropriately scaled to MAXDUPREQS.
*/
#define DRHASHSZ 257
#else
#endif
static int cotsndupreqs = 0;
int cotsmaxdupreqs = MAXDUPREQS;
static kmutex_t cotsdupreq_lock;
static int cotsdrhashstat[DRHASHSZ];
/*
* cotsdrmru points to the head of a circular linked list in lru order.
* cotsdrmru->dr_next == drlru
*/
/*
* PSARC 2003/523 Contract Private Interface
* svc_cots_kdup
* Changes must be reviewed by Solaris File Sharing
* Changes must be communicated to contract-2003-523@sun.com
*
* svc_cots_kdup searches the request cache and returns 0 if the
* request is not found in the cache. If it is found, then it
* returns the state of the request (in progress or done) and
* the status or attributes that were part of the original reply.
*
* If DUP_DONE (there is a duplicate) svc_cots_kdup copies over the
* value of the response. In that case, also return in *dupcachedp
* whether the response free routine is cached in the dupreq - in which case
* the caller should not be freeing it, because it will be done later
* in the svc_cots_kdup code when the dupreq is reused.
*/
static int
{
int status;
/*
* Check to see whether an entry already exists in the cache.
*/
if (dupcachedp != NULL)
"svc_cots_kdup: DUP_DONE");
} else {
"svc_cots_kdup: DUP_INPROGRESS");
}
return (status);
}
}
/*
* There wasn't an entry, either allocate a new one or recycle
* an old one.
*/
if (cotsndupreqs < cotsmaxdupreqs) {
return (DUP_ERROR);
}
if (cotsdrmru) {
} else {
}
cotsndupreqs++;
} else {
return (DUP_ERROR);
}
}
if (dr->dr_resfree) {
}
}
return (DUP_ERROR);
}
}
return (DUP_ERROR);
}
}
cotsdrhashstat[drhash]++;
return (DUP_NEW);
}
/*
* PSARC 2003/523 Contract Private Interface
* svc_cots_kdupdone
* Changes must be reviewed by Solaris File Sharing
* Changes must be communicated to contract-2003-523@sun.com
*
* svc_cots_kdupdone marks the request done (DUP_DONE or DUP_DROP)
* and stores the response.
*/
static void
{
}
}
/*
* This routine expects that the mutex, cotsdupreq_lock, is already held.
*/
static void
{
cotsdrhashstat[drhash]--;
} else {
}
return;
}
}
}
void
{
sizeof (cots_rsstat_tmpl));
}
void
{
}
void
svc_cots_init(void)
{
/*
* Check to make sure that the cots private data will fit into
* the stack buffer allocated by svc_run. The ASSERT is a safety
* net if the cots_data_t structure ever changes.
*/
/*CONSTANTCONDITION*/
}