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 #include <sys/mount.h> 178 #include <sys/mntent.h> 179 180 /* 181 * For special case support of mnttab (/etc/mnttab). 182 */ 183 extern struct vnode *vfs_mntdummyvp; 184 extern int mntfstype; 185 186 #define PORTFOP_PVFSH(vfsp) (&portvfs_hash[PORTFOP_PVFSHASH(vfsp)]) 187 portfop_vfs_hash_t portvfs_hash[PORTFOP_PVFSHASH_SZ]; 188 189 #define PORTFOP_NVP 20 190 /* 191 * Inactive file event watches(portfop_t) are retained on the vnode's list 192 * for performance reason. If the applications re-registers the file, the 193 * inactive entry is made active and moved up the list. 194 * 195 * If there are greater then the following number of watches on a vnode, 196 * it will attempt to discard an oldest inactive watch(pfp) at the time 197 * a new watch is being registered and when events get delivered. We 198 * do this to avoid accumulating inactive watches on a file. 199 */ 200 int port_fop_maxpfps = 20; 201 202 /* local functions */ 203 static int port_fop_callback(void *, int *, pid_t, int, void *); 204 205 static void port_pcache_insert(portfop_cache_t *, portfop_t *); 206 static void port_pcache_delete(portfop_cache_t *, portfop_t *); 207 static void port_close_fop(void *arg, int port, pid_t pid, int lastclose); 208 209 /* 210 * port fop functions that will be the fem hooks. 211 */ 212 static int port_fop_open(femarg_t *vf, int mode, cred_t *cr, 213 caller_context_t *); 214 static int port_fop_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr, 215 struct caller_context *ct); 216 static int port_fop_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr, 217 caller_context_t *ct); 218 static int port_fop_map(femarg_t *vf, offset_t off, struct as *as, 219 caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport, 220 uint_t flags, cred_t *cr, caller_context_t *ct); 221 static int port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr, 222 caller_context_t *ct); 223 static int port_fop_create(femarg_t *vf, char *name, vattr_t *vap, 224 vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr, int flag, 225 caller_context_t *ct, vsecattr_t *vsecp); 226 static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr, 227 caller_context_t *ct, int flags); 228 static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr, 229 caller_context_t *ct, int flags); 230 static int port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, 231 cred_t *cr, caller_context_t *ct, int flags); 232 static int port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, 233 vnode_t **vpp, cred_t *cr, caller_context_t *ct, int flags, 234 vsecattr_t *vsecp); 235 static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr, 236 caller_context_t *ct, int flags); 237 static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp, 238 caller_context_t *ct, int flags); 239 static int port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, 240 char *target, cred_t *cr, caller_context_t *ct, int flags); 241 static int port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, 242 cred_t *cr, caller_context_t *ct); 243 244 static int port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, 245 char *cname, caller_context_t *ct); 246 247 static int port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr); 248 249 250 /* 251 * Fem hooks. 252 */ 253 const fs_operation_def_t port_vnodesrc_template[] = { 254 VOPNAME_OPEN, { .femop_open = port_fop_open }, 255 VOPNAME_READ, { .femop_read = port_fop_read }, 256 VOPNAME_WRITE, { .femop_write = port_fop_write }, 257 VOPNAME_MAP, { .femop_map = port_fop_map }, 258 VOPNAME_SETATTR, { .femop_setattr = port_fop_setattr }, 259 VOPNAME_CREATE, { .femop_create = port_fop_create }, 260 VOPNAME_REMOVE, { .femop_remove = port_fop_remove }, 261 VOPNAME_LINK, { .femop_link = port_fop_link }, 262 VOPNAME_RENAME, { .femop_rename = port_fop_rename }, 263 VOPNAME_MKDIR, { .femop_mkdir = port_fop_mkdir }, 264 VOPNAME_RMDIR, { .femop_rmdir = port_fop_rmdir }, 265 VOPNAME_READDIR, { .femop_readdir = port_fop_readdir }, 266 VOPNAME_SYMLINK, { .femop_symlink = port_fop_symlink }, 267 VOPNAME_SETSECATTR, { .femop_setsecattr = port_fop_setsecattr }, 268 VOPNAME_VNEVENT, { .femop_vnevent = port_fop_vnevent }, 269 NULL, NULL 270 }; 271 272 /* 273 * Fsem - vfs ops hooks 274 */ 275 const fs_operation_def_t port_vfssrc_template[] = { 276 VFSNAME_UNMOUNT, { .fsemop_unmount = port_fop_unmount }, 277 NULL, NULL 278 }; 279 280 fem_t *fop_femop; 281 fsem_t *fop_fsemop; 282 283 static fem_t * 284 port_fop_femop() 285 { 286 fem_t *femp; 287 if (fop_femop != NULL) 288 return (fop_femop); 289 if (fem_create("portfop_fem", 290 (const struct fs_operation_def *)port_vnodesrc_template, 291 (fem_t **)&femp)) { 292 return (NULL); 293 } 294 if (casptr(&fop_femop, NULL, femp) != NULL) { 295 /* 296 * some other thread beat us to it. 297 */ 298 fem_free(femp); 299 } 300 return (fop_femop); 301 } 302 303 static fsem_t * 304 port_fop_fsemop() 305 { 306 fsem_t *fsemp; 307 if (fop_fsemop != NULL) 308 return (fop_fsemop); 309 if (fsem_create("portfop_fsem", port_vfssrc_template, &fsemp)) { 310 return (NULL); 311 } 312 if (casptr(&fop_fsemop, NULL, fsemp) != NULL) { 313 /* 314 * some other thread beat us to it. 315 */ 316 fsem_free(fsemp); 317 } 318 return (fop_fsemop); 319 } 320 321 /* 322 * port_fop_callback() 323 * - PORT_CALLBACK_DEFAULT 324 * The file event will be delivered to the application. 325 * - PORT_CALLBACK_DISSOCIATE 326 * The object will be dissociated from the port. 327 * - PORT_CALLBACK_CLOSE 328 * The object will be dissociated from the port because the port 329 * is being closed. 330 */ 331 /* ARGSUSED */ 332 static int 333 port_fop_callback(void *arg, int *events, pid_t pid, int flag, void *evp) 334 { 335 portfop_t *pfp = (portfop_t *)arg; 336 port_kevent_t *pkevp = (port_kevent_t *)evp; 337 int error = 0; 338 339 ASSERT((events != NULL)); 340 if (flag == PORT_CALLBACK_DEFAULT) { 341 if (curproc->p_pid != pid) { 342 return (EACCES); /* deny delivery of events */ 343 } 344 345 *events = pkevp->portkev_events; 346 pkevp->portkev_events = 0; 347 if (pfp != NULL) { 348 pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ; 349 } 350 } 351 return (error); 352 } 353 354 /* 355 * Inserts a portfop_t into the port sources cache's. 356 */ 357 static void 358 port_pcache_insert(portfop_cache_t *pfcp, portfop_t *pfp) 359 { 360 portfop_t **bucket; 361 362 ASSERT(MUTEX_HELD(&pfcp->pfc_lock)); 363 bucket = PORT_FOP_BUCKET(pfcp, pfp->pfop_object); 364 pfp->pfop_hashnext = *bucket; 365 *bucket = pfp; 366 pfcp->pfc_objcount++; 367 } 368 369 /* 370 * Remove the pfp from the port source cache. 371 */ 372 static void 373 port_pcache_delete(portfop_cache_t *pfcp, portfop_t *pfp) 374 { 375 portfop_t *lpdp; 376 portfop_t *cpdp; 377 portfop_t **bucket; 378 379 bucket = PORT_FOP_BUCKET(pfcp, pfp->pfop_object); 380 cpdp = *bucket; 381 if (pfp == cpdp) { 382 *bucket = pfp->pfop_hashnext; 383 } else { 384 while (cpdp != NULL) { 385 lpdp = cpdp; 386 cpdp = cpdp->pfop_hashnext; 387 if (cpdp == pfp) { 388 /* portfop struct found */ 389 lpdp->pfop_hashnext = pfp->pfop_hashnext; 390 break; 391 } 392 } 393 } 394 pfcp->pfc_objcount--; 395 } 396 397 /* 398 * The vnode's(portfop_vp_t) pfp list management. The 'pvp_mutex' is held 399 * when these routines are called. 400 * 401 * The 'pvp_lpfop' member points to the oldest inactive entry on the list. 402 * It is used to discard the oldtest inactive pfp if the number of entries 403 * exceed the limit. 404 */ 405 static void 406 port_fop_listinsert(portfop_vp_t *pvp, portfop_t *pfp, int where) 407 { 408 if (where == 1) { 409 list_insert_head(&pvp->pvp_pfoplist, (void *)pfp); 410 } else { 411 list_insert_tail(&pvp->pvp_pfoplist, (void *)pfp); 412 } 413 if (pvp->pvp_lpfop == NULL) { 414 pvp->pvp_lpfop = pfp; 415 } 416 pvp->pvp_cnt++; 417 } 418 419 static void 420 port_fop_listinsert_head(portfop_vp_t *pvp, portfop_t *pfp) 421 { 422 port_fop_listinsert(pvp, pfp, 1); 423 } 424 425 static void 426 port_fop_listinsert_tail(portfop_vp_t *pvp, portfop_t *pfp) 427 { 428 /* 429 * We point lpfop to an inactive one, if it was initially pointing 430 * to an active one. Insert to the tail is done only when a pfp goes 431 * inactive. 432 */ 433 if (pvp->pvp_lpfop && pvp->pvp_lpfop->pfop_flags & PORT_FOP_ACTIVE) { 434 pvp->pvp_lpfop = pfp; 435 } 436 port_fop_listinsert(pvp, pfp, 0); 437 } 438 439 static void 440 port_fop_listremove(portfop_vp_t *pvp, portfop_t *pfp) 441 { 442 if (pvp->pvp_lpfop == pfp) { 443 pvp->pvp_lpfop = list_next(&pvp->pvp_pfoplist, (void *)pfp); 444 } 445 446 list_remove(&pvp->pvp_pfoplist, (void *)pfp); 447 448 pvp->pvp_cnt--; 449 if (pvp->pvp_cnt && pvp->pvp_lpfop == NULL) { 450 pvp->pvp_lpfop = list_head(&pvp->pvp_pfoplist); 451 } 452 } 453 454 static void 455 port_fop_listmove(portfop_vp_t *pvp, list_t *tlist) 456 { 457 list_move_tail(tlist, &pvp->pvp_pfoplist); 458 pvp->pvp_lpfop = NULL; 459 pvp->pvp_cnt = 0; 460 } 461 462 /* 463 * Remove a portfop_t from the port cache hash table and discard it. 464 * It is called only when pfp is not on the vnode's list. Otherwise, 465 * port_remove_fop() is called. 466 */ 467 void 468 port_pcache_remove_fop(portfop_cache_t *pfcp, portfop_t *pfp) 469 { 470 port_kevent_t *pkevp; 471 472 473 ASSERT(MUTEX_HELD(&pfcp->pfc_lock)); 474 475 pkevp = pfp->pfop_pev; 476 pfp->pfop_pev = NULL; 477 478 if (pkevp != NULL) { 479 (void) port_remove_done_event(pkevp); 480 port_free_event_local(pkevp, 0); 481 } 482 483 port_pcache_delete(pfcp, pfp); 484 485 if (pfp->pfop_cname != NULL) 486 kmem_free(pfp->pfop_cname, pfp->pfop_clen + 1); 487 kmem_free(pfp, sizeof (portfop_t)); 488 if (pfcp->pfc_objcount == 0) 489 cv_signal(&pfcp->pfc_lclosecv); 490 } 491 492 /* 493 * if we have too many watches on the vnode, attempt to discard an 494 * inactive one. 495 */ 496 static void 497 port_fop_trimpfplist(vnode_t *vp) 498 { 499 portfop_vp_t *pvp; 500 portfop_t *pfp = NULL; 501 portfop_cache_t *pfcp; 502 vnode_t *tdvp; 503 504 /* 505 * Due to a reference the vnode cannot disappear, v_fopdata should 506 * not change. 507 */ 508 if ((pvp = vp->v_fopdata) != NULL && 509 pvp->pvp_cnt > port_fop_maxpfps) { 510 mutex_enter(&pvp->pvp_mutex); 511 pfp = pvp->pvp_lpfop; 512 pfcp = pfp->pfop_pcache; 513 /* 514 * only if we can get the cache lock, we need to 515 * do this due to reverse lock order and some thread 516 * that may be trying to reactivate this entry. 517 */ 518 if (mutex_tryenter(&pfcp->pfc_lock)) { 519 if (pfp && !(pfp->pfop_flags & PORT_FOP_ACTIVE) && 520 !(pfp->pfop_flags & PORT_FOP_KEV_ONQ)) { 521 port_fop_listremove(pvp, pfp); 522 pfp->pfop_flags |= PORT_FOP_REMOVING; 523 } else { 524 mutex_exit(&pfcp->pfc_lock); 525 pfp = NULL; 526 } 527 } else { 528 pfp = NULL; 529 } 530 mutex_exit(&pvp->pvp_mutex); 531 532 /* 533 * discard pfp if any. 534 */ 535 if (pfp != NULL) { 536 tdvp = pfp->pfop_dvp; 537 port_pcache_remove_fop(pfcp, pfp); 538 mutex_exit(&pfcp->pfc_lock); 539 if (tdvp != NULL) 540 VN_RELE(tdvp); 541 } 542 } 543 } 544 545 /* 546 * This routine returns 1, if the vnode can be rele'ed by the caller. 547 * The caller has to VN_RELE the vnode with out holding any 548 * locks. 549 */ 550 int 551 port_fop_femuninstall(vnode_t *vp) 552 { 553 portfop_vp_t *pvp; 554 vfs_t *vfsp; 555 portfop_vfs_t *pvfsp; 556 portfop_vfs_hash_t *pvfsh; 557 kmutex_t *mtx; 558 int ret = 0; 559 560 /* 561 * if list is empty, uninstall fem. 562 */ 563 pvp = vp->v_fopdata; 564 ASSERT(MUTEX_HELD(&pvp->pvp_mutex)); 565 566 /* 567 * make sure the list is empty. 568 */ 569 if (!list_head(&pvp->pvp_pfoplist)) { 570 571 /* 572 * we could possibly uninstall the fem hooks when 573 * the vnode becomes inactive and the v_fopdata is 574 * free. But the hooks get triggered unnecessarily 575 * even though there are no active watches. So, we 576 * uninstall it here. 577 */ 578 (void) fem_uninstall(vp, (fem_t *)pvp->pvp_femp, vp); 579 pvp->pvp_femp = NULL; 580 mutex_exit(&pvp->pvp_mutex); 581 582 583 /* 584 * If we successfully uninstalled fem, no process is watching 585 * this vnode, Remove it from the vfs's list of watched vnodes. 586 */ 587 pvfsp = pvp->pvp_pvfsp; 588 vfsp = vp->v_vfsp; 589 pvfsh = PORTFOP_PVFSH(vfsp); 590 mtx = &pvfsh->pvfshash_mutex; 591 mutex_enter(mtx); 592 /* 593 * If unmount is in progress, that thread will remove and 594 * release the vnode from the vfs's list, just leave. 595 */ 596 if (!pvfsp->pvfs_unmount) { 597 list_remove(&pvfsp->pvfs_pvplist, pvp); 598 mutex_exit(mtx); 599 ret = 1; 600 } else { 601 mutex_exit(mtx); 602 } 603 } else { 604 mutex_exit(&pvp->pvp_mutex); 605 } 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 (casptr(&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; 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(vp); 1318 1319 1320 if (vp != NULL && vnevent_support(vp, NULL)) { 1321 error = ENOTSUP; 1322 goto errout; 1323 } 1324 1325 /* 1326 * Associate this source to the port and get the per port 1327 * fop cache pointer. If the source is already associated, it 1328 * will just return the cache pointer. 1329 */ 1330 if (error = port_fop_associate_source(&pfcp, pp, source)) { 1331 goto errout; 1332 } 1333 1334 /* 1335 * Check if there is an existing association of this file. 1336 */ 1337 mutex_enter(&pfcp->pfc_lock); 1338 pfp = port_cache_lookup_fop(pfcp, curproc->p_pid, object); 1339 1340 /* 1341 * If it is not the same vnode, just discard it. VN_RELE needs to be 1342 * called with no locks held, therefore save vnode pointers and 1343 * vn_rele them later. 1344 */ 1345 if (pfp != NULL && (pfp->pfop_vp != vp || pfp->pfop_dvp != dvp)) { 1346 (void) port_remove_fop(pfp, pfcp, 1, NULL, &oldvp, &olddvp); 1347 pfp = NULL; 1348 } 1349 1350 if (pfp == NULL) { 1351 vnode_t *tvp, *tdvp; 1352 portfop_t *tpfp; 1353 int error; 1354 1355 /* 1356 * Add a new association, save the file name and the 1357 * directory vnode pointer. 1358 */ 1359 if (error = port_pfp_setup(&pfp, pp, vp, pfcp, object, 1360 events, user, cname, clen, dvp)) { 1361 mutex_exit(&pfcp->pfc_lock); 1362 goto errout; 1363 } 1364 1365 pfp->pfop_callrid = curthread; 1366 /* 1367 * File name used, so make sure we don't free it. 1368 */ 1369 cname = NULL; 1370 1371 /* 1372 * We need to check if the file was removed after the 1373 * the lookup and before the fem hooks where added. If 1374 * so, return error. The vnode will still exist as we have 1375 * a hold on it. 1376 * 1377 * Drop the cache lock before calling port_fop_getdvp(). 1378 * port_fop_getdvp() may block either in the vfs layer 1379 * or some filesystem. Therefore there is potential 1380 * for deadlock if cache lock is held and if some other 1381 * thread is attempting to deliver file events which would 1382 * require getting the cache lock, while it may be holding 1383 * the filesystem or vfs layer locks. 1384 */ 1385 mutex_exit(&pfcp->pfc_lock); 1386 tvp = NULL; 1387 if ((error = port_fop_getdvp(objptr, &tvp, NULL, 1388 NULL, NULL, follow)) == 0) { 1389 if (tvp != NULL) { 1390 tvp = port_resolve_vp(tvp); 1391 /* 1392 * This vnode pointer is just used 1393 * for comparison, so rele it 1394 */ 1395 VN_RELE(tvp); 1396 } 1397 } 1398 1399 if (error || tvp == NULL || tvp != vp) { 1400 /* 1401 * Since we dropped the cache lock, make sure 1402 * we are still dealing with the same pfp and this 1403 * is the thread which registered it. 1404 */ 1405 mutex_enter(&pfcp->pfc_lock); 1406 tpfp = port_cache_lookup_fop(pfcp, 1407 curproc->p_pid, object); 1408 1409 error = 0; 1410 if (tpfp == NULL || tpfp != pfp || 1411 pfp->pfop_vp != vp || 1412 pfp->pfop_dvp != dvp || 1413 pfp->pfop_callrid != curthread) { 1414 /* 1415 * Some other event was delivered, the file 1416 * watch was removed or reassociated, just 1417 * ignore it and leave 1418 */ 1419 mutex_exit(&pfcp->pfc_lock); 1420 goto errout; 1421 } 1422 1423 /* 1424 * remove the pfp and fem hooks, if pfp still 1425 * active and it is not being removed from 1426 * the vnode list. This is checked in 1427 * port_remove_fop with the vnode lock held. 1428 * The vnode returned is VN_RELE'ed after dropping 1429 * the locks. 1430 */ 1431 tdvp = tvp = NULL; 1432 if (port_remove_fop(pfp, pfcp, 0, NULL, &tvp, &tdvp)) { 1433 /* 1434 * The pfp was removed, means no 1435 * events where queued. Report the 1436 * error now. 1437 */ 1438 error = EINVAL; 1439 } 1440 mutex_exit(&pfcp->pfc_lock); 1441 if (tvp != NULL) 1442 VN_RELE(tvp); 1443 if (tdvp != NULL) 1444 VN_RELE(tdvp); 1445 goto errout; 1446 } 1447 } else { 1448 portfop_vp_t *pvp = vp->v_fopdata; 1449 1450 /* 1451 * Re-association of the object. 1452 */ 1453 mutex_enter(&pvp->pvp_mutex); 1454 1455 /* 1456 * remove any queued up event. 1457 */ 1458 if (port_remove_done_event(pfp->pfop_pev)) { 1459 pfp->pfop_flags &= ~PORT_FOP_KEV_ONQ; 1460 } 1461 1462 /* 1463 * set new events to watch. 1464 */ 1465 pfp->pfop_events = events; 1466 1467 /* 1468 * If not active, mark it active even if it is being 1469 * removed. Then it can send an exception event. 1470 * 1471 * Move it to the head, as the active ones are only 1472 * in the beginning. If removing, the pfp will be on 1473 * a temporary list, no need to move it to the front 1474 * all the entries will be processed. Some exception 1475 * events will be delivered in port_fop_excep(); 1476 */ 1477 if (!(pfp->pfop_flags & PORT_FOP_ACTIVE)) { 1478 pfp->pfop_flags |= PORT_FOP_ACTIVE; 1479 if (!(pfp->pfop_flags & PORT_FOP_REMOVING)) { 1480 pvp = (portfop_vp_t *)vp->v_fopdata; 1481 port_fop_listremove(pvp, pfp); 1482 port_fop_listinsert_head(pvp, pfp); 1483 } 1484 } 1485 pfp->pfop_callrid = curthread; 1486 mutex_exit(&pvp->pvp_mutex); 1487 mutex_exit(&pfcp->pfc_lock); 1488 } 1489 1490 /* 1491 * Compare time stamps and deliver events. 1492 */ 1493 if (vp->v_type != VFIFO) { 1494 port_check_timestamp(pfcp, vp, dvp, pfp, objptr, object); 1495 } 1496 1497 error = 0; 1498 1499 /* 1500 * If we have too many watches on the vnode, discard an 1501 * inactive watch. 1502 */ 1503 port_fop_trimpfplist(vp); 1504 1505 errout: 1506 /* 1507 * Release the hold acquired due to the lookup operation. 1508 */ 1509 if (vp != NULL) 1510 VN_RELE(vp); 1511 if (dvp != NULL) 1512 VN_RELE(dvp); 1513 1514 if (oldvp != NULL) 1515 VN_RELE(oldvp); 1516 if (olddvp != NULL) 1517 VN_RELE(olddvp); 1518 1519 /* 1520 * copied file name not used, free it. 1521 */ 1522 if (cname != NULL) { 1523 kmem_free(cname, clen + 1); 1524 } 1525 return (error); 1526 } 1527 1528 1529 /* 1530 * The port_dissociate_fop() function dissociates the file object 1531 * from the event port and removes any events that are already on the queue. 1532 * Only the owner of the association is allowed to dissociate the file from 1533 * the port. Returns success (0) if it was found and removed. Otherwise 1534 * ENOENT. 1535 */ 1536 int 1537 port_dissociate_fop(port_t *pp, uintptr_t object) 1538 { 1539 portfop_cache_t *pfcp; 1540 portfop_t *pfp; 1541 port_source_t *pse; 1542 int active = 0; 1543 vnode_t *tvp = NULL, *tdvp = NULL; 1544 1545 pse = port_getsrc(pp, PORT_SOURCE_FILE); 1546 1547 /* 1548 * if this source is not associated or if there is no 1549 * cache, nothing to do just return. 1550 */ 1551 if (pse == NULL || 1552 (pfcp = (portfop_cache_t *)pse->portsrc_data) == NULL) 1553 return (EINVAL); 1554 1555 /* 1556 * Check if this object is on the cache. Only the owner pid 1557 * is allowed to dissociate. 1558 */ 1559 mutex_enter(&pfcp->pfc_lock); 1560 pfp = port_cache_lookup_fop(pfcp, curproc->p_pid, object); 1561 if (pfp == NULL) { 1562 mutex_exit(&pfcp->pfc_lock); 1563 return (ENOENT); 1564 } 1565 1566 /* 1567 * If this was the last association, it will release 1568 * the hold on the vnode. There is a race condition where 1569 * the the pfp is being removed due to an exception event 1570 * in port_fop_sendevent()->port_fop_excep() and port_remove_fop(). 1571 * Since port source cache lock is held, port_fop_excep() cannot 1572 * complete. The vnode itself will not disappear as long its pfps 1573 * have a reference. 1574 */ 1575 (void) port_remove_fop(pfp, pfcp, 1, &active, &tvp, &tdvp); 1576 mutex_exit(&pfcp->pfc_lock); 1577 if (tvp != NULL) 1578 VN_RELE(tvp); 1579 if (tdvp != NULL) 1580 VN_RELE(tdvp); 1581 return (active ? 0 : ENOENT); 1582 } 1583 1584 1585 /* 1586 * port_close() calls this function to request the PORT_SOURCE_FILE source 1587 * to remove/free all resources allocated and associated with the port. 1588 */ 1589 1590 /* ARGSUSED */ 1591 static void 1592 port_close_fop(void *arg, int port, pid_t pid, int lastclose) 1593 { 1594 port_t *pp = arg; 1595 portfop_cache_t *pfcp; 1596 portfop_t **hashtbl; 1597 portfop_t *pfp; 1598 portfop_t *pfpnext; 1599 int index, i; 1600 port_source_t *pse; 1601 vnode_t *tdvp = NULL; 1602 vnode_t *vpl[PORTFOP_NVP]; 1603 1604 pse = port_getsrc(pp, PORT_SOURCE_FILE); 1605 1606 /* 1607 * No source or no cache, nothing to do. 1608 */ 1609 if (pse == NULL || 1610 (pfcp = (portfop_cache_t *)pse->portsrc_data) == NULL) 1611 return; 1612 /* 1613 * Scan the cache and free all allocated portfop_t and port_kevent_t 1614 * structures of this pid. Note, no new association for this pid will 1615 * be possible as the port is being closed. 1616 * 1617 * The common case is that the port is not shared and all the entries 1618 * are of this pid and have to be freed. Since VN_RELE has to be 1619 * called outside the lock, we do it in batches. 1620 */ 1621 hashtbl = (portfop_t **)pfcp->pfc_hash; 1622 index = i = 0; 1623 bzero(vpl, sizeof (vpl)); 1624 mutex_enter(&pfcp->pfc_lock); 1625 while (index < PORTFOP_HASHSIZE) { 1626 pfp = hashtbl[index]; 1627 while (pfp != NULL && i < (PORTFOP_NVP - 1)) { 1628 pfpnext = pfp->pfop_hashnext; 1629 if (pid == pfp->pfop_pid) { 1630 (void) port_remove_fop(pfp, pfcp, 1, NULL, 1631 &vpl[i], &tdvp); 1632 if (vpl[i] != NULL) { 1633 i++; 1634 } 1635 if (tdvp != NULL) { 1636 vpl[i++] = tdvp; 1637 tdvp = NULL; 1638 } 1639 } 1640 pfp = pfpnext; 1641 } 1642 if (pfp == NULL) 1643 index++; 1644 /* 1645 * Now call VN_RELE if we have collected enough vnodes or 1646 * we have reached the end of the hash table. 1647 */ 1648 if (i >= (PORTFOP_NVP - 1) || 1649 (i > 0 && index == PORTFOP_HASHSIZE)) { 1650 mutex_exit(&pfcp->pfc_lock); 1651 while (i > 0) { 1652 VN_RELE(vpl[--i]); 1653 vpl[i] = NULL; 1654 } 1655 mutex_enter(&pfcp->pfc_lock); 1656 } 1657 } 1658 1659 /* 1660 * Due to a race between port_close_fop() and port_fop() 1661 * trying to remove the pfp's from the port's cache, it is 1662 * possible that some pfp's are still in the process of being 1663 * freed so we wait. 1664 */ 1665 while (lastclose && pfcp->pfc_objcount) { 1666 (void) cv_wait_sig(&pfcp->pfc_lclosecv, &pfcp->pfc_lock); 1667 } 1668 mutex_exit(&pfcp->pfc_lock); 1669 /* 1670 * last close, free the cache. 1671 */ 1672 if (lastclose) { 1673 ASSERT(pfcp->pfc_objcount == 0); 1674 pse->portsrc_data = NULL; 1675 kmem_free(pfcp, sizeof (portfop_cache_t)); 1676 } 1677 } 1678 1679 /* 1680 * Given the list of associations(watches), it will send exception events, 1681 * if still active, and discard them. The exception events are handled 1682 * separately because, the pfp needs to be removed from the port cache and 1683 * freed as the vnode's identity is changing or being removed. To remove 1684 * the pfp from the port's cache, we need to hold the cache lock (pfc_lock). 1685 * The lock order is pfc_lock -> pvp_mutex(vnode's) mutex and that is why 1686 * the cache's lock cannot be acquired in port_fop_sendevent(). 1687 */ 1688 static void 1689 port_fop_excep(list_t *tlist, int op) 1690 { 1691 portfop_t *pfp; 1692 portfop_cache_t *pfcp; 1693 port_t *pp; 1694 port_kevent_t *pkevp; 1695 vnode_t *tdvp; 1696 int error = 0; 1697 1698 while (pfp = (portfop_t *)list_head(tlist)) { 1699 int removed = 0; 1700 /* 1701 * remove from the temp list. Since PORT_FOP_REMOVING is 1702 * set, no other thread should attempt to perform a 1703 * list_remove on this pfp. 1704 */ 1705 list_remove(tlist, pfp); 1706 1707 pfcp = pfp->pfop_pcache; 1708 mutex_enter(&pfcp->pfc_lock); 1709 1710 /* 1711 * Remove the event from the port queue if it was queued up. 1712 * No need to clear the PORT_FOP_KEV_ONQ flag as this pfp is 1713 * no longer on the vnode's list. 1714 */ 1715 if ((pfp->pfop_flags & PORT_FOP_KEV_ONQ)) { 1716 removed = port_remove_done_event(pfp->pfop_pev); 1717 } 1718 1719 /* 1720 * If still active or the event was queued up and 1721 * had not been collected yet, send an EXCEPTION event. 1722 */ 1723 if (pfp->pfop_flags & (PORT_FOP_ACTIVE) || removed) { 1724 pp = pfp->pfop_pp; 1725 /* 1726 * Allocate a port_kevent_t non cached to send this 1727 * event since we will be de-registering. 1728 * The port_kevent_t cannot be pointing back to the 1729 * pfp anymore. 1730 */ 1731 pfp->pfop_flags &= ~PORT_FOP_ACTIVE; 1732 error = port_alloc_event_local(pp, PORT_SOURCE_FILE, 1733 PORT_ALLOC_DEFAULT, &pkevp); 1734 if (!error) { 1735 1736 pkevp->portkev_callback = port_fop_callback; 1737 pkevp->portkev_arg = NULL; 1738 pkevp->portkev_object = 1739 pfp->pfop_pev->portkev_object; 1740 pkevp->portkev_user = 1741 pfp->pfop_pev->portkev_user; 1742 /* 1743 * Copy the pid of the watching process. 1744 */ 1745 pkevp->portkev_pid = 1746 pfp->pfop_pev->portkev_pid; 1747 pkevp->portkev_events = op; 1748 port_send_event(pkevp); 1749 } 1750 } 1751 /* 1752 * At this point the pfp has been removed from the vnode's 1753 * list its cached port_kevent_t is not on the done queue. 1754 * Remove the pfp and free it from the cache. 1755 */ 1756 tdvp = pfp->pfop_dvp; 1757 port_pcache_remove_fop(pfcp, pfp); 1758 mutex_exit(&pfcp->pfc_lock); 1759 if (tdvp != NULL) 1760 VN_RELE(tdvp); 1761 } 1762 } 1763 1764 /* 1765 * Send the file events to all of the processes watching this 1766 * vnode. In case of hard links, the directory vnode pointer and 1767 * the file name are compared. If the names match, then the specified 1768 * event is sent or else, the FILE_ATTRIB event is sent, This is the 1769 * documented behavior. 1770 */ 1771 void 1772 port_fop_sendevent(vnode_t *vp, int events, vnode_t *dvp, char *cname) 1773 { 1774 port_kevent_t *pkevp; 1775 portfop_t *pfp, *npfp; 1776 portfop_vp_t *pvp; 1777 list_t tmplist; 1778 int removeall = 0; 1779 1780 pvp = (portfop_vp_t *)vp->v_fopdata; 1781 mutex_enter(&pvp->pvp_mutex); 1782 1783 /* 1784 * Check if the list is empty. 1785 * 1786 * All entries have been removed by some other thread. 1787 * The vnode may be still active and we got called, 1788 * but some other thread is in the process of removing the hooks. 1789 */ 1790 if (!list_head(&pvp->pvp_pfoplist)) { 1791 mutex_exit(&pvp->pvp_mutex); 1792 return; 1793 } 1794 1795 if ((events & (FILE_EXCEPTION))) { 1796 /* 1797 * If it is an event for which we are going to remove 1798 * the watches so just move it a temporary list and 1799 * release this vnode. 1800 */ 1801 list_create(&tmplist, sizeof (portfop_t), 1802 offsetof(portfop_t, pfop_node)); 1803 1804 /* 1805 * If it is an UNMOUNT, MOUNTEDOVER or no file name has been 1806 * passed for an exception event, all associations need to be 1807 * removed. 1808 */ 1809 if (dvp == NULL || cname == NULL) { 1810 removeall = 1; 1811 } 1812 } 1813 1814 if (!removeall) { 1815 /* 1816 * All the active ones are in the beginning of the list. 1817 */ 1818 for (pfp = (portfop_t *)list_head(&pvp->pvp_pfoplist); 1819 pfp && pfp->pfop_flags & PORT_FOP_ACTIVE; pfp = npfp) { 1820 int levents = events; 1821 1822 npfp = list_next(&pvp->pvp_pfoplist, pfp); 1823 /* 1824 * Hard links case - If the file is being 1825 * removed/renamed, and the name matches 1826 * the watched file, then it is an EXCEPTION 1827 * event or else it will be just a FILE_ATTRIB. 1828 */ 1829 if ((events & (FILE_EXCEPTION))) { 1830 ASSERT(dvp != NULL && cname != NULL); 1831 if (pfp->pfop_dvp == NULL || 1832 (pfp->pfop_dvp == dvp && 1833 (strcmp(cname, pfp->pfop_cname) == 0))) { 1834 /* 1835 * It is an exception event, move it 1836 * to temp list and process it later. 1837 * Note we don't set the pfp->pfop_vp 1838 * to NULL even thought it has been 1839 * removed from the vnode's list. This 1840 * pointer is referenced in 1841 * port_remove_fop(). The vnode it 1842 * self cannot disappear until this 1843 * pfp gets removed and freed. 1844 */ 1845 port_fop_listremove(pvp, pfp); 1846 list_insert_tail(&tmplist, (void *)pfp); 1847 pfp->pfop_flags |= PORT_FOP_REMOVING; 1848 continue; 1849 } else { 1850 levents = FILE_ATTRIB; 1851 } 1852 1853 } 1854 1855 if (pfp->pfop_events & levents) { 1856 /* 1857 * deactivate and move it to the tail. 1858 * If the pfp was active, it cannot be 1859 * on the port's done queue. 1860 */ 1861 pfp->pfop_flags &= ~PORT_FOP_ACTIVE; 1862 port_fop_listremove(pvp, pfp); 1863 port_fop_listinsert_tail(pvp, pfp); 1864 1865 pkevp = pfp->pfop_pev; 1866 pkevp->portkev_events |= 1867 (levents & pfp->pfop_events); 1868 port_send_event(pkevp); 1869 pfp->pfop_flags |= PORT_FOP_KEV_ONQ; 1870 } 1871 } 1872 } 1873 1874 1875 if ((events & (FILE_EXCEPTION))) { 1876 if (!removeall) { 1877 /* 1878 * Check the inactive associations and remove them if 1879 * the file name matches. 1880 */ 1881 for (; pfp; pfp = npfp) { 1882 npfp = list_next(&pvp->pvp_pfoplist, pfp); 1883 if (dvp == NULL || cname == NULL || 1884 pfp->pfop_dvp == NULL || 1885 (pfp->pfop_dvp == dvp && 1886 (strcmp(cname, pfp->pfop_cname) == 0))) { 1887 port_fop_listremove(pvp, pfp); 1888 list_insert_tail(&tmplist, (void *)pfp); 1889 pfp->pfop_flags |= PORT_FOP_REMOVING; 1890 } 1891 } 1892 } else { 1893 /* 1894 * Can be optimized to avoid two pass over this list 1895 * by having a flag in the vnode's portfop_vp_t 1896 * structure to indicate that it is going away, 1897 * Or keep the list short by reusing inactive watches. 1898 */ 1899 port_fop_listmove(pvp, &tmplist); 1900 for (pfp = (portfop_t *)list_head(&tmplist); 1901 pfp; pfp = list_next(&tmplist, pfp)) { 1902 pfp->pfop_flags |= PORT_FOP_REMOVING; 1903 } 1904 } 1905 1906 /* 1907 * Uninstall the fem hooks if there are no more associations. 1908 * This will release the pvp mutex. 1909 * 1910 * Even thought all entries may have been removed, 1911 * the vnode itself cannot disappear as there will be a 1912 * hold on it due to this call to port_fop_sendevent. This is 1913 * important to syncronize with a port_dissociate_fop() call 1914 * that may be attempting to remove an object from the vnode's. 1915 */ 1916 if (port_fop_femuninstall(vp)) 1917 VN_RELE(vp); 1918 1919 /* 1920 * Send exception events and discard the watch entries. 1921 */ 1922 port_fop_excep(&tmplist, events); 1923 list_destroy(&tmplist); 1924 1925 } else { 1926 mutex_exit(&pvp->pvp_mutex); 1927 1928 /* 1929 * trim the list. 1930 */ 1931 port_fop_trimpfplist(vp); 1932 } 1933 } 1934 1935 /* 1936 * Given the file operation, map it to the event types and send. 1937 */ 1938 void 1939 port_fop(vnode_t *vp, int op, int retval) 1940 { 1941 int event = 0; 1942 /* 1943 * deliver events only if the operation was successful. 1944 */ 1945 if (retval) 1946 return; 1947 1948 /* 1949 * These events occurring on the watched file. 1950 */ 1951 if (op & FOP_MODIFIED_MASK) { 1952 event = FILE_MODIFIED; 1953 } 1954 if (op & FOP_ACCESS_MASK) { 1955 event |= FILE_ACCESS; 1956 } 1957 if (op & FOP_ATTRIB_MASK) { 1958 event |= FILE_ATTRIB; 1959 } 1960 1961 if (event) { 1962 port_fop_sendevent(vp, event, NULL, NULL); 1963 } 1964 } 1965 1966 static int port_forceunmount(vfs_t *vfsp) 1967 { 1968 char *fsname = vfssw[vfsp->vfs_fstype].vsw_name; 1969 1970 if (fsname == NULL) { 1971 return (0); 1972 } 1973 1974 if (strcmp(fsname, MNTTYPE_NFS) == 0) { 1975 return (1); 1976 } 1977 1978 if (strcmp(fsname, MNTTYPE_NFS3) == 0) { 1979 return (1); 1980 } 1981 1982 if (strcmp(fsname, MNTTYPE_NFS4) == 0) { 1983 return (1); 1984 } 1985 return (0); 1986 } 1987 /* 1988 * ----- the unmount filesystem op(fsem) hook. 1989 */ 1990 int 1991 port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr) 1992 { 1993 vfs_t *vfsp = (vfs_t *)vf->fa_fnode->fn_available; 1994 kmutex_t *mtx; 1995 portfop_vfs_t *pvfsp, **ppvfsp; 1996 portfop_vp_t *pvp; 1997 int error; 1998 int fmfs; 1999 2000 fmfs = port_forceunmount(vfsp); 2001 2002 mtx = &(portvfs_hash[PORTFOP_PVFSHASH(vfsp)].pvfshash_mutex); 2003 ppvfsp = &(portvfs_hash[PORTFOP_PVFSHASH(vfsp)].pvfshash_pvfsp); 2004 pvfsp = NULL; 2005 mutex_enter(mtx); 2006 /* 2007 * since this fsem hook is triggered, the vfsp has to be on 2008 * the hash list. 2009 */ 2010 for (pvfsp = *ppvfsp; pvfsp->pvfs != vfsp; pvfsp = pvfsp->pvfs_next) 2011 ; 2012 2013 /* 2014 * For some of the filesystems, allow unmounts to proceed only if 2015 * there are no files being watched or it is a forced unmount. 2016 */ 2017 if (fmfs && !(flag & MS_FORCE) && 2018 !list_is_empty(&pvfsp->pvfs_pvplist)) { 2019 mutex_exit(mtx); 2020 return (EBUSY); 2021 } 2022 2023 /* 2024 * Indicate that the unmount is in process. Don't remove it yet. 2025 * The underlying filesystem unmount routine sets the VFS_UNMOUNTED 2026 * flag on the vfs_t structure. But we call the filesystem unmount 2027 * routine after removing all the file watches for this filesystem, 2028 * otherwise the unmount will fail due to active vnodes. 2029 * Meanwhile setting pvfsp->unmount = 1 will prevent any thread 2030 * attempting to add a file watch. 2031 */ 2032 pvfsp->pvfs_unmount = 1; 2033 mutex_exit(mtx); 2034 2035 /* 2036 * uninstall the fsem hooks. 2037 */ 2038 (void) fsem_uninstall(vfsp, (fsem_t *)pvfsp->pvfs_fsemp, vfsp); 2039 2040 while (pvp = list_head(&pvfsp->pvfs_pvplist)) { 2041 list_remove(&pvfsp->pvfs_pvplist, pvp); 2042 /* 2043 * This should send an UNMOUNTED event to all the 2044 * watched vnode of this filesystem and uninstall 2045 * the fem hooks. We release the hold on the vnode here 2046 * because port_fop_femuninstall() will not do it if 2047 * unmount is in process. 2048 */ 2049 port_fop_sendevent(pvp->pvp_vp, UNMOUNTED, NULL, NULL); 2050 VN_RELE(pvp->pvp_vp); 2051 } 2052 2053 error = vfsnext_unmount(vf, flag, cr); 2054 2055 /* 2056 * we free the pvfsp after the unmount has been completed. 2057 */ 2058 mutex_enter(mtx); 2059 for (; *ppvfsp && (*ppvfsp)->pvfs != vfsp; 2060 ppvfsp = &(*ppvfsp)->pvfs_next) 2061 ; 2062 2063 /* 2064 * remove and free it. 2065 */ 2066 ASSERT(list_head(&pvfsp->pvfs_pvplist) == NULL); 2067 if (*ppvfsp) { 2068 pvfsp = *ppvfsp; 2069 *ppvfsp = pvfsp->pvfs_next; 2070 } 2071 mutex_exit(mtx); 2072 kmem_free(pvfsp, sizeof (portfop_vfs_t)); 2073 return (error); 2074 } 2075 2076 /* 2077 * ------------------------------file op hooks-------------------------- 2078 * The O_TRUNC operation is caught with the VOP_SETATTR(AT_SIZE) call. 2079 */ 2080 static int 2081 port_fop_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct) 2082 { 2083 int retval; 2084 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2085 2086 retval = vnext_open(vf, mode, cr, ct); 2087 port_fop(vp, FOP_FILE_OPEN, retval); 2088 return (retval); 2089 } 2090 2091 static int 2092 port_fop_write(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr, 2093 caller_context_t *ct) 2094 { 2095 int retval; 2096 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2097 2098 retval = vnext_write(vf, uiop, ioflag, cr, ct); 2099 port_fop(vp, FOP_FILE_WRITE, retval); 2100 return (retval); 2101 } 2102 2103 static int 2104 port_fop_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp, 2105 size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr, 2106 caller_context_t *ct) 2107 { 2108 int retval; 2109 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2110 2111 retval = vnext_map(vf, off, as, addrp, len, prot, maxport, 2112 flags, cr, ct); 2113 port_fop(vp, FOP_FILE_MAP, retval); 2114 return (retval); 2115 } 2116 2117 static int 2118 port_fop_read(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr, 2119 caller_context_t *ct) 2120 { 2121 int retval; 2122 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2123 2124 retval = vnext_read(vf, uiop, ioflag, cr, ct); 2125 port_fop(vp, FOP_FILE_READ, retval); 2126 return (retval); 2127 } 2128 2129 2130 /* 2131 * AT_SIZE - is for the open(O_TRUNC) case. 2132 */ 2133 int 2134 port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr, 2135 caller_context_t *ct) 2136 { 2137 int retval; 2138 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2139 int events = 0; 2140 2141 retval = vnext_setattr(vf, vap, flags, cr, ct); 2142 if (vap->va_mask & (AT_SIZE|AT_MTIME)) { 2143 events |= FOP_FILE_SETATTR_MTIME; 2144 } 2145 if (vap->va_mask & AT_ATIME) { 2146 events |= FOP_FILE_SETATTR_ATIME; 2147 } 2148 events |= FOP_FILE_SETATTR_CTIME; 2149 2150 port_fop(vp, events, retval); 2151 return (retval); 2152 } 2153 2154 int 2155 port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl, 2156 int mode, vnode_t **vpp, cred_t *cr, int flag, 2157 caller_context_t *ct, vsecattr_t *vsecp) 2158 { 2159 int retval, got = 1; 2160 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2161 vattr_t vatt, vatt1; 2162 2163 /* 2164 * If the file already exists, then there will be no change 2165 * to the directory. Therefore, we need to compare the 2166 * modification time of the directory to determine if the 2167 * file was actually created. 2168 */ 2169 vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME; 2170 if (VOP_GETATTR(vp, &vatt, 0, CRED(), ct)) { 2171 got = 0; 2172 } 2173 retval = vnext_create(vf, name, vap, excl, mode, vpp, cr, 2174 flag, ct, vsecp); 2175 2176 vatt1.va_mask = AT_ATIME|AT_MTIME|AT_CTIME; 2177 if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED(), ct)) { 2178 if ((vatt1.va_mtime.tv_sec > vatt.va_mtime.tv_sec || 2179 (vatt1.va_mtime.tv_sec = vatt.va_mtime.tv_sec && 2180 vatt1.va_mtime.tv_nsec > vatt.va_mtime.tv_nsec))) { 2181 /* 2182 * File was created. 2183 */ 2184 port_fop(vp, FOP_FILE_CREATE, retval); 2185 } 2186 } 2187 return (retval); 2188 } 2189 2190 int 2191 port_fop_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct, 2192 int flags) 2193 { 2194 int retval; 2195 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2196 2197 retval = vnext_remove(vf, nm, cr, ct, flags); 2198 port_fop(vp, FOP_FILE_REMOVE, retval); 2199 return (retval); 2200 } 2201 2202 int 2203 port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr, 2204 caller_context_t *ct, int flags) 2205 { 2206 int retval; 2207 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2208 2209 retval = vnext_link(vf, svp, tnm, cr, ct, flags); 2210 port_fop(vp, FOP_FILE_LINK, retval); 2211 return (retval); 2212 } 2213 2214 /* 2215 * Rename operation is allowed only when from and to directories are 2216 * on the same filesystem. This is checked in vn_rename(). 2217 * The target directory is notified thru a VNEVENT by the filesystem 2218 * if the source dir != target dir. 2219 */ 2220 int 2221 port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, 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_rename(vf, snm, tdvp, tnm, cr, ct, flags); 2228 port_fop(vp, FOP_FILE_RENAMESRC, retval); 2229 return (retval); 2230 } 2231 2232 int 2233 port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp, 2234 cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 2235 { 2236 int retval; 2237 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2238 2239 retval = vnext_mkdir(vf, dirname, vap, vpp, cr, ct, flags, vsecp); 2240 port_fop(vp, FOP_FILE_MKDIR, retval); 2241 return (retval); 2242 } 2243 2244 int 2245 port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, 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_rmdir(vf, nm, cdir, cr, ct, flags); 2252 port_fop(vp, FOP_FILE_RMDIR, retval); 2253 return (retval); 2254 } 2255 2256 int 2257 port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp, 2258 caller_context_t *ct, int flags) 2259 { 2260 int retval; 2261 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2262 2263 retval = vnext_readdir(vf, uiop, cr, eofp, ct, flags); 2264 port_fop(vp, FOP_FILE_READDIR, retval); 2265 return (retval); 2266 } 2267 2268 int 2269 port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target, 2270 cred_t *cr, 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_symlink(vf, linkname, vap, target, cr, ct, flags); 2276 port_fop(vp, FOP_FILE_SYMLINK, retval); 2277 return (retval); 2278 } 2279 2280 /* 2281 * acl, facl call this. 2282 */ 2283 int 2284 port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr, 2285 caller_context_t *ct) 2286 { 2287 int retval; 2288 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2289 retval = vnext_setsecattr(vf, vsap, flags, cr, ct); 2290 port_fop(vp, FOP_FILE_SETSECATTR, retval); 2291 return (retval); 2292 } 2293 2294 /* 2295 * these are events on the watched file/directory 2296 */ 2297 int 2298 port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name, 2299 caller_context_t *ct) 2300 { 2301 vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available; 2302 2303 switch (vnevent) { 2304 case VE_RENAME_SRC: 2305 port_fop_sendevent(vp, FILE_RENAME_FROM, dvp, name); 2306 break; 2307 case VE_RENAME_DEST: 2308 port_fop_sendevent(vp, FILE_RENAME_TO, dvp, name); 2309 break; 2310 case VE_REMOVE: 2311 port_fop_sendevent(vp, FILE_DELETE, dvp, name); 2312 break; 2313 case VE_RMDIR: 2314 port_fop_sendevent(vp, FILE_DELETE, dvp, name); 2315 break; 2316 case VE_CREATE: 2317 port_fop_sendevent(vp, FILE_MODIFIED|FILE_ATTRIB, 2318 NULL, NULL); 2319 break; 2320 case VE_LINK: 2321 port_fop_sendevent(vp, FILE_ATTRIB, NULL, NULL); 2322 break; 2323 2324 case VE_RENAME_DEST_DIR: 2325 port_fop_sendevent(vp, FILE_MODIFIED|FILE_ATTRIB, 2326 NULL, NULL); 2327 break; 2328 2329 case VE_MOUNTEDOVER: 2330 port_fop_sendevent(vp, MOUNTEDOVER, NULL, NULL); 2331 break; 2332 default: 2333 break; 2334 } 2335 return (vnext_vnevent(vf, vnevent, dvp, name, ct)); 2336 } 2337