Home | History | Annotate | Download | only in portfs
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 
     28 #include <sys/types.h>
     29 #include <sys/systm.h>
     30 #include <sys/stat.h>
     31 #include <sys/errno.h>
     32 #include <sys/kmem.h>
     33 #include <sys/sysmacros.h>
     34 #include <sys/debug.h>
     35 #include <sys/poll_impl.h>
     36 #include <sys/port_impl.h>
     37 
     38 #define	PORTHASH_START	256	/* start cache space for events */
     39 #define	PORTHASH_MULT	2	/* growth threshold and factor */
     40 
     41 /* local functions */
     42 static int	port_fd_callback(void *, int *, pid_t, int, void *);
     43 static int	port_bind_pollhead(pollhead_t **, polldat_t *, short *);
     44 static void	port_close_sourcefd(void *, int, pid_t, int);
     45 static void	port_cache_insert_fd(port_fdcache_t *, polldat_t *);
     46 
     47 /*
     48  * port_fd_callback()
     49  * The event port framework uses callback functions to notify associated
     50  * event sources about actions on source specific objects.
     51  * The source itself defines the "arg" required to identify the object with
     52  * events. In the port_fd_callback() case the "arg" is a pointer to portfd_t
     53  * structure. The portfd_t structure is specific for PORT_SOURCE_FD source.
     54  * The port_fd_callback() function is notified in three cases:
     55  * - PORT_CALLBACK_DEFAULT
     56  *	The object (fd) will be delivered to the application.
     57  * - PORT_CALLBACK_DISSOCIATE
     58  *	The object (fd) will be dissociated from  the port.
     59  * - PORT_CALLBACK_CLOSE
     60  *	The object (fd) will be dissociated from the port because the port
     61  *	is being closed.
     62  * A fd is shareable between processes only when
     63  * - processes have the same fd id and
     64  * - processes have the same fp.
     65  * A fd becomes shareable:
     66  * - on fork() across parent and child process and
     67  * - when I_SENDFD is used to pass file descriptors between parent and child
     68  *   immediately after fork() (the sender and receiver must get the same
     69  *   file descriptor id).
     70  * If a fd is shared between processes, all involved processes will get
     71  * the same rights related to re-association of the fd with the port and
     72  * retrieve of events from that fd.
     73  * The process which associated the fd with a port for the first time
     74  * becomes also the owner of the association. Only the owner of the
     75  * association is allowed to dissociate the fd from the port.
     76  */
     77 /* ARGSUSED */
     78 static int
     79 port_fd_callback(void *arg, int *events, pid_t pid, int flag, void *evp)
     80 {
     81 	portfd_t	*pfd = (portfd_t *)arg;
     82 	polldat_t	*pdp = PFTOD(pfd);
     83 	port_fdcache_t	*pcp;
     84 	file_t		*fp;
     85 	int		error;
     86 
     87 	ASSERT((pdp != NULL) && (events != NULL));
     88 	switch (flag) {
     89 	case PORT_CALLBACK_DEFAULT:
     90 		if (curproc->p_pid != pid) {
     91 			/*
     92 			 * Check if current process is allowed to retrieve
     93 			 * events from this fd.
     94 			 */
     95 			fp = getf(pdp->pd_fd);
     96 			if (fp == NULL) {
     97 				error = EACCES; /* deny delivery of events */
     98 				break;
     99 			}
    100 			releasef(pdp->pd_fd);
    101 			if (fp != pdp->pd_fp) {
    102 				error = EACCES; /* deny delivery of events */
    103 				break;
    104 			}
    105 		}
    106 		*events = pdp->pd_portev->portkev_events; /* update events */
    107 		error = 0;
    108 		break;
    109 	case PORT_CALLBACK_DISSOCIATE:
    110 		error = 0;
    111 		break;
    112 	case PORT_CALLBACK_CLOSE:
    113 		/* remove polldat/portfd struct */
    114 		pdp->pd_portev = NULL;
    115 		pcp = (port_fdcache_t *)pdp->pd_pcache;
    116 		mutex_enter(&pcp->pc_lock);
    117 		pdp->pd_fp = NULL;
    118 		pdp->pd_events = 0;
    119 		if (pdp->pd_php != NULL) {
    120 			pollhead_delete(pdp->pd_php, pdp);
    121 			pdp->pd_php = NULL;
    122 		}
    123 		port_pcache_remove_fd(pcp, pfd);
    124 		mutex_exit(&pcp->pc_lock);
    125 		error = 0;
    126 		break;
    127 	default:
    128 		error = EINVAL;
    129 		break;
    130 	}
    131 	return (error);
    132 }
    133 
    134 /*
    135  * This routine returns a pointer to a cached poll fd entry, or NULL if it
    136  * does not find it in the hash table.
    137  * The fd is used as index.
    138  * The fd and the fp are used to detect a valid entry.
    139  * This function returns a pointer to a valid portfd_t structure only when
    140  * the fd and the fp in the args match the entries in polldat_t.
    141  */
    142 portfd_t *
    143 port_cache_lookup_fp(port_fdcache_t *pcp, int fd, file_t *fp)
    144 {
    145 	polldat_t	*pdp;
    146 	portfd_t	**bucket;
    147 
    148 	ASSERT(MUTEX_HELD(&pcp->pc_lock));
    149 	bucket = PORT_FD_BUCKET(pcp, fd);
    150 	pdp = PFTOD(*bucket);
    151 	while (pdp != NULL) {
    152 		if (pdp->pd_fd == fd && pdp->pd_fp == fp)
    153 			break;
    154 		pdp = pdp->pd_hashnext;
    155 	}
    156 	return (PDTOF(pdp));
    157 }
    158 
    159 /*
    160  * port_associate_fd()
    161  * This function associates new file descriptors with a port or
    162  * reactivate already associated file descriptors.
    163  * The reactivation also updates the events types to be checked and the
    164  * attached user pointer.
    165  * Per port a cache is used to store associated file descriptors.
    166  * Internally the VOP_POLL interface is used to poll for existing events.
    167  * The VOP_POLL interface can also deliver a pointer to a pollhead_t structure
    168  * which is used to enqueue polldat_t structures with pending events.
    169  * If VOP_POLL immediately returns valid events (revents) then those events
    170  * will be submitted to the event port with port_send_event().
    171  * Otherwise VOP_POLL does not return events but it delivers a pointer to a
    172  * pollhead_t structure. In such a case the corresponding file system behind
    173  * VOP_POLL will use the pollwakeup() function to notify about existing
    174  * events.
    175  */
    176 int
    177 port_associate_fd(port_t *pp, int source, uintptr_t object, int events,
    178     void *user)
    179 {
    180 	port_fdcache_t	*pcp;
    181 	int		fd;
    182 	struct pollhead	*php = NULL;
    183 	portfd_t	*pfd;
    184 	polldat_t	*pdp;
    185 	file_t		*fp;
    186 	port_kevent_t	*pkevp;
    187 	short		revents;
    188 	int		error = 0;
    189 	int		active;
    190 
    191 	pcp = pp->port_queue.portq_pcp;
    192 	if (object > (uintptr_t)INT_MAX)
    193 		return (EBADFD);
    194 
    195 	fd = object;
    196 
    197 	if ((fp = getf(fd)) == NULL)
    198 		return (EBADFD);
    199 
    200 	mutex_enter(&pcp->pc_lock);
    201 
    202 	if (pcp->pc_hash == NULL) {
    203 		/*
    204 		 * This is the first time that a fd is being associated with
    205 		 * the current port:
    206 		 * - create PORT_SOURCE_FD cache
    207 		 * - associate PORT_SOURCE_FD source with the port
    208 		 */
    209 		error = port_associate_ksource(pp->port_fd, PORT_SOURCE_FD,
    210 		    NULL, port_close_sourcefd, pp, NULL);
    211 		if (error) {
    212 			mutex_exit(&pcp->pc_lock);
    213 			releasef(fd);
    214 			return (error);
    215 		}
    216 
    217 		/* create polldat cache */
    218 		pcp->pc_hashsize = PORTHASH_START;
    219 		pcp->pc_hash = kmem_zalloc(pcp->pc_hashsize *
    220 		    sizeof (portfd_t *), KM_SLEEP);
    221 		pfd = NULL;
    222 	} else {
    223 		/* Check if the fd/fp is already associated with the port */
    224 		pfd = port_cache_lookup_fp(pcp, fd, fp);
    225 	}
    226 
    227 	if (pfd == NULL) {
    228 		/*
    229 		 * new entry
    230 		 * Allocate a polldat_t structure per fd
    231 		 * The use of the polldat_t structure to cache file descriptors
    232 		 * is required to be able to share the pollwakeup() function
    233 		 * with poll(2) and devpoll(7d).
    234 		 */
    235 		pfd = kmem_zalloc(sizeof (portfd_t), KM_SLEEP);
    236 		pdp = PFTOD(pfd);
    237 		pdp->pd_fd = fd;
    238 		pdp->pd_fp = fp;
    239 		pdp->pd_pcache = (void *)pcp;
    240 
    241 		/* Allocate a port event structure per fd */
    242 		error = port_alloc_event_local(pp, source, PORT_ALLOC_CACHED,
    243 		    &pdp->pd_portev);
    244 		if (error) {
    245 			kmem_free(pfd, sizeof (portfd_t));
    246 			releasef(fd);
    247 			mutex_exit(&pcp->pc_lock);
    248 			return (error);
    249 		}
    250 		pkevp = pdp->pd_portev;
    251 		pkevp->portkev_callback = port_fd_callback;
    252 		pkevp->portkev_arg = pfd;
    253 
    254 		/* add portfd_t entry  to the cache */
    255 		port_cache_insert_fd(pcp, pdp);
    256 		pkevp->portkev_object = fd;
    257 		pkevp->portkev_user = user;
    258 
    259 		/*
    260 		 * Add current port to the file descriptor interested list
    261 		 * The members of the list are notified when the file descriptor
    262 		 * is closed.
    263 		 */
    264 		addfd_port(fd, pfd);
    265 	} else {
    266 		/*
    267 		 * The file descriptor is already associated with the port
    268 		 */
    269 		pdp = PFTOD(pfd);
    270 		pkevp = pdp->pd_portev;
    271 
    272 		/*
    273 		 * Check if the re-association happens before the last
    274 		 * submitted event of the file descriptor was retrieved.
    275 		 * Clear the PORT_KEV_VALID flag if set. No new events
    276 		 * should get submitted after this flag is cleared.
    277 		 */
    278 		mutex_enter(&pkevp->portkev_lock);
    279 		if (pkevp->portkev_flags & PORT_KEV_VALID) {
    280 			pkevp->portkev_flags &= ~PORT_KEV_VALID;
    281 		}
    282 		if (pkevp->portkev_flags & PORT_KEV_DONEQ) {
    283 			mutex_exit(&pkevp->portkev_lock);
    284 			/*
    285 			 * Remove any events that where already fired
    286 			 * for this fd and are still in the port queue.
    287 			 */
    288 			(void) port_remove_done_event(pkevp);
    289 		} else {
    290 			mutex_exit(&pkevp->portkev_lock);
    291 		}
    292 		pkevp->portkev_user = user;
    293 	}
    294 
    295 	pfd->pfd_thread = curthread;
    296 	mutex_enter(&pkevp->portkev_lock);
    297 	pkevp->portkev_events = 0;	/* no fired events */
    298 	pdp->pd_events = events;	/* events associated */
    299 	/*
    300 	 * allow new events.
    301 	 */
    302 	pkevp->portkev_flags |= PORT_KEV_VALID;
    303 	mutex_exit(&pkevp->portkev_lock);
    304 
    305 	/*
    306 	 * do VOP_POLL and cache this poll fd.
    307 	 *
    308 	 * XXX - pollrelock() logic needs to know
    309 	 * which pollcache lock to grab. It'd be a
    310 	 * cleaner solution if we could pass pcp as
    311 	 * an arguement in VOP_POLL interface instead
    312 	 * of implicitly passing it using thread_t
    313 	 * struct. On the other hand, changing VOP_POLL
    314 	 * interface will require all driver/file system
    315 	 * poll routine to change.
    316 	 */
    317 	curthread->t_pollcache = (pollcache_t *)pcp;
    318 	error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php, NULL);
    319 	curthread->t_pollcache = NULL;
    320 
    321 	/*
    322 	 * The pc_lock can get dropped and reaquired in VOP_POLL.
    323 	 * In the window pc_lock is dropped another thread in
    324 	 * port_dissociate can remove the pfd from the port cache
    325 	 * and free the pfd.
    326 	 * It is also possible for another thread to sneak in and do a
    327 	 * port_associate on the same fd during the same window.
    328 	 * For both these cases return the current value of error.
    329 	 * The application should take care to ensure that the threads
    330 	 * do not race with each other for association and disassociation
    331 	 * of the same fd.
    332 	 */
    333 	if (((pfd = port_cache_lookup_fp(pcp, fd, fp)) == NULL) ||
    334 	    (pfd->pfd_thread != curthread)) {
    335 		releasef(fd);
    336 		mutex_exit(&pcp->pc_lock);
    337 		return (error);
    338 	}
    339 
    340 	/*
    341 	 * To keep synchronization between VOP_POLL above and
    342 	 * pollhead_insert below, it is necessary to
    343 	 * call VOP_POLL() again (see port_bind_pollhead()).
    344 	 */
    345 	if (error) {
    346 		goto errout;
    347 	}
    348 
    349 	if (php != NULL && (pdp->pd_php != php)) {
    350 		/*
    351 		 * No events delivered yet.
    352 		 * Bind pollhead pointer with current polldat_t structure.
    353 		 * Sub-system will call pollwakeup() later with php as
    354 		 * argument.
    355 		 */
    356 		error = port_bind_pollhead(&php, pdp, &revents);
    357 		/*
    358 		 * The pc_lock can get dropped and reaquired in VOP_POLL.
    359 		 * In the window pc_lock is dropped another thread in
    360 		 * port_dissociate can remove the pfd from the port cache
    361 		 * and free the pfd.
    362 		 * It is also possible for another thread to sneak in and do a
    363 		 * port_associate on the same fd during the same window.
    364 		 * For both these cases return the current value of error.
    365 		 * The application should take care to ensure that the threads
    366 		 * do not race with each other for association
    367 		 * and disassociation of the same fd.
    368 		 */
    369 		if (((pfd = port_cache_lookup_fp(pcp, fd, fp)) == NULL) ||
    370 		    (pfd->pfd_thread != curthread)) {
    371 			releasef(fd);
    372 			mutex_exit(&pcp->pc_lock);
    373 			return (error);
    374 		}
    375 
    376 		if (error) {
    377 			goto errout;
    378 		}
    379 	}
    380 
    381 	/*
    382 	 * Check if new events where detected and no events have been
    383 	 * delivered. The revents was already set after the VOP_POLL
    384 	 * above or it was updated in port_bind_pollhead().
    385 	 */
    386 	mutex_enter(&pkevp->portkev_lock);
    387 	if (revents && (pkevp->portkev_flags & PORT_KEV_VALID)) {
    388 		ASSERT((pkevp->portkev_flags & PORT_KEV_DONEQ) == 0);
    389 		pkevp->portkev_flags &= ~PORT_KEV_VALID;
    390 		revents = revents & (pdp->pd_events | POLLHUP | POLLERR);
    391 		/* send events to the event port */
    392 		pkevp->portkev_events = revents;
    393 		/*
    394 		 * port_send_event will release the portkev_lock mutex.
    395 		 */
    396 		port_send_event(pkevp);
    397 	} else {
    398 		mutex_exit(&pkevp->portkev_lock);
    399 	}
    400 
    401 	releasef(fd);
    402 	mutex_exit(&pcp->pc_lock);
    403 	return (error);
    404 
    405 errout:
    406 	delfd_port(fd, pfd);
    407 	/*
    408 	 * If the portkev is not valid, then an event was
    409 	 * delivered.
    410 	 *
    411 	 * If an event was delivered and got picked up, then
    412 	 * we return error = 0 treating this as a successful
    413 	 * port associate call. The thread which received
    414 	 * the event gets control of the object.
    415 	 */
    416 	active = 0;
    417 	mutex_enter(&pkevp->portkev_lock);
    418 	if (pkevp->portkev_flags & PORT_KEV_VALID) {
    419 		pkevp->portkev_flags &= ~PORT_KEV_VALID;
    420 		active = 1;
    421 	}
    422 	mutex_exit(&pkevp->portkev_lock);
    423 
    424 	if (!port_remove_fd_object(pfd, pp, pcp) && !active) {
    425 		error = 0;
    426 	}
    427 	releasef(fd);
    428 	mutex_exit(&pcp->pc_lock);
    429 	return (error);
    430 }
    431 
    432 /*
    433  * The port_dissociate_fd() function dissociates the delivered file
    434  * descriptor from the event port and removes already fired events.
    435  * If a fd is shared between processes, all involved processes will get
    436  * the same rights related to re-association of the fd with the port and
    437  * retrieve of events from that fd.
    438  * The process which associated the fd with a port for the first time
    439  * becomes also the owner of the association. Only the owner of the
    440  * association is allowed to dissociate the fd from the port.
    441  */
    442 int
    443 port_dissociate_fd(port_t *pp, uintptr_t object)
    444 {
    445 	int		fd;
    446 	port_fdcache_t	*pcp;
    447 	portfd_t	*pfd;
    448 	file_t		*fp;
    449 	int		active;
    450 	port_kevent_t	*pkevp;
    451 
    452 	if (object > (uintptr_t)INT_MAX)
    453 		return (EBADFD);
    454 
    455 	fd = object;
    456 	pcp = pp->port_queue.portq_pcp;
    457 
    458 	mutex_enter(&pcp->pc_lock);
    459 	if (pcp->pc_hash == NULL) {
    460 		/* no file descriptor cache available */
    461 		mutex_exit(&pcp->pc_lock);
    462 		return (ENOENT);
    463 	}
    464 	if ((fp = getf(fd)) == NULL) {
    465 		mutex_exit(&pcp->pc_lock);
    466 		return (EBADFD);
    467 	}
    468 	pfd = port_cache_lookup_fp(pcp, fd, fp);
    469 	if (pfd == NULL) {
    470 		releasef(fd);
    471 		mutex_exit(&pcp->pc_lock);
    472 		return (ENOENT);
    473 	}
    474 	/* only association owner is allowed to remove the association */
    475 	if (curproc->p_pid != PFTOD(pfd)->pd_portev->portkev_pid) {
    476 		releasef(fd);
    477 		mutex_exit(&pcp->pc_lock);
    478 		return (EACCES);
    479 	}
    480 
    481 	/* remove port from the file descriptor interested list */
    482 	delfd_port(fd, pfd);
    483 
    484 	/*
    485 	 * Deactivate the association. No events get posted after
    486 	 * this.
    487 	 */
    488 	pkevp = PFTOD(pfd)->pd_portev;
    489 	mutex_enter(&pkevp->portkev_lock);
    490 	if (pkevp->portkev_flags & PORT_KEV_VALID) {
    491 		pkevp->portkev_flags &= ~PORT_KEV_VALID;
    492 		active = 1;
    493 	} else {
    494 		active = 0;
    495 	}
    496 	mutex_exit(&pkevp->portkev_lock);
    497 
    498 	/* remove polldat & port event structure */
    499 	if (port_remove_fd_object(pfd, pp, pcp)) {
    500 		/*
    501 		 * An event was found and removed from the
    502 		 * port done queue. This means the event has not yet
    503 		 * been retrived. In this case we treat this as an active
    504 		 * association.
    505 		 */
    506 		ASSERT(active == 0);
    507 		active = 1;
    508 	}
    509 	releasef(fd);
    510 	mutex_exit(&pcp->pc_lock);
    511 
    512 	/*
    513 	 * Return ENOENT if there was no active association.
    514 	 */
    515 	return ((active ? 0 : ENOENT));
    516 }
    517 
    518 /*
    519  * Associate event port polldat_t structure with sub-system pointer to
    520  * a polhead_t structure.
    521  */
    522 static int
    523 port_bind_pollhead(pollhead_t **php, polldat_t *pdp, short *revents)
    524 {
    525 	int		error;
    526 	file_t		*fp;
    527 
    528 	/* polldat_t associated with another pollhead_t pointer */
    529 	if (pdp->pd_php != NULL)
    530 		pollhead_delete(pdp->pd_php, pdp);
    531 
    532 	/*
    533 	 * Before pollhead_insert() pollwakeup() will not detect a polldat
    534 	 * entry in the ph_list and the event notification will disappear.
    535 	 * This happens because polldat_t is still not associated with
    536 	 * the pointer to the pollhead_t structure.
    537 	 */
    538 	pollhead_insert(*php, pdp);
    539 
    540 	/*
    541 	 * From now on event notification can be detected in pollwakeup(),
    542 	 * Use VOP_POLL() again to check the current status of the event.
    543 	 */
    544 	pdp->pd_php = *php;
    545 	fp = pdp->pd_fp;
    546 	curthread->t_pollcache = (pollcache_t *)pdp->pd_pcache;
    547 	error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php, NULL);
    548 	curthread->t_pollcache = NULL;
    549 	return (error);
    550 }
    551 
    552 /*
    553  * Grow the hash table. Rehash all the elements on the hash table.
    554  */
    555 static void
    556 port_cache_grow_hashtbl(port_fdcache_t *pcp)
    557 {
    558 	portfd_t	**oldtbl;
    559 	polldat_t	*pdp;
    560 	portfd_t	*pfd;
    561 	polldat_t	*pdp1;
    562 	int		oldsize;
    563 	int		i;
    564 
    565 	ASSERT(MUTEX_HELD(&pcp->pc_lock));
    566 	oldsize = pcp->pc_hashsize;
    567 	oldtbl = pcp->pc_hash;
    568 	pcp->pc_hashsize *= PORTHASH_MULT;
    569 	pcp->pc_hash = kmem_zalloc(pcp->pc_hashsize * sizeof (portfd_t *),
    570 	    KM_SLEEP);
    571 	/*
    572 	 * rehash existing elements
    573 	 */
    574 	pcp->pc_fdcount = 0;
    575 	for (i = 0; i < oldsize; i++) {
    576 		pfd = oldtbl[i];
    577 		pdp = PFTOD(pfd);
    578 		while (pdp != NULL) {
    579 			pdp1 = pdp->pd_hashnext;
    580 			port_cache_insert_fd(pcp, pdp);
    581 			pdp = pdp1;
    582 		}
    583 	}
    584 	kmem_free(oldtbl, oldsize * sizeof (portfd_t *));
    585 }
    586 /*
    587  * This routine inserts a polldat into the portcache's hash table. It
    588  * may be necessary to grow the size of the hash table.
    589  */
    590 static void
    591 port_cache_insert_fd(port_fdcache_t *pcp, polldat_t *pdp)
    592 {
    593 	portfd_t	**bucket;
    594 
    595 	ASSERT(MUTEX_HELD(&pcp->pc_lock));
    596 	if (pcp->pc_fdcount > (pcp->pc_hashsize * PORTHASH_MULT))
    597 		port_cache_grow_hashtbl(pcp);
    598 	bucket = PORT_FD_BUCKET(pcp, pdp->pd_fd);
    599 	pdp->pd_hashnext = PFTOD(*bucket);
    600 	*bucket = PDTOF(pdp);
    601 	pcp->pc_fdcount++;
    602 }
    603 
    604 
    605 /*
    606  * The port_remove_portfd() function dissociates the port from the fd
    607  * and vive versa.
    608  */
    609 static void
    610 port_remove_portfd(polldat_t *pdp, port_fdcache_t *pcp)
    611 {
    612 	port_t	*pp;
    613 	file_t	*fp;
    614 	int	fd;
    615 
    616 	ASSERT(MUTEX_HELD(&pcp->pc_lock));
    617 	pp = pdp->pd_portev->portkev_port;
    618 	fp = getf(fd = pdp->pd_fd);
    619 	/*
    620 	 * If we did not get the fp for pd_fd but its portfd_t
    621 	 * still exist in the cache, it means the pd_fd is being
    622 	 * closed by some other thread which will also free the portfd_t.
    623 	 */
    624 	if (fp != NULL) {
    625 		delfd_port(pdp->pd_fd, PDTOF(pdp));
    626 		(void) port_remove_fd_object(PDTOF(pdp), pp, pcp);
    627 		releasef(fd);
    628 	}
    629 }
    630 
    631 /*
    632  * This function is used by port_close_sourcefd() to destroy the cache
    633  * on last close.
    634  */
    635 static void
    636 port_pcache_destroy(port_fdcache_t *pcp)
    637 {
    638 	ASSERT(pcp->pc_fdcount == 0);
    639 	kmem_free(pcp->pc_hash, sizeof (polldat_t *) * pcp->pc_hashsize);
    640 	mutex_destroy(&pcp->pc_lock);
    641 	kmem_free(pcp, sizeof (port_fdcache_t));
    642 }
    643 
    644 /*
    645  * port_close() calls this function to request the PORT_SOURCE_FD source
    646  * to remove/free all resources allocated and associated with the port.
    647  */
    648 /* ARGSUSED */
    649 static void
    650 port_close_sourcefd(void *arg, int port, pid_t pid, int lastclose)
    651 {
    652 	port_t		*pp = arg;
    653 	port_fdcache_t	*pcp;
    654 	portfd_t	**hashtbl;
    655 	polldat_t	*pdp;
    656 	polldat_t	*pdpnext;
    657 	int		index;
    658 
    659 	pcp = pp->port_queue.portq_pcp;
    660 	if (pcp == NULL)
    661 		/* no cache available -> nothing to do */
    662 		return;
    663 
    664 	mutex_enter(&pcp->pc_lock);
    665 	/*
    666 	 * Scan the cache and free all allocated portfd_t and port_kevent_t
    667 	 * structures.
    668 	 */
    669 	hashtbl = pcp->pc_hash;
    670 	for (index = 0; index < pcp->pc_hashsize; index++) {
    671 		for (pdp = PFTOD(hashtbl[index]); pdp != NULL; pdp = pdpnext) {
    672 			pdpnext = pdp->pd_hashnext;
    673 			if (pid == pdp->pd_portev->portkev_pid) {
    674 				/*
    675 				 * remove polldat + port_event_t from cache
    676 				 * only when current process did the
    677 				 * association.
    678 				 */
    679 				port_remove_portfd(pdp, pcp);
    680 			}
    681 		}
    682 	}
    683 	if (lastclose) {
    684 		/*
    685 		 * Wait for all the portfd's to be freed.
    686 		 * The remaining portfd_t's are the once we did not
    687 		 * free in port_remove_portfd since some other thread
    688 		 * is closing the fd. These threads will free the portfd_t's
    689 		 * once we drop the pc_lock mutex.
    690 		 */
    691 		while (pcp->pc_fdcount) {
    692 			(void) cv_wait_sig(&pcp->pc_lclosecv, &pcp->pc_lock);
    693 		}
    694 		/* event port vnode will be destroyed -> remove everything */
    695 		pp->port_queue.portq_pcp = NULL;
    696 	}
    697 	mutex_exit(&pcp->pc_lock);
    698 	/*
    699 	 * last close:
    700 	 * pollwakeup() can not further interact with this cache
    701 	 * (all polldat structs are removed from pollhead entries).
    702 	 */
    703 	if (lastclose)
    704 		port_pcache_destroy(pcp);
    705 }
    706