xref: /illumos-gate/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c (revision 45818ee124adeaaf947698996b4f4c722afc6d1f)
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 2014 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 	struct timeval 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 		times[0].tv_sec = 0;
278 		times[0].tv_usec = UTIME_OMIT;
279 		times[1].tv_sec = 0;
280 		times[1].tv_usec = UTIME_OMIT;
281 		if (vap->va_mask & AT_ATIME) {
282 			times[0].tv_sec = vap->va_atime.tv_sec;
283 			times[0].tv_usec = vap->va_atime.tv_nsec / 1000;
284 		}
285 		if (vap->va_mask & AT_MTIME) {
286 			times[1].tv_sec = vap->va_mtime.tv_sec;
287 			times[1].tv_usec = vap->va_mtime.tv_nsec / 1000;
288 		}
289 
290 		(void) futimesat(vp->v_fd, NULL, 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 	 * Truncate (if requested).
453 	 */
454 	if ((vap->va_mask & AT_SIZE) && vap->va_size == 0) {
455 		(void) ftruncate(vp->v_fd, 0);
456 	}
457 
458 	*vpp = vp;
459 	return (0);
460 }
461 
462 /* ARGSUSED */
463 int
464 fop_remove(
465 	vnode_t *dvp,
466 	char *name,
467 	cred_t *cr,
468 	caller_context_t *ct,
469 	int flags)
470 {
471 
472 	if (unlinkat(dvp->v_fd, name, 0))
473 		return (errno);
474 
475 	return (0);
476 }
477 
478 /* ARGSUSED */
479 int
480 fop_link(
481 	vnode_t *to_dvp,
482 	vnode_t *fr_vp,
483 	char *to_name,
484 	cred_t *cr,
485 	caller_context_t *ct,
486 	int flags)
487 {
488 	int err;
489 
490 	/*
491 	 * Would prefer to specify "from" as the combination:
492 	 * (fr_vp->v_fd, NULL) but linkat does not permit it.
493 	 */
494 	err = linkat(AT_FDCWD, fr_vp->v_path, to_dvp->v_fd, to_name,
495 	    AT_SYMLINK_FOLLOW);
496 	if (err == -1)
497 		err = errno;
498 
499 	return (err);
500 }
501 
502 /* ARGSUSED */
503 int
504 fop_rename(
505 	vnode_t *from_dvp,
506 	char *from_name,
507 	vnode_t *to_dvp,
508 	char *to_name,
509 	cred_t *cr,
510 	caller_context_t *ct,
511 	int flags)
512 {
513 	struct stat st;
514 	vnode_t *vp;
515 	int err;
516 
517 	if (fstatat(from_dvp->v_fd, from_name, &st,
518 	    AT_SYMLINK_NOFOLLOW) == -1)
519 		return (errno);
520 
521 	vp = vncache_lookup(&st);
522 	if (vp == NULL)
523 		return (ENOENT);
524 
525 	err = renameat(from_dvp->v_fd, from_name, to_dvp->v_fd, to_name);
526 	if (err == -1)
527 		err = errno;
528 	else
529 		vncache_renamed(vp, to_dvp, to_name);
530 
531 	vn_rele(vp);
532 
533 	return (err);
534 }
535 
536 /* ARGSUSED */
537 int
538 fop_mkdir(
539 	vnode_t *dvp,
540 	char *name,
541 	vattr_t *vap,
542 	vnode_t **vpp,
543 	cred_t *cr,
544 	caller_context_t *ct,
545 	int flags,
546 	vsecattr_t *vsecp)	/* ACL to set during create */
547 {
548 	struct stat st;
549 	int err, fd;
550 
551 	mode_t mode = vap->va_mode & 0777;
552 
553 	if (mkdirat(dvp->v_fd, name, mode) == -1)
554 		return (errno);
555 
556 	if ((fd = openat(dvp->v_fd, name, O_RDONLY)) == -1)
557 		return (errno);
558 	if (fstat(fd, &st) == -1) {
559 		err = errno;
560 		(void) close(fd);
561 		return (err);
562 	}
563 
564 	*vpp = vncache_enter(&st, dvp, name, fd);
565 
566 	return (0);
567 }
568 
569 /* ARGSUSED */
570 int
571 fop_rmdir(
572 	vnode_t *dvp,
573 	char *name,
574 	vnode_t *cdir,
575 	cred_t *cr,
576 	caller_context_t *ct,
577 	int flags)
578 {
579 
580 	if (unlinkat(dvp->v_fd, name, AT_REMOVEDIR) == -1)
581 		return (errno);
582 
583 	return (0);
584 }
585 
586 /* ARGSUSED */
587 int
588 fop_readdir(
589 	vnode_t *vp,
590 	uio_t *uiop,
591 	cred_t *cr,
592 	int *eofp,
593 	caller_context_t *ct,
594 	int flags)
595 {
596 	struct iovec *iov;
597 	int cnt;
598 	int error = 0;
599 	int fd = vp->v_fd;
600 
601 	if (eofp) {
602 		*eofp = 0;
603 	}
604 
605 	error = lseek(fd, uiop->uio_loffset, SEEK_SET);
606 	if (error == -1)
607 		return (errno);
608 
609 	ASSERT(uiop->uio_iovcnt > 0);
610 	iov = uiop->uio_iov;
611 	if (iov->iov_len < sizeof (struct dirent))
612 		return (EINVAL);
613 
614 	/* LINTED E_BAD_PTR_CAST_ALIGN */
615 	cnt = getdents(fd, (struct dirent *)(uiop->uio_iov->iov_base),
616 	    uiop->uio_resid);
617 	if (cnt == -1)
618 		return (errno);
619 	if (cnt == 0) {
620 		if (eofp) {
621 			*eofp = 1;
622 		}
623 		return (ENOENT);
624 	}
625 
626 	iov->iov_base += cnt;
627 	iov->iov_len  -= cnt;
628 	uiop->uio_resid -= cnt;
629 	uiop->uio_loffset = lseek(fd, 0LL, SEEK_CUR);
630 
631 	return (0);
632 }
633 
634 /* ARGSUSED */
635 int
636 fop_symlink(
637 	vnode_t *dvp,
638 	char *linkname,
639 	vattr_t *vap,
640 	char *target,
641 	cred_t *cr,
642 	caller_context_t *ct,
643 	int flags)
644 {
645 	return (ENOSYS);
646 }
647 
648 /* ARGSUSED */
649 int
650 fop_readlink(
651 	vnode_t *vp,
652 	uio_t *uiop,
653 	cred_t *cr,
654 	caller_context_t *ct)
655 {
656 	return (ENOSYS);
657 }
658 
659 /* ARGSUSED */
660 int
661 fop_fsync(
662 	vnode_t *vp,
663 	int syncflag,
664 	cred_t *cr,
665 	caller_context_t *ct)
666 {
667 
668 	if (fsync(vp->v_fd) == -1)
669 		return (errno);
670 
671 	return (0);
672 }
673 
674 /* ARGSUSED */
675 void
676 fop_inactive(
677 	vnode_t *vp,
678 	cred_t *cr,
679 	caller_context_t *ct)
680 {
681 	vncache_inactive(vp);
682 }
683 
684 /* ARGSUSED */
685 int
686 fop_fid(
687 	vnode_t *vp,
688 	fid_t *fidp,
689 	caller_context_t *ct)
690 {
691 	return (ENOSYS);
692 }
693 
694 /* ARGSUSED */
695 int
696 fop_rwlock(
697 	vnode_t *vp,
698 	int write_lock,
699 	caller_context_t *ct)
700 {
701 	/* See: fs_rwlock */
702 	return (-1);
703 }
704 
705 /* ARGSUSED */
706 void
707 fop_rwunlock(
708 	vnode_t *vp,
709 	int write_lock,
710 	caller_context_t *ct)
711 {
712 	/* See: fs_rwunlock */
713 }
714 
715 /* ARGSUSED */
716 int
717 fop_seek(
718 	vnode_t *vp,
719 	offset_t ooff,
720 	offset_t *noffp,
721 	caller_context_t *ct)
722 {
723 	return (ENOSYS);
724 }
725 
726 /* ARGSUSED */
727 int
728 fop_cmp(
729 	vnode_t *vp1,
730 	vnode_t *vp2,
731 	caller_context_t *ct)
732 {
733 	/* See fs_cmp */
734 	return (vncache_cmp(vp1, vp2));
735 }
736 
737 /* ARGSUSED */
738 int
739 fop_frlock(
740 	vnode_t *vp,
741 	int cmd,
742 	flock64_t *bfp,
743 	int flag,
744 	offset_t offset,
745 	struct flk_callback *flk_cbp,
746 	cred_t *cr,
747 	caller_context_t *ct)
748 {
749 	/* See fs_frlock */
750 
751 	switch (cmd) {
752 	case F_GETLK:
753 	case F_SETLK_NBMAND:
754 	case F_SETLK:
755 	case F_SETLKW:
756 		break;
757 	default:
758 		return (EINVAL);
759 	}
760 
761 	if (fcntl(vp->v_fd, cmd, bfp) == -1)
762 		return (errno);
763 
764 	return (0);
765 }
766 
767 /* ARGSUSED */
768 int
769 fop_space(
770 	vnode_t *vp,
771 	int cmd,
772 	flock64_t *bfp,
773 	int flag,
774 	offset_t offset,
775 	cred_t *cr,
776 	caller_context_t *ct)
777 {
778 	/* See fs_frlock */
779 
780 	switch (cmd) {
781 	case F_ALLOCSP:
782 	case F_FREESP:
783 		break;
784 	default:
785 		return (EINVAL);
786 	}
787 
788 	if (fcntl(vp->v_fd, cmd, bfp) == -1)
789 		return (errno);
790 
791 	return (0);
792 }
793 
794 /* ARGSUSED */
795 int
796 fop_realvp(
797 	vnode_t *vp,
798 	vnode_t **vpp,
799 	caller_context_t *ct)
800 {
801 	return (ENOSYS);
802 }
803 
804 /* ARGSUSED */
805 int
806 fop_getpage(
807 	vnode_t *vp,
808 	offset_t off,
809 	size_t len,
810 	uint_t *protp,
811 	struct page **plarr,
812 	size_t plsz,
813 	struct seg *seg,
814 	caddr_t addr,
815 	enum seg_rw rw,
816 	cred_t *cr,
817 	caller_context_t *ct)
818 {
819 	return (ENOSYS);
820 }
821 
822 /* ARGSUSED */
823 int
824 fop_putpage(
825 	vnode_t *vp,
826 	offset_t off,
827 	size_t len,
828 	int flags,
829 	cred_t *cr,
830 	caller_context_t *ct)
831 {
832 	return (ENOSYS);
833 }
834 
835 /* ARGSUSED */
836 int
837 fop_map(
838 	vnode_t *vp,
839 	offset_t off,
840 	struct as *as,
841 	caddr_t *addrp,
842 	size_t len,
843 	uchar_t prot,
844 	uchar_t maxprot,
845 	uint_t flags,
846 	cred_t *cr,
847 	caller_context_t *ct)
848 {
849 	return (ENOSYS);
850 }
851 
852 /* ARGSUSED */
853 int
854 fop_addmap(
855 	vnode_t *vp,
856 	offset_t off,
857 	struct as *as,
858 	caddr_t addr,
859 	size_t len,
860 	uchar_t prot,
861 	uchar_t maxprot,
862 	uint_t flags,
863 	cred_t *cr,
864 	caller_context_t *ct)
865 {
866 	return (ENOSYS);
867 }
868 
869 /* ARGSUSED */
870 int
871 fop_delmap(
872 	vnode_t *vp,
873 	offset_t off,
874 	struct as *as,
875 	caddr_t addr,
876 	size_t len,
877 	uint_t prot,
878 	uint_t maxprot,
879 	uint_t flags,
880 	cred_t *cr,
881 	caller_context_t *ct)
882 {
883 	return (ENOSYS);
884 }
885 
886 /* ARGSUSED */
887 int
888 fop_poll(
889 	vnode_t *vp,
890 	short events,
891 	int anyyet,
892 	short *reventsp,
893 	struct pollhead **phpp,
894 	caller_context_t *ct)
895 {
896 	*reventsp = 0;
897 	if (events & POLLIN)
898 		*reventsp |= POLLIN;
899 	if (events & POLLRDNORM)
900 		*reventsp |= POLLRDNORM;
901 	if (events & POLLRDBAND)
902 		*reventsp |= POLLRDBAND;
903 	if (events & POLLOUT)
904 		*reventsp |= POLLOUT;
905 	if (events & POLLWRBAND)
906 		*reventsp |= POLLWRBAND;
907 	*phpp = NULL; /* or fake_pollhead? */
908 
909 	return (0);
910 }
911 
912 /* ARGSUSED */
913 int
914 fop_dump(
915 	vnode_t *vp,
916 	caddr_t addr,
917 	offset_t lbdn,
918 	offset_t dblks,
919 	caller_context_t *ct)
920 {
921 	return (ENOSYS);
922 }
923 
924 /*
925  * See fs_pathconf
926  */
927 /* ARGSUSED */
928 int
929 fop_pathconf(
930 	vnode_t *vp,
931 	int cmd,
932 	ulong_t *valp,
933 	cred_t *cr,
934 	caller_context_t *ct)
935 {
936 	register ulong_t val;
937 	register int error = 0;
938 
939 	switch (cmd) {
940 
941 	case _PC_LINK_MAX:
942 		val = MAXLINK;
943 		break;
944 
945 	case _PC_MAX_CANON:
946 		val = MAX_CANON;
947 		break;
948 
949 	case _PC_MAX_INPUT:
950 		val = MAX_INPUT;
951 		break;
952 
953 	case _PC_NAME_MAX:
954 		val = MAXNAMELEN;
955 		break;
956 
957 	case _PC_PATH_MAX:
958 	case _PC_SYMLINK_MAX:
959 		val = MAXPATHLEN;
960 		break;
961 
962 	case _PC_PIPE_BUF:
963 		val = PIPE_BUF;
964 		break;
965 
966 	case _PC_NO_TRUNC:
967 		val = (ulong_t)-1;
968 		break;
969 
970 	case _PC_VDISABLE:
971 		val = _POSIX_VDISABLE;
972 		break;
973 
974 	case _PC_CHOWN_RESTRICTED:
975 		val = 1; /* chown restricted enabled */
976 		break;
977 
978 	case _PC_FILESIZEBITS:
979 		val = (ulong_t)-1;    /* large file support */
980 		break;
981 
982 	case _PC_ACL_ENABLED:
983 		val = 0;
984 		break;
985 
986 	case _PC_CASE_BEHAVIOR:
987 		val = _CASE_SENSITIVE;
988 		break;
989 
990 	case _PC_SATTR_ENABLED:
991 	case _PC_SATTR_EXISTS:
992 		val = 0;
993 		break;
994 
995 	case _PC_ACCESS_FILTERING:
996 		val = 0;
997 		break;
998 
999 	default:
1000 		error = EINVAL;
1001 		break;
1002 	}
1003 
1004 	if (error == 0)
1005 		*valp = val;
1006 	return (error);
1007 }
1008 
1009 /* ARGSUSED */
1010 int
1011 fop_pageio(
1012 	vnode_t *vp,
1013 	struct page *pp,
1014 	u_offset_t io_off,
1015 	size_t io_len,
1016 	int flags,
1017 	cred_t *cr,
1018 	caller_context_t *ct)
1019 {
1020 	return (ENOSYS);
1021 }
1022 
1023 /* ARGSUSED */
1024 int
1025 fop_dumpctl(
1026 	vnode_t *vp,
1027 	int action,
1028 	offset_t *blkp,
1029 	caller_context_t *ct)
1030 {
1031 	return (ENOSYS);
1032 }
1033 
1034 /* ARGSUSED */
1035 void
1036 fop_dispose(
1037 	vnode_t *vp,
1038 	struct page *pp,
1039 	int flag,
1040 	int dn,
1041 	cred_t *cr,
1042 	caller_context_t *ct)
1043 {
1044 }
1045 
1046 /* ARGSUSED */
1047 int
1048 fop_setsecattr(
1049 	vnode_t *vp,
1050 	vsecattr_t *vsap,
1051 	int flag,
1052 	cred_t *cr,
1053 	caller_context_t *ct)
1054 {
1055 	return (0);
1056 }
1057 
1058 /*
1059  * Fake up just enough of this so we can test get/set SDs.
1060  */
1061 /* ARGSUSED */
1062 int
1063 fop_getsecattr(
1064 	vnode_t *vp,
1065 	vsecattr_t *vsecattr,
1066 	int flag,
1067 	cred_t *cr,
1068 	caller_context_t *ct)
1069 {
1070 
1071 	vsecattr->vsa_aclcnt	= 0;
1072 	vsecattr->vsa_aclentsz	= 0;
1073 	vsecattr->vsa_aclentp	= NULL;
1074 	vsecattr->vsa_dfaclcnt	= 0;	/* Default ACLs are not fabricated */
1075 	vsecattr->vsa_dfaclentp	= NULL;
1076 
1077 	if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
1078 		aclent_t *aclentp;
1079 		size_t aclsize;
1080 
1081 		aclsize = sizeof (aclent_t);
1082 		vsecattr->vsa_aclcnt = 1;
1083 		vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
1084 		aclentp = vsecattr->vsa_aclentp;
1085 
1086 		aclentp->a_type = OTHER_OBJ;
1087 		aclentp->a_perm = 0777;
1088 		aclentp->a_id = (gid_t)-1;
1089 		aclentp++;
1090 	} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
1091 		ace_t *acl;
1092 
1093 		acl = kmem_alloc(sizeof (ace_t), KM_SLEEP);
1094 		acl->a_who = (uint32_t)-1;
1095 		acl->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1096 		acl->a_flags = ACE_EVERYONE;
1097 		acl->a_access_mask  = ACE_MODIFY_PERMS;
1098 
1099 		vsecattr->vsa_aclentp = (void *)acl;
1100 		vsecattr->vsa_aclcnt = 1;
1101 		vsecattr->vsa_aclentsz = sizeof (ace_t);
1102 	}
1103 
1104 	return (0);
1105 }
1106 
1107 /* ARGSUSED */
1108 int
1109 fop_shrlock(
1110 	vnode_t *vp,
1111 	int cmd,
1112 	struct shrlock *shr,
1113 	int flag,
1114 	cred_t *cr,
1115 	caller_context_t *ct)
1116 {
1117 
1118 	switch (cmd) {
1119 	case F_SHARE:
1120 	case F_SHARE_NBMAND:
1121 	case F_UNSHARE:
1122 		break;
1123 	default:
1124 		return (EINVAL);
1125 	}
1126 
1127 	if (!fop_shrlock_enable)
1128 		return (0);
1129 
1130 	if (fcntl(vp->v_fd, cmd, shr) == -1)
1131 		return (errno);
1132 
1133 	return (0);
1134 }
1135 
1136 /* ARGSUSED */
1137 int
1138 fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
1139     caller_context_t *ct)
1140 {
1141 	return (ENOSYS);
1142 }
1143 
1144 /* ARGSUSED */
1145 int
1146 fop_reqzcbuf(vnode_t *vp, enum uio_rw ioflag, xuio_t *uiop, cred_t *cr,
1147     caller_context_t *ct)
1148 {
1149 	return (ENOSYS);
1150 }
1151 
1152 /* ARGSUSED */
1153 int
1154 fop_retzcbuf(vnode_t *vp, xuio_t *uiop, cred_t *cr, caller_context_t *ct)
1155 {
1156 	return (ENOSYS);
1157 }
1158 
1159 
1160 /*
1161  * ***************************************************************
1162  * other VOP support
1163  */
1164 
1165 /*
1166  * Convert stat(2) formats to vnode types and vice versa.  (Knows about
1167  * numerical order of S_IFMT and vnode types.)
1168  */
1169 enum vtype iftovt_tab[] = {
1170 	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
1171 	VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
1172 };
1173 
1174 ushort_t vttoif_tab[] = {
1175 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
1176 	S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
1177 };
1178 
1179 /*
1180  * stat_to_vattr()
1181  *
1182  * Convert from a stat structure to an vattr structure
1183  * Note: only set fields according to va_mask
1184  */
1185 
1186 int
1187 stat_to_vattr(const struct stat *st, vattr_t *vap)
1188 {
1189 
1190 	if (vap->va_mask & AT_TYPE)
1191 		vap->va_type = IFTOVT(st->st_mode);
1192 
1193 	if (vap->va_mask & AT_MODE)
1194 		vap->va_mode = st->st_mode;
1195 
1196 	if (vap->va_mask & AT_UID)
1197 		vap->va_uid = st->st_uid;
1198 
1199 	if (vap->va_mask & AT_GID)
1200 		vap->va_gid = st->st_gid;
1201 
1202 	if (vap->va_mask & AT_FSID)
1203 		vap->va_fsid = st->st_dev;
1204 
1205 	if (vap->va_mask & AT_NODEID)
1206 		vap->va_nodeid = st->st_ino;
1207 
1208 	if (vap->va_mask & AT_NLINK)
1209 		vap->va_nlink = st->st_nlink;
1210 
1211 	if (vap->va_mask & AT_SIZE)
1212 		vap->va_size = (u_offset_t)st->st_size;
1213 
1214 	if (vap->va_mask & AT_ATIME) {
1215 		vap->va_atime.tv_sec  = st->st_atim.tv_sec;
1216 		vap->va_atime.tv_nsec = st->st_atim.tv_nsec;
1217 	}
1218 
1219 	if (vap->va_mask & AT_MTIME) {
1220 		vap->va_mtime.tv_sec  = st->st_mtim.tv_sec;
1221 		vap->va_mtime.tv_nsec = st->st_mtim.tv_nsec;
1222 	}
1223 
1224 	if (vap->va_mask & AT_CTIME) {
1225 		vap->va_ctime.tv_sec  = st->st_ctim.tv_sec;
1226 		vap->va_ctime.tv_nsec = st->st_ctim.tv_nsec;
1227 	}
1228 
1229 	if (vap->va_mask & AT_RDEV)
1230 		vap->va_rdev = st->st_rdev;
1231 
1232 	if (vap->va_mask & AT_BLKSIZE)
1233 		vap->va_blksize = (uint_t)st->st_blksize;
1234 
1235 
1236 	if (vap->va_mask & AT_NBLOCKS)
1237 		vap->va_nblocks = (u_longlong_t)st->st_blocks;
1238 
1239 	if (vap->va_mask & AT_SEQ)
1240 		vap->va_seq = 0;
1241 
1242 	return (0);
1243 }
1244 
1245 /* ARGSUSED */
1246 void
1247 flk_init_callback(flk_callback_t *flk_cb,
1248 	callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata)
1249 {
1250 }
1251 
1252 void
1253 vn_hold(vnode_t *vp)
1254 {
1255 	mutex_enter(&vp->v_lock);
1256 	vp->v_count++;
1257 	mutex_exit(&vp->v_lock);
1258 }
1259 
1260 void
1261 vn_rele(vnode_t *vp)
1262 {
1263 	VERIFY3U(vp->v_count, !=, 0);
1264 	mutex_enter(&vp->v_lock);
1265 	if (vp->v_count == 1) {
1266 		mutex_exit(&vp->v_lock);
1267 		vncache_inactive(vp);
1268 	} else {
1269 		vp->v_count--;
1270 		mutex_exit(&vp->v_lock);
1271 	}
1272 }
1273 
1274 int
1275 vn_has_other_opens(
1276 	vnode_t *vp,
1277 	v_mode_t mode)
1278 {
1279 
1280 	switch (mode) {
1281 	case V_WRITE:
1282 		if (vp->v_wrcnt > 1)
1283 			return (V_TRUE);
1284 		break;
1285 	case V_RDORWR:
1286 		if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
1287 			return (V_TRUE);
1288 		break;
1289 	case V_RDANDWR:
1290 		if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
1291 			return (V_TRUE);
1292 		break;
1293 	case V_READ:
1294 		if (vp->v_rdcnt > 1)
1295 			return (V_TRUE);
1296 		break;
1297 	}
1298 
1299 	return (V_FALSE);
1300 }
1301 
1302 /*
1303  * vn_is_opened() checks whether a particular file is opened and
1304  * whether the open is for read and/or write.
1305  *
1306  * Vnode counts are only kept on regular files (v_type=VREG).
1307  */
1308 int
1309 vn_is_opened(
1310 	vnode_t *vp,
1311 	v_mode_t mode)
1312 {
1313 
1314 	ASSERT(vp != NULL);
1315 
1316 	switch (mode) {
1317 	case V_WRITE:
1318 		if (vp->v_wrcnt)
1319 			return (V_TRUE);
1320 		break;
1321 	case V_RDANDWR:
1322 		if (vp->v_rdcnt && vp->v_wrcnt)
1323 			return (V_TRUE);
1324 		break;
1325 	case V_RDORWR:
1326 		if (vp->v_rdcnt || vp->v_wrcnt)
1327 			return (V_TRUE);
1328 		break;
1329 	case V_READ:
1330 		if (vp->v_rdcnt)
1331 			return (V_TRUE);
1332 		break;
1333 	}
1334 
1335 	return (V_FALSE);
1336 }
1337 
1338 /*
1339  * vn_is_mapped() checks whether a particular file is mapped and whether
1340  * the file is mapped read and/or write.
1341  */
1342 /* ARGSUSED */
1343 int
1344 vn_is_mapped(
1345 	vnode_t *vp,
1346 	v_mode_t mode)
1347 {
1348 	return (V_FALSE);
1349 }
1350