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
fop_open(vnode_t ** vpp,int mode,cred_t * cr,caller_context_t * ct)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
fop_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)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
fop_read(vnode_t * vp,uio_t * uio,int ioflag,cred_t * cr,caller_context_t * ct)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
fop_write(vnode_t * vp,uio_t * uio,int ioflag,cred_t * cr,caller_context_t * ct)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
fop_ioctl(vnode_t * vp,int cmd,intptr_t arg,int flag,cred_t * cr,int * rvalp,caller_context_t * ct)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
fop_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)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
fop_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)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
fop_setattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)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
fop_access(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)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
fop_lookup(vnode_t * dvp,char * name,vnode_t ** vpp,pathname_t * pnp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * deflags,pathname_t * ppnp)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
fop_create(vnode_t * dvp,char * name,vattr_t * vap,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cr,int flags,caller_context_t * ct,vsecattr_t * vsecp)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
fop_remove(vnode_t * dvp,char * name,cred_t * cr,caller_context_t * ct,int flags)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
fop_link(vnode_t * to_dvp,vnode_t * fr_vp,char * to_name,cred_t * cr,caller_context_t * ct,int flags)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
fop_rename(vnode_t * from_dvp,char * from_name,vnode_t * to_dvp,char * to_name,cred_t * cr,caller_context_t * ct,int flags)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
fop_mkdir(vnode_t * dvp,char * name,vattr_t * vap,vnode_t ** vpp,cred_t * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)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
fop_rmdir(vnode_t * dvp,char * name,vnode_t * cdir,cred_t * cr,caller_context_t * ct,int flags)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
fop_readdir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)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
fop_symlink(vnode_t * dvp,char * linkname,vattr_t * vap,char * target,cred_t * cr,caller_context_t * ct,int flags)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
fop_readlink(vnode_t * vp,uio_t * uiop,cred_t * cr,caller_context_t * ct)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
fop_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)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
fop_inactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)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
fop_fid(vnode_t * vp,fid_t * fidp,caller_context_t * ct)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
fop_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)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
fop_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)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
fop_frlock(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)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
fop_space(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)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
fop_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)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
fop_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * protp,struct page ** plarr,size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr,caller_context_t * ct)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
fop_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ct)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
fop_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)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
fop_dump(vnode_t * vp,caddr_t addr,offset_t lbdn,offset_t dblks,caller_context_t * ct)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
fop_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)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
fop_pageio(vnode_t * vp,struct page * pp,u_offset_t io_off,size_t io_len,int flags,cred_t * cr,caller_context_t * ct)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
fop_dumpctl(vnode_t * vp,int action,offset_t * blkp,caller_context_t * ct)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
fop_dispose(vnode_t * vp,struct page * pp,int flag,int dn,cred_t * cr,caller_context_t * ct)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
fop_setsecattr(vnode_t * vp,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)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
fop_getsecattr(vnode_t * vp,vsecattr_t * vsecattr,int flag,cred_t * cr,caller_context_t * ct)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
fop_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)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
fop_vnevent(vnode_t * vp,vnevent_t vnevent,vnode_t * dvp,char * fnm,caller_context_t * ct)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
fop_reqzcbuf(vnode_t * vp,enum uio_rw ioflag,xuio_t * uiop,cred_t * cr,caller_context_t * ct)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
fop_retzcbuf(vnode_t * vp,xuio_t * uiop,cred_t * cr,caller_context_t * ct)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
stat_to_vattr(const struct stat * st,vattr_t * vap)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
flk_init_callback(flk_callback_t * flk_cb,callb_cpr_t * (* cb_fcn)(flk_cb_when_t,void *),void * cbdata)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
vn_hold(vnode_t * vp)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
vn_rele(vnode_t * vp)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
vn_has_other_opens(vnode_t * vp,v_mode_t mode)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
vn_is_opened(vnode_t * vp,v_mode_t mode)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
vn_is_mapped(vnode_t * vp,v_mode_t mode)1347 vn_is_mapped(
1348 vnode_t *vp,
1349 v_mode_t mode)
1350 {
1351 return (V_FALSE);
1352 }
1353