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