1    	/*
2    	 * Copyright IBM Corporation, 2010
3    	 *  Contributor: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4    	 *
5    	 * --------------------------
6    	 *
7    	 * This program is free software; you can redistribute it and/or
8    	 * modify it under the terms of the GNU Lesser General Public
9    	 * License as published by the Free Software Foundation; either
10   	 * version 3 of the License, or (at your option) any later version.
11   	 *
12   	 * This program is distributed in the hope that it will be useful,
13   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   	 * Lesser General Public License for more details.
16   	 *
17   	 * You should have received a copy of the GNU Lesser General Public
18   	 * License along with this library; if not, write to the Free Software
19   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20   	 * 02110-1301 USA
21   	 *
22   	 *
23   	 */
24   	
25   	#include "config.h"
26   	#include <stdio.h>
27   	#include <pthread.h>
28   	#include <rpc/types.h>
29   	#include <rpc/nettype.h>
30   	#include <netdb.h>
31   	
32   	#include "nfs_core.h"
33   	#include "nfs_proto_functions.h"
34   	#include "sal_functions.h"
35   	#include "nlm_util.h"
36   	#include "nlm_async.h"
37   	
38   	pthread_mutex_t nlm_async_resp_mutex = PTHREAD_MUTEX_INITIALIZER;
39   	pthread_cond_t nlm_async_resp_cond = PTHREAD_COND_INITIALIZER;
40   	
41   	int nlm_send_async_res_nlm4(state_nlm_client_t *host, state_async_func_t func,
42   				    nfs_res_t *pres)
43   	{
44   		state_async_queue_t *arg = gsh_malloc(sizeof(*arg));
45   		state_nlm_async_data_t *nlm_arg;
46   		state_status_t status;
47   	
48   		nlm_arg = &arg->state_async_data.state_nlm_async_data;
49   		memset(arg, 0, sizeof(*arg));
50   		arg->state_async_func = func;
51   		nlm_arg->nlm_async_host = host;
52   		nlm_arg->nlm_async_args.nlm_async_res = *pres;
53   	
54   		copy_netobj(&nlm_arg->nlm_async_args.nlm_async_res.res_nlm4.cookie,
55   			    &pres->res_nlm4.cookie);
56   	
57   		status = state_async_schedule(arg);
58   	
59   		if (status != STATE_SUCCESS) {
60   			gsh_free(arg);
61   			return NFS_REQ_DROP;
62   		}
63   	
64   		return NFS_REQ_OK;
65   	}
66   	
67   	int nlm_send_async_res_nlm4test(state_nlm_client_t *host,
68   					state_async_func_t func, nfs_res_t *pres)
69   	{
70   		state_async_queue_t *arg = gsh_malloc(sizeof(*arg));
71   		state_nlm_async_data_t *nlm_arg;
72   		state_status_t status;
73   		nfs_res_t *res;
74   	
75   		nlm_arg = &arg->state_async_data.state_nlm_async_data;
76   		res = &nlm_arg->nlm_async_args.nlm_async_res;
77   		memset(arg, 0, sizeof(*arg));
78   		arg->state_async_func = func;
79   		nlm_arg->nlm_async_host = host;
80   		*res = *pres;
81   	
82   		copy_netobj(&res->res_nlm4test.cookie, &pres->res_nlm4test.cookie);
83   	
84   		if (pres->res_nlm4test.test_stat.stat == NLM4_DENIED) {
85   			copy_netobj(
86   			     &res->res_nlm4test.test_stat.nlm4_testrply_u.holder.oh,
87   			     &pres->res_nlm4test.test_stat.nlm4_testrply_u.holder.oh);
88   		}
89   	
90   		status = state_async_schedule(arg);
91   	
92   		if (status != STATE_SUCCESS) {
93   			nlm4_Test_Free(res);
94   			gsh_free(arg);
95   			return NFS_REQ_DROP;
96   		}
97   	
98   		return NFS_REQ_OK;
99   	}
100  	
101  	xdrproc_t nlm_reply_proc[] = {
102  		[NLMPROC4_GRANTED_MSG] = (xdrproc_t) xdr_nlm4_testargs,
103  		[NLMPROC4_TEST_RES] = (xdrproc_t) xdr_nlm4_testres,
104  		[NLMPROC4_LOCK_RES] = (xdrproc_t) xdr_nlm4_res,
105  		[NLMPROC4_CANCEL_RES] = (xdrproc_t) xdr_nlm4_res,
106  		[NLMPROC4_UNLOCK_RES] = (xdrproc_t) xdr_nlm4_res,
107  	};
108  	
109  	static void *resp_key;
110  	
111  	static const int MAX_ASYNC_RETRY = 2;
112  	static const struct timespec tout = { 0, 0 }; /* one-shot */
113  	
114  	/* Client routine  to send the asynchrnous response,
115  	 * key is used to wait for a response
116  	 */
117  	int nlm_send_async(int proc, state_nlm_client_t *host, void *inarg, void *key)
118  	{
119  		struct clnt_req *cc;
120  		char *t;
121  		struct timeval start, now;
122  		struct timespec timeout;
(1) Event var_decl: Declaring variable "retval" without initializer.
Also see events: [uninit_use]
123  		int retval, retry;
124  		char *caller_name = host->slc_nsm_client->ssc_nlm_caller_name;
125  		const char *client_type_str = xprt_type_to_str(host->slc_client_type);
126  	
(2) Event cond_true: Condition "retry < 2 /* MAX_ASYNC_RETRY */", taking true branch.
(33) Event loop_begin: Jumped back to beginning of loop.
(34) Event cond_true: Condition "retry < 2 /* MAX_ASYNC_RETRY */", taking true branch.
(65) Event loop_begin: Jumped back to beginning of loop.
(66) Event cond_false: Condition "retry < 2 /* MAX_ASYNC_RETRY */", taking false branch.
127  		for (retry = 0; retry < MAX_ASYNC_RETRY; retry++) {
(3) Event cond_true: Condition "host->slc_callback_clnt == NULL", taking true branch.
(35) Event cond_true: Condition "host->slc_callback_clnt == NULL", taking true branch.
128  			if (host->slc_callback_clnt == NULL) {
(4) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(5) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(36) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(37) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
129  				LogFullDebug(COMPONENT_NLM,
130  					     "clnt_ncreate %s",
131  					     caller_name);
132  	
(6) Event cond_false: Condition "host->slc_client_type == XPRT_TCP", taking false branch.
(38) Event cond_false: Condition "host->slc_client_type == XPRT_TCP", taking false branch.
133  				if (host->slc_client_type == XPRT_TCP) {
134  					int fd;
135  					struct sockaddr_in6 server_addr;
136  					struct netbuf *buf, local_buf;
137  					struct addrinfo *result;
138  					struct addrinfo hints;
139  					char port_str[20];
140  	
141  					fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
142  					if (fd < 0)
143  						return -1;
144  	
145  					memcpy(&server_addr,
146  					       &(host->slc_server_addr),
147  					       sizeof(struct sockaddr_in6));
148  					server_addr.sin6_port = 0;
149  	
150  					if (bind(fd,
151  						 (struct sockaddr *)&server_addr,
152  						  sizeof(server_addr)) == -1) {
153  						LogMajor(COMPONENT_NLM, "Cannot bind");
154  						close(fd);
155  						return -1;
156  					}
157  	
158  					buf = rpcb_find_mapped_addr(
159  							(char *) client_type_str,
160  							NLMPROG, NLM4_VERS,
161  							caller_name);
162  					/* handle error here, for example,
163  					 * client side blocking rpc call
164  					 */
165  					if (buf == NULL) {
166  						LogMajor(COMPONENT_NLM,
167  							 "Cannot create NLM async %s connection to client %s",
168  							 client_type_str, caller_name);
169  						close(fd);
170  						return -1;
171  					}
172  	
173  					memset(&hints, 0, sizeof(struct addrinfo));
174  					hints.ai_family = AF_INET6;	/* only INET6 */
175  					hints.ai_socktype = SOCK_STREAM; /* TCP */
176  					hints.ai_protocol = 0;	/* Any protocol */
177  					hints.ai_canonname = NULL;
178  					hints.ai_addr = NULL;
179  					hints.ai_next = NULL;
180  	
181  					/* convert port to string format */
182  					sprintf(port_str, "%d",
183  						htons(((struct sockaddr_in *)
184  							buf->buf)->sin_port));
185  	
186  					/* buf with inet is only needed for the port */
187  					gsh_free(buf->buf);
188  					gsh_free(buf);
189  	
190  					/* get the IPv4 mapped IPv6 address */
191  					retval = getaddrinfo(caller_name,
192  							     port_str,
193  							     &hints,
194  							     &result);
195  	
196  					/* retry for spurious EAI_NONAME errors */
197  					if (retval == EAI_NONAME ||
198  					    retval == EAI_AGAIN) {
199  						LogEvent(COMPONENT_NLM,
200  							 "failed to resolve %s to an address: %s",
201  							 caller_name,
202  							 gai_strerror(retval));
203  						/* getaddrinfo() failed, retry */
204  						retval = RPC_UNKNOWNADDR;
205  						usleep(1000);
206  						continue;
207  					} else if (retval != 0) {
208  						LogMajor(COMPONENT_NLM,
209  							 "failed to resolve %s to an address: %s",
210  							 caller_name,
211  							 gai_strerror(retval));
212  						return -1;
213  					}
214  	
215  					/* setup the netbuf with in6 address */
216  					local_buf.buf = result->ai_addr;
217  					local_buf.len = local_buf.maxlen =
218  					    result->ai_addrlen;
219  	
220  					host->slc_callback_clnt =
221  					    clnt_vc_ncreate(fd, &local_buf, NLMPROG,
222  							    NLM4_VERS, 0, 0);
223  					freeaddrinfo(result);
(7) Event else_branch: Reached else branch.
(39) Event else_branch: Reached else branch.
224  				} else {
225  	
226  					host->slc_callback_clnt =
227  					    clnt_ncreate(caller_name, NLMPROG,
228  							 NLM4_VERS,
229  							 (char *) client_type_str);
230  				}
231  	
(8) Event cond_false: Condition "host->slc_callback_clnt->cl_error.re_status != RPC_SUCCESS", taking false branch.
(40) Event cond_false: Condition "host->slc_callback_clnt->cl_error.re_status != RPC_SUCCESS", taking false branch.
232  				if (CLNT_FAILURE(host->slc_callback_clnt)) {
233  					char *err = rpc_sperror(
234  						&host->slc_callback_clnt->cl_error,
235  						"failed");
236  	
237  					LogMajor(COMPONENT_NLM,
238  						 "Create NLM async %s connection to client %s %s",
239  						 client_type_str, caller_name, err);
240  					gsh_free(err);
241  					CLNT_DESTROY(host->slc_callback_clnt);
242  					host->slc_callback_clnt = NULL;
243  					return -1;
(9) Event if_end: End of if statement.
(41) Event if_end: End of if statement.
244  				}
245  	
246  				/* split auth (for authnone, idempotent) */
247  				host->slc_callback_auth = authnone_ncreate();
248  			}
249  	
(10) Event cond_true: Condition "rc == 0", taking true branch.
(11) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(12) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(13) Event if_fallthrough: Falling through to end of if statement.
(14) Event if_end: End of if statement.
(42) Event cond_true: Condition "rc == 0", taking true branch.
(43) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(44) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(45) Event if_fallthrough: Falling through to end of if statement.
(46) Event if_end: End of if statement.
250  			PTHREAD_MUTEX_lock(&nlm_async_resp_mutex);
251  			resp_key = key;
(15) Event cond_true: Condition "rc == 0", taking true branch.
(16) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(17) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(18) Event if_fallthrough: Falling through to end of if statement.
(19) Event if_end: End of if statement.
(47) Event cond_true: Condition "rc == 0", taking true branch.
(48) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(49) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(50) Event if_fallthrough: Falling through to end of if statement.
(51) Event if_end: End of if statement.
252  			PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex);
253  	
(20) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(21) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(52) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(53) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
254  			LogFullDebug(COMPONENT_NLM, "About to make clnt_call");
255  	
(22) Event cond_false: Condition "p_ == NULL", taking false branch.
(23) Event if_end: End of if statement.
(54) Event cond_false: Condition "p_ == NULL", taking false branch.
(55) Event if_end: End of if statement.
256  			cc = gsh_malloc(sizeof(*cc));
257  			clnt_req_fill(cc, host->slc_callback_clnt,
258  				      host->slc_callback_auth, proc,
259  				      (xdrproc_t) nlm_reply_proc[proc], inarg,
260  				      (xdrproc_t) xdr_void, NULL);
261  			cc->cc_error.re_status = clnt_req_setup(cc, tout);
(24) Event cond_true: Condition "cc->cc_error.re_status == RPC_SUCCESS", taking true branch.
(56) Event cond_true: Condition "cc->cc_error.re_status == RPC_SUCCESS", taking true branch.
262  			if (cc->cc_error.re_status == RPC_SUCCESS) {
263  				cc->cc_refreshes = 0;
264  				cc->cc_error.re_status = CLNT_CALL_ONCE(cc);
265  			}
266  	
(25) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(26) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(57) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
(58) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_FULL_DEBUG)", taking true branch.
267  			LogFullDebug(COMPONENT_NLM, "Done with clnt_call");
268  	
(27) Event cond_false: Condition "cc->cc_error.re_status == RPC_TIMEDOUT", taking false branch.
(28) Event cond_false: Condition "cc->cc_error.re_status == RPC_SUCCESS", taking false branch.
(59) Event cond_false: Condition "cc->cc_error.re_status == RPC_TIMEDOUT", taking false branch.
(60) Event cond_false: Condition "cc->cc_error.re_status == RPC_SUCCESS", taking false branch.
269  			if (cc->cc_error.re_status == RPC_TIMEDOUT ||
270  			    cc->cc_error.re_status == RPC_SUCCESS) {
271  				cc->cc_error.re_status = RPC_SUCCESS;
272  				clnt_req_release(cc);
273  				break;
(29) Event if_end: End of if statement.
(61) Event if_end: End of if statement.
274  			}
275  	
276  			t = rpc_sperror(&cc->cc_error, "failed");
(30) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_CRIT)", taking true branch.
(31) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_CRIT)", taking true branch.
(62) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_CRIT)", taking true branch.
(63) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_CRIT)", taking true branch.
277  			LogCrit(COMPONENT_NLM,
278  				"NLM async Client procedure call %d %s",
279  				proc, t);
280  			gsh_free(t);
281  	
282  			clnt_req_release(cc);
283  			CLNT_DESTROY(host->slc_callback_clnt);
284  			host->slc_callback_clnt = NULL;
(32) Event loop: Jumping back to the beginning of the loop.
(64) Event loop: Jumping back to the beginning of the loop.
(67) Event loop_end: Reached end of loop.
285  		}
286  	
(68) Event cond_true: Condition "retry == 2 /* MAX_ASYNC_RETRY */", taking true branch.
287  		if (retry == MAX_ASYNC_RETRY) {
(69) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_MAJ)", taking true branch.
(70) Event cond_true: Condition "!!(component_log_level[COMPONENT_NLM] >= NIV_MAJ)", taking true branch.
288  			LogMajor(COMPONENT_NLM,
289  				 "NLM async Client exceeded retry count %d",
290  				 MAX_ASYNC_RETRY);
(71) Event cond_true: Condition "rc == 0", taking true branch.
(72) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(73) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(74) Event if_fallthrough: Falling through to end of if statement.
(75) Event if_end: End of if statement.
291  			PTHREAD_MUTEX_lock(&nlm_async_resp_mutex);
292  			resp_key = NULL;
(76) Event cond_true: Condition "rc == 0", taking true branch.
(77) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(78) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(79) Event if_fallthrough: Falling through to end of if statement.
(80) Event if_end: End of if statement.
293  			PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex);
(81) Event uninit_use: Using uninitialized value "retval".
Also see events: [var_decl]
294  			return retval;
295  		}
296  	
297  		PTHREAD_MUTEX_lock(&nlm_async_resp_mutex);
298  	
299  		if (resp_key != NULL) {
300  			/* Wait for 5 seconds or a signal */
301  			gettimeofday(&start, NULL);
302  			gettimeofday(&now, NULL);
303  			timeout.tv_sec = 5 + start.tv_sec;
304  			timeout.tv_nsec = 0;
305  	
306  			LogFullDebug(COMPONENT_NLM,
307  				     "About to wait for signal for key %p", resp_key);
308  	
309  			while (resp_key != NULL && now.tv_sec < (start.tv_sec + 5)) {
310  				int rc;
311  	
312  				rc = pthread_cond_timedwait(&nlm_async_resp_cond,
313  							    &nlm_async_resp_mutex,
314  							    &timeout);
315  				LogFullDebug(COMPONENT_NLM,
316  					     "pthread_cond_timedwait returned %d",
317  					     rc);
318  				gettimeofday(&now, NULL);
319  			}
320  			LogFullDebug(COMPONENT_NLM, "Done waiting");
321  		}
322  	
323  		PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex);
324  	
325  		return retval;
326  	}
327  	
328  	void nlm_signal_async_resp(void *key)
329  	{
330  		PTHREAD_MUTEX_lock(&nlm_async_resp_mutex);
331  	
332  		if (resp_key == key) {
333  			resp_key = NULL;
334  			pthread_cond_signal(&nlm_async_resp_cond);
335  			LogFullDebug(COMPONENT_NLM, "Signaled condition variable");
336  		} else {
337  			LogFullDebug(COMPONENT_NLM, "Didn't signal condition variable");
338  		}
339  	
340  		PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex);
341  	}
342