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  */
 182 extern struct vnode *vfs_mntdummyvp;
 183 extern int mntfstype;
 184 
 185 #define PORTFOP_PVFSH(vfsp)     (&portvfs_hash[PORTFOP_PVFSHASH(vfsp)])
 186 portfop_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  */
 199 int     port_fop_maxpfps = 20;
 200 
 201 /* local functions */
 202 static int      port_fop_callback(void *, int *, pid_t, int, void *);
 203 
 204 static void     port_pcache_insert(portfop_cache_t *, portfop_t *);
 205 static void     port_pcache_delete(portfop_cache_t *, portfop_t *);
 206 static 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  */
 211 static int port_fop_open(femarg_t *vf, int mode, cred_t *cr,
 212     caller_context_t *);
 213 static int port_fop_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
 214     struct caller_context *ct);
 215 static int port_fop_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
 216     caller_context_t *ct);
 217 static 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);
 220 static int port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
 221     caller_context_t *ct);
 222 static 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);
 225 static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr,
 226     caller_context_t *ct, int flags);
 227 static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
 228     caller_context_t *ct, int flags);
 229 static int port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
 230     cred_t *cr, caller_context_t *ct, int flags);
 231 static 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);
 234 static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
 235     caller_context_t *ct, int flags);
 236 static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
 237     caller_context_t *ct, int flags);
 238 static int port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
 239     char *target, cred_t *cr, caller_context_t *ct, int flags);
 240 static int port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
 241     cred_t *cr, caller_context_t *ct);
 242 
 243 static int port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp,
 244     char *cname, caller_context_t *ct);
 245 
 246 static int port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr);
 247 
 248 
 249 /*
 250  * Fem hooks.
 251  */
 252 const 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  */
 274 const fs_operation_def_t        port_vfssrc_template[] = {
 275         VFSNAME_UNMOUNT,        { .fsemop_unmount = port_fop_unmount },
 276         NULL,   NULL
 277 };
 278 
 279 fem_t *fop_femop;
 280 fsem_t *fop_fsemop;
 281 
 282 static fem_t *
 283 port_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 
 302 static fsem_t *
 303 port_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 */
 331 static int
 332 port_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  */
 356 static void
 357 port_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  */
 371 static void
 372 port_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  */
 404 static void
 405 port_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 
 418 static void
 419 port_fop_listinsert_head(portfop_vp_t *pvp, portfop_t *pfp)
 420 {
 421         port_fop_listinsert(pvp, pfp, 1);
 422 }
 423 
 424 static void
 425 port_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 
 438 static void
 439 port_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 
 453 static void
 454 port_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  */
 466 void
 467 port_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  */
 495 static void
 496 port_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  */
 549 int
 550 port_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  */
 620 int
 621 port_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  */
 709 portfop_t *
 710 port_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  */
 731 int
 732 port_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 
 783 port_source_t *
 784 port_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  */
 815 static void
 816 port_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  */
 969 int
 970 port_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  */
1019 int
1020 port_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  */
1076 void
1077 port_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  */
1102 int
1103 port_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 
1216 vnode_t *
1217 port_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  */
1254 int
1255 port_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 
1513 errout:
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  */
1544 int
1545 port_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 */
1599 static void
1600 port_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  */
1696 static void
1697 port_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  */
1779 void
1780 port_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  */
1946 void
1947 port_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 
1974 static 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  */
1998 int
1999 port_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  */
2088 static int
2089 port_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 
2099 static int
2100 port_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 
2111 static int
2112 port_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 
2125 static int
2126 port_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  */
2141 int
2142 port_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 
2162 int
2163 port_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 
2198 int
2199 port_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 
2210 int
2211 port_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  */
2228 int
2229 port_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 
2240 int
2241 port_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 
2252 int
2253 port_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 
2264 int
2265 port_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 
2276 int
2277 port_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  */
2291 int
2292 port_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  */
2305 int
2306 port_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 }