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