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