4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
36 #include "idmap_impl.h"
38 #define _UDT_SIZE_INCR 1
40 #define _GET_IDS_SIZE_INCR 1
42 static struct timeval TIMEOUT
= { 25, 0 };
50 static struct idmap_handle idmap_handle
= {
53 DEFAULTRWLOCK
, /* lock */
56 static idmap_stat
_idmap_clnt_connect(void);
57 static void _idmap_clnt_disconnect(void);
60 _udt_extend_batch(idmap_udt_handle_t
*udthandle
)
62 idmap_update_op
*tmplist
;
65 if (udthandle
->next
>= udthandle
->batch
.idmap_update_batch_len
) {
66 nsize
= (udthandle
->batch
.idmap_update_batch_len
+
67 _UDT_SIZE_INCR
) * sizeof (*tmplist
);
69 udthandle
->batch
.idmap_update_batch_val
, nsize
);
71 return (IDMAP_ERR_MEMORY
);
72 (void) memset((uchar_t
*)tmplist
+
73 (udthandle
->batch
.idmap_update_batch_len
*
74 sizeof (*tmplist
)), 0,
75 _UDT_SIZE_INCR
* sizeof (*tmplist
));
76 udthandle
->batch
.idmap_update_batch_val
= tmplist
;
77 udthandle
->batch
.idmap_update_batch_len
+= _UDT_SIZE_INCR
;
79 udthandle
->batch
.idmap_update_batch_val
[udthandle
->next
].opnum
=
81 return (IDMAP_SUCCESS
);
85 _get_ids_extend_batch(idmap_get_handle_t
*gh
)
91 len
= gh
->batch
.idmap_mapping_batch_len
;
92 if (gh
->next
>= len
) {
93 /* extend the request array */
94 nsize
= (len
+ _GET_IDS_SIZE_INCR
) * sizeof (*t1
);
95 t1
= realloc(gh
->batch
.idmap_mapping_batch_val
, nsize
);
97 return (IDMAP_ERR_MEMORY
);
98 (void) memset((uchar_t
*)t1
+ (len
* sizeof (*t1
)), 0,
99 _GET_IDS_SIZE_INCR
* sizeof (*t1
));
100 gh
->batch
.idmap_mapping_batch_val
= t1
;
102 /* extend the return list */
103 nsize
= (len
+ _GET_IDS_SIZE_INCR
) * sizeof (*t2
);
104 t2
= realloc(gh
->retlist
, nsize
);
106 return (IDMAP_ERR_MEMORY
);
107 (void) memset((uchar_t
*)t2
+ (len
* sizeof (*t2
)), 0,
108 _GET_IDS_SIZE_INCR
* sizeof (*t2
));
111 gh
->batch
.idmap_mapping_batch_len
+= _GET_IDS_SIZE_INCR
;
113 return (IDMAP_SUCCESS
);
117 _iter_get_next_list(int type
, idmap_iter_t
*iter
,
118 void *arg
, uchar_t
**list
, size_t valsize
,
119 xdrproc_t xdr_arg_proc
, xdrproc_t xdr_res_proc
)
124 iter
->retlist
= NULL
;
126 /* init the result */
128 xdr_free(xdr_res_proc
, (caddr_t
)*list
);
130 if ((*list
= malloc(valsize
)) == NULL
) {
132 return (IDMAP_ERR_MEMORY
);
135 (void) memset(*list
, 0, valsize
);
137 rc
= _idmap_clnt_call(type
,
138 xdr_arg_proc
, (caddr_t
)arg
,
139 xdr_res_proc
, (caddr_t
)*list
,
141 if (rc
!= IDMAP_SUCCESS
) {
145 iter
->retlist
= *list
;
146 return (IDMAP_SUCCESS
);
150 * Convert the return values from an RPC request into an idmap return code.
151 * Set errno on error.
155 _idmap_rpc2stat(enum clnt_stat clntstat
, CLIENT
*clnt
)
158 * We only deal with door_call(3C) errors here. We look at
159 * r_err.re_errno instead of r_err.re_status because we need
160 * to differentiate between RPC failures caused by bad door fd
163 struct rpc_err r_err
;
165 if (clntstat
== RPC_SUCCESS
)
166 return (IDMAP_SUCCESS
);
168 clnt_geterr(clnt
, &r_err
);
169 errno
= r_err
.re_errno
;
170 switch (r_err
.re_errno
) {
172 return (IDMAP_ERR_MEMORY
);
174 return (IDMAP_ERR_RPC_HANDLE
);
176 return (IDMAP_ERR_RPC
);
181 * Management of the connection to idmapd.
183 * The intent is that connections to idmapd are automatically maintained,
184 * reconnecting if necessary. No attempt is made to retry connnection
185 * attempts; a failure to connect yields an immediate error return.
187 * State of the connection is maintained through the "client" and "failed"
188 * elements of the handle structure:
191 * NULL true Failed on a previous request and was not recovered.
192 * NULL false Should never happen.
193 * nonNULL true Structure exists, but an error has occurred. Waiting
194 * for a chance to attempt to reconnect.
195 * nonNULL false Connection is good.
197 * Note that the initial state is NULL/true, so that the first request
198 * will establish the initial connection.
200 * Concurrency is managed through the rw lock "lock". Only the writer is
201 * allowed to connect or disconnect, and thus only the writer can set
202 * "failed" to "false". Readers are allowed to use the "client" pointer,
203 * and to set "failed" to "true", indicating that they have encountered a
204 * failure. The "client" pointer is only valid while one holds a reader
205 * lock. Once "failed" has been set to "true", all requests (including
206 * the retry of the failing request) will attempt to gain the writer lock.
207 * When they succeed, indicating that there are no requests in flight and
208 * thus no outstanding references to the CLIENT structure, they check
209 * again to see if the connection is still failed (since another thread
210 * might have fixed it), and then if it is still failed they disconnect
215 * Make an RPC call. Automatically reconnect if the connection to idmapd
216 * fails. Convert RPC results to idmap return codes.
220 const rpcproc_t procnum
,
221 const xdrproc_t inproc
,
223 const xdrproc_t outproc
,
225 const struct timeval tout
)
227 enum clnt_stat clntstat
;
230 (void) rw_rdlock(&idmap_handle
.lock
);
232 if (idmap_handle
.failed
) {
233 /* No connection. Bid to see if we should fix it. */
234 (void) rw_unlock(&idmap_handle
.lock
);
235 /* Somebody else might fix it here. */
236 (void) rw_wrlock(&idmap_handle
.lock
);
238 * At this point, everybody else is asleep waiting
239 * for us. Check to see if somebody else has already
242 if (idmap_handle
.failed
) {
243 /* It's our job to fix. */
244 _idmap_clnt_disconnect();
245 rc
= _idmap_clnt_connect();
246 if (rc
!= IDMAP_SUCCESS
) {
247 /* We couldn't fix it. */
248 assert(idmap_handle
.failed
);
249 assert(idmap_handle
.client
== NULL
);
253 idmap_handle
.failed
= B_FALSE
;
256 /* It's fixed now. */
257 (void) rw_unlock(&idmap_handle
.lock
);
259 * Starting here, somebody might declare it failed
262 (void) rw_rdlock(&idmap_handle
.lock
);
266 clntstat
= clnt_call(idmap_handle
.client
, procnum
, inproc
, in
,
268 rc
= _idmap_rpc2stat(clntstat
, idmap_handle
.client
);
269 if (rc
== IDMAP_ERR_RPC_HANDLE
) {
270 /* Failed. Needs to be reconnected. */
271 idmap_handle
.failed
= B_TRUE
;
275 /* Success or unrecoverable failure. */
278 (void) rw_unlock(&idmap_handle
.lock
);
282 #define MIN_STACK_NEEDS 65536
286 * Must be single-threaded through rw_wrlock(&idmap_handle.lock).
290 _idmap_clnt_connect(void)
296 * clnt_door_call() alloca()s sendsz bytes (twice too, once for
297 * the call args buffer and once for the call result buffer), so
298 * we want to pick a sendsz that will be large enough, but not
301 if (stack_getbounds(&st
) == 0) {
303 * Estimate how much stack space is left;
304 * st.ss_sp is the top of stack.
306 if ((char *)&sendsz
< (char *)st
.ss_sp
)
308 sendsz
= ((char *)st
.ss_sp
- (char *)&sendsz
);
310 /* stack grows down */
311 sendsz
= ((char *)&sendsz
- (char *)st
.ss_sp
);
313 if (sendsz
<= MIN_STACK_NEEDS
) {
314 sendsz
= 0; /* RPC call may fail */
316 /* Leave 64Kb (just a guess) for our needs */
317 sendsz
-= MIN_STACK_NEEDS
;
319 /* Divide the stack space left by two */
320 sendsz
= RNDUP(sendsz
/ 2);
322 /* Limit sendsz to 256KB */
323 if (sendsz
> IDMAP_MAX_DOOR_RPC
)
324 sendsz
= IDMAP_MAX_DOOR_RPC
;
328 idmap_handle
.client
= clnt_door_create(IDMAP_PROG
, IDMAP_V1
, sendsz
);
329 if (idmap_handle
.client
== NULL
)
330 return (IDMAP_ERR_RPC
);
332 return (IDMAP_SUCCESS
);
336 * Disconnect from idmapd, if we're connected.
340 _idmap_clnt_disconnect(void)
344 clnt
= idmap_handle
.client
;
347 auth_destroy(clnt
->cl_auth
);
349 idmap_handle
.client
= NULL
;