1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate * All rights reserved.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate * Doors-daemon (dsvclockd) synchronization strategy: contacts a standalone
31*0Sstevel@tonic-gate * daemon to coordinate access to the shared resource across multiple
32*0Sstevel@tonic-gate * processes and multiple threads within a process. Performance is slow
33*0Sstevel@tonic-gate * (about 1200 locks and unlocks per second on a Ultra 170E/167 MHz) but it
34*0Sstevel@tonic-gate * provides robust locks and scales well as the number of CPUs increase.
35*0Sstevel@tonic-gate */
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate #include <sys/types.h>
38*0Sstevel@tonic-gate #include <sys/mman.h>
39*0Sstevel@tonic-gate #include <sys/wait.h>
40*0Sstevel@tonic-gate #include <fcntl.h>
41*0Sstevel@tonic-gate #include <unistd.h>
42*0Sstevel@tonic-gate #include <dsvclockd.h>
43*0Sstevel@tonic-gate #include <door.h>
44*0Sstevel@tonic-gate #include <stdlib.h>
45*0Sstevel@tonic-gate #include <errno.h>
46*0Sstevel@tonic-gate #include <string.h>
47*0Sstevel@tonic-gate #include <stdio.h>
48*0Sstevel@tonic-gate #include <dhcp_svc_private.h>
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gate static int dsvcd_lock(dsvc_synch_t *, dsvcd_locktype_t, void **);
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate * Our synchronization-private data which hangs off of sp->s_data; This
54*0Sstevel@tonic-gate * data is thus per-open-container-instance and (of course) per-process.
55*0Sstevel@tonic-gate */
56*0Sstevel@tonic-gate typedef struct {
57*0Sstevel@tonic-gate int s_lockfd; /* door lock request fd */
58*0Sstevel@tonic-gate boolean_t s_crosshost; /* request crosshost synch */
59*0Sstevel@tonic-gate } dsvcd_synch_t;
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate * Initialize the dsvclockd synchronization strategy for an open container,
63*0Sstevel@tonic-gate * whose synchronization information ("synchronization instance") is
64*0Sstevel@tonic-gate * pointed to by `sp', by opening the door to the dsvclockd. On success,
65*0Sstevel@tonic-gate * hang our synchronization-private data off of `sp->s_data'. Returns a
66*0Sstevel@tonic-gate * DSVC_* code.
67*0Sstevel@tonic-gate */
68*0Sstevel@tonic-gate static int
dsvcd_init(dsvc_synch_t * sp,unsigned int synchflags)69*0Sstevel@tonic-gate dsvcd_init(dsvc_synch_t *sp, unsigned int synchflags)
70*0Sstevel@tonic-gate {
71*0Sstevel@tonic-gate dsvcd_synch_t *dsp;
72*0Sstevel@tonic-gate char doorpath[MAXPATHLEN];
73*0Sstevel@tonic-gate door_info_t info;
74*0Sstevel@tonic-gate unsigned int tries;
75*0Sstevel@tonic-gate pid_t dsvclockd_pid;
76*0Sstevel@tonic-gate int fd;
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate if (geteuid() != 0)
79*0Sstevel@tonic-gate return (DSVC_ACCESS);
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate dsp = malloc(sizeof (dsvcd_synch_t));
82*0Sstevel@tonic-gate sp->s_data = dsp;
83*0Sstevel@tonic-gate if (dsp == NULL)
84*0Sstevel@tonic-gate return (DSVC_NO_MEMORY);
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gate (void) snprintf(doorpath, MAXPATHLEN, DSVCD_DOOR_FMT,
87*0Sstevel@tonic-gate sp->s_datastore->d_resource);
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate dsp->s_lockfd = -1;
90*0Sstevel@tonic-gate dsp->s_crosshost = (synchflags & DSVC_SYNCH_CROSSHOST) != 0;
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gate fd = open(doorpath, O_RDONLY);
93*0Sstevel@tonic-gate if (fd == -1) {
94*0Sstevel@tonic-gate if (errno == EACCES) {
95*0Sstevel@tonic-gate free(dsp);
96*0Sstevel@tonic-gate sp->s_data = NULL;
97*0Sstevel@tonic-gate return (DSVC_ACCESS);
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate } else {
100*0Sstevel@tonic-gate if (door_info(fd, &info) == 0 && info.di_target != -1) {
101*0Sstevel@tonic-gate dsp->s_lockfd = fd;
102*0Sstevel@tonic-gate return (DSVC_SUCCESS);
103*0Sstevel@tonic-gate }
104*0Sstevel@tonic-gate (void) close(fd);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate switch (dsvclockd_pid = fork()) {
108*0Sstevel@tonic-gate case -1:
109*0Sstevel@tonic-gate break;
110*0Sstevel@tonic-gate case 0:
111*0Sstevel@tonic-gate /*
112*0Sstevel@tonic-gate * Close all descriptors so messages don't leak through.
113*0Sstevel@tonic-gate */
114*0Sstevel@tonic-gate (void) closefrom(0);
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate /*
117*0Sstevel@tonic-gate * It's okay if the exec fails; the `default' case below
118*0Sstevel@tonic-gate * will give up and return DSVC_NO_LOCKMGR.
119*0Sstevel@tonic-gate */
120*0Sstevel@tonic-gate (void) execl(DSVCD_PATH, DSVCD_PATH, (char *)0);
121*0Sstevel@tonic-gate _exit(EXIT_FAILURE);
122*0Sstevel@tonic-gate default:
123*0Sstevel@tonic-gate /*
124*0Sstevel@tonic-gate * Make five attempts to open the dsvclockd door, each
125*0Sstevel@tonic-gate * spaced a half second apart.
126*0Sstevel@tonic-gate */
127*0Sstevel@tonic-gate for (tries = 0; tries < 5; tries++) {
128*0Sstevel@tonic-gate fd = open(doorpath, O_RDONLY);
129*0Sstevel@tonic-gate if (fd != -1) {
130*0Sstevel@tonic-gate if (door_info(fd, &info) == 0 &&
131*0Sstevel@tonic-gate info.di_target != -1) {
132*0Sstevel@tonic-gate (void) waitpid(dsvclockd_pid, NULL, 0);
133*0Sstevel@tonic-gate dsp->s_lockfd = fd;
134*0Sstevel@tonic-gate return (DSVC_SUCCESS);
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate (void) close(fd);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate (void) poll(NULL, 0, 500);
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate (void) waitpid(dsvclockd_pid, NULL, 0);
141*0Sstevel@tonic-gate break;
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate free(dsp);
145*0Sstevel@tonic-gate sp->s_data = NULL;
146*0Sstevel@tonic-gate return (DSVC_NO_LOCKMGR);
147*0Sstevel@tonic-gate }
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate /*
150*0Sstevel@tonic-gate * Finish using the dsvclockd synchronization strategy on synchronization
151*0Sstevel@tonic-gate * instance `sp'.
152*0Sstevel@tonic-gate */
153*0Sstevel@tonic-gate static void
dsvcd_fini(dsvc_synch_t * sp)154*0Sstevel@tonic-gate dsvcd_fini(dsvc_synch_t *sp)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate dsvcd_synch_t *dsp = sp->s_data;
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate sp->s_data = NULL;
159*0Sstevel@tonic-gate (void) close(dsp->s_lockfd);
160*0Sstevel@tonic-gate free(dsp);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate /*
164*0Sstevel@tonic-gate * Obtain a shared lock on synchronization instance `sp'. Upon success,
165*0Sstevel@tonic-gate * `unlock_cookiep' is set to a token to pass to `dsvcd_unlock' to unlock
166*0Sstevel@tonic-gate * the lock. Returns a DSVC_* code.
167*0Sstevel@tonic-gate */
168*0Sstevel@tonic-gate static int
dsvcd_rdlock(dsvc_synch_t * sp,void ** unlock_cookiep)169*0Sstevel@tonic-gate dsvcd_rdlock(dsvc_synch_t *sp, void **unlock_cookiep)
170*0Sstevel@tonic-gate {
171*0Sstevel@tonic-gate return (dsvcd_lock(sp, DSVCD_RDLOCK, unlock_cookiep));
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate /*
175*0Sstevel@tonic-gate * Obtain an exclusive lock on synchronization instance `sp'. Upon
176*0Sstevel@tonic-gate * success, `unlock_cookiep' is set to a token to pass to `dsvcd_unlock' to
177*0Sstevel@tonic-gate * unlock the lock. Returns a DSVC_* code.
178*0Sstevel@tonic-gate */
179*0Sstevel@tonic-gate static int
dsvcd_wrlock(dsvc_synch_t * sp,void ** unlock_cookiep)180*0Sstevel@tonic-gate dsvcd_wrlock(dsvc_synch_t *sp, void **unlock_cookiep)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate return (dsvcd_lock(sp, DSVCD_WRLOCK, unlock_cookiep));
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate /*
186*0Sstevel@tonic-gate * Lock the synchronization instance `sp' with a lock of type `locktype'.
187*0Sstevel@tonic-gate * Upon success, `unlock_cookiep' is set to point to a door descriptor
188*0Sstevel@tonic-gate * which is used to unlock the lock and to detect if the caller dies
189*0Sstevel@tonic-gate * holding the lock. Returns a DSVC_* code.
190*0Sstevel@tonic-gate */
191*0Sstevel@tonic-gate static int
dsvcd_lock(dsvc_synch_t * sp,dsvcd_locktype_t locktype,void ** unlock_cookiep)192*0Sstevel@tonic-gate dsvcd_lock(dsvc_synch_t *sp, dsvcd_locktype_t locktype, void **unlock_cookiep)
193*0Sstevel@tonic-gate {
194*0Sstevel@tonic-gate door_arg_t args;
195*0Sstevel@tonic-gate dsvcd_lock_request_t request;
196*0Sstevel@tonic-gate dsvcd_reply_t reply;
197*0Sstevel@tonic-gate door_desc_t *descp;
198*0Sstevel@tonic-gate int unlockfd;
199*0Sstevel@tonic-gate int i;
200*0Sstevel@tonic-gate dsvcd_synch_t *dsp = sp->s_data;
201*0Sstevel@tonic-gate
202*0Sstevel@tonic-gate if (dsp->s_lockfd == -1)
203*0Sstevel@tonic-gate return (DSVC_NO_LOCKMGR);
204*0Sstevel@tonic-gate
205*0Sstevel@tonic-gate request.lrq_request.rq_version = DSVCD_DOOR_VERSION;
206*0Sstevel@tonic-gate request.lrq_request.rq_reqtype = DSVCD_LOCK;
207*0Sstevel@tonic-gate request.lrq_locktype = locktype;
208*0Sstevel@tonic-gate request.lrq_nonblock = sp->s_nonblock;
209*0Sstevel@tonic-gate request.lrq_crosshost = dsp->s_crosshost;
210*0Sstevel@tonic-gate request.lrq_conver = sp->s_datastore->d_conver;
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gate (void) strlcpy(request.lrq_loctoken, sp->s_loctoken,
213*0Sstevel@tonic-gate sizeof (request.lrq_loctoken));
214*0Sstevel@tonic-gate (void) strlcpy(request.lrq_conname, sp->s_conname,
215*0Sstevel@tonic-gate sizeof (request.lrq_conname));
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gate args.data_ptr = (char *)&request;
218*0Sstevel@tonic-gate args.data_size = sizeof (dsvcd_lock_request_t);
219*0Sstevel@tonic-gate args.desc_ptr = NULL;
220*0Sstevel@tonic-gate args.desc_num = 0;
221*0Sstevel@tonic-gate args.rbuf = (char *)&reply;
222*0Sstevel@tonic-gate args.rsize = sizeof (dsvcd_reply_t);
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate if (door_call(dsp->s_lockfd, &args) == -1) {
225*0Sstevel@tonic-gate /*
226*0Sstevel@tonic-gate * If the lock manager went away, we'll get back EBADF.
227*0Sstevel@tonic-gate */
228*0Sstevel@tonic-gate return (errno == EBADF ? DSVC_NO_LOCKMGR : DSVC_SYNCH_ERR);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate descp = args.desc_ptr;
232*0Sstevel@tonic-gate if (args.desc_num == 0)
233*0Sstevel@tonic-gate unlockfd = -1;
234*0Sstevel@tonic-gate else {
235*0Sstevel@tonic-gate unlockfd = descp->d_data.d_desc.d_descriptor;
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate /*
238*0Sstevel@tonic-gate * There shouldn't be more than one descriptor, but close
239*0Sstevel@tonic-gate * any extras to ease future compatibility.
240*0Sstevel@tonic-gate */
241*0Sstevel@tonic-gate for (i = 1; i < args.desc_num; i++)
242*0Sstevel@tonic-gate (void) close(descp[i].d_data.d_desc.d_descriptor);
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate if (args.rbuf != (char *)&reply) {
246*0Sstevel@tonic-gate (void) memcpy(&reply, args.rbuf, sizeof (reply));
247*0Sstevel@tonic-gate (void) munmap(args.rbuf, args.rsize);
248*0Sstevel@tonic-gate }
249*0Sstevel@tonic-gate
250*0Sstevel@tonic-gate if (args.data_size != sizeof (dsvcd_reply_t) ||
251*0Sstevel@tonic-gate reply.rp_version != DSVCD_DOOR_VERSION) {
252*0Sstevel@tonic-gate (void) close(unlockfd);
253*0Sstevel@tonic-gate return (DSVC_SYNCH_ERR);
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate if (reply.rp_retval == DSVC_SUCCESS && unlockfd == -1)
257*0Sstevel@tonic-gate return (DSVC_SYNCH_ERR);
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate *unlock_cookiep = (void *)unlockfd;
260*0Sstevel@tonic-gate return (reply.rp_retval);
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gate /*
264*0Sstevel@tonic-gate * Unlock the synchronization instance `sp' using the unlock token
265*0Sstevel@tonic-gate * `unlock_cookiep'. Returns a DSVC_* code.
266*0Sstevel@tonic-gate */
267*0Sstevel@tonic-gate /* ARGSUSED */
268*0Sstevel@tonic-gate static int
dsvcd_unlock(dsvc_synch_t * sp,void * unlock_cookie)269*0Sstevel@tonic-gate dsvcd_unlock(dsvc_synch_t *sp, void *unlock_cookie)
270*0Sstevel@tonic-gate {
271*0Sstevel@tonic-gate door_arg_t args;
272*0Sstevel@tonic-gate dsvcd_unlock_request_t request;
273*0Sstevel@tonic-gate dsvcd_reply_t reply;
274*0Sstevel@tonic-gate int unlockfd = (int)unlock_cookie;
275*0Sstevel@tonic-gate int i;
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate request.urq_request.rq_version = DSVCD_DOOR_VERSION;
278*0Sstevel@tonic-gate request.urq_request.rq_reqtype = DSVCD_UNLOCK;
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate args.data_ptr = (char *)&request;
281*0Sstevel@tonic-gate args.data_size = sizeof (dsvcd_unlock_request_t);
282*0Sstevel@tonic-gate args.desc_ptr = NULL;
283*0Sstevel@tonic-gate args.desc_num = 0;
284*0Sstevel@tonic-gate args.rbuf = (char *)&reply;
285*0Sstevel@tonic-gate args.rsize = sizeof (dsvcd_reply_t);
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate if (door_call(unlockfd, &args) == -1) {
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate * If the lock manager went away while we had a lock
290*0Sstevel@tonic-gate * checked out, regard that as a synchronization error --
291*0Sstevel@tonic-gate * it should never happen under correct operation.
292*0Sstevel@tonic-gate */
293*0Sstevel@tonic-gate return (DSVC_SYNCH_ERR);
294*0Sstevel@tonic-gate }
295*0Sstevel@tonic-gate
296*0Sstevel@tonic-gate /*
297*0Sstevel@tonic-gate * There shouldn't be any descriptors returned from the server
298*0Sstevel@tonic-gate * here, but this may change in the future -- close any to ease
299*0Sstevel@tonic-gate * future compatibility.
300*0Sstevel@tonic-gate */
301*0Sstevel@tonic-gate for (i = 0; i < args.desc_num; i++)
302*0Sstevel@tonic-gate (void) close(args.desc_ptr[i].d_data.d_desc.d_descriptor);
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate /*
305*0Sstevel@tonic-gate * Close the unlock door even if the door_call() fails; this is so
306*0Sstevel@tonic-gate * the container gets unlocked even if there's some screwup in the
307*0Sstevel@tonic-gate * graceful unlocking protocol (in that case, this will generate
308*0Sstevel@tonic-gate * a DOOR_UNREF_DATA call).
309*0Sstevel@tonic-gate */
310*0Sstevel@tonic-gate (void) close(unlockfd);
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate if (args.rbuf != (char *)&reply) {
313*0Sstevel@tonic-gate (void) memcpy(&reply, args.rbuf, sizeof (reply));
314*0Sstevel@tonic-gate (void) munmap(args.rbuf, args.rsize);
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate
317*0Sstevel@tonic-gate if (args.data_size != sizeof (dsvcd_reply_t) ||
318*0Sstevel@tonic-gate reply.rp_version != DSVCD_DOOR_VERSION)
319*0Sstevel@tonic-gate return (DSVC_SYNCH_ERR);
320*0Sstevel@tonic-gate
321*0Sstevel@tonic-gate return (reply.rp_retval);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate dsvc_synch_ops_t dsvcd_synch_ops = {
325*0Sstevel@tonic-gate dsvcd_init, dsvcd_fini, dsvcd_rdlock, dsvcd_wrlock, dsvcd_unlock
326*0Sstevel@tonic-gate };
327