xref: /illumos-gate/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/t_lock.h>
19 #include <sys/errno.h>
20 #include <sys/cred.h>
21 #include <sys/user.h>
22 #include <sys/uio.h>
23 #include <sys/file.h>
24 #include <sys/pathname.h>
25 #include <sys/vfs.h>
26 #include <sys/vnode.h>
27 #include <sys/stat.h>
28 #include <sys/mode.h>
29 #include <sys/kmem.h>
30 #include <sys/debug.h>
31 #include <sys/atomic.h>
32 #include <sys/acl.h>
33 #include <sys/flock.h>
34 #include <sys/nbmlock.h>
35 #include <sys/fcntl.h>
36 #include <sys/poll.h>
37 #include <sys/time.h>
38 
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 
43 #include "vncache.h"
44 
45 #define	O_RWMASK	(O_WRONLY | O_RDWR) /* == 3 */
46 
47 int fop_shrlock_enable = 0;
48 
49 int stat_to_vattr(const struct stat *, vattr_t *);
50 int fop__getxvattr(vnode_t *, xvattr_t *);
51 int fop__setxvattr(vnode_t *, xvattr_t *);
52 
53 
54 /* ARGSUSED */
55 int
56 fop_open(
57 	vnode_t **vpp,
58 	int mode,
59 	cred_t *cr,
60 	caller_context_t *ct)
61 {
62 
63 	if ((*vpp)->v_type == VREG) {
64 		if (mode & FREAD)
65 			atomic_add_32(&((*vpp)->v_rdcnt), 1);
66 		if (mode & FWRITE)
67 			atomic_add_32(&((*vpp)->v_wrcnt), 1);
68 	}
69 
70 	/* call to ->vop_open was here */
71 
72 	return (0);
73 }
74 
75 /* ARGSUSED */
76 int
77 fop_close(
78 	vnode_t *vp,
79 	int flag,
80 	int count,
81 	offset_t offset,
82 	cred_t *cr,
83 	caller_context_t *ct)
84 {
85 
86 	/* call to ->vop_close was here */
87 
88 	/*
89 	 * Check passed in count to handle possible dups. Vnode counts are only
90 	 * kept on regular files
91 	 */
92 	if ((vp->v_type == VREG) && (count == 1))  {
93 		if (flag & FREAD) {
94 			ASSERT(vp->v_rdcnt > 0);
95 			atomic_add_32(&(vp->v_rdcnt), -1);
96 		}
97 		if (flag & FWRITE) {
98 			ASSERT(vp->v_wrcnt > 0);
99 			atomic_add_32(&(vp->v_wrcnt), -1);
100 		}
101 	}
102 	return (0);
103 }
104 
105 /* ARGSUSED */
106 int
107 fop_read(
108 	vnode_t *vp,
109 	uio_t *uio,
110 	int ioflag,
111 	cred_t *cr,
112 	caller_context_t *ct)
113 {
114 	struct stat st;
115 	struct iovec *iov;
116 	ssize_t resid;
117 	size_t cnt;
118 	int n;
119 
120 	/*
121 	 * If that caller asks for read beyond end of file,
122 	 * that causes the pread call to block.  (Ugh!)
123 	 * Get the file size and return what we can.
124 	 */
125 	(void) fstat(vp->v_fd, &st);
126 	resid = uio->uio_resid;
127 	if ((uio->uio_loffset + resid) > st.st_size)
128 		resid = st.st_size - uio->uio_loffset;
129 
130 	while (resid > 0) {
131 
132 		ASSERT(uio->uio_iovcnt > 0);
133 		iov = uio->uio_iov;
134 
135 		if (iov->iov_len == 0) {
136 			uio->uio_iov++;
137 			uio->uio_iovcnt--;
138 			continue;
139 		}
140 		cnt = iov->iov_len;
141 		if (cnt > resid)
142 			cnt = resid;
143 
144 		n = pread(vp->v_fd, iov->iov_base, cnt, uio->uio_loffset);
145 		if (n < 0)
146 			return (errno);
147 
148 		iov->iov_base += n;
149 		iov->iov_len -= n;
150 
151 		uio->uio_resid -= n;
152 		uio->uio_loffset += n;
153 
154 		resid -= n;
155 	}
156 
157 	return (0);
158 }
159 
160 /* ARGSUSED */
161 int
162 fop_write(
163 	vnode_t *vp,
164 	uio_t *uio,
165 	int ioflag,
166 	cred_t *cr,
167 	caller_context_t *ct)
168 {
169 	struct iovec *iov;
170 	size_t cnt;
171 	int n;
172 
173 	while (uio->uio_resid > 0) {
174 
175 		ASSERT(uio->uio_iovcnt > 0);
176 		iov = uio->uio_iov;
177 
178 		if (iov->iov_len == 0) {
179 			uio->uio_iov++;
180 			uio->uio_iovcnt--;
181 			continue;
182 		}
183 		cnt = iov->iov_len;
184 		if (cnt > uio->uio_resid)
185 			cnt = uio->uio_resid;
186 
187 		n = pwrite(vp->v_fd, iov->iov_base, iov->iov_len,
188 		    uio->uio_loffset);
189 		if (n < 0)
190 			return (errno);
191 
192 		iov->iov_base += n;
193 		iov->iov_len -= n;
194 
195 		uio->uio_resid -= n;
196 		uio->uio_loffset += n;
197 	}
198 
199 	if (ioflag == FSYNC) {
200 		(void) fsync(vp->v_fd);
201 	}
202 
203 	return (0);
204 }
205 
206 /* ARGSUSED */
207 int
208 fop_ioctl(
209 	vnode_t *vp,
210 	int cmd,
211 	intptr_t arg,
212 	int flag,
213 	cred_t *cr,
214 	int *rvalp,
215 	caller_context_t *ct)
216 {
217 	return (ENOSYS);
218 }
219 
220 /* ARGSUSED */
221 int
222 fop_setfl(
223 	vnode_t *vp,
224 	int oflags,
225 	int nflags,
226 	cred_t *cr,
227 	caller_context_t *ct)
228 {
229 	/* allow any flags? See fs_setfl */
230 	return (0);
231 }
232 
233 /* ARGSUSED */
234 int
235 fop_getattr(
236 	vnode_t *vp,
237 	vattr_t *vap,
238 	int flags,
239 	cred_t *cr,
240 	caller_context_t *ct)
241 {
242 	int error;
243 	struct stat st;
244 
245 	if (fstat(vp->v_fd, &st) == -1)
246 		return (errno);
247 	error = stat_to_vattr(&st, vap);
248 
249 	if (vap->va_mask & AT_XVATTR)
250 		(void) fop__getxvattr(vp, (xvattr_t *)vap);
251 
252 	return (error);
253 }
254 
255 /* ARGSUSED */
256 int
257 fop_setattr(
258 	vnode_t *vp,
259 	vattr_t *vap,
260 	int flags,
261 	cred_t *cr,
262 	caller_context_t *ct)
263 {
264 	timespec_t times[2];
265 
266 	if (vap->va_mask & AT_SIZE) {
267 		if (ftruncate(vp->v_fd, vap->va_size) == -1)
268 			return (errno);
269 	}
270 
271 	/* AT_MODE or anything else? */
272 
273 	if (vap->va_mask & AT_XVATTR)
274 		(void) fop__setxvattr(vp, (xvattr_t *)vap);
275 
276 	if (vap->va_mask & (AT_ATIME | AT_MTIME)) {
277 		if (vap->va_mask & AT_ATIME) {
278 			times[0] = vap->va_atime;
279 		} else {
280 			times[0].tv_sec = 0;
281 			times[0].tv_nsec = UTIME_OMIT;
282 		}
283 		if (vap->va_mask & AT_MTIME) {
284 			times[1] = vap->va_mtime;
285 		} else {
286 			times[1].tv_sec = 0;
287 			times[1].tv_nsec = UTIME_OMIT;
288 		}
289 
290 		(void) futimens(vp->v_fd, times);
291 	}
292 
293 	return (0);
294 }
295 
296 /* ARGSUSED */
297 int
298 fop_access(
299 	vnode_t *vp,
300 	int mode,
301 	int flags,
302 	cred_t *cr,
303 	caller_context_t *ct)
304 {
305 	return (0);
306 }
307 
308 /* ARGSUSED */
309 int
310 fop_lookup(
311 	vnode_t *dvp,
312 	char *name,
313 	vnode_t **vpp,
314 	pathname_t *pnp,
315 	int flags,
316 	vnode_t *rdir,
317 	cred_t *cr,
318 	caller_context_t *ct,
319 	int *deflags,		/* Returned per-dirent flags */
320 	pathname_t *ppnp)	/* Returned case-preserved name in directory */
321 {
322 	int fd;
323 	int omode = O_RDWR | O_NOFOLLOW;
324 	vnode_t *vp;
325 	struct stat st;
326 
327 	if (flags & LOOKUP_XATTR)
328 		return (ENOENT);
329 
330 	/*
331 	 * If lookup is for "", just return dvp.
332 	 */
333 	if (name[0] == '\0') {
334 		vn_hold(dvp);
335 		*vpp = dvp;
336 		return (0);
337 	}
338 
339 	if (fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW) == -1)
340 		return (errno);
341 
342 	vp = vncache_lookup(&st);
343 	if (vp != NULL) {
344 		/* lookup gave us a hold */
345 		*vpp = vp;
346 		return (0);
347 	}
348 
349 	if (S_ISDIR(st.st_mode))
350 		omode = O_RDONLY | O_NOFOLLOW;
351 
352 again:
353 	fd = openat(dvp->v_fd, name, omode, 0);
354 	if (fd < 0) {
355 		if ((omode & O_RWMASK) == O_RDWR) {
356 			omode &= ~O_RWMASK;
357 			omode |= O_RDONLY;
358 			goto again;
359 		}
360 		return (errno);
361 	}
362 
363 	if (fstat(fd, &st) == -1) {
364 		(void) close(fd);
365 		return (errno);
366 	}
367 
368 	vp = vncache_enter(&st, dvp, name, fd);
369 
370 	*vpp = vp;
371 	return (0);
372 }
373 
374 /* ARGSUSED */
375 int
376 fop_create(
377 	vnode_t *dvp,
378 	char *name,
379 	vattr_t *vap,
380 	vcexcl_t excl,
381 	int mode,
382 	vnode_t **vpp,
383 	cred_t *cr,
384 	int flags,
385 	caller_context_t *ct,
386 	vsecattr_t *vsecp)	/* ACL to set during create */
387 {
388 	struct stat st;
389 	vnode_t *vp;
390 	int err, fd, omode;
391 
392 	/*
393 	 * If creating "", just return dvp.
394 	 */
395 	if (name[0] == '\0') {
396 		vn_hold(dvp);
397 		*vpp = dvp;
398 		return (0);
399 	}
400 
401 	err = fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW);
402 	if (err != 0)
403 		err = errno;
404 
405 	vp = NULL;
406 	if (err == 0) {
407 		/* The file already exists. */
408 		if (excl == EXCL)
409 			return (EEXIST);
410 
411 		vp = vncache_lookup(&st);
412 		/* vp gained a hold */
413 	}
414 
415 	if (vp == NULL) {
416 		/*
417 		 * Open it. (may or may not exist)
418 		 */
419 		omode = O_RDWR | O_CREAT | O_NOFOLLOW;
420 		if (excl == EXCL)
421 			omode |= O_EXCL;
422 	open_again:
423 		fd = openat(dvp->v_fd, name, omode, mode);
424 		if (fd < 0) {
425 			if ((omode & O_RWMASK) == O_RDWR) {
426 				omode &= ~O_RWMASK;
427 				omode |= O_RDONLY;
428 				goto open_again;
429 			}
430 			return (errno);
431 		}
432 		(void) fstat(fd, &st);
433 
434 		vp = vncache_enter(&st, dvp, name, fd);
435 		/* vp has its initial hold */
436 	}
437 
438 	/* Should have the vp now. */
439 	if (vp == NULL)
440 		return (EFAULT);
441 
442 	if (vp->v_type == VDIR && vap->va_type != VDIR) {
443 		vn_rele(vp);
444 		return (EISDIR);
445 	}
446 	if (vp->v_type != VDIR && vap->va_type == VDIR) {
447 		vn_rele(vp);
448 		return (ENOTDIR);
449 	}
450 
451 	/*
452 	 * Might need to set attributes.
453 	 */
454 	(void) fop_setattr(vp, vap, 0, cr, ct);
455 
456 	*vpp = vp;
457 	return (0);
458 }
459 
460 /* ARGSUSED */
461 int
462 fop_remove(
463 	vnode_t *dvp,
464 	char *name,
465 	cred_t *cr,
466 	caller_context_t *ct,
467 	int flags)
468 {
469 
470 	if (unlinkat(dvp->v_fd, name, 0))
471 		return (errno);
472 
473 	return (0);
474 }
475 
476 /* ARGSUSED */
477 int
478 fop_link(
479 	vnode_t *to_dvp,
480 	vnode_t *fr_vp,
481 	char *to_name,
482 	cred_t *cr,
483 	caller_context_t *ct,
484 	int flags)
485 {
486 	int err;
487 
488 	/*
489 	 * Would prefer to specify "from" as the combination:
490 	 * (fr_vp->v_fd, NULL) but linkat does not permit it.
491 	 */
492 	err = linkat(AT_FDCWD, fr_vp->v_path, to_dvp->v_fd, to_name,
493 	    AT_SYMLINK_FOLLOW);
494 	if (err == -1)
495 		err = errno;
496 
497 	return (err);
498 }
499 
500 /* ARGSUSED */
501 int
502 fop_rename(
503 	vnode_t *from_dvp,
504 	char *from_name,
505 	vnode_t *to_dvp,
506 	char *to_name,
507 	cred_t *cr,
508 	caller_context_t *ct,
509 	int flags)
510 {
511 	struct stat st;
512 	vnode_t *vp;
513 	int err;
514 
515 	if (fstatat(from_dvp->v_fd, from_name, &st,
516 	    AT_SYMLINK_NOFOLLOW) == -1)
517 		return (errno);
518 
519 	vp = vncache_lookup(&st);
520 	if (vp == NULL)
521 		return (ENOENT);
522 
523 	err = renameat(from_dvp->v_fd, from_name, to_dvp->v_fd, to_name);
524 	if (err == -1)
525 		err = errno;
526 	else
527 		vncache_renamed(vp, to_dvp, to_name);
528 
529 	vn_rele(vp);
530 
531 	return (err);
532 }
533 
534 /* ARGSUSED */
535 int
536 fop_mkdir(
537 	vnode_t *dvp,
538 	char *name,
539 	vattr_t *vap,
540 	vnode_t **vpp,
541 	cred_t *cr,
542 	caller_context_t *ct,
543 	int flags,
544 	vsecattr_t *vsecp)	/* ACL to set during create */
545 {
546 	struct stat st;
547 	int err, fd;
548 
549 	mode_t mode = vap->va_mode & 0777;
550 
551 	if (mkdirat(dvp->v_fd, name, mode) == -1)
552 		return (errno);
553 
554 	if ((fd = openat(dvp->v_fd, name, O_RDONLY)) == -1)
555 		return (errno);
556 	if (fstat(fd, &st) == -1) {
557 		err = errno;
558 		(void) close(fd);
559 		return (err);
560 	}
561 
562 	*vpp = vncache_enter(&st, dvp, name, fd);
563 
564 	/*
565 	 * Might need to set attributes.
566 	 */
567 	(void) fop_setattr(*vpp, vap, 0, cr, ct);
568 
569 	return (0);
570 }
571 
572 /* ARGSUSED */
573 int
574 fop_rmdir(
575 	vnode_t *dvp,
576 	char *name,
577 	vnode_t *cdir,
578 	cred_t *cr,
579 	caller_context_t *ct,
580 	int flags)
581 {
582 
583 	if (unlinkat(dvp->v_fd, name, AT_REMOVEDIR) == -1)
584 		return (errno);
585 
586 	return (0);
587 }
588 
589 /* ARGSUSED */
590 int
591 fop_readdir(
592 	vnode_t *vp,
593 	uio_t *uiop,
594 	cred_t *cr,
595 	int *eofp,
596 	caller_context_t *ct,
597 	int flags)
598 {
599 	struct iovec *iov;
600 	int cnt;
601 	int error = 0;
602 	int fd = vp->v_fd;
603 
604 	if (eofp) {
605 		*eofp = 0;
606 	}
607 
608 	error = lseek(fd, uiop->uio_loffset, SEEK_SET);
609 	if (error == -1)
610 		return (errno);
611 
612 	ASSERT(uiop->uio_iovcnt > 0);
613 	iov = uiop->uio_iov;
614 	if (iov->iov_len < sizeof (struct dirent))
615 		return (EINVAL);
616 
617 	/* LINTED E_BAD_PTR_CAST_ALIGN */
618 	cnt = getdents(fd, (struct dirent *)(uiop->uio_iov->iov_base),
619 	    uiop->uio_resid);
620 	if (cnt == -1)
621 		return (errno);
622 	if (cnt == 0) {
623 		if (eofp) {
624 			*eofp = 1;
625 		}
626 		return (ENOENT);
627 	}
628 
629 	iov->iov_base += cnt;
630 	iov->iov_len  -= cnt;
631 	uiop->uio_resid -= cnt;
632 	uiop->uio_loffset = lseek(fd, 0LL, SEEK_CUR);
633 
634 	return (0);
635 }
636 
637 /* ARGSUSED */
638 int
639 fop_symlink(
640 	vnode_t *dvp,
641 	char *linkname,
642 	vattr_t *vap,
643 	char *target,
644 	cred_t *cr,
645 	caller_context_t *ct,
646 	int flags)
647 {
648 	return (ENOSYS);
649 }
650 
651 /* ARGSUSED */
652 int
653 fop_readlink(
654 	vnode_t *vp,
655 	uio_t *uiop,
656 	cred_t *cr,
657 	caller_context_t *ct)
658 {
659 	return (ENOSYS);
660 }
661 
662 /* ARGSUSED */
663 int
664 fop_fsync(
665 	vnode_t *vp,
666 	int syncflag,
667 	cred_t *cr,
668 	caller_context_t *ct)
669 {
670 
671 	if (fsync(vp->v_fd) == -1)
672 		return (errno);
673 
674 	return (0);
675 }
676 
677 /* ARGSUSED */
678 void
679 fop_inactive(
680 	vnode_t *vp,
681 	cred_t *cr,
682 	caller_context_t *ct)
683 {
684 	vncache_inactive(vp);
685 }
686 
687 /* ARGSUSED */
688 int
689 fop_fid(
690 	vnode_t *vp,
691 	fid_t *fidp,
692 	caller_context_t *ct)
693 {
694 	return (ENOSYS);
695 }
696 
697 /* ARGSUSED */
698 int
699 fop_rwlock(
700 	vnode_t *vp,
701 	int write_lock,
702 	caller_context_t *ct)
703 {
704 	/* See: fs_rwlock */
705 	return (-1);
706 }
707 
708 /* ARGSUSED */
709 void
710 fop_rwunlock(
711 	vnode_t *vp,
712 	int write_lock,
713 	caller_context_t *ct)
714 {
715 	/* See: fs_rwunlock */
716 }
717 
718 /* ARGSUSED */
719 int
720 fop_seek(
721 	vnode_t *vp,
722 	offset_t ooff,
723 	offset_t *noffp,
724 	caller_context_t *ct)
725 {
726 	return (ENOSYS);
727 }
728 
729 /* ARGSUSED */
730 int
731 fop_cmp(
732 	vnode_t *vp1,
733 	vnode_t *vp2,
734 	caller_context_t *ct)
735 {
736 	/* See fs_cmp */
737 	return (vncache_cmp(vp1, vp2));
738 }
739 
740 /* ARGSUSED */
741 int
742 fop_frlock(
743 	vnode_t *vp,
744 	int cmd,
745 	flock64_t *bfp,
746 	int flag,
747 	offset_t offset,
748 	struct flk_callback *flk_cbp,
749 	cred_t *cr,
750 	caller_context_t *ct)
751 {
752 	/* See fs_frlock */
753 
754 	switch (cmd) {
755 	case F_GETLK:
756 	case F_SETLK_NBMAND:
757 	case F_SETLK:
758 	case F_SETLKW:
759 		break;
760 	default:
761 		return (EINVAL);
762 	}
763 
764 	if (fcntl(vp->v_fd, cmd, bfp) == -1)
765 		return (errno);
766 
767 	return (0);
768 }
769 
770 /* ARGSUSED */
771 int
772 fop_space(
773 	vnode_t *vp,
774 	int cmd,
775 	flock64_t *bfp,
776 	int flag,
777 	offset_t offset,
778 	cred_t *cr,
779 	caller_context_t *ct)
780 {
781 	/* See fs_frlock */
782 
783 	switch (cmd) {
784 	case F_ALLOCSP:
785 	case F_FREESP:
786 		break;
787 	default:
788 		return (EINVAL);
789 	}
790 
791 	if (fcntl(vp->v_fd, cmd, bfp) == -1)
792 		return (errno);
793 
794 	return (0);
795 }
796 
797 /* ARGSUSED */
798 int
799 fop_realvp(
800 	vnode_t *vp,
801 	vnode_t **vpp,
802 	caller_context_t *ct)
803 {
804 	return (ENOSYS);
805 }
806 
807 /* ARGSUSED */
808 int
809 fop_getpage(
810 	vnode_t *vp,
811 	offset_t off,
812 	size_t len,
813 	uint_t *protp,
814 	struct page **plarr,
815 	size_t plsz,
816 	struct seg *seg,
817 	caddr_t addr,
818 	enum seg_rw rw,
819 	cred_t *cr,
820 	caller_context_t *ct)
821 {
822 	return (ENOSYS);
823 }
824 
825 /* ARGSUSED */
826 int
827 fop_putpage(
828 	vnode_t *vp,
829 	offset_t off,
830 	size_t len,
831 	int flags,
832 	cred_t *cr,
833 	caller_context_t *ct)
834 {
835 	return (ENOSYS);
836 }
837 
838 /* ARGSUSED */
839 int
840 fop_map(
841 	vnode_t *vp,
842 	offset_t off,
843 	struct as *as,
844 	caddr_t *addrp,
845 	size_t len,
846 	uchar_t prot,
847 	uchar_t maxprot,
848 	uint_t flags,
849 	cred_t *cr,
850 	caller_context_t *ct)
851 {
852 	return (ENOSYS);
853 }
854 
855 /* ARGSUSED */
856 int
857 fop_addmap(
858 	vnode_t *vp,
859 	offset_t off,
860 	struct as *as,
861 	caddr_t addr,
862 	size_t len,
863 	uchar_t prot,
864 	uchar_t maxprot,
865 	uint_t flags,
866 	cred_t *cr,
867 	caller_context_t *ct)
868 {
869 	return (ENOSYS);
870 }
871 
872 /* ARGSUSED */
873 int
874 fop_delmap(
875 	vnode_t *vp,
876 	offset_t off,
877 	struct as *as,
878 	caddr_t addr,
879 	size_t len,
880 	uint_t prot,
881 	uint_t maxprot,
882 	uint_t flags,
883 	cred_t *cr,
884 	caller_context_t *ct)
885 {
886 	return (ENOSYS);
887 }
888 
889 /* ARGSUSED */
890 int
891 fop_poll(
892 	vnode_t *vp,
893 	short events,
894 	int anyyet,
895 	short *reventsp,
896 	struct pollhead **phpp,
897 	caller_context_t *ct)
898 {
899 	*reventsp = 0;
900 	if (events & POLLIN)
901 		*reventsp |= POLLIN;
902 	if (events & POLLRDNORM)
903 		*reventsp |= POLLRDNORM;
904 	if (events & POLLRDBAND)
905 		*reventsp |= POLLRDBAND;
906 	if (events & POLLOUT)
907 		*reventsp |= POLLOUT;
908 	if (events & POLLWRBAND)
909 		*reventsp |= POLLWRBAND;
910 	*phpp = NULL; /* or fake_pollhead? */
911 
912 	return (0);
913 }
914 
915 /* ARGSUSED */
916 int
917 fop_dump(
918 	vnode_t *vp,
919 	caddr_t addr,
920 	offset_t lbdn,
921 	offset_t dblks,
922 	caller_context_t *ct)
923 {
924 	return (ENOSYS);
925 }
926 
927 /*
928  * See fs_pathconf
929  */
930 /* ARGSUSED */
931 int
932 fop_pathconf(
933 	vnode_t *vp,
934 	int cmd,
935 	ulong_t *valp,
936 	cred_t *cr,
937 	caller_context_t *ct)
938 {
939 	register ulong_t val;
940 	register int error = 0;
941 
942 	switch (cmd) {
943 
944 	case _PC_LINK_MAX:
945 		val = MAXLINK;
946 		break;
947 
948 	case _PC_MAX_CANON:
949 		val = MAX_CANON;
950 		break;
951 
952 	case _PC_MAX_INPUT:
953 		val = MAX_INPUT;
954 		break;
955 
956 	case _PC_NAME_MAX:
957 		val = MAXNAMELEN;
958 		break;
959 
960 	case _PC_PATH_MAX:
961 	case _PC_SYMLINK_MAX:
962 		val = MAXPATHLEN;
963 		break;
964 
965 	case _PC_PIPE_BUF:
966 		val = PIPE_BUF;
967 		break;
968 
969 	case _PC_NO_TRUNC:
970 		val = (ulong_t)-1;
971 		break;
972 
973 	case _PC_VDISABLE:
974 		val = _POSIX_VDISABLE;
975 		break;
976 
977 	case _PC_CHOWN_RESTRICTED:
978 		val = 1; /* chown restricted enabled */
979 		break;
980 
981 	case _PC_FILESIZEBITS:
982 		val = (ulong_t)-1;    /* large file support */
983 		break;
984 
985 	case _PC_ACL_ENABLED:
986 		val = 0;
987 		break;
988 
989 	case _PC_CASE_BEHAVIOR:
990 		val = _CASE_SENSITIVE;
991 		break;
992 
993 	case _PC_SATTR_ENABLED:
994 	case _PC_SATTR_EXISTS:
995 		val = 0;
996 		break;
997 
998 	case _PC_ACCESS_FILTERING:
999 		val = 0;
1000 		break;
1001 
1002 	default:
1003 		error = EINVAL;
1004 		break;
1005 	}
1006 
1007 	if (error == 0)
1008 		*valp = val;
1009 	return (error);
1010 }
1011 
1012 /* ARGSUSED */
1013 int
1014 fop_pageio(
1015 	vnode_t *vp,
1016 	struct page *pp,
1017 	u_offset_t io_off,
1018 	size_t io_len,
1019 	int flags,
1020 	cred_t *cr,
1021 	caller_context_t *ct)
1022 {
1023 	return (ENOSYS);
1024 }
1025 
1026 /* ARGSUSED */
1027 int
1028 fop_dumpctl(
1029 	vnode_t *vp,
1030 	int action,
1031 	offset_t *blkp,
1032 	caller_context_t *ct)
1033 {
1034 	return (ENOSYS);
1035 }
1036 
1037 /* ARGSUSED */
1038 void
1039 fop_dispose(
1040 	vnode_t *vp,
1041 	struct page *pp,
1042 	int flag,
1043 	int dn,
1044 	cred_t *cr,
1045 	caller_context_t *ct)
1046 {
1047 }
1048 
1049 /* ARGSUSED */
1050 int
1051 fop_setsecattr(
1052 	vnode_t *vp,
1053 	vsecattr_t *vsap,
1054 	int flag,
1055 	cred_t *cr,
1056 	caller_context_t *ct)
1057 {
1058 	return (0);
1059 }
1060 
1061 /*
1062  * Fake up just enough of this so we can test get/set SDs.
1063  */
1064 /* ARGSUSED */
1065 int
1066 fop_getsecattr(
1067 	vnode_t *vp,
1068 	vsecattr_t *vsecattr,
1069 	int flag,
1070 	cred_t *cr,
1071 	caller_context_t *ct)
1072 {
1073 
1074 	vsecattr->vsa_aclcnt	= 0;
1075 	vsecattr->vsa_aclentsz	= 0;
1076 	vsecattr->vsa_aclentp	= NULL;
1077 	vsecattr->vsa_dfaclcnt	= 0;	/* Default ACLs are not fabricated */
1078 	vsecattr->vsa_dfaclentp	= NULL;
1079 
1080 	if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
1081 		aclent_t *aclentp;
1082 		size_t aclsize;
1083 
1084 		aclsize = sizeof (aclent_t);
1085 		vsecattr->vsa_aclcnt = 1;
1086 		vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
1087 		aclentp = vsecattr->vsa_aclentp;
1088 
1089 		aclentp->a_type = OTHER_OBJ;
1090 		aclentp->a_perm = 0777;
1091 		aclentp->a_id = (gid_t)-1;
1092 		aclentp++;
1093 	} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
1094 		ace_t *acl;
1095 
1096 		acl = kmem_alloc(sizeof (ace_t), KM_SLEEP);
1097 		acl->a_who = (uint32_t)-1;
1098 		acl->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1099 		acl->a_flags = ACE_EVERYONE;
1100 		acl->a_access_mask  = ACE_MODIFY_PERMS;
1101 
1102 		vsecattr->vsa_aclentp = (void *)acl;
1103 		vsecattr->vsa_aclcnt = 1;
1104 		vsecattr->vsa_aclentsz = sizeof (ace_t);
1105 	}
1106 
1107 	return (0);
1108 }
1109 
1110 /* ARGSUSED */
1111 int
1112 fop_shrlock(
1113 	vnode_t *vp,
1114 	int cmd,
1115 	struct shrlock *shr,
1116 	int flag,
1117 	cred_t *cr,
1118 	caller_context_t *ct)
1119 {
1120 
1121 	switch (cmd) {
1122 	case F_SHARE:
1123 	case F_SHARE_NBMAND:
1124 	case F_UNSHARE:
1125 		break;
1126 	default:
1127 		return (EINVAL);
1128 	}
1129 
1130 	if (!fop_shrlock_enable)
1131 		return (0);
1132 
1133 	if (fcntl(vp->v_fd, cmd, shr) == -1)
1134 		return (errno);
1135 
1136 	return (0);
1137 }
1138 
1139 /* ARGSUSED */
1140 int
1141 fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
1142     caller_context_t *ct)
1143 {
1144 	return (ENOSYS);
1145 }
1146 
1147 /* ARGSUSED */
1148 int
1149 fop_reqzcbuf(vnode_t *vp, enum uio_rw ioflag, xuio_t *uiop, cred_t *cr,
1150     caller_context_t *ct)
1151 {
1152 	return (ENOSYS);
1153 }
1154 
1155 /* ARGSUSED */
1156 int
1157 fop_retzcbuf(vnode_t *vp, xuio_t *uiop, cred_t *cr, caller_context_t *ct)
1158 {
1159 	return (ENOSYS);
1160 }
1161 
1162 
1163 /*
1164  * ***************************************************************
1165  * other VOP support
1166  */
1167 
1168 /*
1169  * Convert stat(2) formats to vnode types and vice versa.  (Knows about
1170  * numerical order of S_IFMT and vnode types.)
1171  */
1172 enum vtype iftovt_tab[] = {
1173 	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
1174 	VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
1175 };
1176 
1177 ushort_t vttoif_tab[] = {
1178 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
1179 	S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
1180 };
1181 
1182 /*
1183  * stat_to_vattr()
1184  *
1185  * Convert from a stat structure to an vattr structure
1186  * Note: only set fields according to va_mask
1187  */
1188 
1189 int
1190 stat_to_vattr(const struct stat *st, vattr_t *vap)
1191 {
1192 
1193 	if (vap->va_mask & AT_TYPE)
1194 		vap->va_type = IFTOVT(st->st_mode);
1195 
1196 	if (vap->va_mask & AT_MODE)
1197 		vap->va_mode = st->st_mode;
1198 
1199 	if (vap->va_mask & AT_UID)
1200 		vap->va_uid = st->st_uid;
1201 
1202 	if (vap->va_mask & AT_GID)
1203 		vap->va_gid = st->st_gid;
1204 
1205 	if (vap->va_mask & AT_FSID)
1206 		vap->va_fsid = st->st_dev;
1207 
1208 	if (vap->va_mask & AT_NODEID)
1209 		vap->va_nodeid = st->st_ino;
1210 
1211 	if (vap->va_mask & AT_NLINK)
1212 		vap->va_nlink = st->st_nlink;
1213 
1214 	if (vap->va_mask & AT_SIZE)
1215 		vap->va_size = (u_offset_t)st->st_size;
1216 
1217 	if (vap->va_mask & AT_ATIME) {
1218 		vap->va_atime.tv_sec  = st->st_atim.tv_sec;
1219 		vap->va_atime.tv_nsec = st->st_atim.tv_nsec;
1220 	}
1221 
1222 	if (vap->va_mask & AT_MTIME) {
1223 		vap->va_mtime.tv_sec  = st->st_mtim.tv_sec;
1224 		vap->va_mtime.tv_nsec = st->st_mtim.tv_nsec;
1225 	}
1226 
1227 	if (vap->va_mask & AT_CTIME) {
1228 		vap->va_ctime.tv_sec  = st->st_ctim.tv_sec;
1229 		vap->va_ctime.tv_nsec = st->st_ctim.tv_nsec;
1230 	}
1231 
1232 	if (vap->va_mask & AT_RDEV)
1233 		vap->va_rdev = st->st_rdev;
1234 
1235 	if (vap->va_mask & AT_BLKSIZE)
1236 		vap->va_blksize = (uint_t)st->st_blksize;
1237 
1238 
1239 	if (vap->va_mask & AT_NBLOCKS)
1240 		vap->va_nblocks = (u_longlong_t)st->st_blocks;
1241 
1242 	if (vap->va_mask & AT_SEQ)
1243 		vap->va_seq = 0;
1244 
1245 	return (0);
1246 }
1247 
1248 /* ARGSUSED */
1249 void
1250 flk_init_callback(flk_callback_t *flk_cb,
1251 	callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata)
1252 {
1253 }
1254 
1255 void
1256 vn_hold(vnode_t *vp)
1257 {
1258 	mutex_enter(&vp->v_lock);
1259 	vp->v_count++;
1260 	mutex_exit(&vp->v_lock);
1261 }
1262 
1263 void
1264 vn_rele(vnode_t *vp)
1265 {
1266 	VERIFY3U(vp->v_count, !=, 0);
1267 	mutex_enter(&vp->v_lock);
1268 	if (vp->v_count == 1) {
1269 		mutex_exit(&vp->v_lock);
1270 		vncache_inactive(vp);
1271 	} else {
1272 		vp->v_count--;
1273 		mutex_exit(&vp->v_lock);
1274 	}
1275 }
1276 
1277 int
1278 vn_has_other_opens(
1279 	vnode_t *vp,
1280 	v_mode_t mode)
1281 {
1282 
1283 	switch (mode) {
1284 	case V_WRITE:
1285 		if (vp->v_wrcnt > 1)
1286 			return (V_TRUE);
1287 		break;
1288 	case V_RDORWR:
1289 		if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
1290 			return (V_TRUE);
1291 		break;
1292 	case V_RDANDWR:
1293 		if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
1294 			return (V_TRUE);
1295 		break;
1296 	case V_READ:
1297 		if (vp->v_rdcnt > 1)
1298 			return (V_TRUE);
1299 		break;
1300 	}
1301 
1302 	return (V_FALSE);
1303 }
1304 
1305 /*
1306  * vn_is_opened() checks whether a particular file is opened and
1307  * whether the open is for read and/or write.
1308  *
1309  * Vnode counts are only kept on regular files (v_type=VREG).
1310  */
1311 int
1312 vn_is_opened(
1313 	vnode_t *vp,
1314 	v_mode_t mode)
1315 {
1316 
1317 	ASSERT(vp != NULL);
1318 
1319 	switch (mode) {
1320 	case V_WRITE:
1321 		if (vp->v_wrcnt)
1322 			return (V_TRUE);
1323 		break;
1324 	case V_RDANDWR:
1325 		if (vp->v_rdcnt && vp->v_wrcnt)
1326 			return (V_TRUE);
1327 		break;
1328 	case V_RDORWR:
1329 		if (vp->v_rdcnt || vp->v_wrcnt)
1330 			return (V_TRUE);
1331 		break;
1332 	case V_READ:
1333 		if (vp->v_rdcnt)
1334 			return (V_TRUE);
1335 		break;
1336 	}
1337 
1338 	return (V_FALSE);
1339 }
1340 
1341 /*
1342  * vn_is_mapped() checks whether a particular file is mapped and whether
1343  * the file is mapped read and/or write.
1344  */
1345 /* ARGSUSED */
1346 int
1347 vn_is_mapped(
1348 	vnode_t *vp,
1349 	v_mode_t mode)
1350 {
1351 	return (V_FALSE);
1352 }
1353