1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2008)
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22   	 * 02110-1301 USA
23   	 *
24   	 * ---------------------------------------
25   	 */
26   	
27   	/**
28   	 * @file  nfs_init.c
29   	 * @brief Most of the init routines
30   	 */
31   	#include "config.h"
32   	#include "nfs_init.h"
33   	#include "log.h"
34   	#include "fsal.h"
35   	#include "rquota.h"
36   	#include "nfs_core.h"
37   	#include "nfs_file_handle.h"
38   	#include "nfs_exports.h"
39   	#include "nfs_ip_stats.h"
40   	#include "nfs_proto_functions.h"
41   	#include "nfs_dupreq.h"
42   	#include "config_parsing.h"
43   	#include "nfs4_acls.h"
44   	#include "nfs_rpc_callback.h"
45   	#ifdef USE_DBUS
46   	#include "gsh_dbus.h"
47   	#endif
48   	#include "FSAL/fsal_commonlib.h"
49   	#ifdef _USE_CB_SIMULATOR
50   	#include "nfs_rpc_callback_simulator.h"
51   	#endif
52   	#include <sys/time.h>
53   	#include <sys/resource.h>
54   	#include <unistd.h>
55   	#include <string.h>
56   	#include <signal.h>
57   	#include <math.h>
58   	#ifdef _USE_NLM
59   	#include "nlm_util.h"
60   	#endif /* _USE_NLM */
61   	#include "nsm.h"
62   	#include "sal_functions.h"
63   	#include "fridgethr.h"
64   	#include "idmapper.h"
65   	#include "delayed_exec.h"
66   	#include "client_mgr.h"
67   	#include "export_mgr.h"
68   	#ifdef USE_CAPS
69   	#include <sys/capability.h>	/* For capget/capset */
70   	#endif
71   	#include "uid2grp.h"
72   	#include "netgroup_cache.h"
73   	#include "pnfs_utils.h"
74   	#include "mdcache.h"
75   	#include "common_utils.h"
76   	#include "nfs_init.h"
77   	#include "conf_url_rados.h"
78   	#include <urcu-bp.h>
79   	
80   	/**
81   	 * @brief init_complete used to indicate if ganesha is during
82   	 * startup or not
83   	 */
84   	struct nfs_init nfs_init;
85   	
86   	/* global information exported to all layers (as extern vars) */
87   	nfs_parameter_t nfs_param;
88   	struct _nfs_health nfs_health_;
89   	
90   	static struct _nfs_health healthstats;
91   	
92   	/* ServerEpoch is ServerBootTime unless overriden by -E command line option */
93   	struct timespec nfs_ServerBootTime;
94   	time_t nfs_ServerEpoch;
95   	
96   	verifier4 NFS4_write_verifier;	/* NFS V4 write verifier */
97   	writeverf3 NFS3_write_verifier;	/* NFS V3 write verifier */
98   	
99   	/* node ID used to identify an individual node in a cluster */
100  	int g_nodeid;
101  	
102  	nfs_start_info_t nfs_start_info;
103  	
104  	pthread_t admin_thrid;
105  	pthread_t sigmgr_thrid;
106  	
107  	tirpc_pkg_params ntirpc_pp = {
108  		TIRPC_DEBUG_FLAG_DEFAULT,
109  		0,
110  		SetNameFunction,
111  		(mem_format_t)rpc_warnx,
112  		gsh_free_size,
113  		gsh_malloc__,
114  		gsh_malloc_aligned__,
115  		gsh_calloc__,
116  		gsh_realloc__,
117  	};
118  	
119  	#ifdef _USE_9P
120  	pthread_t _9p_dispatcher_thrid;
121  	#endif
122  	
123  	#ifdef _USE_9P_RDMA
124  	pthread_t _9p_rdma_dispatcher_thrid;
125  	#endif
126  	
127  	#ifdef _USE_NFS_RDMA
128  	pthread_t nfs_rdma_dispatcher_thrid;
129  	#endif
130  	
131  	char *nfs_config_path = GANESHA_CONFIG_PATH;
132  	
133  	char *nfs_pidfile_path = GANESHA_PIDFILE_PATH;
134  	
135  	/**
136  	 * @brief Reread the configuration file to accomplish update of options.
137  	 *
138  	 * The following option blocks are currently supported for update:
139  	 *
140  	 * LOG {}
141  	 * LOG { COMPONENTS {} }
142  	 * LOG { FACILITY {} }
143  	 * LOG { FORMAT {} }
144  	 * EXPORT {}
145  	 * EXPORT { CLIENT {} }
146  	 *
147  	 */
148  	
149  	struct config_error_type err_type;
150  	
151  	void reread_config(void)
152  	{
153  		int status = 0;
154  		int i;
155  		config_file_t config_struct;
156  	
157  		/* Clear out the flag indicating component was set from environment. */
158  		for (i = COMPONENT_ALL; i < COMPONENT_COUNT; i++)
159  			LogComponents[i].comp_env_set = false;
160  	
161  		/* If no configuration file is given, then the caller must want to
162  		 * reparse the configuration file from startup.
163  		 */
164  		if (nfs_config_path[0] == '\0') {
165  			LogCrit(COMPONENT_CONFIG,
166  				"No configuration file was specified for reloading log config.");
167  			return;
168  		}
169  	
170  		/* Create a memstream for parser+processing error messages */
171  		if (!init_error_type(&err_type))
172  			return;
173  		/* Attempt to parse the new configuration file */
174  		config_struct = config_ParseFile(nfs_config_path, &err_type);
175  		if (!config_error_no_error(&err_type)) {
176  			config_Free(config_struct);
177  			LogCrit(COMPONENT_CONFIG,
178  				"Error while parsing new configuration file %s",
179  				nfs_config_path);
180  			report_config_errors(&err_type, NULL, config_errs_to_log);
181  			return;
182  		}
183  	
184  		/* Update the logging configuration */
185  		status = read_log_config(config_struct, &err_type);
186  		if (status < 0)
187  			LogCrit(COMPONENT_CONFIG, "Error while parsing LOG entries");
188  	
189  		/* Update the export configuration */
190  		status = reread_exports(config_struct, &err_type);
191  		if (status < 0)
192  			LogCrit(COMPONENT_CONFIG, "Error while parsing EXPORT entries");
193  	
194  		report_config_errors(&err_type, NULL, config_errs_to_log);
195  		config_Free(config_struct);
196  	}
197  	
198  	/**
199  	 * @brief This thread is in charge of signal management
200  	 *
201  	 * @param[in] UnusedArg Unused
202  	 *
203  	 * @return NULL.
204  	 */
205  	static void *sigmgr_thread(void *UnusedArg)
206  	{
207  		int signal_caught = 0;
208  	
209  		SetNameFunction("sigmgr");
210  		rcu_register_thread();
211  	
212  		/* Loop until we catch SIGTERM */
213  		while (signal_caught != SIGTERM) {
214  			sigset_t signals_to_catch;
215  	
216  			sigemptyset(&signals_to_catch);
217  			sigaddset(&signals_to_catch, SIGTERM);
218  			sigaddset(&signals_to_catch, SIGHUP);
219  			if (sigwait(&signals_to_catch, &signal_caught) != 0) {
220  				LogFullDebug(COMPONENT_THREAD,
221  					     "sigwait exited with error");
222  				continue;
223  			}
224  			if (signal_caught == SIGHUP) {
225  				LogEvent(COMPONENT_MAIN,
226  					 "SIGHUP_HANDLER: Received SIGHUP.... initiating export list reload");
227  				reread_config();
228  	#ifdef _HAVE_GSSAPI
229  				svcauth_gss_release_cred();
230  	#endif /* _HAVE_GSSAPI */
231  			}
232  		}
233  		LogDebug(COMPONENT_THREAD, "sigmgr thread exiting");
234  	
235  		admin_halt();
236  	
237  		/* Might as well exit - no need for this thread any more */
238  		rcu_unregister_thread();
239  		return NULL;
240  	}
241  	
242  	
243  	static void crash_handler(int signo, siginfo_t *info, void *ctx)
244  	{
245  		gsh_backtrace();
246  		/* re-raise the signal for the default signal handler to dump core */
247  		raise(signo);
248  	}
249  	
250  	static void install_sighandler(int signo,
251  				       void (*handler)(int, siginfo_t *, void *))
252  	{
253  		struct sigaction sa = {};
254  		int ret;
255  	
256  		sa.sa_sigaction = handler;
257  		/* set SA_RESETHAND to restore default handler */
258  		sa.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER;
259  	
260  		sigemptyset(&sa.sa_mask);
261  	
262  		ret = sigaction(signo, &sa, NULL);
263  		if (ret) {
264  			LogWarn(COMPONENT_INIT,
265  				"Install handler for signal (%s) failed",
266  				strsignal(signo));
267  		}
268  	}
269  	
270  	static void init_crash_handlers(void)
271  	{
272  		install_sighandler(SIGSEGV, crash_handler);
273  		install_sighandler(SIGABRT, crash_handler);
274  		install_sighandler(SIGBUS, crash_handler);
275  		install_sighandler(SIGILL, crash_handler);
276  		install_sighandler(SIGFPE, crash_handler);
277  		install_sighandler(SIGQUIT, crash_handler);
278  	}
279  	
280  	/**
281  	 * @brief Initialize NFSd prerequisites
282  	 *
283  	 * @param[in] program_name Name of the program
284  	 * @param[in] host_name    Server host name
285  	 * @param[in] debug_level  Debug level
286  	 * @param[in] log_path     Log path
287  	 * @param[in] dump_trace   Dump trace when segfault
288  	 */
289  	void nfs_prereq_init(const char *program_name, const char *host_name,
290  			     int debug_level, const char *log_path, bool dump_trace)
291  	{
292  		healthstats.enqueued_reqs = nfs_health_.enqueued_reqs = 0;
293  		healthstats.enqueued_reqs = nfs_health_.dequeued_reqs = 0;
294  	
295  		/* Initialize logging */
296  		SetNamePgm(program_name);
297  		SetNameFunction("main");
298  		SetNameHost(host_name);
299  	
300  		init_logging(log_path, debug_level);
301  		if (dump_trace) {
302  			init_crash_handlers();
303  		}
304  	
305  		/* Redirect TI-RPC allocators, log channel */
306  		if (!tirpc_control(TIRPC_PUT_PARAMETERS, &ntirpc_pp)) {
307  			LogFatal(COMPONENT_INIT, "Setting nTI-RPC parameters failed");
308  		}
309  	}
310  	
311  	/**
312  	 * @brief Print the nfs_parameter_structure
313  	 */
314  	void nfs_print_param_config(void)
315  	{
316  		printf("NFS_Core_Param\n{\n");
317  	
318  		printf("\tNFS_Port = %u ;\n", nfs_param.core_param.port[P_NFS]);
319  		printf("\tMNT_Port = %u ;\n", nfs_param.core_param.port[P_MNT]);
320  		printf("\tNFS_Program = %u ;\n", nfs_param.core_param.program[P_NFS]);
321  		printf("\tMNT_Program = %u ;\n", nfs_param.core_param.program[P_NFS]);
322  		printf("\tDRC_TCP_Npart = %u ;\n", nfs_param.core_param.drc.tcp.npart);
323  		printf("\tDRC_TCP_Size = %u ;\n", nfs_param.core_param.drc.tcp.size);
324  		printf("\tDRC_TCP_Cachesz = %u ;\n",
325  		       nfs_param.core_param.drc.tcp.cachesz);
326  		printf("\tDRC_TCP_Hiwat = %u ;\n", nfs_param.core_param.drc.tcp.hiwat);
327  		printf("\tDRC_TCP_Recycle_Npart = %u ;\n",
328  		       nfs_param.core_param.drc.tcp.recycle_npart);
329  		printf("\tDRC_TCP_Recycle_Expire_S = %u ;\n",
330  		       nfs_param.core_param.drc.tcp.recycle_expire_s);
331  		printf("\tDRC_TCP_Checksum = %u ;\n",
332  		       nfs_param.core_param.drc.tcp.checksum);
333  		printf("\tDRC_UDP_Npart = %u ;\n", nfs_param.core_param.drc.udp.npart);
334  		printf("\tDRC_UDP_Size = %u ;\n", nfs_param.core_param.drc.udp.size);
335  		printf("\tDRC_UDP_Cachesz = %u ;\n",
336  		       nfs_param.core_param.drc.udp.cachesz);
337  		printf("\tDRC_UDP_Hiwat = %u ;\n", nfs_param.core_param.drc.udp.hiwat);
338  		printf("\tDRC_UDP_Checksum = %u ;\n",
339  		       nfs_param.core_param.drc.udp.checksum);
340  		printf("\tBlocked_Lock_Poller_Interval = %" PRIu64 " ;\n",
341  		       (uint64_t) nfs_param.core_param.blocked_lock_poller_interval);
342  	
343  		printf("\tManage_Gids_Expiration = %" PRIu64 " ;\n",
344  		       (uint64_t) nfs_param.core_param.manage_gids_expiration);
345  	
346  		printf("\tDrop_IO_Errors = %s ;\n",
347  		       nfs_param.core_param.drop_io_errors ?  "true" : "false");
348  	
349  		printf("\tDrop_Inval_Errors = %s ;\n",
350  		       nfs_param.core_param.drop_inval_errors ?  "true" : "false");
351  	
352  		printf("\tDrop_Delay_Errors = %s ;\n",
353  		       nfs_param.core_param.drop_delay_errors ? "true" : "false");
354  	
355  		printf("\tEnable UDP = %s ;\n", nfs_param.core_param.enable_UDP ?
356  		       "true" : "false");
357  	
358  		printf("}\n\n");
359  	}
360  	
361  	/**
362  	 * @brief Load parameters from config file
363  	 *
364  	 * @param[in]  config_struct Parsed config file
365  	 * @param[out] p_start_info  Startup parameters
366  	 * @param[out] err_type error reporting state
367  	 *
368  	 * @return -1 on failure.
369  	 */
370  	int nfs_set_param_from_conf(config_file_t parse_tree,
371  				    nfs_start_info_t *p_start_info,
372  				    struct config_error_type *err_type)
373  	{
374  		/*
375  		 * Initialize exports and clients so config parsing can use them
376  		 * early.
377  		 */
378  		client_pkginit();
379  		export_pkginit();
380  		server_pkginit();
381  	
382  		/* Core parameters */
383  		(void) load_config_from_parse(parse_tree,
384  					      &nfs_core,
385  					      &nfs_param.core_param,
386  					      true,
387  					      err_type);
388  		if (!config_error_is_harmless(err_type)) {
389  			LogCrit(COMPONENT_INIT,
390  				"Error while parsing core configuration");
391  			return -1;
392  		}
393  	
394  		/* Worker paramters: ip/name hash table and expiration for each entry */
395  		(void) load_config_from_parse(parse_tree,
396  					      &nfs_ip_name,
397  					      NULL,
398  					      true,
399  					      err_type);
400  		if (!config_error_is_harmless(err_type)) {
401  			LogCrit(COMPONENT_INIT,
402  				"Error while parsing IP/name configuration");
403  			return -1;
404  		}
405  	
406  	#ifdef _HAVE_GSSAPI
407  		/* NFS kerberos5 configuration */
408  		(void) load_config_from_parse(parse_tree,
409  					      &krb5_param,
410  					      &nfs_param.krb5_param,
411  					      true,
412  					      err_type);
413  		if (!config_error_is_harmless(err_type)) {
414  			LogCrit(COMPONENT_INIT,
415  				"Error while parsing NFS/KRB5 configuration for RPCSEC_GSS");
416  			return -1;
417  		}
418  	#endif
419  	
420  		/* NFSv4 specific configuration */
421  		(void) load_config_from_parse(parse_tree,
422  					      &version4_param,
423  					      &nfs_param.nfsv4_param,
424  					      true,
425  					      err_type);
426  		if (!config_error_is_harmless(err_type)) {
427  			LogCrit(COMPONENT_INIT,
428  				"Error while parsing NFSv4 specific configuration");
429  			return -1;
430  		}
431  	
432  	#ifdef _USE_9P
433  		(void) load_config_from_parse(parse_tree,
434  					      &_9p_param_blk,
435  					      NULL,
436  					      true,
437  					      err_type);
438  		if (!config_error_is_harmless(err_type)) {
439  			LogCrit(COMPONENT_INIT,
440  				"Error while parsing 9P specific configuration");
441  			return -1;
442  		}
443  	#endif
444  	
445  		if (mdcache_set_param_from_conf(parse_tree, err_type) < 0)
446  			return -1;
447  	
448  	#ifdef USE_RADOS_RECOV
449  		if (rados_kv_set_param_from_conf(parse_tree, err_type) < 0)
450  			return -1;
451  	#endif
452  	
453  		if (rados_url_setup_watch() != 0)
454  			return -1;
455  	
456  		LogEvent(COMPONENT_INIT, "Configuration file successfully parsed");
457  	
458  		return 0;
459  	}
460  	
461  	int init_server_pkgs(void)
462  	{
463  		fsal_status_t fsal_status;
464  		state_status_t state_status;
465  	
466  		/* init uid2grp cache */
467  		uid2grp_cache_init();
468  	
469  		ng_cache_init(); /* netgroup cache */
470  	
471  		/* MDCACHE Initialisation */
472  		fsal_status = mdcache_pkginit();
473  		if (FSAL_IS_ERROR(fsal_status)) {
474  			LogCrit(COMPONENT_INIT,
475  				"MDCACHE FSAL could not be initialized, status=%s",
476  				fsal_err_txt(fsal_status));
477  			return -1;
478  		}
479  	
480  		state_status = state_lock_init();
481  		if (state_status != STATE_SUCCESS) {
482  			LogCrit(COMPONENT_INIT,
483  				"State Lock Layer could not be initialized, status=%s",
484  				state_err_str(state_status));
485  			return -1;
486  		}
487  		LogInfo(COMPONENT_INIT, "State lock layer successfully initialized");
488  	
489  		/* Init the IP/name cache */
490  		LogDebug(COMPONENT_INIT, "Now building IP/name cache");
491  		if (nfs_Init_ip_name() != IP_NAME_SUCCESS) {
492  			LogCrit(COMPONENT_INIT,
493  				"Error while initializing IP/name cache");
494  			return -1;
495  		}
496  		LogInfo(COMPONENT_INIT, "IP/name cache successfully initialized");
497  	
498  		LogEvent(COMPONENT_INIT, "Initializing ID Mapper.");
499  		if (!idmapper_init()) {
500  			LogCrit(COMPONENT_INIT, "Failed initializing ID Mapper.");
501  			return -1;
502  		}
503  		LogEvent(COMPONENT_INIT, "ID Mapper successfully initialized.");
504  		return 0;
505  	}
506  	
507  	static void nfs_Start_threads(void)
508  	{
509  		int rc = 0;
510  		pthread_attr_t attr_thr;
511  	
512  		LogDebug(COMPONENT_THREAD, "Starting threads");
513  	
514  		/* Init for thread parameter (mostly for scheduling) */
515  		if (pthread_attr_init(&attr_thr) != 0)
516  			LogDebug(COMPONENT_THREAD, "can't init pthread's attributes");
517  	
518  		if (pthread_attr_setscope(&attr_thr, PTHREAD_SCOPE_SYSTEM) != 0)
519  			LogDebug(COMPONENT_THREAD, "can't set pthread's scope");
520  	
521  		if (pthread_attr_setdetachstate(&attr_thr,
522  						PTHREAD_CREATE_JOINABLE) != 0)
523  			LogDebug(COMPONENT_THREAD, "can't set pthread's join state");
524  	
525  		LogEvent(COMPONENT_THREAD, "Starting delayed executor.");
526  		delayed_start();
527  	
528  		/* Starting the thread dedicated to signal handling */
529  		rc = pthread_create(&sigmgr_thrid, &attr_thr, sigmgr_thread, NULL);
530  		if (rc != 0) {
531  			LogFatal(COMPONENT_THREAD,
532  				 "Could not create sigmgr_thread, error = %d (%s)",
533  				 errno, strerror(errno));
534  		}
535  		LogDebug(COMPONENT_THREAD, "sigmgr thread started");
536  	
537  	#ifdef _USE_9P
538  		if (nfs_param.core_param.core_options & CORE_OPTION_9P) {
539  			/* Start 9P worker threads */
540  			rc = _9p_worker_init();
541  			if (rc != 0) {
542  				LogFatal(COMPONENT_THREAD,
543  					 "Could not start worker threads: %d", errno);
544  			}
545  	
546  			/* Starting the 9P/TCP dispatcher thread */
547  			rc = pthread_create(&_9p_dispatcher_thrid, &attr_thr,
548  					    _9p_dispatcher_thread, NULL);
549  			if (rc != 0) {
550  				LogFatal(COMPONENT_THREAD,
551  					 "Could not create  9P/TCP dispatcher, error = %d (%s)",
552  					 errno, strerror(errno));
553  			}
554  			LogEvent(COMPONENT_THREAD,
555  				 "9P/TCP dispatcher thread was started successfully");
556  		}
557  	#endif
558  	
559  	#ifdef _USE_9P_RDMA
560  		/* Starting the 9P/RDMA dispatcher thread */
561  		if (nfs_param.core_param.core_options & CORE_OPTION_9P) {
562  			rc = pthread_create(&_9p_rdma_dispatcher_thrid, &attr_thr,
563  					    _9p_rdma_dispatcher_thread, NULL);
564  			if (rc != 0) {
565  				LogFatal(COMPONENT_THREAD,
566  					 "Could not create  9P/RDMA dispatcher, error = %d (%s)",
567  					 errno, strerror(errno));
568  			}
569  			LogEvent(COMPONENT_THREAD,
570  				 "9P/RDMA dispatcher thread was started successfully");
571  		}
572  	#endif
573  	
574  	#ifdef USE_DBUS
575  		/* DBUS event thread */
576  		rc = pthread_create(&gsh_dbus_thrid, &attr_thr, gsh_dbus_thread, NULL);
577  		if (rc != 0) {
578  			LogFatal(COMPONENT_THREAD,
579  				 "Could not create gsh_dbus_thread, error = %d (%s)",
580  				 errno, strerror(errno));
581  		}
582  		LogEvent(COMPONENT_THREAD, "gsh_dbusthread was started successfully");
583  	#endif
584  	
585  		/* Starting the admin thread */
(129) Event example_assign: Example 4: Assigning: "rc" = return value from "pthread_create(&admin_thrid, &attr_thr, admin_thread, NULL)".
Also see events: [check_return][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_checked][example_assign][example_checked]
586  		rc = pthread_create(&admin_thrid, &attr_thr, admin_thread, NULL);
(130) Event example_checked: Example 4 (cont.): "rc" has its value checked in "rc != 0".
Also see events: [check_return][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_assign][example_assign][example_checked]
587  		if (rc != 0) {
588  			LogFatal(COMPONENT_THREAD,
589  				 "Could not create admin_thread, error = %d (%s)",
590  				 errno, strerror(errno));
591  		}
592  		LogEvent(COMPONENT_THREAD, "admin thread was started successfully");
593  	
594  		/* Starting the reaper thread */
595  		rc = reaper_init();
596  		if (rc != 0) {
597  			LogFatal(COMPONENT_THREAD,
598  				 "Could not create reaper_thread, error = %d (%s)",
599  				 errno, strerror(errno));
600  		}
601  		LogEvent(COMPONENT_THREAD, "reaper thread was started successfully");
602  	
603  		/* Starting the general fridge */
604  		rc = general_fridge_init();
605  		if (rc != 0) {
606  			LogFatal(COMPONENT_THREAD,
607  				 "Could not create general fridge, error = %d (%s)",
608  				 errno, strerror(errno));
609  		}
610  		LogEvent(COMPONENT_THREAD, "General fridge was started successfully");
611  	
612  		pthread_attr_destroy(&attr_thr);
613  	}
614  	
615  	/**
616  	 * @brief Init the nfs daemon
617  	 *
618  	 * @param[in] p_start_info Unused
619  	 */
620  	
621  	static void nfs_Init(const nfs_start_info_t *p_start_info)
622  	{
623  	#ifdef _HAVE_GSSAPI
624  		gss_buffer_desc gss_service_buf;
625  		OM_uint32 maj_stat, min_stat;
626  		char GssError[MAXNAMLEN + 1];
627  	#endif
628  	
629  	#ifdef USE_DBUS
630  		/* DBUS init */
631  		gsh_dbus_pkginit();
632  		dbus_export_init();
633  		dbus_client_init();
634  		dbus_cache_init();
635  	#endif
636  	
637  		/* acls cache may be needed by exports_pkginit */
638  		LogDebug(COMPONENT_INIT, "Now building NFSv4 ACL cache");
639  		if (nfs4_acls_init() != 0)
640  			LogFatal(COMPONENT_INIT, "Error while initializing NFSv4 ACLs");
641  		LogInfo(COMPONENT_INIT, "NFSv4 ACL cache successfully initialized");
642  	
643  		/* finish the job with exports by caching the root entries
644  		 */
645  		exports_pkginit();
646  	
647  		nfs41_session_pool =
648  		    pool_basic_init("NFSv4.1 session pool", sizeof(nfs41_session_t));
649  	
650  		/* If rpcsec_gss is used, set the path to the keytab */
651  	#ifdef _HAVE_GSSAPI
652  	#ifdef HAVE_KRB5
653  		if (nfs_param.krb5_param.active_krb5) {
654  			OM_uint32 gss_status = GSS_S_COMPLETE;
655  	
656  			if (*nfs_param.krb5_param.keytab != '\0')
657  				gss_status = krb5_gss_register_acceptor_identity(
658  							nfs_param.krb5_param.keytab);
659  	
660  			if (gss_status != GSS_S_COMPLETE) {
661  				log_sperror_gss(GssError, gss_status, 0);
662  				LogFatal(COMPONENT_INIT,
663  					 "Error setting krb5 keytab to value %s is %s",
664  					 nfs_param.krb5_param.keytab, GssError);
665  			}
666  			LogInfo(COMPONENT_INIT,
667  				"krb5 keytab path successfully set to %s",
668  				nfs_param.krb5_param.keytab);
669  	#endif				/* HAVE_KRB5 */
670  	
671  			/* Set up principal to be use for GSSAPPI within GSSRPC/KRB5 */
672  			gss_service_buf.value = nfs_param.krb5_param.svc.principal;
673  			gss_service_buf.length =
674  				strlen(nfs_param.krb5_param.svc.principal) + 1;
675  			/* The '+1' is not to be forgotten, for the '\0' at the end */
676  	
677  			maj_stat = gss_import_name(&min_stat, &gss_service_buf,
678  						   (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
679  						   &nfs_param.krb5_param.svc.gss_name);
680  			if (maj_stat != GSS_S_COMPLETE) {
681  				log_sperror_gss(GssError, maj_stat, min_stat);
682  				LogFatal(COMPONENT_INIT,
683  					 "Error importing gss principal %s is %s",
684  					 nfs_param.krb5_param.svc.principal, GssError);
685  			}
686  	
687  			if (nfs_param.krb5_param.svc.gss_name == GSS_C_NO_NAME)
688  				LogInfo(COMPONENT_INIT,
689  					"Regression:  svc.gss_name == GSS_C_NO_NAME");
690  	
691  			LogInfo(COMPONENT_INIT, "gss principal \"%s\" successfully set",
692  				nfs_param.krb5_param.svc.principal);
693  	
694  			/* Set the principal to GSSRPC */
695  			if (!svcauth_gss_set_svc_name
696  			    (nfs_param.krb5_param.svc.gss_name)) {
697  				LogFatal(COMPONENT_INIT,
698  					 "Impossible to set gss principal to GSSRPC");
699  			}
700  	
701  			/* Don't release name until shutdown, it will be used by the
702  			 * backchannel. */
703  	
704  	#ifdef HAVE_KRB5
705  		}			/*  if( nfs_param.krb5_param.active_krb5 ) */
706  	#endif				/* HAVE_KRB5 */
707  	#endif				/* _HAVE_GSSAPI */
708  		/* Init the NFSv4 Clientid cache */
709  		LogDebug(COMPONENT_INIT, "Now building NFSv4 clientid cache");
710  		if (nfs_Init_client_id() !=
711  		    CLIENT_ID_SUCCESS) {
712  			LogFatal(COMPONENT_INIT,
713  				 "Error while initializing NFSv4 clientid cache");
714  		}
715  		LogInfo(COMPONENT_INIT,
716  			"NFSv4 clientid cache successfully initialized");
717  	
718  		/* Init duplicate request cache */
719  		dupreq2_pkginit();
720  		LogInfo(COMPONENT_INIT,
721  			"duplicate request hash table cache successfully initialized");
722  	
723  		/* Init The NFSv4 State id cache */
724  		LogDebug(COMPONENT_INIT, "Now building NFSv4 State Id cache");
725  		if (nfs4_Init_state_id() != 0) {
726  			LogFatal(COMPONENT_INIT,
727  				 "Error while initializing NFSv4 State Id cache");
728  		}
729  		LogInfo(COMPONENT_INIT,
730  			"NFSv4 State Id cache successfully initialized");
731  	
732  		/* Init The NFSv4 Open Owner cache */
733  		LogDebug(COMPONENT_INIT, "Now building NFSv4 Owner cache");
734  		if (Init_nfs4_owner() != 0) {
735  			LogFatal(COMPONENT_INIT,
736  				 "Error while initializing NFSv4 Owner cache");
737  		}
738  		LogInfo(COMPONENT_INIT,
739  			"NFSv4 Open Owner cache successfully initialized");
740  	
741  	#ifdef _USE_NLM
742  		if (nfs_param.core_param.enable_NLM) {
743  			/* Init The NLM Owner cache */
744  			LogDebug(COMPONENT_INIT, "Now building NLM Owner cache");
745  			if (Init_nlm_hash() != 0) {
746  				LogFatal(COMPONENT_INIT,
747  					 "Error while initializing NLM Owner cache");
748  			}
749  			LogInfo(COMPONENT_INIT,
750  				"NLM Owner cache successfully initialized");
751  			/* Init The NLM Owner cache */
752  			LogDebug(COMPONENT_INIT, "Now building NLM State cache");
753  			if (Init_nlm_state_hash() != 0) {
754  				LogFatal(COMPONENT_INIT,
755  					 "Error while initializing NLM State cache");
756  			}
757  			LogInfo(COMPONENT_INIT,
758  				"NLM State cache successfully initialized");
759  			nlm_init();
760  		}
761  	#endif /* _USE_NLM */
762  	#ifdef _USE_9P
763  		/* Init the 9P lock owner cache */
764  		LogDebug(COMPONENT_INIT, "Now building 9P Owner cache");
765  		if (Init_9p_hash() != 0) {
766  			LogFatal(COMPONENT_INIT,
767  				 "Error while initializing 9P Owner cache");
768  		}
769  		LogInfo(COMPONENT_INIT, "9P Owner cache successfully initialized");
770  	#endif
771  	
772  		LogDebug(COMPONENT_INIT, "Now building NFSv4 Session Id cache");
773  		if (nfs41_Init_session_id() != 0) {
774  			LogFatal(COMPONENT_INIT,
775  				 "Error while initializing NFSv4 Session Id cache");
776  		}
777  		LogInfo(COMPONENT_INIT,
778  			"NFSv4 Session Id cache successfully initialized");
779  	
780  	#ifdef _USE_9P
781  		LogDebug(COMPONENT_INIT, "Now building 9P resources");
782  		if (_9p_init()) {
783  			LogCrit(COMPONENT_INIT,
784  				"Error while initializing 9P Resources");
785  			exit(1);
786  		}
787  		LogInfo(COMPONENT_INIT, "9P resources successfully initialized");
788  	#endif				/* _USE_9P */
789  	
790  		/* Creates the pseudo fs */
791  		LogDebug(COMPONENT_INIT, "Now building pseudo fs");
792  	
793  		create_pseudofs();
794  	
795  		LogInfo(COMPONENT_INIT,
796  			"NFSv4 pseudo file system successfully initialized");
797  	
798  		/* Save Ganesha thread credentials with Frank's routine for later use */
799  		fsal_save_ganesha_credentials();
800  	
801  		/* RPC Initialisation - exits on failure */
802  		nfs_Init_svc();
803  		LogInfo(COMPONENT_INIT, "RPC resources successfully initialized");
804  	
805  		/* Admin initialisation */
806  		nfs_Init_admin_thread();
807  	
808  		/* callback dispatch */
809  		nfs_rpc_cb_pkginit();
810  	#ifdef _USE_CB_SIMULATOR
811  		nfs_rpc_cbsim_pkginit();
812  	#endif				/*  _USE_CB_SIMULATOR */
813  	
814  	}				/* nfs_Init */
815  	
816  	#ifdef USE_CAPS
817  	/**
818  	 * @brief Lower my capabilities (privs) so quotas work right
819  	 *
820  	 * This will/should be moved to set_credentials where it belongs
821  	 * Deal with capabilities in order to remove CAP_SYS_RESOURCE (needed
822  	 * for proper management of data quotas)
823  	 */
824  	
825  	static void lower_my_caps(void)
826  	{
827  		cap_value_t cap_values[] = {CAP_SYS_RESOURCE};
828  		cap_t cap;
829  		char *cap_text;
830  		ssize_t capstrlen = 0;
831  		int ret;
832  	
833  		if (!nfs_start_info.drop_caps) {
834  			/* Skip dropping caps by request */
835  			return;
836  		}
837  	
838  		cap = cap_get_proc();
839  		if (cap == NULL) {
840  			LogFatal(COMPONENT_INIT,
841  				 "cap_get_proc() failed, %s", strerror(errno));
842  		}
843  	
844  		ret = cap_set_flag(cap, CAP_EFFECTIVE,
845  				   sizeof(cap_values) / sizeof(cap_values[0]),
846  				   cap_values, CAP_CLEAR);
847  		if (ret != 0) {
848  			LogFatal(COMPONENT_INIT,
849  				 "cap_set_flag() failed, %s", strerror(errno));
850  		}
851  	
852  		ret = cap_set_flag(cap, CAP_PERMITTED,
853  				   sizeof(cap_values) / sizeof(cap_values[0]),
854  				   cap_values, CAP_CLEAR);
855  		if (ret != 0) {
856  			LogFatal(COMPONENT_INIT,
857  				 "cap_set_flag() failed, %s", strerror(errno));
858  		}
859  	
860  		ret = cap_set_flag(cap, CAP_INHERITABLE,
861  				   sizeof(cap_values) / sizeof(cap_values[0]),
862  				   cap_values, CAP_CLEAR);
863  		if (ret != 0) {
864  			LogFatal(COMPONENT_INIT,
865  				 "cap_set_flag() failed, %s", strerror(errno));
866  		}
867  	
868  		ret = cap_set_proc(cap);
869  		if (ret != 0) {
870  			LogFatal(COMPONENT_INIT,
871  				 "Failed to set capabilities for process, %s",
872  				 strerror(errno));
873  		}
874  	
875  		LogEvent(COMPONENT_INIT,
876  			 "CAP_SYS_RESOURCE was successfully removed for proper quota management in FSAL");
877  	
878  		/* Print newly set capabilities (same as what CLI "getpcaps" displays */
879  		cap_text = cap_to_text(cap, &capstrlen);
880  		LogEvent(COMPONENT_INIT, "currenty set capabilities are: %s",
881  			 cap_text);
882  		cap_free(cap_text);
883  		cap_free(cap);
884  	}
885  	#endif
886  	
887  	/**
888  	 * @brief Start NFS service
889  	 *
890  	 * @param[in] p_start_info Startup parameters
891  	 */
892  	void nfs_start(nfs_start_info_t *p_start_info)
893  	{
894  		/* store the start info so it is available for all layers */
895  		nfs_start_info = *p_start_info;
896  	
897  		if (p_start_info->dump_default_config == true) {
898  			nfs_print_param_config();
899  			exit(0);
900  		}
901  	
902  		/* Make sure Ganesha runs with a 0000 umask. */
903  		umask(0000);
904  	
905  		{
906  			/* Set the write verifiers */
907  			union {
908  				verifier4 NFS4_write_verifier;
909  				writeverf3 NFS3_write_verifier;
910  				uint64_t epoch;
911  			} build_verifier;
912  	
913  			build_verifier.epoch = (uint64_t) nfs_ServerEpoch;
914  	
915  			memcpy(NFS3_write_verifier, build_verifier.NFS3_write_verifier,
916  			       sizeof(NFS3_write_verifier));
917  			memcpy(NFS4_write_verifier, build_verifier.NFS4_write_verifier,
918  			       sizeof(NFS4_write_verifier));
919  		}
920  	
921  	#ifdef USE_CAPS
922  		lower_my_caps();
923  	#endif
924  	
925  		/* Initialize all layers and service threads */
926  		nfs_Init(p_start_info);
927  		nfs_Start_threads(); /* Spawns service threads */
928  	
929  		nfs_init_complete();
930  	
931  	#ifdef _USE_NLM
932  		if (nfs_param.core_param.enable_NLM) {
933  			/* NSM Unmonitor all */
934  			nsm_unmonitor_all();
935  		}
936  	#endif /* _USE_NLM */
937  	
938  		LogEvent(COMPONENT_INIT,
939  			 "-------------------------------------------------");
940  		LogEvent(COMPONENT_INIT, "             NFS SERVER INITIALIZED");
941  		LogEvent(COMPONENT_INIT,
942  			 "-------------------------------------------------");
943  	
944  		/* Set the time of NFS stat counting */
945  		now(&nfs_stats_time);
946  	
947  		/* Wait for dispatcher to exit */
948  		LogDebug(COMPONENT_THREAD, "Wait for admin thread to exit");
949  		pthread_join(admin_thrid, NULL);
950  	
951  		/* Regular exit */
952  		LogEvent(COMPONENT_MAIN, "NFS EXIT: regular exit");
953  	
954  		Cleanup();
955  		/* let main return 0 to exit */
956  	}
957  	
958  	void nfs_init_init(void)
959  	{
960  		PTHREAD_MUTEX_init(&nfs_init.init_mutex, NULL);
961  		PTHREAD_COND_init(&nfs_init.init_cond, NULL);
962  		nfs_init.init_complete = false;
963  	}
964  	
965  	void nfs_init_complete(void)
966  	{
967  		PTHREAD_MUTEX_lock(&nfs_init.init_mutex);
968  		nfs_init.init_complete = true;
969  		pthread_cond_broadcast(&nfs_init.init_cond);
970  		PTHREAD_MUTEX_unlock(&nfs_init.init_mutex);
971  	}
972  	
973  	void nfs_init_wait(void)
974  	{
975  		PTHREAD_MUTEX_lock(&nfs_init.init_mutex);
976  		while (!nfs_init.init_complete) {
977  			pthread_cond_wait(&nfs_init.init_cond, &nfs_init.init_mutex);
978  		}
979  		PTHREAD_MUTEX_unlock(&nfs_init.init_mutex);
980  	}
981  	
982  	bool nfs_health(void)
983  	{
984  		uint64_t newenq, newdeq;
985  		uint64_t dequeue_diff, enqueue_diff;
986  		bool healthy;
987  	
988  		newenq = nfs_health_.enqueued_reqs;
989  		newdeq = nfs_health_.dequeued_reqs;
990  		enqueue_diff = newenq - healthstats.enqueued_reqs;
991  		dequeue_diff = newdeq - healthstats.dequeued_reqs;
992  	
993  		/* Consider healthy and making progress if we have dequeued some
994  		 * requests or there is nothing to dequeue.
995  		 */
996  		healthy = dequeue_diff > 0 || enqueue_diff == 0;
997  	
998  		if (!healthy) {
999  			LogWarn(COMPONENT_DBUS,
1000 				"Health status is unhealthy. "
1001 				"enq new: %" PRIu64 ", old: %" PRIu64 "; "
1002 				"deq new: %" PRIu64 ", old: %" PRIu64,
1003 				newenq, healthstats.enqueued_reqs,
1004 				newdeq, healthstats.dequeued_reqs);
1005 		}
1006 	
1007 		healthstats.enqueued_reqs = newenq;
1008 		healthstats.dequeued_reqs = newdeq;
1009 	
1010 		return healthy;
1011 	}
1012