diff options
| author | joyce mcintosh <Joyce.McIntosh@Sun.COM> | 2010-07-26 15:02:13 -0700 | 
|---|---|---|
| committer | joyce mcintosh <Joyce.McIntosh@Sun.COM> | 2010-07-26 15:02:13 -0700 | 
| commit | 1fdeec650620e8498c06f832ea4bd2292f7e9632 (patch) | |
| tree | 93e66a90f7f7260ca1086e7701a6c8dc1e46c5fb /usr/src/lib/libidmap/common/utils.c | |
| parent | 1a024a4828552f36f41749085bad547c64a0f0a6 (diff) | |
| download | illumos-joyent-1fdeec650620e8498c06f832ea4bd2292f7e9632.tar.gz | |
6779186 need domain controller hot failover
6970986 Level II oplocks - smb_oplock_grant_t shouldn't be dynamically allocated
6971031 Unable add ACL on the share which has only the default owner tab by ZFS
6971899 OpenSSL not MT-safe and takes down smbd
6936762 libidmap should transparently handle interruption in connection to idmapd
6954902 mapping to unknown type does not use directory-based mapping information
--HG--
rename : usr/src/lib/libidmap/common/idmap_priv.h => usr/src/cmd/idmap/idmap/namemaps.h
Diffstat (limited to 'usr/src/lib/libidmap/common/utils.c')
| -rw-r--r-- | usr/src/lib/libidmap/common/utils.c | 237 | 
1 files changed, 213 insertions, 24 deletions
| diff --git a/usr/src/lib/libidmap/common/utils.c b/usr/src/lib/libidmap/common/utils.c index 1c073b75d6..1068e0aa2c 100644 --- a/usr/src/lib/libidmap/common/utils.c +++ b/usr/src/lib/libidmap/common/utils.c @@ -19,12 +19,9 @@   * CDDL HEADER END   */  /* - * Copyright 2008 Sun Microsystems, Inc.  All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.   */ -#pragma ident	"%Z%%M%	%I%	%E% SMI" -  /*   * Utility routines   */ @@ -33,6 +30,9 @@  #include <stdlib.h>  #include <errno.h>  #include <libintl.h> +#include <assert.h> +#include <ucontext.h> +#include <pthread.h>  #include "idmap_impl.h"  #define	_UDT_SIZE_INCR	1 @@ -41,6 +41,21 @@  static struct timeval TIMEOUT = { 25, 0 }; +struct idmap_handle { +	CLIENT		*client; +	boolean_t	failed; +	rwlock_t	lock; +}; + +static struct idmap_handle idmap_handle = { +	NULL,		/* client */ +	B_TRUE,		/* failed */ +	DEFAULTRWLOCK,	/* lock */ +}; + +static idmap_stat _idmap_clnt_connect(void); +static void _idmap_clnt_disconnect(void); +  idmap_retcode  _udt_extend_batch(idmap_udt_handle_t *udthandle)  { @@ -103,13 +118,10 @@ _iter_get_next_list(int type, idmap_iter_t *iter,  		void *arg, uchar_t **list, size_t valsize,  		xdrproc_t xdr_arg_proc, xdrproc_t xdr_res_proc)  { - -	CLIENT		*clnt; -	enum clnt_stat	clntstat; +	idmap_stat rc;  	iter->next = 0;  	iter->retlist = NULL; -	_IDMAP_GET_CLIENT_HANDLE(iter->ih, clnt);  	/* init the result */  	if (*list) { @@ -122,20 +134,25 @@ _iter_get_next_list(int type, idmap_iter_t *iter,  	}  	(void) memset(*list, 0, valsize); -	clntstat = clnt_call(clnt, type, +	rc = _idmap_clnt_call(type,  	    xdr_arg_proc, (caddr_t)arg,  	    xdr_res_proc, (caddr_t)*list,  	    TIMEOUT); -	if (clntstat != RPC_SUCCESS) { +	if (rc != IDMAP_SUCCESS) {  		free(*list); -		return (_idmap_rpc2stat(clnt)); +		return (rc);  	}  	iter->retlist = *list;  	return (IDMAP_SUCCESS);  } +/* + * Convert the return values from an RPC request into an idmap return code. + * Set errno on error. + */ +static  idmap_stat -_idmap_rpc2stat(CLIENT *clnt) +_idmap_rpc2stat(enum clnt_stat clntstat, CLIENT *clnt)  {  	/*  	 * We only deal with door_call(3C) errors here. We look at @@ -144,19 +161,191 @@ _idmap_rpc2stat(CLIENT *clnt)  	 * and others.  	 */  	struct rpc_err r_err; -	if (clnt) { -		clnt_geterr(clnt, &r_err); -		errno = r_err.re_errno; -		switch (r_err.re_errno) { -		case ENOMEM: -			return (IDMAP_ERR_MEMORY); -		case EBADF: -			return (IDMAP_ERR_RPC_HANDLE); -		default: -			return (IDMAP_ERR_RPC); + +	if (clntstat == RPC_SUCCESS) +		return (IDMAP_SUCCESS); + +	clnt_geterr(clnt, &r_err); +	errno = r_err.re_errno; +	switch (r_err.re_errno) { +	case ENOMEM: +		return (IDMAP_ERR_MEMORY); +	case EBADF: +		return (IDMAP_ERR_RPC_HANDLE); +	default: +		return (IDMAP_ERR_RPC); +	} +} + +/* + * Management of the connection to idmapd. + * + * The intent is that connections to idmapd are automatically maintained, + * reconnecting if necessary.  No attempt is made to retry connnection + * attempts; a failure to connect yields an immediate error return. + * + * State of the connection is maintained through the "client" and "failed" + * elements of the handle structure: + * + * client   failed + * NULL     true     Failed on a previous request and was not recovered. + * NULL     false    Should never happen. + * nonNULL  true     Structure exists, but an error has occurred.  Waiting + *                   for a chance to attempt to reconnect. + * nonNULL  false    Connection is good. + * + * Note that the initial state is NULL/true, so that the first request + * will establish the initial connection. + * + * Concurrency is managed through the rw lock "lock".  Only the writer is + * allowed to connect or disconnect, and thus only the writer can set + * "failed" to "false".  Readers are allowed to use the "client" pointer, + * and to set "failed" to "true", indicating that they have encountered a + * failure.  The "client" pointer is only valid while one holds a reader + * lock.  Once "failed" has been set to "true", all requests (including + * the retry of the failing request) will attempt to gain the writer lock. + * When they succeed, indicating that there are no requests in flight and + * thus no outstanding references to the CLIENT structure, they check + * again to see if the connection is still failed (since another thread + * might have fixed it), and then if it is still failed they disconnect + * and reconnect. + */ + +/* + * Make an RPC call.  Automatically reconnect if the connection to idmapd + * fails.  Convert RPC results to idmap return codes. + */ +idmap_stat +_idmap_clnt_call( +    const rpcproc_t procnum, +    const xdrproc_t inproc, +    const caddr_t in, +    const xdrproc_t outproc, +    caddr_t out, +    const struct timeval tout) +{ +	enum clnt_stat	clntstat; +	idmap_stat rc; + +	(void) rw_rdlock(&idmap_handle.lock); +	for (;;) { +		if (idmap_handle.failed) { +			/* No connection.  Bid to see if we should fix it. */ +			(void) rw_unlock(&idmap_handle.lock); +			/* Somebody else might fix it here. */ +			(void) rw_wrlock(&idmap_handle.lock); +			/* +			 * At this point, everybody else is asleep waiting +			 * for us.  Check to see if somebody else has already +			 * fixed the problem. +			 */ +			if (idmap_handle.failed) { +				/* It's our job to fix. */ +				_idmap_clnt_disconnect(); +				rc = _idmap_clnt_connect(); +				if (rc != IDMAP_SUCCESS) { +					/* We couldn't fix it. */ +					assert(idmap_handle.failed); +					assert(idmap_handle.client == NULL); +					break; +				} +				/* We fixed it. */ +				idmap_handle.failed = B_FALSE; +			} + +			/* It's fixed now. */ +			(void) rw_unlock(&idmap_handle.lock); +			/* +			 * Starting here, somebody might declare it failed +			 * again. +			 */ +			(void) rw_rdlock(&idmap_handle.lock); +			continue; +		} + +		clntstat = clnt_call(idmap_handle.client, procnum, inproc, in, +		    outproc, out, tout); +		rc = _idmap_rpc2stat(clntstat, idmap_handle.client); +		if (rc == IDMAP_ERR_RPC_HANDLE) { +			/* Failed.  Needs to be reconnected. */ +			idmap_handle.failed = B_TRUE; +			continue; +		} + +		/* Success or unrecoverable failure. */ +		break; +	} +	(void) rw_unlock(&idmap_handle.lock); +	return (rc); +} + +#define	MIN_STACK_NEEDS	65536 + +/* + * Connect to idmapd. + * Must be single-threaded through rw_wrlock(&idmap_handle.lock). + */ +static +idmap_stat +_idmap_clnt_connect(void) +{ +	uint_t			sendsz = 0; +	stack_t			st; + +	/* +	 * clnt_door_call() alloca()s sendsz bytes (twice too, once for +	 * the call args buffer and once for the call result buffer), so +	 * we want to pick a sendsz that will be large enough, but not +	 * too large. +	 */ +	if (stack_getbounds(&st) == 0) { +		/* +		 * Estimate how much stack space is left; +		 * st.ss_sp is the top of stack. +		 */ +		if ((char *)&sendsz < (char *)st.ss_sp) +			/* stack grows up */ +			sendsz = ((char *)st.ss_sp - (char *)&sendsz); +		else +			/* stack grows down */ +			sendsz = ((char *)&sendsz - (char *)st.ss_sp); + +		if (sendsz <= MIN_STACK_NEEDS) { +			sendsz = 0;	/* RPC call may fail */ +		} else { +			/* Leave 64Kb (just a guess) for our needs */ +			sendsz -= MIN_STACK_NEEDS; + +			/* Divide the stack space left by two */ +			sendsz = RNDUP(sendsz / 2); + +			/* Limit sendsz to 256KB */ +			if (sendsz > IDMAP_MAX_DOOR_RPC) +				sendsz = IDMAP_MAX_DOOR_RPC;  		}  	} -	/* null handle */ -	return (IDMAP_ERR_RPC_HANDLE); +	idmap_handle.client = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz); +	if (idmap_handle.client == NULL) +		return (IDMAP_ERR_RPC); + +	return (IDMAP_SUCCESS); +} + +/* + * Disconnect from idmapd, if we're connected. + */ +static +void +_idmap_clnt_disconnect(void) +{ +	CLIENT *clnt; + +	clnt = idmap_handle.client; +	if (clnt != NULL) { +		if (clnt->cl_auth) +			auth_destroy(clnt->cl_auth); +		clnt_destroy(clnt); +		idmap_handle.client = NULL; +	}  } | 
