xref: /titanic_41/usr/src/cmd/lvm/rpc.mdcommd/mddoors.c (revision 414388d7cb2ee98771e2ac7c2338c460abd44304)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <door.h>
30 #include <locale.h>
31 #include <meta.h>
32 #include <strings.h>
33 #include <syslog.h>
34 
35 static pid_t enter_daemon_lock(void);
36 static void exit_daemon_lock(void);
37 #define	DAEMON_LOCK_FILE "/var/run/.mddoors.lock"
38 
39 static int hold_daemon_lock;
40 static const char *daemon_lock_file = DAEMON_LOCK_FILE;
41 static int daemon_lock_fd;
42 
43 void
44 daemon_cleanup()
45 {
46 	if (hold_daemon_lock) {
47 		meta_mirror_resync_block_all();
48 		exit_daemon_lock();
49 	}
50 }
51 
52 /*
53  * Use an advisory lock to ensure that only one daemon process is
54  * active at any point in time.
55  */
56 static pid_t
57 enter_daemon_lock(void)
58 {
59 	struct flock	lock;
60 
61 	daemon_lock_fd = open(daemon_lock_file, O_CREAT|O_RDWR, 0644);
62 
63 	if (daemon_lock_fd < 0) {
64 		exit(-1);
65 	}
66 
67 	lock.l_type = F_WRLCK;
68 	lock.l_whence = SEEK_SET;
69 	lock.l_start = 0;
70 	lock.l_len = 0;
71 
72 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
73 
74 		if (errno == EAGAIN || errno == EDEADLK) {
75 
76 			if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) {
77 				exit(1);
78 			}
79 			return (lock.l_pid);
80 		}
81 	}
82 	hold_daemon_lock = 1;
83 	return (getpid());
84 }
85 
86 
87 /*
88  * Drop the advisory daemon lock, close lock file
89  */
90 static void
91 exit_daemon_lock(void)
92 {
93 	struct flock lock;
94 
95 	lock.l_type = F_UNLCK;
96 	lock.l_whence = SEEK_SET;
97 	lock.l_start = 0;
98 	lock.l_len = 0;
99 
100 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
101 		syslog(LOG_DAEMON | LOG_DEBUG, gettext("unlock(%s) - %s"),
102 		    daemon_lock_file, strerror(errno));
103 		return;
104 	}
105 
106 	if (close(daemon_lock_fd) == -1) {
107 		syslog(LOG_DAEMON | LOG_DEBUG,
108 		    gettext("close(%s) failed - %s\n"),
109 			    daemon_lock_file, strerror(errno));
110 		return;
111 	}
112 	unlink(daemon_lock_file);
113 }
114 
115 /*
116  * Purpose of this routine is to accept a message from the local kernel and
117  * send this message using rpc to the master node.
118  * when an ok comes from the master we call door_return()
119  */
120 
121 /* ARGSUSED */
122 static void
123 door2rpc(void *cookie,		/* required by the doors infrastructure */
124 	char *argp,
125 	size_t arg_size,	/* required by the doors infrastructure */
126 	door_desc_t *dp,	/* required by the doors infrastructure */
127 	uint_t n_desc)		/* required by the doors infrastructure */
128 {
129 	int		err;
130 	int		size;
131 	md_error_t	ep = mdnullerror;
132 	md_mn_result_t	*result = NULL;
133 	md_mn_kresult_t	kresult;
134 
135 	md_mn_kmsg_t *kmsg = (md_mn_kmsg_t *)(void *)argp;
136 	err = mdmn_send_message(kmsg->kmsg_setno,
137 				kmsg->kmsg_type,
138 				kmsg->kmsg_flags,
139 				(char *)&(kmsg->kmsg_data),
140 				kmsg->kmsg_size,
141 				&result,
142 				&ep);
143 	if (result == NULL) {
144 		kresult.kmmr_comm_state = MDMNE_RPC_FAIL;
145 	} else {
146 		kresult.kmmr_comm_state = result->mmr_comm_state;
147 	}
148 	if (err == 0) {
149 		kresult.kmmr_msgtype = result->mmr_msgtype;
150 		kresult.kmmr_flags = result->mmr_flags;
151 		kresult.kmmr_exitval = result->mmr_exitval;
152 		kresult.kmmr_failing_node = result->mmr_failing_node;
153 		size = result->mmr_out_size;
154 		if (size > 0) {
155 			/* This is the maximum of data we can transfer, here */
156 			if (size > MDMN_MAX_KRES_DATA) {
157 				size = MDMN_MAX_KRES_DATA;
158 			}
159 			bcopy(result->mmr_out, &(kresult.kmmr_res_data), size);
160 			kresult.kmmr_res_size = size;
161 		} else {
162 			kresult.kmmr_res_size = 0;
163 		}
164 	}
165 
166 	if (result != NULL) {
167 		free_result(result);
168 	}
169 
170 	door_return((char *)&kresult, sizeof (md_mn_kresult_t), NULL, 0);
171 }
172 
173 
174 /* ARGSUSED */
175 int
176 main(void)
177 {
178 
179 	int		i;
180 	int		mdmn_door_handle;
181 	pid_t		pid;
182 	int		size;
183 	md_error_t	ep = mdnullerror;
184 	struct rlimit	rl;
185 
186 	/*
187 	 * Get the locale set up before calling any other routines
188 	 * with messages to ouput.  Just in case we're not in a build
189 	 * environment, make sure that TEXT_DOMAIN gets set to
190 	 * something.
191 	 */
192 #if !defined(TEXT_DOMAIN)
193 #define	TEXT_DOMAIN "SYS_TEST"
194 #endif
195 	(void) setlocale(LC_ALL, "");
196 	(void) textdomain(TEXT_DOMAIN);
197 
198 	openlog("mddoors", LOG_PID, LOG_DAEMON);
199 
200 	/* here beginneth the daemonizing code */
201 	pid = fork();
202 	if (pid < 0) {
203 		syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot fork"));
204 		exit(1);
205 	}
206 
207 	if (pid) {
208 		exit(0);
209 	}
210 
211 	/*
212 	 * Only one daemon can run at a time.
213 	 * If another instance is already running, this is not an error.
214 	 */
215 	if ((pid = enter_daemon_lock()) != getpid()) {
216 		exit(0);
217 	}
218 
219 	rl.rlim_max = 0;
220 	getrlimit(RLIMIT_NOFILE, &rl);
221 	if ((size = rl.rlim_max) == 0) {
222 		syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot getrlimit"));
223 		exit(1);
224 	}
225 
226 	for (i = 0; i < size; i++) {
227 		if (i == daemon_lock_fd)
228 			continue;
229 		(void) close(i);
230 	}
231 
232 
233 	i = open("/dev/null", 2);
234 	(void) dup2(i, 1);
235 	(void) dup2(i, 2);
236 	setsid();
237 
238 	/* here endeth the daemonizing code */
239 
240 	/* Block out the usual signals so we don't get killed unintentionally */
241 	(void) signal(SIGHUP, SIG_IGN);
242 	(void) signal(SIGINT, SIG_IGN);
243 	(void) signal(SIGQUIT, SIG_IGN);
244 	(void) signal(SIGTERM, SIG_IGN);
245 
246 	atexit(daemon_cleanup);
247 
248 	/* Resume any previously blocked resync */
249 	meta_mirror_resync_unblock_all();
250 
251 	/*
252 	 * At this point we are single threaded.
253 	 * We give mdmn_send_message() a chance to initialize safely.
254 	 */
255 	(void) mdmn_send_message(0, 0, 0, 0, 0, 0, 0);
256 
257 	/* setup the door handle */
258 	mdmn_door_handle = door_create(door2rpc, NULL,
259 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
260 	if (mdmn_door_handle == -1) {
261 		perror(gettext("door_create failed"));
262 		syslog(LOG_DAEMON | LOG_ERR, gettext("door_create failed"));
263 		exit(1);
264 	}
265 
266 	if (metaioctl(MD_MN_SET_DOORH, &mdmn_door_handle, &ep,
267 	    "mddoors") != 0) {
268 		syslog(LOG_DAEMON | LOG_DEBUG, gettext(
269 			"Couldn't set door handle"));
270 		exit(1);
271 	}
272 
273 	(void) pause();
274 	syslog(LOG_DAEMON | LOG_ERR, gettext(
275 			"Unexpected exit from pause()"));
276 	return (1);
277 }
278