xref: /illumos-gate/usr/src/uts/common/rpc/svc_gen.c (revision 2e67aa296fc3707ae8e2b532f67387daf0823499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *  Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  *  Use is subject to license terms.
25  */
26 /*
27  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
28  */
29 
30 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
31 /*	  All Rights Reserved	*/
32 
33 /*
34  * Portions of this source code were derived from Berkeley 4.3 BSD
35  * under license from the Regents of the University of California.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/sysmacros.h>
40 #include <sys/param.h>
41 #include <sys/cmn_err.h>
42 #include <sys/debug.h>
43 #include <rpc/types.h>
44 #include <netinet/in.h>
45 #include <rpc/auth.h>
46 #include <rpc/clnt.h>
47 #include <sys/tiuser.h>
48 #include <sys/t_kuser.h>
49 #include <rpc/svc.h>
50 #include <sys/file.h>
51 #include <sys/user.h>
52 #include <sys/stream.h>
53 #include <sys/strsubr.h>
54 #include <sys/stropts.h>
55 #include <sys/tihdr.h>
56 #include <sys/timod.h>
57 #include <sys/sunddi.h>
58 #include <sys/fcntl.h>
59 #include <sys/errno.h>
60 
61 /*
62  * Create server-side kernel RPC `master' transport handle
63  *
64  * This is public interface for creation of a server RPC transport handle
65  * for a given file descriptor. This function is called from nfs_svc()
66  * and lm_svc().
67  *
68  * PSARC 2003/523 Contract Private Interface
69  * svc_tli_kcreate
70  * Changes must be reviewed by Solaris File Sharing
71  * Changes must be communicated to contract-2003-523@sun.com
72  *
73  * Arguments:
74  * - fp		 - connection end point
75  * - max_msgsize - max receive size
76  * - netid	 - netid
77  * - addrmask	 - address mask
78  * - nxprt       - filled with outgoing transport handle
79  * - sct	 - callout table to be registered with this transport handle
80  * - closeproc	 - optional pointer to a closeproc for this transport or NULL
81  * - id	         - RPC pool id (currently only NFS_SVCPOOL_ID or LM_SVCPOOL_ID)
82  * - hotstream	 - very MT-hot flag (TRUE for NFS, FALSE for Lock Manager)
83  *
84  * Description:
85  * - make sure rpcmod is on the stream
86  * - call T_INFO_REQ to get the transport service type info
87  * - call transport-type specific `create' routine (svc_clts_kcreate(),
88  *   svc_cots_kcreate()) to create and initialize transport for the stream
89  * - call svc_xprt_register() to register the transport handle into the
90  *   service thread pool
91  * - initialize transport-type independent fields (synchronization objects,
92  *   thread counts, callout table, closeproc)
93  * - optionally, for CLTS transports tell streams framework that the
94  *   stream can be MT-hot
95  * - call transport-type specific `start' function to tell rpcmod that
96  *   the transport is ready to receive.
97  */
98 int
99 svc_tli_kcreate(
100 	struct file	*fp,		/* connection end point */
101 	uint_t		max_msgsize,	/* max receive size */
102 	char		*netid,
103 	struct netbuf	*addrmask,
104 	SVCMASTERXPRT	**nxprt,
105 	SVC_CALLOUT_TABLE *sct,
106 	void		(*closeproc)(const SVCMASTERXPRT *),
107 	int		id,		/* thread pool  */
108 	bool_t		hotstream)
109 {
110 	queue_t		*wq;
111 	SVCMASTERXPRT	*xprt = NULL;	/* service handle */
112 	int		retval;
113 	struct strioctl strioc;
114 	struct T_info_ack tinfo;
115 	int		error;
116 	void		**vp;
117 	major_t		udpmaj;
118 
119 	RPCLOG(16, "svc_tli_kcreate: on file %p\n", (void *)fp);
120 
121 	if (fp == NULL || nxprt == NULL)
122 		return (EINVAL);
123 
124 	if (fp->f_vnode->v_stream == NULL)
125 		return (ENOSTR);
126 
127 	/*
128 	 * Make sure that an RPC interface module is on the stream.
129 	 */
130 	wq = fp->f_vnode->v_stream->sd_wrq;
131 	while ((wq = wq->q_next) != NULL) {
132 		if (strcmp(wq->q_qinfo->qi_minfo->mi_idname, "rpcmod") == 0)
133 			break;
134 	}
135 	if (!wq) {
136 		RPCLOG0(1, "svc_tli_kcreate: no RPC module on stream\n");
137 		return (EINVAL);
138 	}
139 
140 	/*
141 	 * Find out what type of transport this is.
142 	 */
143 	strioc.ic_cmd = TI_GETINFO;
144 	strioc.ic_timout = -1;
145 	strioc.ic_len = sizeof (tinfo);
146 	strioc.ic_dp = (char *)&tinfo;
147 	tinfo.PRIM_type = T_INFO_REQ;
148 
149 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
150 	    CRED(), &retval);
151 	if (error || retval) {
152 		RPCLOG(1, "svc_tli_kcreate: getinfo ioctl: %d\n", error);
153 		return (error);
154 	}
155 
156 	/*
157 	 * Call transport-type specific `create' function.
158 	 * It will allocate transport structure.
159 	 */
160 	switch (tinfo.SERV_type) {
161 	case T_CLTS:
162 		error = svc_clts_kcreate(fp, max_msgsize, &tinfo, &xprt);
163 		break;
164 	case T_COTS:
165 	case T_COTS_ORD:
166 		error = svc_cots_kcreate(fp, max_msgsize, &tinfo, &xprt);
167 		break;
168 	default:
169 		RPCLOG(1, "svc_tli_kcreate: Bad service type %d\n",
170 		    tinfo.SERV_type);
171 		error = EINVAL;
172 	}
173 	if (error)
174 		return (error);
175 
176 	/*
177 	 * Initialize transport-type independent fields.
178 	 */
179 	xprt->xp_req_head = (mblk_t *)0;
180 	xprt->xp_req_tail = (mblk_t *)0;
181 	xprt->xp_full = FALSE;
182 	xprt->xp_enable = FALSE;
183 	xprt->xp_reqs = 0;
184 	xprt->xp_size = 0;
185 	mutex_init(&xprt->xp_req_lock, NULL, MUTEX_DEFAULT, NULL);
186 	mutex_init(&xprt->xp_thread_lock, NULL, MUTEX_DEFAULT, NULL);
187 	xprt->xp_type = tinfo.SERV_type;
188 	xprt->xp_threads = 0;
189 	xprt->xp_detached_threads = 0;
190 	xprt->xp_fp = fp;
191 	xprt->xp_wq = wq;
192 	xprt->xp_closeproc = closeproc;
193 	xprt->xp_sct = sct;
194 	xprt->xp_netid = NULL;
195 	if (netid != NULL) {
196 		xprt->xp_netid = kmem_alloc(strlen(netid) + 1, KM_SLEEP);
197 		(void) strcpy(xprt->xp_netid, netid);
198 	}
199 
200 	xprt->xp_addrmask.len = 0;
201 	xprt->xp_addrmask.maxlen = 0;
202 	xprt->xp_addrmask.buf = NULL;
203 
204 	if (addrmask != NULL) {
205 		xprt->xp_addrmask = *addrmask;
206 	}
207 
208 	/*
209 	 * Register this transport handle after all fields have been
210 	 * initialized. The registration can fail only if we try to register
211 	 * with a non-existent pool (ENOENT) or a closing pool (EBUSY).
212 	 */
213 	if (error = svc_xprt_register(xprt, id)) {
214 		/* if there was an addrmask, caller will delete it */
215 		xprt->xp_addrmask.maxlen = 0;
216 		SVC_DESTROY(xprt);
217 		cmn_err(CE_WARN, "svc_tli_kcreate: xprt_register failed");
218 
219 		return (error);
220 	}
221 
222 	/*
223 	 * Set the private RPC cell in the module's data.
224 	 */
225 	vp = (void **)wq->q_ptr;
226 	vp[0] = xprt;
227 
228 	/*
229 	 * Inform the streams framework that the stream may be very MT hot.
230 	 */
231 	if (hotstream && tinfo.SERV_type == T_CLTS) {
232 		udpmaj = ddi_name_to_major("udp");
233 		if (udpmaj != (major_t)-1 &&
234 		    getmajor(fp->f_vnode->v_rdev) == udpmaj)
235 			create_putlocks(wq, 1);
236 	}
237 
238 	*nxprt = xprt;
239 
240 	/*
241 	 * Tell rpcmod that the transport is fully initialized and
242 	 * ready to process requests.
243 	 */
244 	SVC_START(xprt);
245 
246 	return (0);
247 }
248