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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * File Events Notification
     30  * ------------------------
     31  *
     32  * The File Events Notification facility provides file and directory change
     33  * notification. It is implemented as an event source(PORT_SOURCE_FILE)
     34  * under the Event Ports framework. Therefore the API is an extension to
     35  * the Event Ports API.
     36  *
     37  * It uses the FEM (File Events Monitoring) framework to intercept
     38  * operations on the files & directories and generate appropriate events.
     39  *
     40  * It provides event notification in accordance with what an application
     41  * can find out by stat`ing the file and comparing time stamps. The various
     42  * system calls that update the file's access, modification, and change
     43  * time stamps are documented in the man page section 2.
     44  *
     45  * It is non intrusive. That is, having an active file event watch on a file
     46  * or directory will not prevent it from being removed or renamed or block an
     47  * unmount operation of the file system where the watched file or directory
     48  * resides.
     49  *
     50  *
     51  * Interface:
     52  * ----------
     53  *
     54  *   The object for this event source is of type 'struct file_obj *'
     55  *
     56  *   The file that needs to be monitored is specified in 'fo_name'.
     57  *   The time stamps collected by a stat(2) call are passed in fo_atime,
     58  *   fo_mtime, fo_ctime. At the time a file events watch is registered, the
     59  *   time stamps passed in are compared with the current time stamps of the
     60  *   file. If it has changed, relevant events are sent immediately. If the time
     61  *   stamps are all '0', they will not be compared.
     62  *
     63  *
     64  * The events are delivered to an event port. A port is created using
     65  * port_create().
     66  *
     67  * To register a file events watch on a file or directory.
     68  *
     69  *   port_associate(int port, PORT_SOURCE_FILE, (uintptr_t)&fobj, events, user)
     70  *
     71  *   'user' is the user pointer to be returned with the event.
     72  *
     73  * To de-register a file events watch,
     74  *
     75  *   port_dissociate(int port, PORT_SOURCE_FILE, (uintptr_t)&fobj)
     76  *
     77  * The events are collected using the port_get()/port_getn() interface. The
     78  * event source will be PORT_SOURCE_FILE.
     79  *
     80  * After an event is delivered, the file events watch gets de-activated. To
     81  * receive the next event, the process will have to re-register the watch and
     82  * activate it by calling port_associate() again. This behavior is intentional
     83  * and supports proper multi threaded programming when using file events
     84  * notification API.
     85  *
     86  *
     87  * Implementation overview:
     88  * ------------------------
     89  *
     90  * Each file events watch is represented by 'portfop_t' in the kernel. A
     91  * cache(in portfop_cache_t) of these portfop_t's are maintained per event
     92  * port by this source. The object here is the pointer to the file_obj
     93  * structure. The portfop_t's are hashed in using the object pointer. Therefore
     94  * it is possible to have multiple file events watches on a file by the same
     95  * process by using different object structure(file_obj_t) and hence can
     96  * receive multiple event notification for a file. These watches can be for
     97  * different event types.
     98  *
     99  * The cached entries of these file objects are retained, even after delivering
    100  * an event, marking them inactive for performance reasons. The assumption
    101  * is that the process would come back and re-register the file to receive
    102  * further events. When there are more then 'port_fop_maxpfps' watches per file
    103  * it will attempt to free the oldest inactive watches.
    104  *
    105  * In case the event that is being delivered is an exception event, the cached
    106  * entries get removed. An exception event on a file or directory means its
    107  * identity got changed(rename to/from, delete, mounted over, file system
    108  * unmount).
    109  *
    110  * If the event port gets closed, all the associated file event watches will be
    111  * removed and discarded.
    112  *
    113  *
    114  * Data structures:
    115  * ----------------
    116  *
    117  * The list of file event watches per file are managed by the data structure
    118  * portfop_vp_t. The first time a file events watch is registered for a file,
    119  * a portfop_vp_t is installed on the vnode_t's member v_fopdata. This gets
    120  * removed and freed only when the vnode becomes inactive. The FEM hooks are
    121  * also installed when the first watch is registered on a file. The FEM hooks
    122  * get un-installed when all the watches are removed.
    123  *
    124  * Each file events watch is represented by the structure portfop_t. They
    125  * get added to a list of portfop_t's on the vnode(portfop_vp_t). After
    126  * delivering an event, the portfop_t is marked inactive but retained. It is
    127  * moved to the end of the list. All the active portfop_t's are maintained at
    128  * the beginning. In case of exception events, the portfop_t will be removed
    129  * and discarded.
    130  *
    131  * To intercept unmount operations, FSEM hooks are added to the file system
    132  * under which files are being watched. A hash table('portfop_vfs_hash_t') of
    133  * active file systems is maintained. Each file system that has active watches
    134  * is represented by 'portfop_vfs_t' and is added to the hash table.
    135  * The vnode's 'portfop_vp_t' structure is added to the list of files(vnodes)
    136  * being watched on the portfop_vfs_t structure.
    137  *
    138  *
    139  * File system support:
    140  * -------------------
    141  *
    142  * The file system implementation has to provide vnode event notifications
    143  * (vnevents) in order to support watching any files on that file system.
    144  * The vnode events(vnevents) are notifications provided by the file system
    145  * for name based file operations like rename, remove etc, which do not go
    146  * thru the VOP_** interfaces. If the file system does not implement vnode
    147  * notifications, watching for file events on such file systems is not
    148  * supported. The vnode event notifications support is determined by the call
    149  * vnevent_support(vp) (VOP_VNEVENT(vp, VE_SUPPORT)), which the file system
    150  * has to implement.
    151  *
    152  *
    153  * Locking order:
    154  * --------------
    155  *
    156  * A file(vnode) can have file event watches registered by different processes.
    157  * There is one portfop_t per watch registered. These are on the vnode's list
    158  * protected by the mutex 'pvp_mutex' in 'portfop_vp_t'. The portfop_t's are
    159  * also on the per port cache. The cache is protected by the pfc_lock of
    160  * portfop_cache_t. The lock order here is 'pfc_lock' -> 'pvp_mutex'.
    161  *
    162  */
    163 
    164 #include <sys/types.h>
    165 #include <sys/systm.h>
    166 #include <sys/stat.h>
    167 #include <sys/errno.h>
    168 #include <sys/kmem.h>
    169 #include <sys/sysmacros.h>
    170 #include <sys/debug.h>
    171 #include <sys/vnode.h>
    172 #include <sys/poll_impl.h>
    173 #include <sys/port_impl.h>
    174 #include <sys/fem.h>
    175 #include <sys/vfs_opreg.h>
    176 #include <sys/atomic.h>
    177 #include <sys/mount.h>
    178 #include <sys/mntent.h>
    179 
    180 /*
    181  * For special case support of mnttab (/etc/mnttab).
    182  */
    183 extern struct vnode *vfs_mntdummyvp;
    184 extern int mntfstype;
    185 
    186 #define	PORTFOP_PVFSH(vfsp)	(&portvfs_hash[PORTFOP_PVFSHASH(vfsp)])
    187 portfop_vfs_hash_t	 portvfs_hash[PORTFOP_PVFSHASH_SZ];
    188 
    189 #define	PORTFOP_NVP	20
    190 /*
    191  * Inactive file event watches(portfop_t) are retained on the vnode's list
    192  * for performance reason. If the applications re-registers the file, the
    193  * inactive entry is made active and moved up the list.
    194  *
    195  * If there are greater then the following number of watches on a vnode,
    196  * it will attempt to discard an oldest inactive watch(pfp) at the time
    197  * a new watch is being registered and when events get delivered. We
    198  * do this to avoid accumulating inactive watches on a file.
    199  */
    200 int	port_fop_maxpfps = 20;
    201 
    202 /* local functions */
    203 static int	port_fop_callback(void *, int *, pid_t, int, void *);
    204 
    205 static void	port_pcache_insert(portfop_cache_t *, portfop_t *);
    206 static void	port_pcache_delete(portfop_cache_t *, portfop_t *);
    207 static void	port_close_fop(void *arg, int port, pid_t pid, int lastclose);
    208 
    209 /*
    210  * port fop functions that will be the fem hooks.
    211  */
    212 static int port_fop_open(femarg_t *vf, int mode, cred_t *cr,
    213     caller_context_t *);
    214 static int port_fop_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
    215     struct caller_context *ct);
    216 static int port_fop_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
    217     caller_context_t *ct);
    218 static int port_fop_map(femarg_t *vf, offset_t off, struct as *as,
    219     caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport,
    220     uint_t flags, cred_t *cr, caller_context_t *ct);
    221 static int port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
    222     caller_context_t *ct);
    223 static int port_fop_create(femarg_t *vf, char *name, vattr_t *vap,
    224     vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr, int flag,
    225     caller_context_t *ct, vsecattr_t *vsecp);
    226 static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr,
    227     caller_context_t *ct, int flags);
    228 static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
    229     caller_context_t *ct, int flags);
    230 static int port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
    231     cred_t *cr, caller_context_t *ct, int flags);
    232 static int port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap,
    233     vnode_t **vpp, cred_t *cr, caller_context_t *ct, int flags,
    234     vsecattr_t *vsecp);
    235 static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
    236     caller_context_t *ct, int flags);
    237 static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
    238     caller_context_t *ct, int flags);
    239 static int port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
    240     char *target, cred_t *cr, caller_context_t *ct, int flags);
    241 static int port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
    242     cred_t *cr, caller_context_t *ct);
    243 
    244 static int port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp,
    245     char *cname, caller_context_t *ct);
    246 
    247 static int port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr);
    248 
    249 
    250 /*
    251  * Fem hooks.
    252  */
    253 const fs_operation_def_t	port_vnodesrc_template[] = {
    254 	VOPNAME_OPEN,		{ .femop_open = port_fop_open },
    255 	VOPNAME_READ,		{ .femop_read = port_fop_read },
    256 	VOPNAME_WRITE,		{ .femop_write = port_fop_write },
    257 	VOPNAME_MAP,		{ .femop_map = port_fop_map },
    258 	VOPNAME_SETATTR, 	{ .femop_setattr = port_fop_setattr },
    259 	VOPNAME_CREATE,		{ .femop_create = port_fop_create },
    260 	VOPNAME_REMOVE,		{ .femop_remove = port_fop_remove },
    261 	VOPNAME_LINK,		{ .femop_link = port_fop_link },
    262 	VOPNAME_RENAME,		{ .femop_rename = port_fop_rename },
    263 	VOPNAME_MKDIR,		{ .femop_mkdir = port_fop_mkdir },
    264 	VOPNAME_RMDIR,		{ .femop_rmdir = port_fop_rmdir },
    265 	VOPNAME_READDIR,	{ .femop_readdir = port_fop_readdir },
    266 	VOPNAME_SYMLINK,	{ .femop_symlink = port_fop_symlink },
    267 	VOPNAME_SETSECATTR, 	{ .femop_setsecattr = port_fop_setsecattr },
    268 	VOPNAME_VNEVENT,	{ .femop_vnevent = port_fop_vnevent },
    269 	NULL,	NULL
    270 };
    271 
    272 /*
    273  * Fsem - vfs ops hooks
    274  */
    275 const fs_operation_def_t	port_vfssrc_template[] = {
    276 	VFSNAME_UNMOUNT, 	{ .fsemop_unmount = port_fop_unmount },
    277 	NULL,	NULL
    278 };
    279 
    280 fem_t *fop_femop;
    281 fsem_t *fop_fsemop;
    282 
    283 static fem_t *
    284 port_fop_femop()
    285 {
    286 	fem_t *femp;
    287 	if (fop_femop != NULL)
    288 		return (fop_femop);
    289 	if (fem_create("portfop_fem",
    290 	    (const struct fs_operation_def *)port_vnodesrc_template,
    291 	    (fem_t **)&femp)) {
    292 		return (NULL);
    293 	}
    294 	if (casptr(&fop_femop, NULL, femp) != NULL) {
    295 		/*
    296 		 * some other thread beat us to it.
    297 		 */
    298 		fem_free(femp);
    299 	}
    300 	return (fop_femop);
    301 }
    302 
    303 static fsem_t *
    304 port_fop_fsemop()
    305 {
    306 	fsem_t *fsemp;
    307 	if (fop_fsemop != NULL)
    308 		return (fop_fsemop);
    309 	if (fsem_create("portfop_fsem", port_vfssrc_template, &fsemp)) {
    310 		return (NULL);
    311 	}
    312 	if (casptr(&fop_fsemop, NULL, fsemp) != NULL) {
    313 		/*
    314 		 * some other thread beat us to it.
    315 		 */
    316 		fsem_free(fsemp);
    317 	}
    318 	return (fop_fsemop);
    319 }
    320 
    321 /*
    322  * port_fop_callback()
    323  * - PORT_CALLBACK_DEFAULT
    324  *	The file event will be delivered to the application.
    325  * - PORT_CALLBACK_DISSOCIATE
    326  *	The object will be dissociated from  the port.
    327  * - PORT_CALLBACK_CLOSE
    328  *	The object will be dissociated from the port because the port
    329  *	is being closed.
    330  */
    331 /* ARGSUSED */
    332 static int
    333 port_fop_callback(void *arg, int *events, pid_t pid, int flag, void *evp)
    334 {
    335 	portfop_t	*pfp = (portfop_t *)arg;
    336 	port_kevent_t	*pkevp = (port_kevent_t *)evp;
    337 	int		error = 0;
    338 
    339 	ASSERT((events != NULL));
    340 	if (flag == PORT_CALLBACK_DEFAULT) {
    341 		if (curproc->p_pid != pid) {
    342 				return (EACCES); /* deny delivery of events */
    343 		}
    344 
    345 		*events = pkevp->portkev_events;
    346 		pkevp->portkev_events = 0;
    347 		if (pfp != NULL) {
    348 			pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ;
    349 		}
    350 	}
    351 	return (error);
    352 }
    353 
    354 /*
    355  * Inserts a portfop_t into the port sources cache's.
    356  */
    357 static void
    358 port_pcache_insert(portfop_cache_t *pfcp, portfop_t *pfp)
    359 {
    360 	portfop_t	**bucket;
    361 
    362 	ASSERT(MUTEX_HELD(&pfcp->pfc_lock));
    363 	bucket = PORT_FOP_BUCKET(pfcp, pfp->pfop_object);
    364 	pfp->pfop_hashnext = *bucket;
    365 	*bucket = pfp;
    366 	pfcp->pfc_objcount++;
    367 }
    368 
    369 /*
    370  * Remove the pfp from the port source cache.
    371  */
    372 static void
    373 port_pcache_delete(portfop_cache_t *pfcp, portfop_t *pfp)
    374 {
    375 	portfop_t	*lpdp;
    376 	portfop_t	*cpdp;
    377 	portfop_t	**bucket;
    378 
    379 	bucket = PORT_FOP_BUCKET(pfcp, pfp->pfop_object);
    380 	cpdp = *bucket;
    381 	if (pfp == cpdp) {
    382 		*bucket = pfp->pfop_hashnext;
    383 	} else {
    384 		while (cpdp != NULL) {
    385 			lpdp = cpdp;
    386 			cpdp = cpdp->pfop_hashnext;
    387 			if (cpdp == pfp) {
    388 				/* portfop struct found */
    389 				lpdp->pfop_hashnext = pfp->pfop_hashnext;
    390 				break;
    391 			}
    392 		}
    393 	}
    394 	pfcp->pfc_objcount--;
    395 }
    396 
    397 /*
    398  * The vnode's(portfop_vp_t) pfp list management. The 'pvp_mutex' is held
    399  * when these routines are called.
    400  *
    401  * The 'pvp_lpfop' member points to the oldest inactive entry on the list.
    402  * It is used to discard the oldtest inactive pfp if the number of entries
    403  * exceed the limit.
    404  */
    405 static void
    406 port_fop_listinsert(portfop_vp_t *pvp, portfop_t *pfp, int where)
    407 {
    408 	if (where == 1) {
    409 		list_insert_head(&pvp->pvp_pfoplist, (void *)pfp);
    410 	} else {
    411 		list_insert_tail(&pvp->pvp_pfoplist, (void *)pfp);
    412 	}
    413 	if (pvp->pvp_lpfop == NULL) {
    414 		pvp->pvp_lpfop = pfp;
    415 	}
    416 	pvp->pvp_cnt++;
    417 }
    418 
    419 static void
    420 port_fop_listinsert_head(portfop_vp_t *pvp, portfop_t *pfp)
    421 {
    422 	port_fop_listinsert(pvp, pfp, 1);
    423 }
    424 
    425 static void
    426 port_fop_listinsert_tail(portfop_vp_t *pvp, portfop_t *pfp)
    427 {
    428 	/*
    429 	 * We point lpfop to an inactive one, if it was initially pointing
    430 	 * to an active one. Insert to the tail is done only when a pfp goes
    431 	 * inactive.
    432 	 */
    433 	if (pvp->pvp_lpfop && pvp->pvp_lpfop->pfop_flags & PORT_FOP_ACTIVE) {
    434 		pvp->pvp_lpfop = pfp;
    435 	}
    436 	port_fop_listinsert(pvp, pfp, 0);
    437 }
    438 
    439 static void
    440 port_fop_listremove(portfop_vp_t *pvp, portfop_t *pfp)
    441 {
    442 	if (pvp->pvp_lpfop == pfp) {
    443 		pvp->pvp_lpfop = list_next(&pvp->pvp_pfoplist, (void *)pfp);
    444 	}
    445 
    446 	list_remove(&pvp->pvp_pfoplist, (void *)pfp);
    447 
    448 	pvp->pvp_cnt--;
    449 	if (pvp->pvp_cnt && pvp->pvp_lpfop == NULL) {
    450 		pvp->pvp_lpfop = list_head(&pvp->pvp_pfoplist);
    451 	}
    452 }
    453 
    454 static void
    455 port_fop_listmove(portfop_vp_t *pvp, list_t *tlist)
    456 {
    457 	list_move_tail(tlist, &pvp->pvp_pfoplist);
    458 	pvp->pvp_lpfop = NULL;
    459 	pvp->pvp_cnt = 0;
    460 }
    461 
    462 /*
    463  * Remove a portfop_t from the port cache hash table and discard it.
    464  * It is called only when pfp is not on the vnode's list. Otherwise,
    465  * port_remove_fop() is called.
    466  */
    467 void
    468 port_pcache_remove_fop(portfop_cache_t *pfcp, portfop_t *pfp)
    469 {
    470 	port_kevent_t	*pkevp;
    471 
    472 
    473 	ASSERT(MUTEX_HELD(&pfcp->pfc_lock));
    474 
    475 	pkevp = pfp->pfop_pev;
    476 	pfp->pfop_pev = NULL;
    477 
    478 	if (pkevp != NULL) {
    479 		(void) port_remove_done_event(pkevp);
    480 		port_free_event_local(pkevp, 0);
    481 	}
    482 
    483 	port_pcache_delete(pfcp, pfp);
    484 
    485 	if (pfp->pfop_cname != NULL)
    486 		kmem_free(pfp->pfop_cname, pfp->pfop_clen + 1);
    487 	kmem_free(pfp, sizeof (portfop_t));
    488 	if (pfcp->pfc_objcount == 0)
    489 		cv_signal(&pfcp->pfc_lclosecv);
    490 }
    491 
    492 /*
    493  * if we have too many watches on the vnode, attempt to discard an
    494  * inactive one.
    495  */
    496 static void
    497 port_fop_trimpfplist(vnode_t *vp)
    498 {
    499 	portfop_vp_t *pvp;
    500 	portfop_t *pfp = NULL;
    501 	portfop_cache_t *pfcp;
    502 	vnode_t	*tdvp;
    503 
    504 	/*
    505 	 * Due to a reference the vnode cannot disappear, v_fopdata should
    506 	 * not change.
    507 	 */
    508 	if ((pvp = vp->v_fopdata) != NULL &&
    509 	    pvp->pvp_cnt > port_fop_maxpfps) {
    510 		mutex_enter(&pvp->pvp_mutex);
    511 		pfp = pvp->pvp_lpfop;
    512 		pfcp = pfp->pfop_pcache;
    513 		/*
    514 		 * only if we can get the cache lock, we need to
    515 		 * do this due to reverse lock order and some thread
    516 		 * that may be trying to reactivate this entry.
    517 		 */
    518 		if (mutex_tryenter(&pfcp->pfc_lock)) {
    519 			if (pfp && !(pfp->pfop_flags & PORT_FOP_ACTIVE) &&
    520 			    !(pfp->pfop_flags & PORT_FOP_KEV_ONQ)) {
    521 				port_fop_listremove(pvp, pfp);
    522 				pfp->pfop_flags |= PORT_FOP_REMOVING;
    523 			} else {
    524 				mutex_exit(&pfcp->pfc_lock);
    525 				pfp = NULL;
    526 			}
    527 		} else {
    528 			pfp = NULL;
    529 		}
    530 		mutex_exit(&pvp->pvp_mutex);
    531 
    532 		/*
    533 		 * discard pfp if any.
    534 		 */
    535 		if (pfp != NULL) {
    536 			tdvp = pfp->pfop_dvp;
    537 			port_pcache_remove_fop(pfcp, pfp);
    538 			mutex_exit(&pfcp->pfc_lock);
    539 			if (tdvp != NULL)
    540 				VN_RELE(tdvp);
    541 		}
    542 	}
    543 }
    544 
    545 /*
    546  * This routine returns 1, if the vnode can be rele'ed by the caller.
    547  * The caller has to VN_RELE the vnode with out holding any
    548  * locks.
    549  */
    550 int
    551 port_fop_femuninstall(vnode_t *vp)
    552 {
    553 	portfop_vp_t	*pvp;
    554 	vfs_t		*vfsp;
    555 	portfop_vfs_t *pvfsp;
    556 	portfop_vfs_hash_t	*pvfsh;
    557 	kmutex_t	*mtx;
    558 	int	ret = 0;
    559 
    560 	/*
    561 	 * if list is empty, uninstall fem.
    562 	 */
    563 	pvp = vp->v_fopdata;
    564 	ASSERT(MUTEX_HELD(&pvp->pvp_mutex));
    565 
    566 	/*
    567 	 * make sure the list is empty.
    568 	 */
    569 	if (!list_head(&pvp->pvp_pfoplist)) {
    570 
    571 		/*
    572 		 * we could possibly uninstall the fem hooks when
    573 		 * the vnode becomes inactive and the v_fopdata is
    574 		 * free. But the hooks get triggered unnecessarily
    575 		 * even though there are no active watches. So, we
    576 		 * uninstall it here.
    577 		 */
    578 		(void) fem_uninstall(vp, (fem_t *)pvp->pvp_femp, vp);
    579 		pvp->pvp_femp = NULL;
    580 		mutex_exit(&pvp->pvp_mutex);
    581 
    582 
    583 		/*
    584 		 * If we successfully uninstalled fem, no process is watching
    585 		 * this vnode, Remove it from the vfs's list of watched vnodes.
    586 		 */
    587 		pvfsp = pvp->pvp_pvfsp;
    588 		vfsp = vp->v_vfsp;
    589 		pvfsh = PORTFOP_PVFSH(vfsp);
    590 		mtx = &pvfsh->pvfshash_mutex;
    591 		mutex_enter(mtx);
    592 		/*
    593 		 * If unmount is in progress, that thread will remove and
    594 		 * release the vnode from the vfs's list, just leave.
    595 		 */
    596 		if (!pvfsp->pvfs_unmount) {
    597 			list_remove(&pvfsp->pvfs_pvplist, pvp);
    598 			mutex_exit(mtx);
    599 			ret = 1;
    600 		} else {
    601 			mutex_exit(mtx);
    602 		}
    603 	} else {
    604 		mutex_exit(&pvp->pvp_mutex);
    605 	}
    606 	return (ret);
    607 }
    608 
    609 /*
    610  * Remove pfp from the vnode's watch list and the cache and discard it.
    611  * If it is the last pfp on the vnode's list, the fem hooks get uninstalled.
    612  * Returns 1 if pfp removed successfully.
    613  *
    614  * The *active is set to indicate if the pfp was still active(no events had
    615  * been posted, or the posted event had not been collected yet and it was
    616  * able to remove it from the port's queue).
    617  *
    618  * vpp and dvpp will point to the vnode and directory vnode which the caller
    619  * is required to VN_RELE without holding any locks.
    620  */
    621 int
    622 port_remove_fop(portfop_t *pfp, portfop_cache_t *pfcp, int cleanup,
    623     int *active, vnode_t **vpp, vnode_t **dvpp)
    624 {
    625 	vnode_t		*vp;
    626 	portfop_vp_t	*pvp;
    627 	int	tactive = 0;
    628 
    629 	ASSERT(MUTEX_HELD(&pfcp->pfc_lock));
    630 	vp = pfp->pfop_vp;
    631 	pvp = vp->v_fopdata;
    632 	mutex_enter(&pvp->pvp_mutex);
    633 
    634 	/*
    635 	 * if not cleanup, remove it only if the pfp is still active and
    636 	 * is not being removed by some other thread.
    637 	 */
    638 	if (!cleanup && (!(pfp->pfop_flags & PORT_FOP_ACTIVE) ||
    639 	    pfp->pfop_flags & PORT_FOP_REMOVING)) {
    640 		mutex_exit(&pvp->pvp_mutex);
    641 		return (0);
    642 	}
    643 
    644 	/*
    645 	 * mark it inactive.
    646 	 */
    647 	if (pfp->pfop_flags & PORT_FOP_ACTIVE) {
    648 		pfp->pfop_flags &= ~PORT_FOP_ACTIVE;
    649 		tactive = 1;
    650 	}
    651 
    652 	/*
    653 	 * Check if the pfp is still on the vnode's list. This can
    654 	 * happen if port_fop_excep() is in the process of removing it.
    655 	 * In case of cleanup, just mark this pfp as inactive so that no
    656 	 * new events (VNEVENT) will be delivered, and remove it from the
    657 	 * event queue if it was already queued. Since the cache lock is
    658 	 * held, the pfp will not disappear, even though it is being
    659 	 * removed.
    660 	 */
    661 	if (pfp->pfop_flags & PORT_FOP_REMOVING) {
    662 		mutex_exit(&pvp->pvp_mutex);
    663 		if (!tactive && port_remove_done_event(pfp->pfop_pev)) {
    664 			pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ;
    665 			tactive = 1;
    666 		}
    667 		if (active) {
    668 			*active = tactive;
    669 		}
    670 		return (1);
    671 	}
    672 
    673 	/*
    674 	 * if we find an event on the queue and removed it, then this
    675 	 * association is considered active.
    676 	 */
    677 	if (!tactive && port_remove_done_event(pfp->pfop_pev)) {
    678 		pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ;
    679 		tactive = 1;
    680 	}
    681 
    682 	if (active) {
    683 		*active = tactive;
    684 	}
    685 	pvp = (portfop_vp_t *)vp->v_fopdata;
    686 
    687 	/*
    688 	 * remove pfp from the vnode's list
    689 	 */
    690 	port_fop_listremove(pvp, pfp);
    691 
    692 	/*
    693 	 * If no more associations on the vnode, uninstall fem hooks.
    694 	 * The pvp mutex will be released in this routine.
    695 	 */
    696 	if (port_fop_femuninstall(vp))
    697 		*vpp = vp;
    698 	*dvpp = pfp->pfop_dvp;
    699 	port_pcache_remove_fop(pfcp, pfp);
    700 	return (1);
    701 }
    702 
    703 /*
    704  * This routine returns a pointer to a cached portfop entry, or NULL if it
    705  * does not find it in the hash table. The object pointer is used as index.
    706  * The entries are hashed by the object's address. We need to match the pid
    707  * as the evet port can be shared between processes. The file events
    708  * watches are per process only.
    709  */
    710 portfop_t *
    711 port_cache_lookup_fop(portfop_cache_t *pfcp, pid_t pid, uintptr_t obj)
    712 {
    713 	portfop_t	*pfp = NULL;
    714 	portfop_t	**bucket;
    715 
    716 	ASSERT(MUTEX_HELD(&pfcp->pfc_lock));
    717 	bucket = PORT_FOP_BUCKET(pfcp, obj);
    718 	pfp = *bucket;
    719 	while (pfp != NULL) {
    720 		if (pfp->pfop_object == obj && pfp->pfop_pid == pid)
    721 			break;
    722 		pfp = pfp->pfop_hashnext;
    723 	}
    724 	return (pfp);
    725 }
    726 
    727 /*
    728  * Given the file name, get the vnode and also the directory vnode
    729  * On return, the vnodes are held (VN_HOLD). The caller has to VN_RELE
    730  * the vnode(s).
    731  */
    732 int
    733 port_fop_getdvp(void *objptr, vnode_t **vp, vnode_t **dvp,
    734 	char **cname, int *len, int follow)
    735 {
    736 	int error = 0;
    737 	struct pathname pn;
    738 	char *fname;
    739 
    740 	if (get_udatamodel() == DATAMODEL_NATIVE) {
    741 		fname = ((file_obj_t *)objptr)->fo_name;
    742 #ifdef  _SYSCALL32_IMPL
    743 	} else {
    744 		fname = (caddr_t)(uintptr_t)((file_obj32_t *)objptr)->fo_name;
    745 #endif	/* _SYSCALL32_IMPL */
    746 	}
    747 
    748 	/*
    749 	 * lookuppn may fail with EINVAL, if dvp is  non-null(like when
    750 	 * looking for "."). So call again with dvp = NULL.
    751 	 */
    752 	if ((error = pn_get(fname, UIO_USERSPACE, &pn)) != 0) {
    753 		return (error);
    754 	}
    755 
    756 	error = lookuppn(&pn, NULL, follow, dvp, vp);
    757 	if (error == EINVAL) {
    758 		pn_free(&pn);
    759 		if ((error = pn_get(fname, UIO_USERSPACE, &pn)) != 0) {
    760 			return (error);
    761 		}
    762 		error = lookuppn(&pn, NULL, follow, NULL, vp);
    763 		if (dvp != NULL) {
    764 			*dvp = NULL;
    765 		}
    766 	}
    767 
    768 	if (error == 0 && cname != NULL && len != NULL) {
    769 		pn_setlast(&pn);
    770 		*len = pn.pn_pathlen;
    771 		*cname = kmem_alloc(*len + 1, KM_SLEEP);
    772 		(void) strcpy(*cname, pn.pn_path);
    773 	} else {
    774 		if (cname != NULL && len != NULL) {
    775 			*cname = NULL;
    776 			*len = 0;
    777 		}
    778 	}
    779 
    780 	pn_free(&pn);
    781 	return (error);
    782 }
    783 
    784 port_source_t *
    785 port_getsrc(port_t *pp, int source)
    786 {
    787 	port_source_t *pse;
    788 	int	lock = 0;
    789 	/*
    790 	 * get the port source structure.
    791 	 */
    792 	if (!MUTEX_HELD(&pp->port_queue.portq_source_mutex)) {
    793 		mutex_enter(&pp->port_queue.portq_source_mutex);
    794 		lock = 1;
    795 	}
    796 
    797 	pse = pp->port_queue.portq_scache[PORT_SHASH(source)];
    798 	for (; pse != NULL; pse = pse->portsrc_next) {
    799 		if (pse->portsrc_source == source)
    800 			break;
    801 	}
    802 
    803 	if (lock) {
    804 		mutex_exit(&pp->port_queue.portq_source_mutex);
    805 	}
    806 	return (pse);
    807 }
    808 
    809 
    810 /*
    811  * Compare time stamps and generate an event if it has changed.
    812  * Note that the port cache pointer will be valid due to a reference
    813  * to the port. We need to grab the port cache lock and verify that
    814  * the pfp is still the same before proceeding to deliver an event.
    815  */
    816 static void
    817 port_check_timestamp(portfop_cache_t *pfcp, vnode_t *vp, vnode_t *dvp,
    818 	portfop_t *pfp, void *objptr, uintptr_t object)
    819 {
    820 	vattr_t		vatt;
    821 	portfop_vp_t	*pvp = vp->v_fopdata;
    822 	int		events = 0;
    823 	port_kevent_t	*pkevp;
    824 	file_obj_t	*fobj;
    825 	portfop_t	*tpfp;
    826 
    827 	/*
    828 	 * If time stamps are specified, get attributes and compare.
    829 	 */
    830 	vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
    831 	if (get_udatamodel() == DATAMODEL_NATIVE) {
    832 		fobj = (file_obj_t *)objptr;
    833 		if (fobj->fo_atime.tv_sec || fobj->fo_atime.tv_nsec ||
    834 		    fobj->fo_mtime.tv_sec || fobj->fo_mtime.tv_nsec ||
    835 		    fobj->fo_ctime.tv_sec || fobj->fo_ctime.tv_nsec) {
    836 			if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
    837 				return;
    838 			}
    839 		} else {
    840 			/*
    841 			 * timestamp not specified, all 0's,
    842 			 */
    843 			return;
    844 		}
    845 #ifdef  _SYSCALL32_IMPL
    846 	} else {
    847 		file_obj32_t	*fobj32;
    848 		fobj32 = (file_obj32_t *)objptr;
    849 		if (fobj32->fo_atime.tv_sec || fobj32->fo_atime.tv_nsec ||
    850 		    fobj32->fo_mtime.tv_sec || fobj32->fo_mtime.tv_nsec ||
    851 		    fobj32->fo_ctime.tv_sec || fobj32->fo_ctime.tv_nsec) {
    852 			if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
    853 				return;
    854 			}
    855 		} else {
    856 			/*
    857 			 * timestamp not specified, all 0.
    858 			 */
    859 			return;
    860 		}
    861 #endif /* _SYSCALL32_IMPL */
    862 	}
    863 
    864 	/*
    865 	 * Now grab the cache lock and verify that we are still
    866 	 * dealing with the same pfp and curthread is the one
    867 	 * which registered it. We need to do this to avoid
    868 	 * delivering redundant events.
    869 	 */
    870 	mutex_enter(&pfcp->pfc_lock);
    871 	tpfp = port_cache_lookup_fop(pfcp, curproc->p_pid, object);
    872 
    873 	if (tpfp == NULL || tpfp != pfp ||
    874 	    pfp->pfop_vp != vp || pfp->pfop_dvp != dvp ||
    875 	    pfp->pfop_callrid != curthread ||
    876 	    !(pfp->pfop_flags & PORT_FOP_ACTIVE)) {
    877 		/*
    878 		 * Some other event was delivered, the file
    879 		 * watch was removed or reassociated. Just
    880 		 * ignore it and leave
    881 		 */
    882 		mutex_exit(&pfcp->pfc_lock);
    883 		return;
    884 	}
    885 
    886 	mutex_enter(&pvp->pvp_mutex);
    887 	/*
    888 	 * The pfp cannot disappear as the port cache lock is held.
    889 	 * While the pvp_mutex is held, no events will get delivered.
    890 	 */
    891 	if (pfp->pfop_flags & PORT_FOP_ACTIVE &&
    892 	    !(pfp->pfop_flags & PORT_FOP_REMOVING)) {
    893 		if (get_udatamodel() == DATAMODEL_NATIVE) {
    894 			fobj = (file_obj_t *)objptr;
    895 			if (pfp->pfop_events & FILE_ACCESS &&
    896 			    (fobj->fo_atime.tv_sec || fobj->fo_atime.tv_nsec) &&
    897 			    (vatt.va_atime.tv_sec != fobj->fo_atime.tv_sec ||
    898 			    vatt.va_atime.tv_nsec != fobj->fo_atime.tv_nsec))
    899 				events |= FILE_ACCESS;
    900 
    901 			if (pfp->pfop_events & FILE_MODIFIED &&
    902 			    (fobj->fo_mtime.tv_sec || fobj->fo_mtime.tv_nsec) &&
    903 			    (vatt.va_mtime.tv_sec != fobj->fo_mtime.tv_sec ||
    904 			    vatt.va_mtime.tv_nsec != fobj->fo_mtime.tv_nsec))
    905 				events |= FILE_MODIFIED;
    906 
    907 			if (pfp->pfop_events & FILE_ATTRIB &&
    908 			    (fobj->fo_ctime.tv_sec || fobj->fo_ctime.tv_nsec) &&
    909 			    (vatt.va_ctime.tv_sec != fobj->fo_ctime.tv_sec ||
    910 			    vatt.va_ctime.tv_nsec != fobj->fo_ctime.tv_nsec))
    911 				events |= FILE_ATTRIB;
    912 #ifdef  _SYSCALL32_IMPL
    913 		} else {
    914 			file_obj32_t	*fobj32;
    915 			fobj32 = (file_obj32_t *)objptr;
    916 			if (pfp->pfop_events & FILE_ACCESS &&
    917 			    (fobj32->fo_atime.tv_sec ||
    918 			    fobj32->fo_atime.tv_nsec) &&
    919 			    (vatt.va_atime.tv_sec != fobj32->fo_atime.tv_sec ||
    920 			    vatt.va_atime.tv_nsec != fobj32->fo_atime.tv_nsec))
    921 				events |= FILE_ACCESS;
    922 
    923 			if (pfp->pfop_events & FILE_MODIFIED &&
    924 			    (fobj32->fo_mtime.tv_sec ||
    925 			    fobj32->fo_mtime.tv_nsec) &&
    926 			    (vatt.va_mtime.tv_sec != fobj32->fo_mtime.tv_sec ||
    927 			    vatt.va_mtime.tv_nsec != fobj32->fo_mtime.tv_nsec))
    928 				events |= FILE_MODIFIED;
    929 
    930 			if (pfp->pfop_events & FILE_ATTRIB &&
    931 			    (fobj32->fo_ctime.tv_sec ||
    932 			    fobj32->fo_ctime.tv_nsec) &&
    933 			    (vatt.va_ctime.tv_sec != fobj32->fo_ctime.tv_sec ||
    934 			    vatt.va_ctime.tv_nsec != fobj32->fo_ctime.tv_nsec))
    935 				events |= FILE_ATTRIB;
    936 #endif /* _SYSCALL32_IMPL */
    937 		}
    938 
    939 		/*
    940 		 * No events to deliver
    941 		 */
    942 		if (events == 0) {
    943 			mutex_exit(&pvp->pvp_mutex);
    944 			mutex_exit(&pfcp->pfc_lock);
    945 			return;
    946 		}
    947 
    948 		/*
    949 		 * Deliver the event now.
    950 		 */
    951 		pkevp = pfp->pfop_pev;
    952 		pfp->pfop_flags &= ~PORT_FOP_ACTIVE;
    953 		pkevp->portkev_events |= events;
    954 		/*
    955 		 * Move it to the tail as active once are in the
    956 		 * beginning of the list.
    957 		 */
    958 		port_fop_listremove(pvp, pfp);
    959 		port_fop_listinsert_tail(pvp, pfp);
    960 		port_send_event(pkevp);
    961 		pfp->pfop_flags |= PORT_FOP_KEV_ONQ;
    962 	}
    963 	mutex_exit(&pvp->pvp_mutex);
    964 	mutex_exit(&pfcp->pfc_lock);
    965 }
    966 
    967 /*
    968  * Add the event source to the port and return the port source cache pointer.
    969  */
    970 int
    971 port_fop_associate_source(portfop_cache_t **pfcpp, port_t *pp, int source)
    972 {
    973 	portfop_cache_t *pfcp;
    974 	port_source_t	*pse;
    975 	int		error;
    976 
    977 	/*
    978 	 * associate PORT_SOURCE_FILE source with the port, if it is
    979 	 * not associated yet. Note the PORT_SOURCE_FILE source is
    980 	 * associated once and will not be dissociated.
    981 	 */
    982 	if ((pse = port_getsrc(pp, PORT_SOURCE_FILE)) == NULL) {
    983 		if (error = port_associate_ksource(pp->port_fd, source,
    984 		    &pse, port_close_fop, pp, NULL)) {
    985 			*pfcpp = NULL;
    986 			return (error);
    987 		}
    988 	}
    989 
    990 	/*
    991 	 * Get the portfop cache pointer.
    992 	 */
    993 	if ((pfcp = pse->portsrc_data) == NULL) {
    994 		/*
    995 		 * This is the first time that a file is being associated,
    996 		 * create the portfop cache.
    997 		 */
    998 		pfcp = kmem_zalloc(sizeof (portfop_cache_t), KM_SLEEP);
    999 		mutex_enter(&pp->port_queue.portq_source_mutex);
   1000 		if (pse->portsrc_data == NULL) {
   1001 			pse->portsrc_data = pfcp;
   1002 			mutex_exit(&pp->port_queue.portq_source_mutex);
   1003 		} else {
   1004 			/*
   1005 			 * someone else created the port cache, free
   1006 			 * what we just now allocated.
   1007 			 */
   1008 			mutex_exit(&pp->port_queue.portq_source_mutex);
   1009 			kmem_free(pfcp, sizeof (portfop_cache_t));
   1010 			pfcp = pse->portsrc_data;
   1011 		}
   1012 	}
   1013 	*pfcpp = pfcp;
   1014 	return (0);
   1015 }
   1016 
   1017 /*
   1018  * Add the given pvp on the file system's list of vnodes watched.
   1019  */
   1020 int
   1021 port_fop_pvfsadd(portfop_vp_t *pvp)
   1022 {
   1023 	int error = 0;
   1024 	vnode_t	*vp = pvp->pvp_vp;
   1025 	portfop_vfs_hash_t *pvfsh;
   1026 	portfop_vfs_t	 *pvfsp;
   1027 	fsem_t		*fsemp;
   1028 
   1029 	pvfsh = PORTFOP_PVFSH(vp->v_vfsp);
   1030 	mutex_enter(&pvfsh->pvfshash_mutex);
   1031 	for (pvfsp = pvfsh->pvfshash_pvfsp; pvfsp &&
   1032 	    pvfsp->pvfs != vp->v_vfsp; pvfsp = pvfsp->pvfs_next)
   1033 		;
   1034 
   1035 	if (!pvfsp) {
   1036 		if ((fsemp = port_fop_fsemop()) != NULL) {
   1037 			if ((error = fsem_install(vp->v_vfsp, fsemp,
   1038 			    vp->v_vfsp, OPUNIQ, NULL, NULL))) {
   1039 				mutex_exit(&pvfsh->pvfshash_mutex);
   1040 				return (error);
   1041 			}
   1042 		} else {
   1043 			mutex_exit(&pvfsh->pvfshash_mutex);
   1044 			return (EINVAL);
   1045 		}
   1046 		pvfsp = kmem_zalloc(sizeof (portfop_vfs_t), KM_SLEEP);
   1047 		pvfsp->pvfs = vp->v_vfsp;
   1048 		list_create(&(pvfsp->pvfs_pvplist), sizeof (portfop_vp_t),
   1049 		    offsetof(portfop_vp_t, pvp_pvfsnode));
   1050 		pvfsp->pvfs_fsemp = fsemp;
   1051 		pvfsp->pvfs_next = pvfsh->pvfshash_pvfsp;
   1052 		pvfsh->pvfshash_pvfsp = pvfsp;
   1053 	}
   1054 
   1055 	/*
   1056 	 * check if an unmount is in progress.
   1057 	 */
   1058 	if (!pvfsp->pvfs_unmount) {
   1059 		/*
   1060 		 * insert the pvp on list.
   1061 		 */
   1062 		pvp->pvp_pvfsp = pvfsp;
   1063 		list_insert_head(&pvfsp->pvfs_pvplist, (void *)pvp);
   1064 	} else {
   1065 		error = EINVAL;
   1066 	}
   1067 	mutex_exit(&pvfsh->pvfshash_mutex);
   1068 	return (error);
   1069 }
   1070 
   1071 /*
   1072  * Installs the portfop_vp_t data structure on the
   1073  * vnode. The 'pvp_femp == NULL' indicates it is not
   1074  * active. The fem hooks have to be installed.
   1075  * The portfop_vp_t is only freed when the vnode gets freed.
   1076  */
   1077 void
   1078 port_install_fopdata(vnode_t *vp)
   1079 {
   1080 	portfop_vp_t *npvp;
   1081 
   1082 	npvp = kmem_zalloc(sizeof (*npvp), KM_SLEEP);
   1083 	mutex_init(&npvp->pvp_mutex, NULL, MUTEX_DEFAULT, NULL);
   1084 	list_create(&npvp->pvp_pfoplist, sizeof (portfop_t),
   1085 	    offsetof(portfop_t, pfop_node));
   1086 	npvp->pvp_vp = vp;
   1087 	/*
   1088 	 * If v_fopdata is not null, some other thread beat us to it.
   1089 	 */
   1090 	if (casptr(&vp->v_fopdata, NULL, npvp) != NULL) {
   1091 		mutex_destroy(&npvp->pvp_mutex);
   1092 		list_destroy(&npvp->pvp_pfoplist);
   1093 		kmem_free(npvp, sizeof (*npvp));
   1094 	}
   1095 }
   1096 
   1097 
   1098 /*
   1099  * Allocate and add a portfop_t to the per port cache. Also add the portfop_t
   1100  * to the vnode's list. The association is identified by the object pointer
   1101  * address and pid.
   1102  */
   1103 int
   1104 port_pfp_setup(portfop_t **pfpp, port_t *pp, vnode_t *vp, portfop_cache_t *pfcp,
   1105 	uintptr_t object, int events, void *user, char *cname, int clen,
   1106 	vnode_t *dvp)
   1107 {
   1108 	portfop_t	*pfp = NULL;
   1109 	port_kevent_t	*pkevp;
   1110 	fem_t		*femp;
   1111 	int		error = 0;
   1112 	portfop_vp_t	*pvp;
   1113 
   1114 
   1115 	/*
   1116 	 * The port cache mutex is held.
   1117 	 */
   1118 	*pfpp  = NULL;
   1119 
   1120 
   1121 	/*
   1122 	 * At this point the fem monitor is installed.
   1123 	 * Allocate a port event structure per vnode association.
   1124 	 */
   1125 	if (pfp == NULL) {
   1126 		if (error = port_alloc_event_local(pp, PORT_SOURCE_FILE,
   1127 		    PORT_ALLOC_CACHED, &pkevp)) {
   1128 			return (error);
   1129 		}
   1130 		pfp = kmem_zalloc(sizeof (portfop_t), KM_SLEEP);
   1131 		pfp->pfop_pev = pkevp;
   1132 	}
   1133 
   1134 	pfp->pfop_vp = vp;
   1135 	pfp->pfop_pid = curproc->p_pid;
   1136 	pfp->pfop_pcache = pfcp;
   1137 	pfp->pfop_pp = pp;
   1138 	pfp->pfop_flags |= PORT_FOP_ACTIVE;
   1139 	pfp->pfop_cname = cname;
   1140 	pfp->pfop_clen = clen;
   1141 	pfp->pfop_dvp = dvp;
   1142 	pfp->pfop_object = object;
   1143 
   1144 	pkevp->portkev_callback = port_fop_callback;
   1145 	pkevp->portkev_arg = pfp;
   1146 	pkevp->portkev_object = object;
   1147 	pkevp->portkev_user = user;
   1148 	pkevp->portkev_events = 0;
   1149 
   1150 	port_pcache_insert(pfcp, pfp);
   1151 
   1152 	/*
   1153 	 * Register a new file events monitor for this file(vnode), if not
   1154 	 * done already.
   1155 	 */
   1156 	if ((pvp = vp->v_fopdata) == NULL) {
   1157 		port_install_fopdata(vp);
   1158 		pvp = vp->v_fopdata;
   1159 	}
   1160 
   1161 	mutex_enter(&pvp->pvp_mutex);
   1162 	/*
   1163 	 * if the vnode does not have the file events hooks, install it.
   1164 	 */
   1165 	if (pvp->pvp_femp == NULL) {
   1166 		if ((femp = port_fop_femop()) != NULL) {
   1167 			if (!(error = fem_install(pfp->pfop_vp, femp,
   1168 			    (void *)vp, OPUNIQ, NULL, NULL))) {
   1169 				pvp->pvp_femp = femp;
   1170 				/*
   1171 				 * add fsem_t hooks to the vfsp and add pvp to
   1172 				 * the list of vnodes for this vfs.
   1173 				 */
   1174 				if (!(error = port_fop_pvfsadd(pvp))) {
   1175 					/*
   1176 					 * Hold a reference to the vnode since
   1177 					 * we successfully installed the hooks.
   1178 					 */
   1179 					VN_HOLD(vp);
   1180 				} else {
   1181 					(void) fem_uninstall(vp, femp, vp);
   1182 					pvp->pvp_femp = NULL;
   1183 				}
   1184 			}
   1185 		} else {
   1186 			error = EINVAL;
   1187 		}
   1188 	}
   1189 
   1190 	if (error) {
   1191 		/*
   1192 		 * pkevp will get freed here.
   1193 		 */
   1194 		pfp->pfop_cname = NULL;
   1195 		port_pcache_remove_fop(pfcp, pfp);
   1196 		mutex_exit(&pvp->pvp_mutex);
   1197 		return (error);
   1198 	}
   1199 
   1200 	/*
   1201 	 * insert the pfp on the vnode's list. After this
   1202 	 * events can get delivered.
   1203 	 */
   1204 	pfp->pfop_events = events;
   1205 	port_fop_listinsert_head(pvp, pfp);
   1206 
   1207 	mutex_exit(&pvp->pvp_mutex);
   1208 	/*
   1209 	 * Hold the directory vnode since we have a reference now.
   1210 	 */
   1211 	if (dvp != NULL)
   1212 		VN_HOLD(dvp);
   1213 	*pfpp = pfp;
   1214 	return (0);
   1215 }
   1216 
   1217 vnode_t *
   1218 port_resolve_vp(vnode_t *vp)
   1219 {
   1220 	vnode_t *rvp;
   1221 	/*
   1222 	 * special case /etc/mnttab(mntfs type). The mntfstype != 0
   1223 	 * if mntfs got mounted.
   1224 	 */
   1225 	if (vfs_mntdummyvp && mntfstype != 0 &&
   1226 	    vp->v_vfsp->vfs_fstype == mntfstype) {
   1227 		VN_RELE(vp);
   1228 		vp = vfs_mntdummyvp;
   1229 		VN_HOLD(vfs_mntdummyvp);
   1230 	}
   1231 
   1232 	/*
   1233 	 * This should take care of lofs mounted fs systems and nfs4
   1234 	 * hardlinks.
   1235 	 */
   1236 	if ((VOP_REALVP(vp, &rvp, NULL) == 0) && vp != rvp) {
   1237 		VN_HOLD(rvp);
   1238 		VN_RELE(vp);
   1239 		vp = rvp;
   1240 	}
   1241 	return (vp);
   1242 }
   1243 
   1244 /*
   1245  * Register a file events watch on the given file associated to the port *pp.
   1246  *
   1247  * The association is identified by the object pointer and the pid.
   1248  * The events argument contains the events to be monitored for.
   1249  *
   1250  * The vnode will have a VN_HOLD once the fem hooks are installed.
   1251  *
   1252  * Every reference(pfp) to the directory vnode will have a VN_HOLD to ensure
   1253  * that the directory vnode pointer does not change.
   1254  */
   1255 int
   1256 port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
   1257     void *user)
   1258 {
   1259 	portfop_cache_t	*pfcp;
   1260 	vnode_t		*vp, *dvp, *oldvp = NULL, *olddvp = NULL;
   1261 	portfop_t	*pfp;
   1262 	int		error = 0;
   1263 	file_obj_t	fobj;
   1264 	void		*objptr;
   1265 	char		*cname;
   1266 	int		clen;
   1267 	int		follow;
   1268 
   1269 	/*
   1270 	 * check that events specified are valid.
   1271 	 */
   1272 	if ((events & ~FILE_EVENTS_MASK) != 0)
   1273 		return (EINVAL);
   1274 
   1275 	if (get_udatamodel() == DATAMODEL_NATIVE) {
   1276 		if (copyin((void *)object, &fobj, sizeof (file_obj_t)))
   1277 			return (EFAULT);
   1278 		objptr = (void *)&fobj;
   1279 #ifdef  _SYSCALL32_IMPL
   1280 	} else {
   1281 		file_obj32_t	fobj32;
   1282 		if (copyin((void *)object, &fobj32, sizeof (file_obj32_t)))
   1283 			return (EFAULT);
   1284 		objptr = (void *)&fobj32;
   1285 #endif  /* _SYSCALL32_IMPL */
   1286 	}
   1287 
   1288 	vp = dvp = NULL;
   1289 
   1290 	/*
   1291 	 * find out if we need to follow symbolic links.
   1292 	 */
   1293 	follow = !(events & FILE_NOFOLLOW);
   1294 	events = events & ~FILE_NOFOLLOW;
   1295 
   1296 	/*
   1297 	 * lookup and find the vnode and its directory vnode of the given
   1298 	 * file.
   1299 	 */
   1300 	if ((error = port_fop_getdvp(objptr, &vp, &dvp, &cname, &clen,
   1301 	    follow)) != 0) {
   1302 		return (error);
   1303 	}
   1304 
   1305 	if (dvp != NULL) {
   1306 		dvp = port_resolve_vp(dvp);
   1307 	}
   1308 
   1309 	/*
   1310 	 * Not found
   1311 	 */
   1312 	if (vp == NULL) {
   1313 		error = ENOENT;
   1314 		goto errout;
   1315 	}
   1316 
   1317 	vp = port_resolve_vp(vp);
   1318 
   1319 
   1320 	if (vp != NULL && vnevent_support(vp, NULL)) {
   1321 		error = ENOTSUP;
   1322 		goto errout;
   1323 	}
   1324 
   1325 	/*
   1326 	 * Associate this source to the port and get the per port
   1327 	 * fop cache pointer. If the source is already associated, it
   1328 	 * will just return the cache pointer.
   1329 	 */
   1330 	if (error = port_fop_associate_source(&pfcp, pp, source)) {
   1331 		goto errout;
   1332 	}
   1333 
   1334 	/*
   1335 	 * Check if there is an existing association of this file.
   1336 	 */
   1337 	mutex_enter(&pfcp->pfc_lock);
   1338 	pfp = port_cache_lookup_fop(pfcp, curproc->p_pid, object);
   1339 
   1340 	/*
   1341 	 * If it is not the same vnode, just discard it. VN_RELE needs to be
   1342 	 * called with no locks held, therefore save vnode pointers and
   1343 	 * vn_rele them later.
   1344 	 */
   1345 	if (pfp != NULL && (pfp->pfop_vp != vp || pfp->pfop_dvp != dvp)) {
   1346 		(void) port_remove_fop(pfp, pfcp, 1, NULL, &oldvp, &olddvp);
   1347 		pfp = NULL;
   1348 	}
   1349 
   1350 	if (pfp == NULL) {
   1351 		vnode_t *tvp, *tdvp;
   1352 		portfop_t	*tpfp;
   1353 		int error;
   1354 
   1355 		/*
   1356 		 * Add a new association, save the file name and the
   1357 		 * directory vnode pointer.
   1358 		 */
   1359 		if (error = port_pfp_setup(&pfp, pp, vp, pfcp, object,
   1360 		    events, user, cname, clen, dvp)) {
   1361 			mutex_exit(&pfcp->pfc_lock);
   1362 			goto errout;
   1363 		}
   1364 
   1365 		pfp->pfop_callrid = curthread;
   1366 		/*
   1367 		 * File name used, so make sure we don't free it.
   1368 		 */
   1369 		cname = NULL;
   1370 
   1371 		/*
   1372 		 * We need to check if the file was removed after the
   1373 		 * the lookup and before the fem hooks where added. If
   1374 		 * so, return error. The vnode will still exist as we have
   1375 		 * a hold on it.
   1376 		 *
   1377 		 * Drop the cache lock before calling port_fop_getdvp().
   1378 		 * port_fop_getdvp() may block either in the vfs layer
   1379 		 * or some filesystem.  Therefore there is potential
   1380 		 * for deadlock if cache lock is held and if some other
   1381 		 * thread is attempting to deliver file events which would
   1382 		 * require getting the cache lock, while it may be holding
   1383 		 * the filesystem or vfs layer locks.
   1384 		 */
   1385 		mutex_exit(&pfcp->pfc_lock);
   1386 		tvp = NULL;
   1387 		if ((error = port_fop_getdvp(objptr, &tvp, NULL,
   1388 		    NULL, NULL, follow)) == 0) {
   1389 			if (tvp != NULL) {
   1390 				tvp = port_resolve_vp(tvp);
   1391 				/*
   1392 				 * This vnode pointer is just used
   1393 				 * for comparison, so rele it
   1394 				 */
   1395 				VN_RELE(tvp);
   1396 			}
   1397 		}
   1398 
   1399 		if (error || tvp == NULL || tvp != vp) {
   1400 			/*
   1401 			 * Since we dropped the cache lock, make sure
   1402 			 * we are still dealing with the same pfp and this
   1403 			 * is the thread which registered it.
   1404 			 */
   1405 			mutex_enter(&pfcp->pfc_lock);
   1406 			tpfp = port_cache_lookup_fop(pfcp,
   1407 			    curproc->p_pid, object);
   1408 
   1409 			error = 0;
   1410 			if (tpfp == NULL || tpfp != pfp ||
   1411 			    pfp->pfop_vp != vp ||
   1412 			    pfp->pfop_dvp != dvp ||
   1413 			    pfp->pfop_callrid != curthread) {
   1414 				/*
   1415 				 * Some other event was delivered, the file
   1416 				 * watch was removed or reassociated, just
   1417 				 * ignore it and leave
   1418 				 */
   1419 				mutex_exit(&pfcp->pfc_lock);
   1420 				goto errout;
   1421 			}
   1422 
   1423 			/*
   1424 			 * remove the pfp and fem hooks, if pfp still
   1425 			 * active and it is not being removed from
   1426 			 * the vnode list. This is checked in
   1427 			 * port_remove_fop with the vnode lock held.
   1428 			 * The vnode returned is VN_RELE'ed after dropping
   1429 			 * the locks.
   1430 			 */
   1431 			tdvp = tvp = NULL;
   1432 			if (port_remove_fop(pfp, pfcp, 0, NULL, &tvp, &tdvp)) {
   1433 				/*
   1434 				 * The pfp was removed, means no
   1435 				 * events where queued. Report the
   1436 				 * error now.
   1437 				 */
   1438 				error = EINVAL;
   1439 			}
   1440 			mutex_exit(&pfcp->pfc_lock);
   1441 			if (tvp != NULL)
   1442 				VN_RELE(tvp);
   1443 			if (tdvp != NULL)
   1444 				VN_RELE(tdvp);
   1445 			goto errout;
   1446 		}
   1447 	} else {
   1448 		portfop_vp_t	*pvp = vp->v_fopdata;
   1449 
   1450 		/*
   1451 		 * Re-association of the object.
   1452 		 */
   1453 		mutex_enter(&pvp->pvp_mutex);
   1454 
   1455 		/*
   1456 		 * remove any queued up event.
   1457 		 */
   1458 		if (port_remove_done_event(pfp->pfop_pev)) {
   1459 			pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ;
   1460 		}
   1461 
   1462 		/*
   1463 		 * set new events to watch.
   1464 		 */
   1465 		pfp->pfop_events = events;
   1466 
   1467 		/*
   1468 		 * If not active, mark it active even if it is being
   1469 		 * removed. Then it can send an exception event.
   1470 		 *
   1471 		 * Move it to the head, as the active ones are only
   1472 		 * in the beginning. If removing, the pfp will be on
   1473 		 * a temporary list, no need to move it to the front
   1474 		 * all the entries will be processed. Some exception
   1475 		 * events will be delivered in port_fop_excep();
   1476 		 */
   1477 		if (!(pfp->pfop_flags & PORT_FOP_ACTIVE)) {
   1478 			pfp->pfop_flags |= PORT_FOP_ACTIVE;
   1479 			if (!(pfp->pfop_flags & PORT_FOP_REMOVING)) {
   1480 				pvp = (portfop_vp_t *)vp->v_fopdata;
   1481 				port_fop_listremove(pvp, pfp);
   1482 				port_fop_listinsert_head(pvp, pfp);
   1483 			}
   1484 		}
   1485 		pfp->pfop_callrid = curthread;
   1486 		mutex_exit(&pvp->pvp_mutex);
   1487 		mutex_exit(&pfcp->pfc_lock);
   1488 	}
   1489 
   1490 	/*
   1491 	 * Compare time stamps and deliver events.
   1492 	 */
   1493 	if (vp->v_type != VFIFO) {
   1494 		port_check_timestamp(pfcp, vp, dvp, pfp, objptr, object);
   1495 	}
   1496 
   1497 	error = 0;
   1498 
   1499 	/*
   1500 	 *  If we have too many watches on the vnode, discard an
   1501 	 *  inactive watch.
   1502 	 */
   1503 	port_fop_trimpfplist(vp);
   1504 
   1505 errout:
   1506 	/*
   1507 	 * Release the hold acquired due to the lookup operation.
   1508 	 */
   1509 	if (vp != NULL)
   1510 		VN_RELE(vp);
   1511 	if (dvp != NULL)
   1512 		VN_RELE(dvp);
   1513 
   1514 	if (oldvp != NULL)
   1515 		VN_RELE(oldvp);
   1516 	if (olddvp != NULL)
   1517 		VN_RELE(olddvp);
   1518 
   1519 	/*
   1520 	 * copied file name not used, free it.
   1521 	 */
   1522 	if (cname != NULL) {
   1523 		kmem_free(cname, clen + 1);
   1524 	}
   1525 	return (error);
   1526 }
   1527 
   1528 
   1529 /*
   1530  * The port_dissociate_fop() function dissociates the file object
   1531  * from the event port and removes any events that are already on the queue.
   1532  * Only the owner of the association is allowed to dissociate the file from
   1533  * the port. Returns  success (0) if it was found and removed. Otherwise
   1534  * ENOENT.
   1535  */
   1536 int
   1537 port_dissociate_fop(port_t *pp, uintptr_t object)
   1538 {
   1539 	portfop_cache_t	*pfcp;
   1540 	portfop_t	*pfp;
   1541 	port_source_t	*pse;
   1542 	int		active = 0;
   1543 	vnode_t		*tvp = NULL, *tdvp = NULL;
   1544 
   1545 	pse = port_getsrc(pp, PORT_SOURCE_FILE);
   1546 
   1547 	/*
   1548 	 * if this source is not associated or if there is no
   1549 	 * cache, nothing to do just return.
   1550 	 */
   1551 	if (pse == NULL ||
   1552 	    (pfcp = (portfop_cache_t *)pse->portsrc_data) == NULL)
   1553 		return (EINVAL);
   1554 
   1555 	/*
   1556 	 * Check if this object is on the cache. Only the owner pid
   1557 	 * is allowed to dissociate.
   1558 	 */
   1559 	mutex_enter(&pfcp->pfc_lock);
   1560 	pfp = port_cache_lookup_fop(pfcp, curproc->p_pid, object);
   1561 	if (pfp == NULL) {
   1562 		mutex_exit(&pfcp->pfc_lock);
   1563 		return (ENOENT);
   1564 	}
   1565 
   1566 	/*
   1567 	 * If this was the last association, it will release
   1568 	 * the hold on the vnode. There is a race condition where
   1569 	 * the the pfp is being removed due to an exception event
   1570 	 * in port_fop_sendevent()->port_fop_excep() and port_remove_fop().
   1571 	 * Since port source cache lock is held, port_fop_excep() cannot
   1572 	 * complete. The vnode itself will not disappear as long its pfps
   1573 	 * have a reference.
   1574 	 */
   1575 	(void) port_remove_fop(pfp, pfcp, 1, &active, &tvp, &tdvp);
   1576 	mutex_exit(&pfcp->pfc_lock);
   1577 	if (tvp != NULL)
   1578 		VN_RELE(tvp);
   1579 	if (tdvp != NULL)
   1580 		VN_RELE(tdvp);
   1581 	return (active ? 0 : ENOENT);
   1582 }
   1583 
   1584 
   1585 /*
   1586  * port_close() calls this function to request the PORT_SOURCE_FILE source
   1587  * to remove/free all resources allocated and associated with the port.
   1588  */
   1589 
   1590 /* ARGSUSED */
   1591 static void
   1592 port_close_fop(void *arg, int port, pid_t pid, int lastclose)
   1593 {
   1594 	port_t		*pp = arg;
   1595 	portfop_cache_t	*pfcp;
   1596 	portfop_t	**hashtbl;
   1597 	portfop_t	*pfp;
   1598 	portfop_t	*pfpnext;
   1599 	int		index, i;
   1600 	port_source_t	*pse;
   1601 	vnode_t 	*tdvp = NULL;
   1602 	vnode_t		*vpl[PORTFOP_NVP];
   1603 
   1604 	pse = port_getsrc(pp, PORT_SOURCE_FILE);
   1605 
   1606 	/*
   1607 	 * No source or no cache, nothing to do.
   1608 	 */
   1609 	if (pse == NULL ||
   1610 	    (pfcp = (portfop_cache_t *)pse->portsrc_data) == NULL)
   1611 		return;
   1612 	/*
   1613 	 * Scan the cache and free all allocated portfop_t and port_kevent_t
   1614 	 * structures of this pid. Note, no new association for this pid will
   1615 	 * be possible as the port is being closed.
   1616 	 *
   1617 	 * The common case is that the port is not shared and all the entries
   1618 	 * are of this pid and have to be freed. Since VN_RELE has to be
   1619 	 * called outside the lock, we do it in batches.
   1620 	 */
   1621 	hashtbl = (portfop_t **)pfcp->pfc_hash;
   1622 	index = i = 0;
   1623 	bzero(vpl, sizeof (vpl));
   1624 	mutex_enter(&pfcp->pfc_lock);
   1625 	while (index < PORTFOP_HASHSIZE) {
   1626 		pfp = hashtbl[index];
   1627 		while (pfp != NULL && i < (PORTFOP_NVP - 1)) {
   1628 			pfpnext = pfp->pfop_hashnext;
   1629 			if (pid == pfp->pfop_pid) {
   1630 				(void) port_remove_fop(pfp, pfcp, 1, NULL,
   1631 				    &vpl[i], &tdvp);
   1632 				if (vpl[i] != NULL) {
   1633 					i++;
   1634 				}
   1635 				if (tdvp != NULL) {
   1636 					vpl[i++] = tdvp;
   1637 					tdvp = NULL;
   1638 				}
   1639 			}
   1640 			pfp = pfpnext;
   1641 		}
   1642 		if (pfp == NULL)
   1643 			index++;
   1644 		/*
   1645 		 * Now call VN_RELE if we have collected enough vnodes or
   1646 		 * we have reached the end of the hash table.
   1647 		 */
   1648 		if (i >= (PORTFOP_NVP - 1) ||
   1649 		    (i > 0 && index == PORTFOP_HASHSIZE)) {
   1650 			mutex_exit(&pfcp->pfc_lock);
   1651 			while (i > 0) {
   1652 				VN_RELE(vpl[--i]);
   1653 				vpl[i] = NULL;
   1654 			}
   1655 			mutex_enter(&pfcp->pfc_lock);
   1656 		}
   1657 	}
   1658 
   1659 	/*
   1660 	 * Due to a race between port_close_fop() and port_fop()
   1661 	 * trying to remove the pfp's from the port's cache, it is
   1662 	 * possible that some pfp's are still in the process of being
   1663 	 * freed so we wait.
   1664 	 */
   1665 	while (lastclose && pfcp->pfc_objcount) {
   1666 		(void) cv_wait_sig(&pfcp->pfc_lclosecv, &pfcp->pfc_lock);
   1667 	}
   1668 	mutex_exit(&pfcp->pfc_lock);
   1669 	/*
   1670 	 * last close, free the cache.
   1671 	 */
   1672 	if (lastclose) {
   1673 		ASSERT(pfcp->pfc_objcount == 0);
   1674 		pse->portsrc_data = NULL;
   1675 		kmem_free(pfcp, sizeof (portfop_cache_t));
   1676 	}
   1677 }
   1678 
   1679 /*
   1680  * Given the list of associations(watches), it will send exception events,
   1681  * if still active, and discard them. The exception events are handled
   1682  * separately because, the pfp needs to be removed from the port cache and
   1683  * freed as the vnode's identity is changing or being removed. To remove
   1684  * the pfp from the port's cache, we need to hold the cache lock (pfc_lock).
   1685  * The lock order is pfc_lock -> pvp_mutex(vnode's) mutex and that is why
   1686  * the cache's lock cannot be acquired in port_fop_sendevent().
   1687  */
   1688 static void
   1689 port_fop_excep(list_t *tlist, int op)
   1690 {
   1691 	portfop_t	*pfp;
   1692 	portfop_cache_t *pfcp;
   1693 	port_t	*pp;
   1694 	port_kevent_t	*pkevp;
   1695 	vnode_t		*tdvp;
   1696 	int		error = 0;
   1697 
   1698 	while (pfp = (portfop_t *)list_head(tlist)) {
   1699 		int removed = 0;
   1700 		/*
   1701 		 * remove from the temp list. Since PORT_FOP_REMOVING is
   1702 		 * set, no other thread should attempt to perform a
   1703 		 * list_remove on this pfp.
   1704 		 */
   1705 		list_remove(tlist, pfp);
   1706 
   1707 		pfcp = pfp->pfop_pcache;
   1708 		mutex_enter(&pfcp->pfc_lock);
   1709 
   1710 		/*
   1711 		 * Remove the event from the port queue if it was queued up.
   1712 		 * No need to clear the PORT_FOP_KEV_ONQ flag as this pfp is
   1713 		 * no longer on the vnode's list.
   1714 		 */
   1715 		if ((pfp->pfop_flags & PORT_FOP_KEV_ONQ)) {
   1716 			removed = port_remove_done_event(pfp->pfop_pev);
   1717 		}
   1718 
   1719 		/*
   1720 		 * If still active or the event was queued up and
   1721 		 * had not been collected yet, send an EXCEPTION event.
   1722 		 */
   1723 		if (pfp->pfop_flags & (PORT_FOP_ACTIVE) || removed) {
   1724 			pp = pfp->pfop_pp;
   1725 			/*
   1726 			 * Allocate a port_kevent_t non cached to send this
   1727 			 * event since we will be de-registering.
   1728 			 * The port_kevent_t cannot be pointing back to the
   1729 			 * pfp anymore.
   1730 			 */
   1731 			pfp->pfop_flags &= ~PORT_FOP_ACTIVE;
   1732 			error = port_alloc_event_local(pp, PORT_SOURCE_FILE,
   1733 			    PORT_ALLOC_DEFAULT, &pkevp);
   1734 			if (!error) {
   1735 
   1736 				pkevp->portkev_callback = port_fop_callback;
   1737 				pkevp->portkev_arg = NULL;
   1738 				pkevp->portkev_object =
   1739 				    pfp->pfop_pev->portkev_object;
   1740 				pkevp->portkev_user =
   1741 				    pfp->pfop_pev->portkev_user;
   1742 				/*
   1743 				 * Copy the pid of the watching process.
   1744 				 */
   1745 				pkevp->portkev_pid =
   1746 				    pfp->pfop_pev->portkev_pid;
   1747 				pkevp->portkev_events = op;
   1748 				port_send_event(pkevp);
   1749 			}
   1750 		}
   1751 		/*
   1752 		 * At this point the pfp has been removed from the vnode's
   1753 		 * list its cached port_kevent_t is not on the done queue.
   1754 		 * Remove the pfp and free it from the cache.
   1755 		 */
   1756 		tdvp = pfp->pfop_dvp;
   1757 		port_pcache_remove_fop(pfcp, pfp);
   1758 		mutex_exit(&pfcp->pfc_lock);
   1759 		if (tdvp != NULL)
   1760 			VN_RELE(tdvp);
   1761 	}
   1762 }
   1763 
   1764 /*
   1765  * Send the file events to all of the processes watching this
   1766  * vnode. In case of hard links, the directory vnode pointer and
   1767  * the file name are compared. If the names match, then the specified
   1768  * event is sent or else, the FILE_ATTRIB event is sent, This is the
   1769  * documented behavior.
   1770  */
   1771 void
   1772 port_fop_sendevent(vnode_t *vp, int events, vnode_t *dvp, char *cname)
   1773 {
   1774 	port_kevent_t	*pkevp;
   1775 	portfop_t	*pfp, *npfp;
   1776 	portfop_vp_t	*pvp;
   1777 	list_t		tmplist;
   1778 	int		removeall = 0;
   1779 
   1780 	pvp = (portfop_vp_t *)vp->v_fopdata;
   1781 	mutex_enter(&pvp->pvp_mutex);
   1782 
   1783 	/*
   1784 	 * Check if the list is empty.
   1785 	 *
   1786 	 * All entries have been removed by some other thread.
   1787 	 * The vnode may be still active and we got called,
   1788 	 * but some other thread is in the process of removing the hooks.
   1789 	 */
   1790 	if (!list_head(&pvp->pvp_pfoplist)) {
   1791 		mutex_exit(&pvp->pvp_mutex);
   1792 		return;
   1793 	}
   1794 
   1795 	if ((events & (FILE_EXCEPTION))) {
   1796 		/*
   1797 		 * If it is an event for which we are going to remove
   1798 		 * the watches so just move it a temporary list and
   1799 		 * release this vnode.
   1800 		 */
   1801 		list_create(&tmplist, sizeof (portfop_t),
   1802 		    offsetof(portfop_t, pfop_node));
   1803 
   1804 		/*
   1805 		 * If it is an UNMOUNT, MOUNTEDOVER or no file name has been
   1806 		 * passed for an exception event, all associations need to be
   1807 		 * removed.
   1808 		 */
   1809 		if (dvp == NULL || cname == NULL) {
   1810 			removeall = 1;
   1811 		}
   1812 	}
   1813 
   1814 	if (!removeall) {
   1815 		/*
   1816 		 * All the active ones are in the beginning of the list.
   1817 		 */
   1818 		for (pfp = (portfop_t *)list_head(&pvp->pvp_pfoplist);
   1819 		    pfp && pfp->pfop_flags & PORT_FOP_ACTIVE; pfp = npfp) {
   1820 			int levents = events;
   1821 
   1822 			npfp = list_next(&pvp->pvp_pfoplist, pfp);
   1823 			/*
   1824 			 * Hard links case - If the file is being
   1825 			 * removed/renamed, and the name matches
   1826 			 * the watched file, then it is an EXCEPTION
   1827 			 * event or else it will be just a FILE_ATTRIB.
   1828 			 */
   1829 			if ((events & (FILE_EXCEPTION))) {
   1830 				ASSERT(dvp != NULL && cname != NULL);
   1831 				if (pfp->pfop_dvp == NULL ||
   1832 				    (pfp->pfop_dvp == dvp &&
   1833 				    (strcmp(cname, pfp->pfop_cname) == 0))) {
   1834 					/*
   1835 					 * It is an exception event, move it
   1836 					 * to temp list and process it later.
   1837 					 * Note we don't set the pfp->pfop_vp
   1838 					 * to NULL even thought it has been
   1839 					 * removed from the vnode's list. This
   1840 					 * pointer is referenced in
   1841 					 * port_remove_fop(). The vnode it
   1842 					 * self cannot disappear until this
   1843 					 * pfp gets removed and freed.
   1844 					 */
   1845 					port_fop_listremove(pvp, pfp);
   1846 					list_insert_tail(&tmplist, (void *)pfp);
   1847 					pfp->pfop_flags  |= PORT_FOP_REMOVING;
   1848 					continue;
   1849 				} else {
   1850 					levents = FILE_ATTRIB;
   1851 				}
   1852 
   1853 			}
   1854 
   1855 			if (pfp->pfop_events & levents) {
   1856 				/*
   1857 				 * deactivate and move it to the tail.
   1858 				 * If the pfp was active, it cannot be
   1859 				 * on the port's done queue.
   1860 				 */
   1861 				pfp->pfop_flags &= ~PORT_FOP_ACTIVE;
   1862 				port_fop_listremove(pvp, pfp);
   1863 				port_fop_listinsert_tail(pvp, pfp);
   1864 
   1865 				pkevp = pfp->pfop_pev;
   1866 				pkevp->portkev_events |=
   1867 				    (levents & pfp->pfop_events);
   1868 				port_send_event(pkevp);
   1869 				pfp->pfop_flags |= PORT_FOP_KEV_ONQ;
   1870 			}
   1871 		}
   1872 	}
   1873 
   1874 
   1875 	if ((events & (FILE_EXCEPTION))) {
   1876 		if (!removeall) {
   1877 			/*
   1878 			 * Check the inactive associations and remove them if
   1879 			 * the file name matches.
   1880 			 */
   1881 			for (; pfp; pfp = npfp) {
   1882 				npfp = list_next(&pvp->pvp_pfoplist, pfp);
   1883 				if (dvp == NULL || cname == NULL ||
   1884 				    pfp->pfop_dvp == NULL ||
   1885 				    (pfp->pfop_dvp == dvp &&
   1886 				    (strcmp(cname, pfp->pfop_cname) == 0))) {
   1887 					port_fop_listremove(pvp, pfp);
   1888 					list_insert_tail(&tmplist, (void *)pfp);
   1889 					pfp->pfop_flags  |= PORT_FOP_REMOVING;
   1890 				}
   1891 			}
   1892 		} else {
   1893 			/*
   1894 			 * Can be optimized to avoid two pass over this list
   1895 			 * by having a flag in the vnode's portfop_vp_t
   1896 			 * structure to indicate that it is going away,
   1897 			 * Or keep the list short by reusing inactive watches.
   1898 			 */
   1899 			port_fop_listmove(pvp, &tmplist);
   1900 			for (pfp = (portfop_t *)list_head(&tmplist);
   1901 			    pfp; pfp = list_next(&tmplist, pfp)) {
   1902 				pfp->pfop_flags |= PORT_FOP_REMOVING;
   1903 			}
   1904 		}
   1905 
   1906 		/*
   1907 		 * Uninstall the fem hooks if there are no more associations.
   1908 		 * This will release the pvp mutex.
   1909 		 *
   1910 		 * Even thought all entries may have been removed,
   1911 		 * the vnode itself cannot disappear as there will be a
   1912 		 * hold on it due to this call to port_fop_sendevent. This is
   1913 		 * important to syncronize with a port_dissociate_fop() call
   1914 		 * that may be attempting to remove an object from the vnode's.
   1915 		 */
   1916 		if (port_fop_femuninstall(vp))
   1917 			VN_RELE(vp);
   1918 
   1919 		/*
   1920 		 * Send exception events and discard the watch entries.
   1921 		 */
   1922 		port_fop_excep(&tmplist, events);
   1923 		list_destroy(&tmplist);
   1924 
   1925 	} else {
   1926 		mutex_exit(&pvp->pvp_mutex);
   1927 
   1928 		/*
   1929 		 * trim the list.
   1930 		 */
   1931 		port_fop_trimpfplist(vp);
   1932 	}
   1933 }
   1934 
   1935 /*
   1936  * Given the file operation, map it to the event types and send.
   1937  */
   1938 void
   1939 port_fop(vnode_t *vp, int op, int retval)
   1940 {
   1941 	int event = 0;
   1942 	/*
   1943 	 * deliver events only if the operation was successful.
   1944 	 */
   1945 	if (retval)
   1946 		return;
   1947 
   1948 	/*
   1949 	 * These events occurring on the watched file.
   1950 	 */
   1951 	if (op & FOP_MODIFIED_MASK) {
   1952 		event  = FILE_MODIFIED;
   1953 	}
   1954 	if (op & FOP_ACCESS_MASK) {
   1955 		event  |= FILE_ACCESS;
   1956 	}
   1957 	if (op & FOP_ATTRIB_MASK) {
   1958 		event  |= FILE_ATTRIB;
   1959 	}
   1960 
   1961 	if (event) {
   1962 		port_fop_sendevent(vp, 	event, NULL, NULL);
   1963 	}
   1964 }
   1965 
   1966 static int port_forceunmount(vfs_t *vfsp)
   1967 {
   1968 	char *fsname = vfssw[vfsp->vfs_fstype].vsw_name;
   1969 
   1970 	if (fsname == NULL) {
   1971 		return (0);
   1972 	}
   1973 
   1974 	if (strcmp(fsname, MNTTYPE_NFS) == 0) {
   1975 		return (1);
   1976 	}
   1977 
   1978 	if (strcmp(fsname, MNTTYPE_NFS3) == 0) {
   1979 		return (1);
   1980 	}
   1981 
   1982 	if (strcmp(fsname, MNTTYPE_NFS4) == 0) {
   1983 		return (1);
   1984 	}
   1985 	return (0);
   1986 }
   1987 /*
   1988  * ----- the unmount filesystem op(fsem) hook.
   1989  */
   1990 int
   1991 port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr)
   1992 {
   1993 	vfs_t	*vfsp = (vfs_t *)vf->fa_fnode->fn_available;
   1994 	kmutex_t	*mtx;
   1995 	portfop_vfs_t	*pvfsp, **ppvfsp;
   1996 	portfop_vp_t	*pvp;
   1997 	int error;
   1998 	int fmfs;
   1999 
   2000 	fmfs = port_forceunmount(vfsp);
   2001 
   2002 	mtx = &(portvfs_hash[PORTFOP_PVFSHASH(vfsp)].pvfshash_mutex);
   2003 	ppvfsp = &(portvfs_hash[PORTFOP_PVFSHASH(vfsp)].pvfshash_pvfsp);
   2004 	pvfsp = NULL;
   2005 	mutex_enter(mtx);
   2006 	/*
   2007 	 * since this fsem hook is triggered, the vfsp has to be on
   2008 	 * the hash list.
   2009 	 */
   2010 	for (pvfsp = *ppvfsp; pvfsp->pvfs != vfsp; pvfsp = pvfsp->pvfs_next)
   2011 	;
   2012 
   2013 	/*
   2014 	 * For some of the filesystems, allow unmounts to proceed only if
   2015 	 * there are no files being watched or it is a forced unmount.
   2016 	 */
   2017 	if (fmfs && !(flag & MS_FORCE) &&
   2018 	    !list_is_empty(&pvfsp->pvfs_pvplist)) {
   2019 		mutex_exit(mtx);
   2020 		return (EBUSY);
   2021 	}
   2022 
   2023 	/*
   2024 	 * Indicate that the unmount is in process. Don't remove it yet.
   2025 	 * The underlying filesystem unmount routine sets the VFS_UNMOUNTED
   2026 	 * flag on the vfs_t structure. But we call the filesystem unmount
   2027 	 * routine after removing all the file watches for this filesystem,
   2028 	 * otherwise the unmount will fail due to active vnodes.
   2029 	 * Meanwhile setting pvfsp->unmount = 1 will prevent any thread
   2030 	 * attempting to add a file watch.
   2031 	 */
   2032 	pvfsp->pvfs_unmount = 1;
   2033 	mutex_exit(mtx);
   2034 
   2035 	/*
   2036 	 * uninstall the fsem hooks.
   2037 	 */
   2038 	(void) fsem_uninstall(vfsp, (fsem_t *)pvfsp->pvfs_fsemp, vfsp);
   2039 
   2040 	while (pvp = list_head(&pvfsp->pvfs_pvplist)) {
   2041 		list_remove(&pvfsp->pvfs_pvplist, pvp);
   2042 		/*
   2043 		 * This should send an UNMOUNTED event to all the
   2044 		 * watched vnode of this filesystem and uninstall
   2045 		 * the fem hooks. We release the hold on the vnode here
   2046 		 * because port_fop_femuninstall() will not do it if
   2047 		 * unmount is in process.
   2048 		 */
   2049 		port_fop_sendevent(pvp->pvp_vp, UNMOUNTED, NULL, NULL);
   2050 		VN_RELE(pvp->pvp_vp);
   2051 	}
   2052 
   2053 	error = vfsnext_unmount(vf, flag, cr);
   2054 
   2055 	/*
   2056 	 * we free the pvfsp after the unmount has been completed.
   2057 	 */
   2058 	mutex_enter(mtx);
   2059 	for (; *ppvfsp && (*ppvfsp)->pvfs != vfsp;
   2060 	    ppvfsp = &(*ppvfsp)->pvfs_next)
   2061 	;
   2062 
   2063 	/*
   2064 	 * remove and free it.
   2065 	 */
   2066 	ASSERT(list_head(&pvfsp->pvfs_pvplist) == NULL);
   2067 	if (*ppvfsp) {
   2068 		pvfsp = *ppvfsp;
   2069 		*ppvfsp = pvfsp->pvfs_next;
   2070 	}
   2071 	mutex_exit(mtx);
   2072 	kmem_free(pvfsp, sizeof (portfop_vfs_t));
   2073 	return (error);
   2074 }
   2075 
   2076 /*
   2077  * ------------------------------file op hooks--------------------------
   2078  * The O_TRUNC operation is caught with the VOP_SETATTR(AT_SIZE) call.
   2079  */
   2080 static int
   2081 port_fop_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
   2082 {
   2083 	int		retval;
   2084 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2085 
   2086 	retval = vnext_open(vf, mode, cr, ct);
   2087 	port_fop(vp, FOP_FILE_OPEN, retval);
   2088 	return (retval);
   2089 }
   2090 
   2091 static int
   2092 port_fop_write(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr,
   2093     caller_context_t *ct)
   2094 {
   2095 	int		retval;
   2096 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2097 
   2098 	retval =  vnext_write(vf, uiop, ioflag, cr, ct);
   2099 	port_fop(vp, FOP_FILE_WRITE, retval);
   2100 	return (retval);
   2101 }
   2102 
   2103 static int
   2104 port_fop_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
   2105     size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr,
   2106     caller_context_t *ct)
   2107 {
   2108 	int		retval;
   2109 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2110 
   2111 	retval =  vnext_map(vf, off, as, addrp, len, prot, maxport,
   2112 	    flags, cr, ct);
   2113 	port_fop(vp, FOP_FILE_MAP, retval);
   2114 	return (retval);
   2115 }
   2116 
   2117 static int
   2118 port_fop_read(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr,
   2119     caller_context_t *ct)
   2120 {
   2121 	int		retval;
   2122 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2123 
   2124 	retval =  vnext_read(vf, uiop, ioflag, cr, ct);
   2125 	port_fop(vp, FOP_FILE_READ, retval);
   2126 	return (retval);
   2127 }
   2128 
   2129 
   2130 /*
   2131  * AT_SIZE - is for the open(O_TRUNC) case.
   2132  */
   2133 int
   2134 port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
   2135     caller_context_t *ct)
   2136 {
   2137 	int		retval;
   2138 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2139 	int		events = 0;
   2140 
   2141 	retval = vnext_setattr(vf, vap, flags, cr, ct);
   2142 	if (vap->va_mask & (AT_SIZE|AT_MTIME)) {
   2143 		events |= FOP_FILE_SETATTR_MTIME;
   2144 	}
   2145 	if (vap->va_mask & AT_ATIME) {
   2146 		events |= FOP_FILE_SETATTR_ATIME;
   2147 	}
   2148 	events |= FOP_FILE_SETATTR_CTIME;
   2149 
   2150 	port_fop(vp, events, retval);
   2151 	return (retval);
   2152 }
   2153 
   2154 int
   2155 port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
   2156     int mode, vnode_t **vpp, cred_t *cr, int flag,
   2157     caller_context_t *ct, vsecattr_t *vsecp)
   2158 {
   2159 	int		retval, got = 1;
   2160 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2161 	vattr_t		vatt, vatt1;
   2162 
   2163 	/*
   2164 	 * If the file already exists, then there will be no change
   2165 	 * to the directory. Therefore, we need to compare the
   2166 	 * modification time of the directory to determine if the
   2167 	 * file was actually created.
   2168 	 */
   2169 	vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
   2170 	if (VOP_GETATTR(vp, &vatt, 0, CRED(), ct)) {
   2171 		got = 0;
   2172 	}
   2173 	retval = vnext_create(vf, name, vap, excl, mode, vpp, cr,
   2174 	    flag, ct, vsecp);
   2175 
   2176 	vatt1.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
   2177 	if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED(), ct)) {
   2178 		if ((vatt1.va_mtime.tv_sec > vatt.va_mtime.tv_sec ||
   2179 		    (vatt1.va_mtime.tv_sec = vatt.va_mtime.tv_sec &&
   2180 		    vatt1.va_mtime.tv_nsec > vatt.va_mtime.tv_nsec))) {
   2181 			/*
   2182 			 * File was created.
   2183 			 */
   2184 			port_fop(vp, FOP_FILE_CREATE, retval);
   2185 		}
   2186 	}
   2187 	return (retval);
   2188 }
   2189 
   2190 int
   2191 port_fop_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
   2192     int flags)
   2193 {
   2194 	int		retval;
   2195 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2196 
   2197 	retval = vnext_remove(vf, nm, cr, ct, flags);
   2198 	port_fop(vp, FOP_FILE_REMOVE, retval);
   2199 	return (retval);
   2200 }
   2201 
   2202 int
   2203 port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
   2204     caller_context_t *ct, int flags)
   2205 {
   2206 	int		retval;
   2207 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2208 
   2209 	retval = vnext_link(vf, svp, tnm, cr, ct, flags);
   2210 	port_fop(vp, FOP_FILE_LINK, retval);
   2211 	return (retval);
   2212 }
   2213 
   2214 /*
   2215  * Rename operation is allowed only when from and to directories are
   2216  * on the same filesystem. This is checked in vn_rename().
   2217  * The target directory is notified thru a VNEVENT by the filesystem
   2218  * if the source dir != target dir.
   2219  */
   2220 int
   2221 port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
   2222     caller_context_t *ct, int flags)
   2223 {
   2224 	int		retval;
   2225 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2226 
   2227 	retval = vnext_rename(vf, snm, tdvp, tnm, cr, ct, flags);
   2228 	port_fop(vp, FOP_FILE_RENAMESRC, retval);
   2229 	return (retval);
   2230 }
   2231 
   2232 int
   2233 port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
   2234     cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
   2235 {
   2236 	int		retval;
   2237 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2238 
   2239 	retval = vnext_mkdir(vf, dirname, vap, vpp, cr, ct, flags, vsecp);
   2240 	port_fop(vp, FOP_FILE_MKDIR, retval);
   2241 	return (retval);
   2242 }
   2243 
   2244 int
   2245 port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
   2246     caller_context_t *ct, int flags)
   2247 {
   2248 	int		retval;
   2249 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2250 
   2251 	retval = vnext_rmdir(vf, nm, cdir, cr, ct, flags);
   2252 	port_fop(vp, FOP_FILE_RMDIR, retval);
   2253 	return (retval);
   2254 }
   2255 
   2256 int
   2257 port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
   2258     caller_context_t *ct, int flags)
   2259 {
   2260 	int		retval;
   2261 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2262 
   2263 	retval = vnext_readdir(vf, uiop, cr, eofp, ct, flags);
   2264 	port_fop(vp, FOP_FILE_READDIR, retval);
   2265 	return (retval);
   2266 }
   2267 
   2268 int
   2269 port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
   2270     cred_t *cr, caller_context_t *ct, int flags)
   2271 {
   2272 	int		retval;
   2273 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2274 
   2275 	retval = vnext_symlink(vf, linkname, vap, target, cr, ct, flags);
   2276 	port_fop(vp, FOP_FILE_SYMLINK, retval);
   2277 	return (retval);
   2278 }
   2279 
   2280 /*
   2281  * acl, facl call this.
   2282  */
   2283 int
   2284 port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr,
   2285     caller_context_t *ct)
   2286 {
   2287 	int	retval;
   2288 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2289 	retval = vnext_setsecattr(vf, vsap, flags, cr, ct);
   2290 	port_fop(vp, FOP_FILE_SETSECATTR, retval);
   2291 	return (retval);
   2292 }
   2293 
   2294 /*
   2295  * these are events on the watched file/directory
   2296  */
   2297 int
   2298 port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name,
   2299     caller_context_t *ct)
   2300 {
   2301 	vnode_t		*vp = (vnode_t *)vf->fa_fnode->fn_available;
   2302 
   2303 	switch (vnevent) {
   2304 	case	VE_RENAME_SRC:
   2305 			port_fop_sendevent(vp, FILE_RENAME_FROM, dvp, name);
   2306 		break;
   2307 	case	VE_RENAME_DEST:
   2308 			port_fop_sendevent(vp, FILE_RENAME_TO, dvp, name);
   2309 		break;
   2310 	case	VE_REMOVE:
   2311 			port_fop_sendevent(vp, FILE_DELETE, dvp, name);
   2312 		break;
   2313 	case	VE_RMDIR:
   2314 			port_fop_sendevent(vp, FILE_DELETE, dvp, name);
   2315 		break;
   2316 	case	VE_CREATE:
   2317 			port_fop_sendevent(vp, FILE_MODIFIED|FILE_ATTRIB,
   2318 			    NULL, NULL);
   2319 		break;
   2320 	case	VE_LINK:
   2321 			port_fop_sendevent(vp, FILE_ATTRIB, NULL, NULL);
   2322 		break;
   2323 
   2324 	case	VE_RENAME_DEST_DIR:
   2325 			port_fop_sendevent(vp, FILE_MODIFIED|FILE_ATTRIB,
   2326 			    NULL, NULL);
   2327 		break;
   2328 
   2329 	case	VE_MOUNTEDOVER:
   2330 			port_fop_sendevent(vp, MOUNTEDOVER, NULL, NULL);
   2331 		break;
   2332 	default:
   2333 		break;
   2334 	}
   2335 	return (vnext_vnevent(vf, vnevent, dvp, name, ct));
   2336 }
   2337