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