Home | History | Annotate | Download | only in fs
      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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     22 /*	  All Rights Reserved  	*/
     23 
     24 
     25 /*
     26  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     27  * Use is subject to license terms.
     28  */
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 /*
     33  * Generic vnode operations.
     34  */
     35 #include <sys/types.h>
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/errno.h>
     39 #include <sys/fcntl.h>
     40 #include <sys/flock.h>
     41 #include <sys/statvfs.h>
     42 #include <sys/vfs.h>
     43 #include <sys/vnode.h>
     44 #include <sys/proc.h>
     45 #include <sys/user.h>
     46 #include <sys/unistd.h>
     47 #include <sys/cred.h>
     48 #include <sys/poll.h>
     49 #include <sys/debug.h>
     50 #include <sys/cmn_err.h>
     51 #include <sys/stream.h>
     52 #include <fs/fs_subr.h>
     53 #include <sys/acl.h>
     54 #include <sys/share.h>
     55 #include <sys/file.h>
     56 #include <sys/kmem.h>
     57 #include <sys/file.h>
     58 #include <sys/nbmlock.h>
     59 #include <acl/acl_common.h>
     60 
     61 static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
     62 
     63 /*
     64  * Tunable to limit the number of retry to recover from STALE error.
     65  */
     66 int fs_estale_retry = 5;
     67 
     68 /*
     69  * The associated operation is not supported by the file system.
     70  */
     71 int
     72 fs_nosys()
     73 {
     74 	return (ENOSYS);
     75 }
     76 
     77 /*
     78  * The associated operation is invalid (on this vnode).
     79  */
     80 int
     81 fs_inval()
     82 {
     83 	return (EINVAL);
     84 }
     85 
     86 /*
     87  * The associated operation is valid only for directories.
     88  */
     89 int
     90 fs_notdir()
     91 {
     92 	return (ENOTDIR);
     93 }
     94 
     95 /*
     96  * Free the file system specific resources. For the file systems that
     97  * do not support the forced unmount, it will be a nop function.
     98  */
     99 
    100 /*ARGSUSED*/
    101 void
    102 fs_freevfs(vfs_t *vfsp)
    103 {
    104 }
    105 
    106 /* ARGSUSED */
    107 int
    108 fs_nosys_map(struct vnode *vp,
    109 	offset_t off,
    110 	struct as *as,
    111 	caddr_t *addrp,
    112 	size_t len,
    113 	uchar_t prot,
    114 	uchar_t maxprot,
    115 	uint_t flags,
    116 	struct cred *cr,
    117 	caller_context_t *ct)
    118 {
    119 	return (ENOSYS);
    120 }
    121 
    122 /* ARGSUSED */
    123 int
    124 fs_nosys_addmap(struct vnode *vp,
    125 	offset_t off,
    126 	struct as *as,
    127 	caddr_t addr,
    128 	size_t len,
    129 	uchar_t prot,
    130 	uchar_t maxprot,
    131 	uint_t flags,
    132 	struct cred *cr,
    133 	caller_context_t *ct)
    134 {
    135 	return (ENOSYS);
    136 }
    137 
    138 /* ARGSUSED */
    139 int
    140 fs_nosys_poll(vnode_t *vp,
    141 	register short events,
    142 	int anyyet,
    143 	register short *reventsp,
    144 	struct pollhead **phpp,
    145 	caller_context_t *ct)
    146 {
    147 	return (ENOSYS);
    148 }
    149 
    150 
    151 /*
    152  * The file system has nothing to sync to disk.  However, the
    153  * VFS_SYNC operation must not fail.
    154  */
    155 /* ARGSUSED */
    156 int
    157 fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
    158 {
    159 	return (0);
    160 }
    161 
    162 /*
    163  * Does nothing but VOP_FSYNC must not fail.
    164  */
    165 /* ARGSUSED */
    166 int
    167 fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
    168 {
    169 	return (0);
    170 }
    171 
    172 /*
    173  * Does nothing but VOP_PUTPAGE must not fail.
    174  */
    175 /* ARGSUSED */
    176 int
    177 fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
    178 	caller_context_t *ctp)
    179 {
    180 	return (0);
    181 }
    182 
    183 /*
    184  * Does nothing but VOP_IOCTL must not fail.
    185  */
    186 /* ARGSUSED */
    187 int
    188 fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
    189 	int *rvalp)
    190 {
    191 	return (0);
    192 }
    193 
    194 /*
    195  * Read/write lock/unlock.  Does nothing.
    196  */
    197 /* ARGSUSED */
    198 int
    199 fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
    200 {
    201 	return (-1);
    202 }
    203 
    204 /* ARGSUSED */
    205 void
    206 fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
    207 {
    208 }
    209 
    210 /*
    211  * Compare two vnodes.
    212  */
    213 /*ARGSUSED2*/
    214 int
    215 fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
    216 {
    217 	return (vp1 == vp2);
    218 }
    219 
    220 /*
    221  * No-op seek operation.
    222  */
    223 /* ARGSUSED */
    224 int
    225 fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
    226 {
    227 	return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
    228 }
    229 
    230 /*
    231  * File and record locking.
    232  */
    233 /* ARGSUSED */
    234 int
    235 fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
    236 	offset_t offset, flk_callback_t *flk_cbp, cred_t *cr,
    237 	caller_context_t *ct)
    238 {
    239 	int frcmd;
    240 	int nlmid;
    241 	int error = 0;
    242 	flk_callback_t serialize_callback;
    243 	int serialize = 0;
    244 	v_mode_t mode;
    245 
    246 	switch (cmd) {
    247 
    248 	case F_GETLK:
    249 	case F_O_GETLK:
    250 		if (flag & F_REMOTELOCK) {
    251 			frcmd = RCMDLCK;
    252 		} else if (flag & F_PXFSLOCK) {
    253 			frcmd = PCMDLCK;
    254 		} else {
    255 			frcmd = 0;
    256 			bfp->l_pid = ttoproc(curthread)->p_pid;
    257 			bfp->l_sysid = 0;
    258 		}
    259 		break;
    260 
    261 	case F_SETLK_NBMAND:
    262 		/*
    263 		 * Are NBMAND locks allowed on this file?
    264 		 */
    265 		if (!vp->v_vfsp ||
    266 		    !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
    267 			error = EINVAL;
    268 			goto done;
    269 		}
    270 		if (vp->v_type != VREG) {
    271 			error = EINVAL;
    272 			goto done;
    273 		}
    274 		/*FALLTHROUGH*/
    275 
    276 	case F_SETLK:
    277 		if (flag & F_REMOTELOCK) {
    278 			frcmd = SETFLCK|RCMDLCK;
    279 		} else if (flag & F_PXFSLOCK) {
    280 			frcmd = SETFLCK|PCMDLCK;
    281 		} else {
    282 			frcmd = SETFLCK;
    283 			bfp->l_pid = ttoproc(curthread)->p_pid;
    284 			bfp->l_sysid = 0;
    285 		}
    286 		if (cmd == F_SETLK_NBMAND &&
    287 		    (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
    288 			frcmd |= NBMLCK;
    289 		}
    290 		/*
    291 		 * Check whether there is an NBMAND share reservation that
    292 		 * conflicts with the lock request.
    293 		 */
    294 		if (nbl_need_check(vp)) {
    295 			nbl_start_crit(vp, RW_WRITER);
    296 			serialize = 1;
    297 			if (frcmd & NBMLCK) {
    298 				mode = (bfp->l_type == F_RDLCK) ?
    299 				    V_READ : V_RDANDWR;
    300 				if (vn_is_mapped(vp, mode)) {
    301 					error = EAGAIN;
    302 					goto done;
    303 				}
    304 			}
    305 			if (share_blocks_lock(vp, bfp)) {
    306 				error = EAGAIN;
    307 				goto done;
    308 			}
    309 		}
    310 		break;
    311 
    312 	case F_SETLKW:
    313 		if (flag & F_REMOTELOCK) {
    314 			frcmd = SETFLCK|SLPFLCK|RCMDLCK;
    315 		} else if (flag & F_PXFSLOCK) {
    316 			frcmd = SETFLCK|SLPFLCK|PCMDLCK;
    317 		} else {
    318 			frcmd = SETFLCK|SLPFLCK;
    319 			bfp->l_pid = ttoproc(curthread)->p_pid;
    320 			bfp->l_sysid = 0;
    321 		}
    322 		/*
    323 		 * If there is an NBMAND share reservation that conflicts
    324 		 * with the lock request, block until the conflicting share
    325 		 * reservation goes away.
    326 		 */
    327 		if (nbl_need_check(vp)) {
    328 			nbl_start_crit(vp, RW_WRITER);
    329 			serialize = 1;
    330 			if (share_blocks_lock(vp, bfp)) {
    331 				error = wait_for_share(vp, bfp);
    332 				if (error != 0)
    333 					goto done;
    334 			}
    335 		}
    336 		break;
    337 
    338 	case F_HASREMOTELOCKS:
    339 		nlmid = GETNLMID(bfp->l_sysid);
    340 		if (nlmid != 0) {	/* booted as a cluster */
    341 			l_has_rmt(bfp) =
    342 			    cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
    343 		} else {		/* not booted as a cluster */
    344 			l_has_rmt(bfp) = flk_has_remote_locks(vp);
    345 		}
    346 
    347 		goto done;
    348 
    349 	default:
    350 		error = EINVAL;
    351 		goto done;
    352 	}
    353 
    354 	/*
    355 	 * If this is a blocking lock request and we're serializing lock
    356 	 * requests, modify the callback list to leave the critical region
    357 	 * while we're waiting for the lock.
    358 	 */
    359 
    360 	if (serialize && (frcmd & SLPFLCK) != 0) {
    361 		flk_add_callback(&serialize_callback,
    362 		    frlock_serialize_blocked, vp, flk_cbp);
    363 		flk_cbp = &serialize_callback;
    364 	}
    365 
    366 	error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp);
    367 
    368 done:
    369 	if (serialize)
    370 		nbl_end_crit(vp);
    371 
    372 	return (error);
    373 }
    374 
    375 /*
    376  * Callback when a lock request blocks and we are serializing requests.  If
    377  * before sleeping, leave the critical region.  If after wakeup, reenter
    378  * the critical region.
    379  */
    380 
    381 static callb_cpr_t *
    382 frlock_serialize_blocked(flk_cb_when_t when, void *infop)
    383 {
    384 	vnode_t *vp = (vnode_t *)infop;
    385 
    386 	if (when == FLK_BEFORE_SLEEP)
    387 		nbl_end_crit(vp);
    388 	else {
    389 		nbl_start_crit(vp, RW_WRITER);
    390 	}
    391 
    392 	return (NULL);
    393 }
    394 
    395 /*
    396  * Allow any flags.
    397  */
    398 /* ARGSUSED */
    399 int
    400 fs_setfl(
    401 	vnode_t *vp,
    402 	int oflags,
    403 	int nflags,
    404 	cred_t *cr,
    405 	caller_context_t *ct)
    406 {
    407 	return (0);
    408 }
    409 
    410 /*
    411  * Return the answer requested to poll() for non-device files.
    412  * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
    413  */
    414 struct pollhead fs_pollhd;
    415 
    416 /* ARGSUSED */
    417 int
    418 fs_poll(vnode_t *vp,
    419 	register short events,
    420 	int anyyet,
    421 	register short *reventsp,
    422 	struct pollhead **phpp,
    423 	caller_context_t *ct)
    424 {
    425 	*reventsp = 0;
    426 	if (events & POLLIN)
    427 		*reventsp |= POLLIN;
    428 	if (events & POLLRDNORM)
    429 		*reventsp |= POLLRDNORM;
    430 	if (events & POLLRDBAND)
    431 		*reventsp |= POLLRDBAND;
    432 	if (events & POLLOUT)
    433 		*reventsp |= POLLOUT;
    434 	if (events & POLLWRBAND)
    435 		*reventsp |= POLLWRBAND;
    436 	*phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL;
    437 	return (0);
    438 }
    439 
    440 /*
    441  * POSIX pathconf() support.
    442  */
    443 /* ARGSUSED */
    444 int
    445 fs_pathconf(
    446 	vnode_t *vp,
    447 	int cmd,
    448 	ulong_t *valp,
    449 	cred_t *cr,
    450 	caller_context_t *ct)
    451 {
    452 	register ulong_t val;
    453 	register int error = 0;
    454 	struct statvfs64 vfsbuf;
    455 
    456 	switch (cmd) {
    457 
    458 	case _PC_LINK_MAX:
    459 		val = MAXLINK;
    460 		break;
    461 
    462 	case _PC_MAX_CANON:
    463 		val = MAX_CANON;
    464 		break;
    465 
    466 	case _PC_MAX_INPUT:
    467 		val = MAX_INPUT;
    468 		break;
    469 
    470 	case _PC_NAME_MAX:
    471 		bzero(&vfsbuf, sizeof (vfsbuf));
    472 		if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
    473 			break;
    474 		val = vfsbuf.f_namemax;
    475 		break;
    476 
    477 	case _PC_PATH_MAX:
    478 	case _PC_SYMLINK_MAX:
    479 		val = MAXPATHLEN;
    480 		break;
    481 
    482 	case _PC_PIPE_BUF:
    483 		val = PIPE_BUF;
    484 		break;
    485 
    486 	case _PC_NO_TRUNC:
    487 		if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
    488 			val = 1;	/* NOTRUNC is enabled for vp */
    489 		else
    490 			val = (ulong_t)-1;
    491 		break;
    492 
    493 	case _PC_VDISABLE:
    494 		val = _POSIX_VDISABLE;
    495 		break;
    496 
    497 	case _PC_CHOWN_RESTRICTED:
    498 		if (rstchown)
    499 			val = rstchown; /* chown restricted enabled */
    500 		else
    501 			val = (ulong_t)-1;
    502 		break;
    503 
    504 	case _PC_FILESIZEBITS:
    505 
    506 		/*
    507 		 * If ever we come here it means that underlying file system
    508 		 * does not recognise the command and therefore this
    509 		 * configurable limit cannot be determined. We return -1
    510 		 * and don't change errno.
    511 		 */
    512 
    513 		val = (ulong_t)-1;    /* large file support */
    514 		break;
    515 
    516 	case _PC_ACL_ENABLED:
    517 		val = 0;
    518 		break;
    519 
    520 	case _PC_CASE_BEHAVIOR:
    521 		val = _CASE_SENSITIVE;
    522 		if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
    523 			val |= _CASE_INSENSITIVE;
    524 		if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
    525 			val &= ~_CASE_SENSITIVE;
    526 		break;
    527 
    528 	case _PC_SATTR_ENABLED:
    529 	case _PC_SATTR_EXISTS:
    530 		val = 0;
    531 		break;
    532 
    533 	default:
    534 		error = EINVAL;
    535 		break;
    536 	}
    537 
    538 	if (error == 0)
    539 		*valp = val;
    540 	return (error);
    541 }
    542 
    543 /*
    544  * Dispose of a page.
    545  */
    546 /* ARGSUSED */
    547 void
    548 fs_dispose(
    549 	struct vnode *vp,
    550 	page_t *pp,
    551 	int fl,
    552 	int dn,
    553 	struct cred *cr,
    554 	caller_context_t *ct)
    555 {
    556 
    557 	ASSERT(fl == B_FREE || fl == B_INVAL);
    558 
    559 	if (fl == B_FREE)
    560 		page_free(pp, dn);
    561 	else
    562 		page_destroy(pp, dn);
    563 }
    564 
    565 /* ARGSUSED */
    566 void
    567 fs_nodispose(
    568 	struct vnode *vp,
    569 	page_t *pp,
    570 	int fl,
    571 	int dn,
    572 	struct cred *cr,
    573 	caller_context_t *ct)
    574 {
    575 	cmn_err(CE_PANIC, "fs_nodispose invoked");
    576 }
    577 
    578 /*
    579  * fabricate acls for file systems that do not support acls.
    580  */
    581 /* ARGSUSED */
    582 int
    583 fs_fab_acl(
    584 	vnode_t *vp,
    585 	vsecattr_t *vsecattr,
    586 	int flag,
    587 	cred_t *cr,
    588 	caller_context_t *ct)
    589 {
    590 	aclent_t	*aclentp;
    591 	ace_t		*acep;
    592 	struct vattr	vattr;
    593 	int		error;
    594 	size_t		aclsize;
    595 
    596 	vsecattr->vsa_aclcnt	= 0;
    597 	vsecattr->vsa_aclentsz	= 0;
    598 	vsecattr->vsa_aclentp	= NULL;
    599 	vsecattr->vsa_dfaclcnt	= 0;	/* Default ACLs are not fabricated */
    600 	vsecattr->vsa_dfaclentp	= NULL;
    601 
    602 	vattr.va_mask = AT_MODE | AT_UID | AT_GID;
    603 	if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
    604 		return (error);
    605 
    606 	if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
    607 		aclsize = 4 * sizeof (aclent_t);
    608 		vsecattr->vsa_aclcnt	= 4; /* USER, GROUP, OTHER, and CLASS */
    609 		vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
    610 		aclentp = vsecattr->vsa_aclentp;
    611 
    612 		aclentp->a_type = USER_OBJ;	/* Owner */
    613 		aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6;
    614 		aclentp->a_id = vattr.va_uid;   /* Really undefined */
    615 		aclentp++;
    616 
    617 		aclentp->a_type = GROUP_OBJ;    /* Group */
    618 		aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3;
    619 		aclentp->a_id = vattr.va_gid;   /* Really undefined */
    620 		aclentp++;
    621 
    622 		aclentp->a_type = OTHER_OBJ;    /* Other */
    623 		aclentp->a_perm = vattr.va_mode & 0007;
    624 		aclentp->a_id = (gid_t)-1;	/* Really undefined */
    625 		aclentp++;
    626 
    627 		aclentp->a_type = CLASS_OBJ;    /* Class */
    628 		aclentp->a_perm = (ushort_t)(0007);
    629 		aclentp->a_id = (gid_t)-1;	/* Really undefined */
    630 	} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
    631 		aclsize = 6 * sizeof (ace_t);
    632 		vsecattr->vsa_aclcnt	= 6;
    633 		vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
    634 		vsecattr->vsa_aclentsz = aclsize;
    635 		acep = vsecattr->vsa_aclentp;
    636 		(void) memcpy(acep, trivial_acl, sizeof (ace_t) * 6);
    637 		adjust_ace_pair(acep, (vattr.va_mode & 0700) >> 6);
    638 		adjust_ace_pair(acep + 2, (vattr.va_mode & 0070) >> 3);
    639 		adjust_ace_pair(acep + 4, vattr.va_mode & 0007);
    640 	}
    641 
    642 	return (0);
    643 }
    644 
    645 /*
    646  * Common code for implementing DOS share reservations
    647  */
    648 /* ARGSUSED4 */
    649 int
    650 fs_shrlock(
    651 	struct vnode *vp,
    652 	int cmd,
    653 	struct shrlock *shr,
    654 	int flag,
    655 	cred_t *cr,
    656 	caller_context_t *ct)
    657 {
    658 	int error;
    659 
    660 	/*
    661 	 * Make sure that the file was opened with permissions appropriate
    662 	 * for the request, and make sure the caller isn't trying to sneak
    663 	 * in an NBMAND request.
    664 	 */
    665 	if (cmd == F_SHARE) {
    666 		if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
    667 		    ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
    668 			return (EBADF);
    669 		if (shr->s_access & (F_RMACC | F_MDACC))
    670 			return (EINVAL);
    671 		if (shr->s_deny & (F_MANDDNY | F_RMDNY))
    672 			return (EINVAL);
    673 	}
    674 	if (cmd == F_SHARE_NBMAND) {
    675 		/* make sure nbmand is allowed on the file */
    676 		if (!vp->v_vfsp ||
    677 		    !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
    678 			return (EINVAL);
    679 		}
    680 		if (vp->v_type != VREG) {
    681 			return (EINVAL);
    682 		}
    683 	}
    684 
    685 	nbl_start_crit(vp, RW_WRITER);
    686 
    687 	switch (cmd) {
    688 
    689 	case F_SHARE_NBMAND:
    690 		shr->s_deny |= F_MANDDNY;
    691 		/*FALLTHROUGH*/
    692 	case F_SHARE:
    693 		error = add_share(vp, shr);
    694 		break;
    695 
    696 	case F_UNSHARE:
    697 		error = del_share(vp, shr);
    698 		break;
    699 
    700 	case F_HASREMOTELOCKS:
    701 		/*
    702 		 * We are overloading this command to refer to remote
    703 		 * shares as well as remote locks, despite its name.
    704 		 */
    705 		shr->s_access = shr_has_remote_shares(vp, shr->s_sysid);
    706 		error = 0;
    707 		break;
    708 
    709 	default:
    710 		error = EINVAL;
    711 		break;
    712 	}
    713 
    714 	nbl_end_crit(vp);
    715 	return (error);
    716 }
    717 
    718 /*ARGSUSED1*/
    719 int
    720 fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
    721     caller_context_t *ct)
    722 {
    723 	ASSERT(vp != NULL);
    724 	return (ENOTSUP);
    725 }
    726 
    727 /*ARGSUSED1*/
    728 int
    729 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
    730     caller_context_t *ct)
    731 {
    732 	ASSERT(vp != NULL);
    733 	return (0);
    734 }
    735 
    736 /*
    737  * return 1 for non-trivial ACL.
    738  *
    739  * NB: It is not necessary for the caller to VOP_RWLOCK since
    740  *	we only issue VOP_GETSECATTR.
    741  *
    742  * Returns 0 == trivial
    743  *         1 == NOT Trivial
    744  *	   <0 could not determine.
    745  */
    746 int
    747 fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
    748 {
    749 	ulong_t		acl_styles;
    750 	ulong_t		acl_flavor;
    751 	vsecattr_t 	vsecattr;
    752 	int 		error;
    753 	int		isnontrivial;
    754 
    755 	/* determine the forms of ACLs maintained */
    756 	error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
    757 
    758 	/* clear bits we don't understand and establish default acl_style */
    759 	acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
    760 	if (error || (acl_styles == 0))
    761 		acl_styles = _ACL_ACLENT_ENABLED;
    762 
    763 	vsecattr.vsa_aclentp = NULL;
    764 	vsecattr.vsa_dfaclentp = NULL;
    765 	vsecattr.vsa_aclcnt = 0;
    766 	vsecattr.vsa_dfaclcnt = 0;
    767 
    768 	while (acl_styles) {
    769 		/* select one of the styles as current flavor */
    770 		acl_flavor = 0;
    771 		if (acl_styles & _ACL_ACLENT_ENABLED) {
    772 			acl_flavor = _ACL_ACLENT_ENABLED;
    773 			vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
    774 		} else if (acl_styles & _ACL_ACE_ENABLED) {
    775 			acl_flavor = _ACL_ACE_ENABLED;
    776 			vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE;
    777 		}
    778 
    779 		ASSERT(vsecattr.vsa_mask && acl_flavor);
    780 		error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL);
    781 		if (error == 0)
    782 			break;
    783 
    784 		/* that flavor failed */
    785 		acl_styles &= ~acl_flavor;
    786 	}
    787 
    788 	/* if all styles fail then assume trivial */
    789 	if (acl_styles == 0)
    790 		return (0);
    791 
    792 	/* process the flavor that worked */
    793 	isnontrivial = 0;
    794 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
    795 		if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES)
    796 			isnontrivial = 1;
    797 		if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
    798 			kmem_free(vsecattr.vsa_aclentp,
    799 			    vsecattr.vsa_aclcnt * sizeof (aclent_t));
    800 		if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL)
    801 			kmem_free(vsecattr.vsa_dfaclentp,
    802 			    vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
    803 	}
    804 	if (acl_flavor & _ACL_ACE_ENABLED) {
    805 
    806 		isnontrivial = ace_trivial(vsecattr.vsa_aclentp,
    807 		    vsecattr.vsa_aclcnt);
    808 
    809 		if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
    810 			kmem_free(vsecattr.vsa_aclentp,
    811 			    vsecattr.vsa_aclcnt * sizeof (ace_t));
    812 		/* ACE has no vsecattr.vsa_dfaclcnt */
    813 	}
    814 	return (isnontrivial);
    815 }
    816 
    817 /*
    818  * Check whether we need a retry to recover from STALE error.
    819  */
    820 int
    821 fs_need_estale_retry(int retry_count)
    822 {
    823 	if (retry_count < fs_estale_retry)
    824 		return (1);
    825 	else
    826 		return (0);
    827 }
    828 
    829 
    830 static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
    831 
    832 /*
    833  * Routine for anti-virus scanner to call to register its scanning routine.
    834  */
    835 void
    836 fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
    837 {
    838 	fs_av_scan = av_scan;
    839 }
    840 
    841 /*
    842  * Routine for file systems to call to initiate anti-virus scanning.
    843  * Scanning will only be done on REGular files (currently).
    844  */
    845 int
    846 fs_vscan(vnode_t *vp, cred_t *cr, int async)
    847 {
    848 	int ret = 0;
    849 
    850 	if (fs_av_scan && vp->v_type == VREG)
    851 		ret = (*fs_av_scan)(vp, cr, async);
    852 
    853 	return (ret);
    854 }
    855