1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/t_lock.h>
19 #include <sys/errno.h>
20 #include <sys/cred.h>
21 #include <sys/user.h>
22 #include <sys/uio.h>
23 #include <sys/file.h>
24 #include <sys/pathname.h>
25 #include <sys/vfs.h>
26 #include <sys/vnode.h>
27 #include <sys/stat.h>
28 #include <sys/mode.h>
29 #include <sys/kmem.h>
30 #include <sys/debug.h>
31 #include <sys/atomic.h>
32 #include <sys/acl.h>
33 #include <sys/flock.h>
34 #include <sys/nbmlock.h>
35 #include <sys/fcntl.h>
36 #include <sys/poll.h>
37 #include <sys/time.h>
38
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42
43 #include "vncache.h"
44
45 #define O_RWMASK (O_WRONLY | O_RDWR) /* == 3 */
46
47 int fop_shrlock_enable = 0;
48
49 int stat_to_vattr(const struct stat *, vattr_t *);
50 int fop__getxvattr(vnode_t *, xvattr_t *);
51 int fop__setxvattr(vnode_t *, xvattr_t *);
52
53
54 /* ARGSUSED */
55 int
56 fop_open(
57 vnode_t **vpp,
58 int mode,
59 cred_t *cr,
60 caller_context_t *ct)
61 {
62
63 if ((*vpp)->v_type == VREG) {
64 if (mode & FREAD)
65 atomic_add_32(&((*vpp)->v_rdcnt), 1);
66 if (mode & FWRITE)
67 atomic_add_32(&((*vpp)->v_wrcnt), 1);
68 }
69
70 /* call to ->vop_open was here */
71
72 return (0);
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,
245 if (fstat(vp->v_fd, &st) == -1)
246 return (errno);
247 error = stat_to_vattr(&st, vap);
248
249 if (vap->va_mask & AT_XVATTR)
250 (void) fop__getxvattr(vp, (xvattr_t *)vap);
251
252 return (error);
253 }
254
255 /* ARGSUSED */
256 int
257 fop_setattr(
258 vnode_t *vp,
259 vattr_t *vap,
260 int flags,
261 cred_t *cr,
262 caller_context_t *ct)
263 {
264 timespec_t times[2];
265
266 if (vap->va_mask & AT_SIZE) {
267 if (ftruncate(vp->v_fd, vap->va_size) == -1)
268 return (errno);
269 }
270
271 /* AT_MODE or anything else? */
272
273 if (vap->va_mask & AT_XVATTR)
274 (void) fop__setxvattr(vp, (xvattr_t *)vap);
275
276 if (vap->va_mask & (AT_ATIME | AT_MTIME)) {
277 if (vap->va_mask & AT_ATIME) {
278 times[0] = vap->va_atime;
279 } else {
280 times[0].tv_sec = 0;
281 times[0].tv_nsec = UTIME_OMIT;
282 }
283 if (vap->va_mask & AT_MTIME) {
284 times[1] = vap->va_mtime;
285 } else {
286 times[1].tv_sec = 0;
287 times[1].tv_nsec = UTIME_OMIT;
288 }
289
290 (void) futimens(vp->v_fd, times);
291 }
292
293 return (0);
294 }
295
296 /* ARGSUSED */
297 int
298 fop_access(
299 vnode_t *vp,
300 int mode,
301 int flags,
302 cred_t *cr,
303 caller_context_t *ct)
304 {
305 return (0);
306 }
307
308 /* ARGSUSED */
309 int
310 fop_lookup(
311 vnode_t *dvp,
312 char *name,
313 vnode_t **vpp,
314 pathname_t *pnp,
315 int flags,
316 vnode_t *rdir,
317 cred_t *cr,
318 caller_context_t *ct,
319 int *deflags, /* Returned per-dirent flags */
320 pathname_t *ppnp) /* Returned case-preserved name in directory */
321 {
322 int fd;
323 int omode = O_RDWR | O_NOFOLLOW;
324 vnode_t *vp;
325 struct stat st;
326
327 if (flags & LOOKUP_XATTR)
328 return (ENOENT);
329
330 /*
331 * If lookup is for "", just return dvp.
332 */
333 if (name[0] == '\0') {
334 vn_hold(dvp);
335 *vpp = dvp;
336 return (0);
337 }
338
339 if (fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW) == -1)
340 return (errno);
341
342 vp = vncache_lookup(&st);
343 if (vp != NULL) {
344 /* lookup gave us a hold */
345 *vpp = vp;
346 return (0);
347 }
348
664 fop_fsync(
665 vnode_t *vp,
666 int syncflag,
667 cred_t *cr,
668 caller_context_t *ct)
669 {
670
671 if (fsync(vp->v_fd) == -1)
672 return (errno);
673
674 return (0);
675 }
676
677 /* ARGSUSED */
678 void
679 fop_inactive(
680 vnode_t *vp,
681 cred_t *cr,
682 caller_context_t *ct)
683 {
684 vncache_inactive(vp);
685 }
686
687 /* ARGSUSED */
688 int
689 fop_fid(
690 vnode_t *vp,
691 fid_t *fidp,
692 caller_context_t *ct)
693 {
694 return (ENOSYS);
695 }
696
697 /* ARGSUSED */
698 int
699 fop_rwlock(
700 vnode_t *vp,
701 int write_lock,
702 caller_context_t *ct)
703 {
704 /* See: fs_rwlock */
705 return (-1);
706 }
732 vnode_t *vp1,
733 vnode_t *vp2,
734 caller_context_t *ct)
735 {
736 /* See fs_cmp */
737 return (vncache_cmp(vp1, vp2));
738 }
739
740 /* ARGSUSED */
741 int
742 fop_frlock(
743 vnode_t *vp,
744 int cmd,
745 flock64_t *bfp,
746 int flag,
747 offset_t offset,
748 struct flk_callback *flk_cbp,
749 cred_t *cr,
750 caller_context_t *ct)
751 {
752 /* See fs_frlock */
753
754 switch (cmd) {
755 case F_GETLK:
756 case F_SETLK_NBMAND:
757 case F_SETLK:
758 case F_SETLKW:
759 break;
760 default:
761 return (EINVAL);
762 }
763
764 if (fcntl(vp->v_fd, cmd, bfp) == -1)
765 return (errno);
766
767 return (0);
768 }
769
770 /* ARGSUSED */
771 int
772 fop_space(
773 vnode_t *vp,
774 int cmd,
775 flock64_t *bfp,
776 int flag,
777 offset_t offset,
778 cred_t *cr,
779 caller_context_t *ct)
780 {
781 /* See fs_frlock */
782
783 switch (cmd) {
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
1250 flk_init_callback(flk_callback_t *flk_cb,
1251 callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata)
1252 {
1253 }
1254
1255 void
1256 vn_hold(vnode_t *vp)
1257 {
1258 mutex_enter(&vp->v_lock);
1259 vp->v_count++;
1260 mutex_exit(&vp->v_lock);
1261 }
1262
1263 void
1264 vn_rele(vnode_t *vp)
1265 {
1266 VERIFY3U(vp->v_count, !=, 0);
1267 mutex_enter(&vp->v_lock);
1268 if (vp->v_count == 1) {
1269 mutex_exit(&vp->v_lock);
1270 vncache_inactive(vp);
1271 } else {
1272 vp->v_count--;
1273 mutex_exit(&vp->v_lock);
1274 }
1275 }
1276
1277 int
1278 vn_has_other_opens(
1279 vnode_t *vp,
1280 v_mode_t mode)
1281 {
1282
1283 switch (mode) {
1284 case V_WRITE:
1285 if (vp->v_wrcnt > 1)
1286 return (V_TRUE);
1287 break;
1288 case V_RDORWR:
1289 if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
1290 return (V_TRUE);
|
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 2017 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/t_lock.h>
20 #include <sys/errno.h>
21 #include <sys/cred.h>
22 #include <sys/user.h>
23 #include <sys/uio.h>
24 #include <sys/file.h>
25 #include <sys/pathname.h>
26 #include <sys/vfs.h>
27 #include <sys/vnode.h>
28 #include <sys/stat.h>
29 #include <sys/mode.h>
30 #include <sys/kmem.h>
31 #include <sys/cmn_err.h>
32 #include <sys/debug.h>
33 #include <sys/atomic.h>
34 #include <sys/acl.h>
35 #include <sys/filio.h>
36 #include <sys/flock.h>
37 #include <sys/nbmlock.h>
38 #include <sys/fcntl.h>
39 #include <sys/poll.h>
40 #include <sys/time.h>
41
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45
46 #include "vncache.h"
47
48 #define O_RWMASK (O_WRONLY | O_RDWR) /* == 3 */
49
50 int fop_shrlock_enable = 0;
51
52 int stat_to_vattr(const struct stat *, vattr_t *);
53 int fop__getxvattr(vnode_t *, xvattr_t *);
54 int fop__setxvattr(vnode_t *, xvattr_t *);
55
56 static void fake_inactive_xattrdir(vnode_t *);
57
58 /* ARGSUSED */
59 int
60 fop_open(
61 vnode_t **vpp,
62 int mode,
63 cred_t *cr,
64 caller_context_t *ct)
65 {
66
67 if ((*vpp)->v_type == VREG) {
68 if (mode & FREAD)
69 atomic_add_32(&((*vpp)->v_rdcnt), 1);
70 if (mode & FWRITE)
71 atomic_add_32(&((*vpp)->v_wrcnt), 1);
72 }
73
74 /* call to ->vop_open was here */
75
76 return (0);
201 }
202
203 if (ioflag == FSYNC) {
204 (void) fsync(vp->v_fd);
205 }
206
207 return (0);
208 }
209
210 /* ARGSUSED */
211 int
212 fop_ioctl(
213 vnode_t *vp,
214 int cmd,
215 intptr_t arg,
216 int flag,
217 cred_t *cr,
218 int *rvalp,
219 caller_context_t *ct)
220 {
221 off64_t off;
222 int rv, whence;
223
224 switch (cmd) {
225 case _FIO_SEEK_DATA:
226 case _FIO_SEEK_HOLE:
227 whence = (cmd == _FIO_SEEK_DATA) ? SEEK_DATA : SEEK_HOLE;
228 bcopy((void *)arg, &off, sizeof (off));
229 off = lseek(vp->v_fd, off, whence);
230 if (off == (off64_t)-1) {
231 rv = errno;
232 } else {
233 bcopy(&off, (void *)arg, sizeof (off));
234 rv = 0;
235 }
236 break;
237
238 default:
239 rv = ENOTTY;
240 break;
241 }
242
243 return (rv);
244 }
245
246 /* ARGSUSED */
247 int
248 fop_setfl(
249 vnode_t *vp,
250 int oflags,
251 int nflags,
252 cred_t *cr,
253 caller_context_t *ct)
254 {
255 /* allow any flags? See fs_setfl */
256 return (0);
257 }
258
259 /* ARGSUSED */
260 int
261 fop_getattr(
262 vnode_t *vp,
263 vattr_t *vap,
271 if (fstat(vp->v_fd, &st) == -1)
272 return (errno);
273 error = stat_to_vattr(&st, vap);
274
275 if (vap->va_mask & AT_XVATTR)
276 (void) fop__getxvattr(vp, (xvattr_t *)vap);
277
278 return (error);
279 }
280
281 /* ARGSUSED */
282 int
283 fop_setattr(
284 vnode_t *vp,
285 vattr_t *vap,
286 int flags,
287 cred_t *cr,
288 caller_context_t *ct)
289 {
290 timespec_t times[2];
291 int err;
292
293 if (vap->va_mask & AT_SIZE) {
294 if (ftruncate(vp->v_fd, vap->va_size) == -1) {
295 err = errno;
296 if (err == EBADF)
297 err = EACCES;
298 return (err);
299 }
300 }
301
302 /* AT_MODE or anything else? */
303
304 if (vap->va_mask & AT_XVATTR)
305 (void) fop__setxvattr(vp, (xvattr_t *)vap);
306
307 if (vap->va_mask & (AT_ATIME | AT_MTIME)) {
308 if (vap->va_mask & AT_ATIME) {
309 times[0] = vap->va_atime;
310 } else {
311 times[0].tv_sec = 0;
312 times[0].tv_nsec = UTIME_OMIT;
313 }
314 if (vap->va_mask & AT_MTIME) {
315 times[1] = vap->va_mtime;
316 } else {
317 times[1].tv_sec = 0;
318 times[1].tv_nsec = UTIME_OMIT;
319 }
320
321 (void) futimens(vp->v_fd, times);
322 }
323
324 return (0);
325 }
326
327 /* ARGSUSED */
328 int
329 fop_access(
330 vnode_t *vp,
331 int mode,
332 int flags,
333 cred_t *cr,
334 caller_context_t *ct)
335 {
336 return (0);
337 }
338
339 /*
340 * Conceptually like xattr_dir_lookup()
341 */
342 static int
343 fake_lookup_xattrdir(
344 vnode_t *dvp,
345 vnode_t **vpp)
346 {
347 int len, fd;
348 int omode = O_RDWR | O_NOFOLLOW;
349 vnode_t *vp;
350
351 *vpp = NULL;
352
353 if (dvp->v_type != VDIR && dvp->v_type != VREG)
354 return (EINVAL);
355
356 /*
357 * If we're already in sysattr space, don't allow creation
358 * of another level of sysattrs.
359 */
360 if (dvp->v_flag & V_SYSATTR)
361 return (EINVAL);
362
363 mutex_enter(&dvp->v_lock);
364 if (dvp->v_xattrdir != NULL) {
365 *vpp = dvp->v_xattrdir;
366 VN_HOLD(*vpp);
367 mutex_exit(&dvp->v_lock);
368 return (0);
369 }
370 mutex_exit(&dvp->v_lock);
371
372 omode = O_RDONLY|O_XATTR;
373 fd = openat(dvp->v_fd, ".", omode);
374 if (fd < 0)
375 return (errno);
376
377 vp = vn_alloc(KM_SLEEP);
378 vp->v_fd = fd;
379 vp->v_flag = V_XATTRDIR|V_SYSATTR;
380 vp->v_type = VDIR;
381 vp->v_vfsp = dvp->v_vfsp;
382
383 /* Set v_path to parent path + "/@" (like NFS) */
384 len = strlen(dvp->v_path) + 3;
385 vp->v_path = kmem_alloc(len, KM_SLEEP);
386 (void) snprintf(vp->v_path, len, "%s/@", dvp->v_path);
387
388 /*
389 * Keep a pointer to the parent and a hold on it.
390 * Both are cleaned up in fake_inactive_xattrdir
391 */
392 vp->v_data = dvp;
393 vn_hold(dvp);
394
395 mutex_enter(&dvp->v_lock);
396 if (dvp->v_xattrdir == NULL) {
397 *vpp = dvp->v_xattrdir = vp;
398 mutex_exit(&dvp->v_lock);
399 } else {
400 *vpp = dvp->v_xattrdir;
401 mutex_exit(&dvp->v_lock);
402 fake_inactive_xattrdir(vp);
403 }
404
405 return (0);
406 }
407
408 /* ARGSUSED */
409 int
410 fop_lookup(
411 vnode_t *dvp,
412 char *name,
413 vnode_t **vpp,
414 pathname_t *pnp,
415 int flags,
416 vnode_t *rdir,
417 cred_t *cr,
418 caller_context_t *ct,
419 int *deflags, /* Returned per-dirent flags */
420 pathname_t *ppnp) /* Returned case-preserved name in directory */
421 {
422 int fd;
423 int omode = O_RDWR | O_NOFOLLOW;
424 vnode_t *vp;
425 struct stat st;
426
427 if (flags & LOOKUP_XATTR)
428 return (fake_lookup_xattrdir(dvp, vpp));
429
430 /*
431 * If lookup is for "", just return dvp.
432 */
433 if (name[0] == '\0') {
434 vn_hold(dvp);
435 *vpp = dvp;
436 return (0);
437 }
438
439 if (fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW) == -1)
440 return (errno);
441
442 vp = vncache_lookup(&st);
443 if (vp != NULL) {
444 /* lookup gave us a hold */
445 *vpp = vp;
446 return (0);
447 }
448
764 fop_fsync(
765 vnode_t *vp,
766 int syncflag,
767 cred_t *cr,
768 caller_context_t *ct)
769 {
770
771 if (fsync(vp->v_fd) == -1)
772 return (errno);
773
774 return (0);
775 }
776
777 /* ARGSUSED */
778 void
779 fop_inactive(
780 vnode_t *vp,
781 cred_t *cr,
782 caller_context_t *ct)
783 {
784 if (vp->v_flag & V_XATTRDIR) {
785 fake_inactive_xattrdir(vp);
786 } else {
787 vncache_inactive(vp);
788 }
789 }
790
791 /*
792 * The special xattr directories are not in the vncache AVL, but
793 * hang off the parent's v_xattrdir field. When vn_rele finds
794 * an xattr dir at v_count == 1 it calls here, but until we
795 * take locks on both the parent and the xattrdir, we don't
796 * know if we're really at the last reference. So in here we
797 * take both locks, re-check the count, and either bail out
798 * or proceed with "inactive" vnode cleanup. Part of that
799 * cleanup includes releasing the hold on the parent and
800 * clearing the parent's v_xattrdir field, which were
801 * setup in fake_lookup_xattrdir()
802 */
803 static void
804 fake_inactive_xattrdir(vnode_t *vp)
805 {
806 vnode_t *dvp = vp->v_data; /* parent */
807 mutex_enter(&dvp->v_lock);
808 mutex_enter(&vp->v_lock);
809 if (vp->v_count > 1) {
810 /* new ref. via v_xattrdir */
811 mutex_exit(&vp->v_lock);
812 mutex_exit(&dvp->v_lock);
813 return;
814 }
815 ASSERT(dvp->v_xattrdir == vp);
816 dvp->v_xattrdir = NULL;
817 mutex_exit(&vp->v_lock);
818 mutex_exit(&dvp->v_lock);
819 vn_rele(dvp);
820 vn_free(vp);
821 }
822
823 /* ARGSUSED */
824 int
825 fop_fid(
826 vnode_t *vp,
827 fid_t *fidp,
828 caller_context_t *ct)
829 {
830 return (ENOSYS);
831 }
832
833 /* ARGSUSED */
834 int
835 fop_rwlock(
836 vnode_t *vp,
837 int write_lock,
838 caller_context_t *ct)
839 {
840 /* See: fs_rwlock */
841 return (-1);
842 }
868 vnode_t *vp1,
869 vnode_t *vp2,
870 caller_context_t *ct)
871 {
872 /* See fs_cmp */
873 return (vncache_cmp(vp1, vp2));
874 }
875
876 /* ARGSUSED */
877 int
878 fop_frlock(
879 vnode_t *vp,
880 int cmd,
881 flock64_t *bfp,
882 int flag,
883 offset_t offset,
884 struct flk_callback *flk_cbp,
885 cred_t *cr,
886 caller_context_t *ct)
887 {
888 #if defined(_LP64)
889 offset_t maxoffset = INT64_MAX;
890 #elif defined(_ILP32)
891 /*
892 * Sadly, the fcntl API enforces 32-bit offsets,
893 * even though we have _FILE_OFFSET_BITS=64
894 */
895 offset_t maxoffset = INT32_MAX;
896 #else
897 #error "unsupported env."
898 #endif
899
900 /* See fs_frlock */
901
902 switch (cmd) {
903 case F_GETLK:
904 case F_SETLK_NBMAND:
905 case F_SETLK:
906 case F_SETLKW:
907 break;
908 default:
909 return (EINVAL);
910 }
911
912 /* We only get SEEK_SET ranges here. */
913 if (bfp->l_whence != 0)
914 return (EINVAL);
915
916 /*
917 * One limitation of using fcntl(2) F_SETLK etc is that
918 * the real kernel limits the offsets we can use.
919 * (Maybe the fcntl API should loosen that up?)
920 * See syscall/fcntl.c:flock_check()
921 *
922 * Here in libfksmbsrv we can just ignore such locks,
923 * or ignore the part that extends beyond maxoffset.
924 * The SMB layer still keeps track of such locks for
925 * conflict detection, so not reflecting such locks
926 * into the real FS layer is OK. Note: this may
927 * modify the pased bfp->l_len.
928 */
929 if (bfp->l_start < 0 || bfp->l_start > maxoffset)
930 return (0);
931 if (bfp->l_len < 0 || bfp->l_len > maxoffset)
932 return (0);
933 if (bfp->l_len > (maxoffset - bfp->l_start + 1))
934 bfp->l_len = (maxoffset - bfp->l_start + 1);
935
936 if (fcntl(vp->v_fd, cmd, bfp) == -1)
937 return (errno);
938
939 return (0);
940 }
941
942 /* ARGSUSED */
943 int
944 fop_space(
945 vnode_t *vp,
946 int cmd,
947 flock64_t *bfp,
948 int flag,
949 offset_t offset,
950 cred_t *cr,
951 caller_context_t *ct)
952 {
953 /* See fs_frlock */
954
955 switch (cmd) {
1138 val = PIPE_BUF;
1139 break;
1140
1141 case _PC_NO_TRUNC:
1142 val = (ulong_t)-1;
1143 break;
1144
1145 case _PC_VDISABLE:
1146 val = _POSIX_VDISABLE;
1147 break;
1148
1149 case _PC_CHOWN_RESTRICTED:
1150 val = 1; /* chown restricted enabled */
1151 break;
1152
1153 case _PC_FILESIZEBITS:
1154 val = (ulong_t)-1; /* large file support */
1155 break;
1156
1157 case _PC_ACL_ENABLED:
1158 val = _ACL_ACE_ENABLED;
1159 break;
1160
1161 case _PC_CASE_BEHAVIOR:
1162 val = _CASE_SENSITIVE;
1163 break;
1164
1165 case _PC_SATTR_ENABLED:
1166 case _PC_SATTR_EXISTS:
1167 val = 0;
1168 break;
1169
1170 case _PC_ACCESS_FILTERING:
1171 val = 0;
1172 break;
1173
1174 default:
1175 error = EINVAL;
1176 break;
1177 }
1178
1422 flk_init_callback(flk_callback_t *flk_cb,
1423 callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata)
1424 {
1425 }
1426
1427 void
1428 vn_hold(vnode_t *vp)
1429 {
1430 mutex_enter(&vp->v_lock);
1431 vp->v_count++;
1432 mutex_exit(&vp->v_lock);
1433 }
1434
1435 void
1436 vn_rele(vnode_t *vp)
1437 {
1438 VERIFY3U(vp->v_count, !=, 0);
1439 mutex_enter(&vp->v_lock);
1440 if (vp->v_count == 1) {
1441 mutex_exit(&vp->v_lock);
1442 fop_inactive(vp, NULL, NULL);
1443 } else {
1444 vp->v_count--;
1445 mutex_exit(&vp->v_lock);
1446 }
1447 }
1448
1449 int
1450 vn_has_other_opens(
1451 vnode_t *vp,
1452 v_mode_t mode)
1453 {
1454
1455 switch (mode) {
1456 case V_WRITE:
1457 if (vp->v_wrcnt > 1)
1458 return (V_TRUE);
1459 break;
1460 case V_RDORWR:
1461 if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
1462 return (V_TRUE);
|