fake_vop.c revision b819cea2f73f98c5662230cc9affc8cc84f77fcf
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
47int fop_shrlock_enable = 0;
48
49int stat_to_vattr(const struct stat *, vattr_t *);
50int fop__getxvattr(vnode_t *, xvattr_t *);
51int fop__setxvattr(vnode_t *, xvattr_t *);
52
53
54/* ARGSUSED */
55int
56fop_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 */
76int
77fop_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 */
106int
107fop_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 */
161int
162fop_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 */
207int
208fop_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 */
221int
222fop_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 */
234int
235fop_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 */
256int
257fop_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 */
297int
298fop_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 */
309int
310fop_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
352again:
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 */
375int
376fop_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 */
463int
464fop_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 */
479int
480fop_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 */
503int
504fop_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 */
537int
538fop_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 */
570int
571fop_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 */
587int
588fop_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 */
635int
636fop_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 */
649int
650fop_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 */
660int
661fop_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 */
675void
676fop_inactive(
677	vnode_t *vp,
678	cred_t *cr,
679	caller_context_t *ct)
680{
681	vncache_inactive(vp);
682}
683
684/* ARGSUSED */
685int
686fop_fid(
687	vnode_t *vp,
688	fid_t *fidp,
689	caller_context_t *ct)
690{
691	return (ENOSYS);
692}
693
694/* ARGSUSED */
695int
696fop_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 */
706void
707fop_rwunlock(
708	vnode_t *vp,
709	int write_lock,
710	caller_context_t *ct)
711{
712	/* See: fs_rwunlock */
713}
714
715/* ARGSUSED */
716int
717fop_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 */
727int
728fop_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 */
738int
739fop_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 */
768int
769fop_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 */
795int
796fop_realvp(
797	vnode_t *vp,
798	vnode_t **vpp,
799	caller_context_t *ct)
800{
801	return (ENOSYS);
802}
803
804/* ARGSUSED */
805int
806fop_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 */
823int
824fop_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 */
836int
837fop_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 */
853int
854fop_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 */
870int
871fop_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 */
887int
888fop_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 */
913int
914fop_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 */
928int
929fop_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 */
1010int
1011fop_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 */
1024int
1025fop_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 */
1035void
1036fop_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 */
1047int
1048fop_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 */
1062int
1063fop_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 */
1108int
1109fop_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 */
1137int
1138fop_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 */
1145int
1146fop_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 */
1153int
1154fop_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 */
1169enum vtype iftovt_tab[] = {
1170	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
1171	VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
1172};
1173
1174ushort_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
1186int
1187stat_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 */
1246void
1247flk_init_callback(flk_callback_t *flk_cb,
1248	callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata)
1249{
1250}
1251
1252void
1253vn_hold(vnode_t *vp)
1254{
1255	mutex_enter(&vp->v_lock);
1256	vp->v_count++;
1257	mutex_exit(&vp->v_lock);
1258}
1259
1260void
1261vn_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
1274int
1275vn_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 */
1308int
1309vn_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 */
1343int
1344vn_is_mapped(
1345	vnode_t *vp,
1346	v_mode_t mode)
1347{
1348	return (V_FALSE);
1349}
1350