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
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 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
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 * 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
fop_remove(vnode_t * dvp,char * name,cred_t * cr,caller_context_t * ct,int flags)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
fop_link(vnode_t * to_dvp,vnode_t * fr_vp,char * to_name,cred_t * cr,caller_context_t * ct,int flags)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
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)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
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)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
fop_rmdir(vnode_t * dvp,char * name,vnode_t * cdir,cred_t * cr,caller_context_t * ct,int flags)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
fop_readdir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)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
fop_symlink(vnode_t * dvp,char * linkname,vattr_t * vap,char * target,cred_t * cr,caller_context_t * ct,int flags)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
fop_readlink(vnode_t * vp,uio_t * uiop,cred_t * cr,caller_context_t * ct)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
fop_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)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
fop_inactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)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
fop_fid(vnode_t * vp,fid_t * fidp,caller_context_t * ct)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
fop_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)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
fop_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)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
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)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
fop_space(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)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
fop_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)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
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)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
fop_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ct)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
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)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
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)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
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)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
fop_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)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
fop_dump(vnode_t * vp,caddr_t addr,offset_t lbdn,offset_t dblks,caller_context_t * ct)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
fop_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)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
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)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
fop_dumpctl(vnode_t * vp,int action,offset_t * blkp,caller_context_t * ct)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
fop_dispose(vnode_t * vp,struct page * pp,int flag,int dn,cred_t * cr,caller_context_t * ct)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
fop_setsecattr(vnode_t * vp,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)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
fop_getsecattr(vnode_t * vp,vsecattr_t * vsecattr,int flag,cred_t * cr,caller_context_t * ct)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
fop_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)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
fop_vnevent(vnode_t * vp,vnevent_t vnevent,vnode_t * dvp,char * fnm,caller_context_t * ct)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
fop_reqzcbuf(vnode_t * vp,enum uio_rw ioflag,xuio_t * uiop,cred_t * cr,caller_context_t * ct)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
fop_retzcbuf(vnode_t * vp,xuio_t * uiop,cred_t * cr,caller_context_t * ct)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
stat_to_vattr(const struct stat * st,vattr_t * vap)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
flk_init_callback(flk_callback_t * flk_cb,callb_cpr_t * (* cb_fcn)(flk_cb_when_t,void *),void * cbdata)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
vn_hold(vnode_t * vp)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
vn_rele(vnode_t * vp)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
vn_has_other_opens(vnode_t * vp,v_mode_t mode)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
vn_is_opened(vnode_t * vp,v_mode_t mode)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
vn_is_mapped(vnode_t * vp,v_mode_t mode)1344 vn_is_mapped(
1345 vnode_t *vp,
1346 v_mode_t mode)
1347 {
1348 return (V_FALSE);
1349 }
1350