xref: /onnv-gate/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c (revision 12140:3d7db9f327ef)
110023SGordon.Ross@Sun.COM /*
210023SGordon.Ross@Sun.COM  * CDDL HEADER START
310023SGordon.Ross@Sun.COM  *
410023SGordon.Ross@Sun.COM  * The contents of this file are subject to the terms of the
510023SGordon.Ross@Sun.COM  * Common Development and Distribution License (the "License").
610023SGordon.Ross@Sun.COM  * You may not use this file except in compliance with the License.
710023SGordon.Ross@Sun.COM  *
810023SGordon.Ross@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910023SGordon.Ross@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010023SGordon.Ross@Sun.COM  * See the License for the specific language governing permissions
1110023SGordon.Ross@Sun.COM  * and limitations under the License.
1210023SGordon.Ross@Sun.COM  *
1310023SGordon.Ross@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410023SGordon.Ross@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510023SGordon.Ross@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610023SGordon.Ross@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710023SGordon.Ross@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810023SGordon.Ross@Sun.COM  *
1910023SGordon.Ross@Sun.COM  * CDDL HEADER END
2010023SGordon.Ross@Sun.COM  */
2110023SGordon.Ross@Sun.COM 
2210023SGordon.Ross@Sun.COM /*
23*12140SGordon.Ross@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410023SGordon.Ross@Sun.COM  */
2510023SGordon.Ross@Sun.COM 
2610023SGordon.Ross@Sun.COM /*
2710023SGordon.Ross@Sun.COM  * SMBFS I/O Deamon (smbiod)
2810023SGordon.Ross@Sun.COM  */
2910023SGordon.Ross@Sun.COM 
3010023SGordon.Ross@Sun.COM #include <sys/types.h>
3110023SGordon.Ross@Sun.COM #include <sys/stat.h>
3210023SGordon.Ross@Sun.COM #include <sys/note.h>
3310023SGordon.Ross@Sun.COM 
3410023SGordon.Ross@Sun.COM #include <errno.h>
3510023SGordon.Ross@Sun.COM #include <fcntl.h>
3610023SGordon.Ross@Sun.COM #include <signal.h>
3710023SGordon.Ross@Sun.COM #include <stdarg.h>
3810023SGordon.Ross@Sun.COM #include <stdio.h>
3910023SGordon.Ross@Sun.COM #include <string.h>
4010023SGordon.Ross@Sun.COM #include <strings.h>
4110023SGordon.Ross@Sun.COM #include <stdlib.h>
4210023SGordon.Ross@Sun.COM #include <synch.h>
4310023SGordon.Ross@Sun.COM #include <time.h>
4410023SGordon.Ross@Sun.COM #include <unistd.h>
4510023SGordon.Ross@Sun.COM #include <ucred.h>
4610023SGordon.Ross@Sun.COM 
4710023SGordon.Ross@Sun.COM #include <err.h>
4810023SGordon.Ross@Sun.COM #include <door.h>
4910023SGordon.Ross@Sun.COM #include <thread.h>
5010023SGordon.Ross@Sun.COM 
5110023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h>
5210023SGordon.Ross@Sun.COM 
5310023SGordon.Ross@Sun.COM #define	EXIT_FAIL	1
5410023SGordon.Ross@Sun.COM #define	EXIT_OK		0
5510023SGordon.Ross@Sun.COM 
5610023SGordon.Ross@Sun.COM #if defined(DEBUG) || defined(__lint)
5710023SGordon.Ross@Sun.COM #define	DPRINT(...)	do \
5810023SGordon.Ross@Sun.COM { \
5910023SGordon.Ross@Sun.COM 	if (smb_debug) \
6010023SGordon.Ross@Sun.COM 		fprintf(stderr, __VA_ARGS__); \
6110023SGordon.Ross@Sun.COM 	_NOTE(CONSTCOND) \
6210023SGordon.Ross@Sun.COM } while (0)
6310023SGordon.Ross@Sun.COM #else
6410023SGordon.Ross@Sun.COM #define	DPRINT(...) ((void)0)
6510023SGordon.Ross@Sun.COM #endif
6610023SGordon.Ross@Sun.COM 
6710023SGordon.Ross@Sun.COM mutex_t	iod_mutex = DEFAULTMUTEX;
6810023SGordon.Ross@Sun.COM int iod_thr_count;	/* threads, excluding main */
6910023SGordon.Ross@Sun.COM int iod_terminating;
70*12140SGordon.Ross@Sun.COM int iod_alarm_time = 30; /* sec. */
7110023SGordon.Ross@Sun.COM 
7210023SGordon.Ross@Sun.COM void iod_dispatch(void *cookie, char *argp, size_t argsz,
7310023SGordon.Ross@Sun.COM     door_desc_t *dp, uint_t n_desc);
7410023SGordon.Ross@Sun.COM int iod_newvc(smb_iod_ssn_t *clnt_ssn);
7510023SGordon.Ross@Sun.COM void * iod_work(void *arg);
7610023SGordon.Ross@Sun.COM 
7710023SGordon.Ross@Sun.COM int
7810023SGordon.Ross@Sun.COM main(int argc, char **argv)
7910023SGordon.Ross@Sun.COM {
8010023SGordon.Ross@Sun.COM 	static const int door_attrs =
8110023SGordon.Ross@Sun.COM 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL;
8210023SGordon.Ross@Sun.COM 	sigset_t oldmask, tmpmask;
8310023SGordon.Ross@Sun.COM 	char *env, *door_path = NULL;
8410023SGordon.Ross@Sun.COM 	int door_fd = -1, tmp_fd = -1;
8510023SGordon.Ross@Sun.COM 	int err, i, sig;
8610023SGordon.Ross@Sun.COM 	int rc = EXIT_FAIL;
8710023SGordon.Ross@Sun.COM 
8810023SGordon.Ross@Sun.COM 	/* Debugging support. */
8910023SGordon.Ross@Sun.COM 	if ((env = getenv("SMBFS_DEBUG")) != NULL) {
9010023SGordon.Ross@Sun.COM 		smb_debug = atoi(env);
9110023SGordon.Ross@Sun.COM 		if (smb_debug < 1)
9210023SGordon.Ross@Sun.COM 			smb_debug = 1;
93*12140SGordon.Ross@Sun.COM 		iod_alarm_time = 300;
9410023SGordon.Ross@Sun.COM 	}
9510023SGordon.Ross@Sun.COM 
9610023SGordon.Ross@Sun.COM 	/*
9710023SGordon.Ross@Sun.COM 	 * Find out if an IOD is already running.
9810023SGordon.Ross@Sun.COM 	 * If so, we lost a harmless startup race.
9910023SGordon.Ross@Sun.COM 	 * An IOD did start, so exit success.
10010023SGordon.Ross@Sun.COM 	 */
10110023SGordon.Ross@Sun.COM 	err = smb_iod_open_door(&door_fd);
10210023SGordon.Ross@Sun.COM 	if (err == 0) {
10310023SGordon.Ross@Sun.COM 		close(door_fd);
10410023SGordon.Ross@Sun.COM 		door_fd = -1;
10510023SGordon.Ross@Sun.COM 		DPRINT("main: already running\n");
10610023SGordon.Ross@Sun.COM 		exit(EXIT_OK);
10710023SGordon.Ross@Sun.COM 	}
10810023SGordon.Ross@Sun.COM 
10910023SGordon.Ross@Sun.COM 	/*
11010023SGordon.Ross@Sun.COM 	 * Create a file for the door.
11110023SGordon.Ross@Sun.COM 	 */
11210023SGordon.Ross@Sun.COM 	door_path = smb_iod_door_path();
11310023SGordon.Ross@Sun.COM 	unlink(door_path);
11410023SGordon.Ross@Sun.COM 	tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0600);
11510023SGordon.Ross@Sun.COM 	if (tmp_fd < 0) {
11610023SGordon.Ross@Sun.COM 		perror(door_path);
11710023SGordon.Ross@Sun.COM 		exit(EXIT_FAIL);
11810023SGordon.Ross@Sun.COM 	}
11910023SGordon.Ross@Sun.COM 	close(tmp_fd);
12010023SGordon.Ross@Sun.COM 	tmp_fd = -1;
12110023SGordon.Ross@Sun.COM 
12210023SGordon.Ross@Sun.COM 
12310023SGordon.Ross@Sun.COM 	/*
12410023SGordon.Ross@Sun.COM 	 * Close FDs 0,1,2 so we don't have a TTY, and
12510023SGordon.Ross@Sun.COM 	 * re-open them on /dev/null so they won't be
12610023SGordon.Ross@Sun.COM 	 * used for device handles (etc.) later, and
12710023SGordon.Ross@Sun.COM 	 * we don't have to worry about printf calls
12810023SGordon.Ross@Sun.COM 	 * or whatever going to these FDs.
12910023SGordon.Ross@Sun.COM 	 */
13010023SGordon.Ross@Sun.COM 	for (i = 0; i < 3; i++) {
13110023SGordon.Ross@Sun.COM 		/* Exception: If smb_debug, keep stderr */
13210023SGordon.Ross@Sun.COM 		if (smb_debug && i == 2)
13310023SGordon.Ross@Sun.COM 			break;
13410023SGordon.Ross@Sun.COM 		close(i);
13510023SGordon.Ross@Sun.COM 		tmp_fd = open("/dev/null", O_RDWR);
13610023SGordon.Ross@Sun.COM 		if (tmp_fd < 0)
13710023SGordon.Ross@Sun.COM 			perror("/dev/null");
13810023SGordon.Ross@Sun.COM 		if (tmp_fd != i)
13910023SGordon.Ross@Sun.COM 			DPRINT("Open /dev/null - wrong fd?\n");
14010023SGordon.Ross@Sun.COM 	}
14110023SGordon.Ross@Sun.COM 
14210023SGordon.Ross@Sun.COM 	/*
14310023SGordon.Ross@Sun.COM 	 * Become session leader.
14410023SGordon.Ross@Sun.COM 	 */
14510023SGordon.Ross@Sun.COM 	setsid();
14610023SGordon.Ross@Sun.COM 
14710023SGordon.Ross@Sun.COM 	/*
14810023SGordon.Ross@Sun.COM 	 * Create door service threads with signals blocked.
14910023SGordon.Ross@Sun.COM 	 */
15010023SGordon.Ross@Sun.COM 	sigfillset(&tmpmask);
15110023SGordon.Ross@Sun.COM 	sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
15210023SGordon.Ross@Sun.COM 
15310023SGordon.Ross@Sun.COM 	/* Setup the door service. */
15410023SGordon.Ross@Sun.COM 	door_fd = door_create(iod_dispatch, NULL, door_attrs);
15510023SGordon.Ross@Sun.COM 	if (door_fd < 0) {
15610023SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: door_create failed\n", argv[0]);
15710023SGordon.Ross@Sun.COM 		rc = EXIT_FAIL;
15810023SGordon.Ross@Sun.COM 		goto errout;
15910023SGordon.Ross@Sun.COM 	}
16010023SGordon.Ross@Sun.COM 	fdetach(door_path);
16110023SGordon.Ross@Sun.COM 	if (fattach(door_fd, door_path) < 0) {
16210023SGordon.Ross@Sun.COM 		fprintf(stderr, "%s: fattach failed\n", argv[0]);
16310023SGordon.Ross@Sun.COM 		rc = EXIT_FAIL;
16410023SGordon.Ross@Sun.COM 		goto errout;
16510023SGordon.Ross@Sun.COM 	}
16610023SGordon.Ross@Sun.COM 
16710023SGordon.Ross@Sun.COM 	/*
16810023SGordon.Ross@Sun.COM 	 * Post the initial alarm, and then just
16910023SGordon.Ross@Sun.COM 	 * wait for signals.
17010023SGordon.Ross@Sun.COM 	 */
171*12140SGordon.Ross@Sun.COM 	alarm(iod_alarm_time);
17210023SGordon.Ross@Sun.COM again:
17310023SGordon.Ross@Sun.COM 	sig = sigwait(&tmpmask);
17410023SGordon.Ross@Sun.COM 	DPRINT("main: sig=%d\n", sig);
17510023SGordon.Ross@Sun.COM 
17610023SGordon.Ross@Sun.COM 	/*
17710023SGordon.Ross@Sun.COM 	 * If a door call races with the alarm, ignore the alarm.
17810023SGordon.Ross@Sun.COM 	 * It will be rescheduled when the threads go away.
17910023SGordon.Ross@Sun.COM 	 */
18010023SGordon.Ross@Sun.COM 	mutex_lock(&iod_mutex);
18110023SGordon.Ross@Sun.COM 	if (sig == SIGALRM && iod_thr_count > 0) {
18210023SGordon.Ross@Sun.COM 		mutex_unlock(&iod_mutex);
18310023SGordon.Ross@Sun.COM 		goto again;
18410023SGordon.Ross@Sun.COM 	}
18510023SGordon.Ross@Sun.COM 	iod_terminating = 1;
18610023SGordon.Ross@Sun.COM 	mutex_unlock(&iod_mutex);
18710023SGordon.Ross@Sun.COM 	rc = EXIT_OK;
18810023SGordon.Ross@Sun.COM 
18910023SGordon.Ross@Sun.COM errout:
19010023SGordon.Ross@Sun.COM 	fdetach(door_path);
19110023SGordon.Ross@Sun.COM 	door_revoke(door_fd);
19210023SGordon.Ross@Sun.COM 	door_fd = -1;
19310023SGordon.Ross@Sun.COM 	unlink(door_path);
19410023SGordon.Ross@Sun.COM 
19510023SGordon.Ross@Sun.COM 	return (rc);
19610023SGordon.Ross@Sun.COM }
19710023SGordon.Ross@Sun.COM 
19810023SGordon.Ross@Sun.COM /*ARGSUSED*/
19910023SGordon.Ross@Sun.COM void
20010023SGordon.Ross@Sun.COM iod_dispatch(void *cookie, char *argp, size_t argsz,
20110023SGordon.Ross@Sun.COM     door_desc_t *dp, uint_t n_desc)
20210023SGordon.Ross@Sun.COM {
20310023SGordon.Ross@Sun.COM 	smb_iod_ssn_t *ssn;
20410023SGordon.Ross@Sun.COM 	ucred_t *ucred;
20510023SGordon.Ross@Sun.COM 	uid_t cl_uid;
20610023SGordon.Ross@Sun.COM 	int rc;
20710023SGordon.Ross@Sun.COM 
20810023SGordon.Ross@Sun.COM 	/*
20910023SGordon.Ross@Sun.COM 	 * Verify that the calling process has the same UID.
21010023SGordon.Ross@Sun.COM 	 * Paranoia:  The door we created has mode 0600, so
21110023SGordon.Ross@Sun.COM 	 * this check is probably redundant.
21210023SGordon.Ross@Sun.COM 	 */
21310023SGordon.Ross@Sun.COM 	ucred = NULL;
21410023SGordon.Ross@Sun.COM 	if (door_ucred(&ucred) != 0) {
21510023SGordon.Ross@Sun.COM 		rc = EACCES;
21610023SGordon.Ross@Sun.COM 		goto out;
21710023SGordon.Ross@Sun.COM 	}
21810023SGordon.Ross@Sun.COM 	cl_uid = ucred_getruid(ucred);
21910023SGordon.Ross@Sun.COM 	ucred_free(ucred);
22010023SGordon.Ross@Sun.COM 	ucred = NULL;
22110023SGordon.Ross@Sun.COM 	if (cl_uid != getuid()) {
22210023SGordon.Ross@Sun.COM 		DPRINT("iod_dispatch: wrong UID\n");
22310023SGordon.Ross@Sun.COM 		rc = EACCES;
22410023SGordon.Ross@Sun.COM 		goto out;
22510023SGordon.Ross@Sun.COM 	}
22610023SGordon.Ross@Sun.COM 
22710023SGordon.Ross@Sun.COM 	/*
22810023SGordon.Ross@Sun.COM 	 * The library uses a NULL arg call to check if
22910023SGordon.Ross@Sun.COM 	 * the deamon is running.  Just return zero.
23010023SGordon.Ross@Sun.COM 	 */
23110023SGordon.Ross@Sun.COM 	if (argp == NULL) {
23210023SGordon.Ross@Sun.COM 		rc = 0;
23310023SGordon.Ross@Sun.COM 		goto out;
23410023SGordon.Ross@Sun.COM 	}
23510023SGordon.Ross@Sun.COM 
23610023SGordon.Ross@Sun.COM 	/*
23710023SGordon.Ross@Sun.COM 	 * Otherwise, the arg must be the (fixed size)
23810023SGordon.Ross@Sun.COM 	 * smb_iod_ssn_t
23910023SGordon.Ross@Sun.COM 	 */
24010023SGordon.Ross@Sun.COM 	if (argsz != sizeof (*ssn)) {
24110023SGordon.Ross@Sun.COM 		rc = EINVAL;
24210023SGordon.Ross@Sun.COM 		goto out;
24310023SGordon.Ross@Sun.COM 	}
24410023SGordon.Ross@Sun.COM 
24510023SGordon.Ross@Sun.COM 	mutex_lock(&iod_mutex);
24610023SGordon.Ross@Sun.COM 	if (iod_terminating) {
24710023SGordon.Ross@Sun.COM 		mutex_unlock(&iod_mutex);
24810023SGordon.Ross@Sun.COM 		DPRINT("iod_dispatch: terminating\n");
24910023SGordon.Ross@Sun.COM 		rc = EINTR;
25010023SGordon.Ross@Sun.COM 		goto out;
25110023SGordon.Ross@Sun.COM 	}
25210023SGordon.Ross@Sun.COM 	if (iod_thr_count++ == 0) {
25310023SGordon.Ross@Sun.COM 		alarm(0);
25410023SGordon.Ross@Sun.COM 		DPRINT("iod_dispatch: cancelled alarm\n");
25510023SGordon.Ross@Sun.COM 	}
25610023SGordon.Ross@Sun.COM 	mutex_unlock(&iod_mutex);
25710023SGordon.Ross@Sun.COM 
25810023SGordon.Ross@Sun.COM 	ssn = (void *) argp;
25910023SGordon.Ross@Sun.COM 	rc = iod_newvc(ssn);
26010023SGordon.Ross@Sun.COM 
26110023SGordon.Ross@Sun.COM 	mutex_lock(&iod_mutex);
26210023SGordon.Ross@Sun.COM 	if (--iod_thr_count == 0) {
26310023SGordon.Ross@Sun.COM 		DPRINT("iod_dispatch: schedule alarm\n");
264*12140SGordon.Ross@Sun.COM 		alarm(iod_alarm_time);
26510023SGordon.Ross@Sun.COM 	}
26610023SGordon.Ross@Sun.COM 	mutex_unlock(&iod_mutex);
26710023SGordon.Ross@Sun.COM 
26810023SGordon.Ross@Sun.COM out:
26910023SGordon.Ross@Sun.COM 	door_return((void *)&rc, sizeof (rc), NULL, 0);
27010023SGordon.Ross@Sun.COM }
27110023SGordon.Ross@Sun.COM 
27210023SGordon.Ross@Sun.COM /*
27310023SGordon.Ross@Sun.COM  * Try making a connection with the server described by
27410023SGordon.Ross@Sun.COM  * the info in the smb_iod_ssn_t arg.  If successful,
27510023SGordon.Ross@Sun.COM  * start an IOD thread to service it, then return to
27610023SGordon.Ross@Sun.COM  * the client side of the door.
27710023SGordon.Ross@Sun.COM  */
27810023SGordon.Ross@Sun.COM int
27910023SGordon.Ross@Sun.COM iod_newvc(smb_iod_ssn_t *clnt_ssn)
28010023SGordon.Ross@Sun.COM {
28110023SGordon.Ross@Sun.COM 	smb_ctx_t *ctx;
28210023SGordon.Ross@Sun.COM 	thread_t tid;
28310023SGordon.Ross@Sun.COM 	int err;
28410023SGordon.Ross@Sun.COM 
28510023SGordon.Ross@Sun.COM 
28610023SGordon.Ross@Sun.COM 	/*
28710023SGordon.Ross@Sun.COM 	 * This needs to essentially "clone" the smb_ctx_t
28810023SGordon.Ross@Sun.COM 	 * from the client side of the door, or at least
28910023SGordon.Ross@Sun.COM 	 * as much of it as we need while creating a VC.
29010023SGordon.Ross@Sun.COM 	 */
29110023SGordon.Ross@Sun.COM 	err = smb_ctx_alloc(&ctx);
29210023SGordon.Ross@Sun.COM 	if (err)
29310023SGordon.Ross@Sun.COM 		return (err);
29410023SGordon.Ross@Sun.COM 	bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn));
29510023SGordon.Ross@Sun.COM 
29610023SGordon.Ross@Sun.COM 	/*
29710023SGordon.Ross@Sun.COM 	 * Do the initial connection setup here, so we can
29810023SGordon.Ross@Sun.COM 	 * report the outcome to the door client.
29910023SGordon.Ross@Sun.COM 	 */
30010023SGordon.Ross@Sun.COM 	err = smb_iod_connect(ctx);
30110023SGordon.Ross@Sun.COM 	if (err != 0)
30210023SGordon.Ross@Sun.COM 		goto out;
30310023SGordon.Ross@Sun.COM 
30410023SGordon.Ross@Sun.COM 	/*
30510023SGordon.Ross@Sun.COM 	 * Create the driver session now, so we don't
30610023SGordon.Ross@Sun.COM 	 * race with the door client findvc call.
30710023SGordon.Ross@Sun.COM 	 */
30810023SGordon.Ross@Sun.COM 	if ((err = smb_ctx_gethandle(ctx)) != 0)
30910023SGordon.Ross@Sun.COM 		goto out;
31010023SGordon.Ross@Sun.COM 	if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
31110023SGordon.Ross@Sun.COM 		err = errno;
31210023SGordon.Ross@Sun.COM 		goto out;
31310023SGordon.Ross@Sun.COM 	}
31410023SGordon.Ross@Sun.COM 
31510023SGordon.Ross@Sun.COM 	/* The rest happens in the iod_work thread. */
31610023SGordon.Ross@Sun.COM 	err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
31710023SGordon.Ross@Sun.COM 	if (err == 0) {
31810023SGordon.Ross@Sun.COM 		/*
31910023SGordon.Ross@Sun.COM 		 * Given to the new thread.
32010023SGordon.Ross@Sun.COM 		 * free at end of iod_work
32110023SGordon.Ross@Sun.COM 		 */
32210023SGordon.Ross@Sun.COM 		ctx = NULL;
32310023SGordon.Ross@Sun.COM 	}
32410023SGordon.Ross@Sun.COM 
32510023SGordon.Ross@Sun.COM out:
32610023SGordon.Ross@Sun.COM 	if (ctx)
32710023SGordon.Ross@Sun.COM 		smb_ctx_free(ctx);
32810023SGordon.Ross@Sun.COM 
32910023SGordon.Ross@Sun.COM 	return (err);
33010023SGordon.Ross@Sun.COM }
33110023SGordon.Ross@Sun.COM 
33210023SGordon.Ross@Sun.COM /*
33310023SGordon.Ross@Sun.COM  * Be the reader thread for some VC.
33410023SGordon.Ross@Sun.COM  *
33510023SGordon.Ross@Sun.COM  * This is started by a door call thread, which means
33610023SGordon.Ross@Sun.COM  * this is always at least the 2nd thread, therefore
33710023SGordon.Ross@Sun.COM  * it should never see thr_count==0 or terminating.
33810023SGordon.Ross@Sun.COM  */
33910023SGordon.Ross@Sun.COM void *
34010023SGordon.Ross@Sun.COM iod_work(void *arg)
34110023SGordon.Ross@Sun.COM {
34210023SGordon.Ross@Sun.COM 	smb_ctx_t *ctx = arg;
34310023SGordon.Ross@Sun.COM 
34410023SGordon.Ross@Sun.COM 	mutex_lock(&iod_mutex);
34510023SGordon.Ross@Sun.COM 	if (iod_thr_count++ == 0) {
34610023SGordon.Ross@Sun.COM 		alarm(0);
34710023SGordon.Ross@Sun.COM 		DPRINT("iod_work: cancelled alarm\n");
34810023SGordon.Ross@Sun.COM 	}
34910023SGordon.Ross@Sun.COM 	mutex_unlock(&iod_mutex);
35010023SGordon.Ross@Sun.COM 
35110023SGordon.Ross@Sun.COM 	(void) smb_iod_work(ctx);
35210023SGordon.Ross@Sun.COM 
35310023SGordon.Ross@Sun.COM 	mutex_lock(&iod_mutex);
35410023SGordon.Ross@Sun.COM 	if (--iod_thr_count == 0) {
35510023SGordon.Ross@Sun.COM 		DPRINT("iod_work: schedule alarm\n");
356*12140SGordon.Ross@Sun.COM 		alarm(iod_alarm_time);
35710023SGordon.Ross@Sun.COM 	}
35810023SGordon.Ross@Sun.COM 	mutex_unlock(&iod_mutex);
35910023SGordon.Ross@Sun.COM 
36010023SGordon.Ross@Sun.COM 	smb_ctx_free(ctx);
36110023SGordon.Ross@Sun.COM 	return (NULL);
36210023SGordon.Ross@Sun.COM }
363