xref: /illumos-gate/usr/src/lib/libnsl/rpc/fdsync.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*61961e0fSrobinson 
237c478bd9Sstevel@tonic-gate /*
24*61961e0fSrobinson  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This file contains functions that enables the rpc library to synchronize
307c478bd9Sstevel@tonic-gate  * between various threads while they compete for a particular file descriptor.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "mt.h"
347c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
357c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <sys/poll.h>
387c478bd9Sstevel@tonic-gate #include <syslog.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <unistd.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * A block holds an array of maxBlockSize cell and associated recursive locks
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	CELLTBLSZ	1024
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate typedef struct rpcfd_block {
507c478bd9Sstevel@tonic-gate 	struct rpcfd_block *next;	/* Next Block */
517c478bd9Sstevel@tonic-gate 	struct rpcfd_block *prev;	/* prev Block */
527c478bd9Sstevel@tonic-gate 	int 	end;			/* fd of last lock in the list */
537c478bd9Sstevel@tonic-gate 	mutex_t	lock[CELLTBLSZ];	/* recursive locks */
547c478bd9Sstevel@tonic-gate } rpcfd_block_t;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate mutex_t	rpc_fd_list_lock = DEFAULTMUTEX;	/* protects list manipulation */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* Following functions create and manipulates the dgfd lock object */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static mutex_t *search(const void *handle, int fd);
617c478bd9Sstevel@tonic-gate static rpcfd_block_t *create_block(const void *handle, int fd);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate void *
rpc_fd_init(void)647c478bd9Sstevel@tonic-gate rpc_fd_init(void)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	/*
677c478bd9Sstevel@tonic-gate 	 * Create first chunk of CELLTBLSZ
687c478bd9Sstevel@tonic-gate 	 * (No lock is required for initial creation.)
697c478bd9Sstevel@tonic-gate 	 */
707c478bd9Sstevel@tonic-gate 	return (create_block(NULL, 0));
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * If rpc_fd_lock() fails to acquire a lock, it returns non-zero (ENOMEM).
757c478bd9Sstevel@tonic-gate  * (The operation can only fail due to a malloc() failure.)
767c478bd9Sstevel@tonic-gate  * The caller of rpc_fd_lock() must call rpc_fd_unlock() even if
777c478bd9Sstevel@tonic-gate  * rpc_fd_lock() failed.  This keeps _sigoff() and _sigon() balanced.
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  * If search() and create_block() fail for rpc_fd_lock(), then search()
807c478bd9Sstevel@tonic-gate  * will fail for rpc_fd_unlock(), so mutex_lock() and mutex_unlock()
817c478bd9Sstevel@tonic-gate  * calls will be balanced.  In any case, since the mutex is marked
827c478bd9Sstevel@tonic-gate  * LOCK_ERRORCHECK, an additional mutex_unlock() does nothing.
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate int
rpc_fd_lock(const void * handle,int fd)857c478bd9Sstevel@tonic-gate rpc_fd_lock(const void *handle, int fd)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	mutex_t *mp;
887c478bd9Sstevel@tonic-gate 	rpcfd_block_t *p;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	_sigoff();
917c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&rpc_fd_list_lock);
927c478bd9Sstevel@tonic-gate 	mp = search(handle, fd);
937c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
947c478bd9Sstevel@tonic-gate 		p = create_block(handle, fd);
957c478bd9Sstevel@tonic-gate 		if (p != NULL)
967c478bd9Sstevel@tonic-gate 			mp = &p->lock[fd % CELLTBLSZ];
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&rpc_fd_list_lock);
997c478bd9Sstevel@tonic-gate 	if (mp == NULL)
1007c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1017c478bd9Sstevel@tonic-gate 	(void) mutex_lock(mp);
1027c478bd9Sstevel@tonic-gate 	return (0);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate void
rpc_fd_unlock(const void * handle,int fd)1067c478bd9Sstevel@tonic-gate rpc_fd_unlock(const void *handle, int fd)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	mutex_t *mp;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&rpc_fd_list_lock);
1117c478bd9Sstevel@tonic-gate 	mp = search(handle, fd);
1127c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&rpc_fd_list_lock);
1137c478bd9Sstevel@tonic-gate 	if (mp != NULL)
1147c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(mp);
1157c478bd9Sstevel@tonic-gate 	_sigon();
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static rpcfd_block_t *
create_block(const void * handle,int fd)1197c478bd9Sstevel@tonic-gate create_block(const void *handle, int fd)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	rpcfd_block_t *l, *lprev;
1227c478bd9Sstevel@tonic-gate 	rpcfd_block_t *p;
1237c478bd9Sstevel@tonic-gate 	int i;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	p = malloc(sizeof (rpcfd_block_t));
1267c478bd9Sstevel@tonic-gate 	if (p == NULL)
1277c478bd9Sstevel@tonic-gate 		return (NULL);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	for (i = 0; i < CELLTBLSZ; i++) {
1307c478bd9Sstevel@tonic-gate 		(void) mutex_init(&p->lock[i],
1317c478bd9Sstevel@tonic-gate 			USYNC_THREAD | LOCK_RECURSIVE | LOCK_ERRORCHECK, NULL);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 	p->end = (((fd + CELLTBLSZ) / CELLTBLSZ) * CELLTBLSZ) - 1;
1347c478bd9Sstevel@tonic-gate 	lprev = NULL;
1357c478bd9Sstevel@tonic-gate 	for (l = (rpcfd_block_t *)handle; l; l = l->next) {
1367c478bd9Sstevel@tonic-gate 		lprev = l;
1377c478bd9Sstevel@tonic-gate 		if (fd < l->end)
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	p->next = l;
1427c478bd9Sstevel@tonic-gate 	p->prev = lprev;
1437c478bd9Sstevel@tonic-gate 	if (lprev)
1447c478bd9Sstevel@tonic-gate 		lprev->next = p;
1457c478bd9Sstevel@tonic-gate 	if (l)
1467c478bd9Sstevel@tonic-gate 		l->prev = p;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (p);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Called with rpc_fd_list_lock held.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate static mutex_t *
search(const void * handle,int fd)1557c478bd9Sstevel@tonic-gate search(const void *handle, int fd)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	rpcfd_block_t *p;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	for (p = (rpcfd_block_t *)handle; p; p = p->next) {
1607c478bd9Sstevel@tonic-gate 		if (fd <= p->end)
1617c478bd9Sstevel@tonic-gate 			return (&p->lock[fd % CELLTBLSZ]);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (NULL);
1657c478bd9Sstevel@tonic-gate }
166