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