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