4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
28 * SMBFS I/O Daemon (Per-user IOD)
31 #include <sys/types.h>
53 #include <netsmb/smb_lib.h>
55 #define DPRINT(...) do \
58 fprintf(stderr, __VA_ARGS__); \
62 mutex_t iod_mutex
= DEFAULTMUTEX
;
63 int iod_thr_count
; /* threads, excluding main */
65 int iod_alarm_time
= 30; /* sec. */
67 void iod_dispatch(void *cookie
, char *argp
, size_t argsz
,
68 door_desc_t
*dp
, uint_t n_desc
);
69 int iod_newvc(smb_iod_ssn_t
*clnt_ssn
);
70 void * iod_work(void *arg
);
73 main(int argc
, char **argv
)
75 sigset_t oldmask
, tmpmask
;
76 char *env
, *door_path
= NULL
;
79 int rc
= SMF_EXIT_ERR_FATAL
;
80 boolean_t attached
= B_FALSE
;
82 /* set locale and text domain for i18n */
83 (void) setlocale(LC_ALL
, "");
84 (void) textdomain(TEXT_DOMAIN
);
86 /* Debugging support. */
87 if ((env
= getenv("SMBFS_DEBUG")) != NULL
) {
88 smb_debug
= atoi(env
);
95 * If a user runs this command (i.e. by accident)
96 * don't interfere with any already running IOD.
98 err
= smb_iod_open_door(&door_fd
);
102 DPRINT("%s: already running\n", argv
[0]);
107 * Want all signals blocked, as we're doing
108 * synchronous delivery via sigwait below.
110 sigfillset(&tmpmask
);
111 sigprocmask(SIG_BLOCK
, &tmpmask
, &oldmask
);
113 /* Setup the door service. */
114 door_path
= smb_iod_door_path();
115 door_fd
= door_create(iod_dispatch
, NULL
,
116 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
);
118 perror("iod door_create");
122 if (fattach(door_fd
, door_path
) < 0) {
123 fprintf(stderr
, "%s: fattach failed, %s\n",
124 door_path
, strerror(errno
));
129 /* Initializations done. */
133 * Post the initial alarm, and then just
136 alarm(iod_alarm_time
);
138 sig
= sigwait(&tmpmask
);
139 DPRINT("main: sig=%d\n", sig
);
145 /* No threads active for a while. */
146 mutex_lock(&iod_mutex
);
147 if (iod_thr_count
> 0) {
149 * Door call thread creation raced with
150 * the alarm. Ignore this alaram.
152 mutex_unlock(&iod_mutex
);
155 /* Prevent a race with iod_thr_count */
157 mutex_unlock(&iod_mutex
);
162 break; /* normal termination */
165 /* Unexpected signal. */
166 fprintf(stderr
, "iod_main: unexpected sig=%d\n", sig
);
175 door_revoke(door_fd
);
178 * We need a reference in -lumem to satisfy check_rtime,
179 * else we get build hoise. This is sufficient.
188 iod_dispatch(void *cookie
, char *argp
, size_t argsz
,
189 door_desc_t
*dp
, uint_t n_desc
)
197 * Verify that the calling process has the same UID.
198 * Paranoia: The door we created has mode 0600, so
199 * this check is probably redundant.
202 if (door_ucred(&ucred
) != 0) {
206 cl_uid
= ucred_getruid(ucred
);
209 if (cl_uid
!= getuid()) {
210 DPRINT("iod_dispatch: wrong UID\n");
216 * The library uses a NULL arg call to check if
217 * the daemon is running. Just return zero.
225 * Otherwise, the arg must be the (fixed size)
228 if (argsz
!= sizeof (*ssn
)) {
233 mutex_lock(&iod_mutex
);
234 if (iod_terminating
) {
235 mutex_unlock(&iod_mutex
);
236 DPRINT("iod_dispatch: terminating\n");
240 if (iod_thr_count
++ == 0) {
242 DPRINT("iod_dispatch: cancelled alarm\n");
244 mutex_unlock(&iod_mutex
);
249 mutex_lock(&iod_mutex
);
250 if (--iod_thr_count
== 0) {
251 DPRINT("iod_dispatch: schedule alarm\n");
252 alarm(iod_alarm_time
);
254 mutex_unlock(&iod_mutex
);
257 door_return((void *)&rc
, sizeof (rc
), NULL
, 0);
261 * Try making a connection with the server described by
262 * the info in the smb_iod_ssn_t arg. If successful,
263 * start an IOD thread to service it, then return to
264 * the client side of the door.
267 iod_newvc(smb_iod_ssn_t
*clnt_ssn
)
275 * This needs to essentially "clone" the smb_ctx_t
276 * from the client side of the door, or at least
277 * as much of it as we need while creating a VC.
279 err
= smb_ctx_alloc(&ctx
);
282 bcopy(clnt_ssn
, &ctx
->ct_iod_ssn
, sizeof (ctx
->ct_iod_ssn
));
285 * Create the driver session first, so that any subsequent
286 * requests for the same session will find this one and
287 * wait, the same as when a reconnect is triggered.
289 * There is still an inherent race here, where two callers
290 * both find no VC in the driver, and both come here trying
291 * to create the VC. In this case, we want the first one
292 * to actually do the VC setup, and the second to proceed
293 * as if the VC had been found in the driver. The second
294 * caller gets an EEXIST error from the ioctl in this case,
295 * which we therefore ignore here so that the caller will
296 * go ahead and look again in the driver for the new VC.
298 if ((err
= smb_ctx_gethandle(ctx
)) != 0)
300 if (ioctl(ctx
->ct_dev_fd
, SMBIOC_SSN_CREATE
, &ctx
->ct_ssn
) < 0) {
303 err
= 0; /* see above */
308 * Do the initial connection setup here, so we can
309 * report the outcome to the door client.
311 err
= smb_iod_connect(ctx
);
315 /* The rest happens in the iod_work thread. */
316 err
= thr_create(NULL
, 0, iod_work
, ctx
, THR_DETACHED
, &tid
);
319 * Given to the new thread.
320 * free at end of iod_work
333 * Be the reader thread for some VC.
335 * This is started by a door call thread, which means
336 * this is always at least the 2nd thread, therefore
337 * it should never see thr_count==0 or terminating.
342 smb_ctx_t
*ctx
= arg
;
344 mutex_lock(&iod_mutex
);
345 if (iod_thr_count
++ == 0) {
347 DPRINT("iod_work: cancelled alarm\n");
349 mutex_unlock(&iod_mutex
);
351 (void) smb_iod_work(ctx
);
353 mutex_lock(&iod_mutex
);
354 if (--iod_thr_count
== 0) {
355 DPRINT("iod_work: schedule alarm\n");
356 alarm(iod_alarm_time
);
358 mutex_unlock(&iod_mutex
);