3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/cred.h>
35 #include <sys/buf.h>
36 #include <sys/vfs.h>
37 #include <sys/vnode.h>
38 #include <sys/uio.h>
39 #include <sys/errno.h>
40 #include <sys/sysmacros.h>
41 #include <sys/statvfs.h>
42 #include <sys/kmem.h>
43 #include <sys/dirent.h>
44 #include <sys/cmn_err.h>
45 #include <sys/debug.h>
46 #include <sys/systeminfo.h>
47 #include <sys/flock.h>
48 #include <sys/nbmlock.h>
49 #include <sys/policy.h>
50 #include <sys/sdt.h>
51
52 #include <rpc/types.h>
53 #include <rpc/auth.h>
54 #include <rpc/svc.h>
55 #include <rpc/rpc_rdma.h>
56
57 #include <nfs/nfs.h>
58 #include <nfs/export.h>
59 #include <nfs/nfs_cmd.h>
60
61 #include <sys/strsubr.h>
62 #include <sys/tsol/label.h>
63 #include <sys/tsol/tndb.h>
64
65 #include <sys/zone.h>
66
67 #include <inet/ip.h>
68 #include <inet/ip6.h>
69
70 /*
71 * These are the interface routines for the server side of the
72 * Network File System. See the NFS version 3 protocol specification
73 * for a description of this interface.
74 */
75
76 static writeverf3 write3verf;
77
78 static int sattr3_to_vattr(sattr3 *, struct vattr *);
79 static int vattr_to_fattr3(struct vattr *, fattr3 *);
80 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
81 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
82 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
83 static int rdma_setup_read_data3(READ3args *, READ3resok *);
84
85 extern int nfs_loaned_buffers;
86
87 u_longlong_t nfs3_srv_caller_id;
88
89 /* ARGSUSED */
90 void
91 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
92 struct svc_req *req, cred_t *cr, bool_t ro)
93 {
94 int error;
95 vnode_t *vp;
96 struct vattr va;
97
98 vp = nfs3_fhtovp(&args->object, exi);
99
100 DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
101 cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
102
103 if (vp == NULL) {
104 error = ESTALE;
105 goto out;
106 }
107
108 va.va_mask = AT_ALL;
109 error = rfs4_delegated_getattr(vp, &va, 0, cr);
110
111 if (!error) {
112 /* Lie about the object type for a referral */
113 if (vn_is_nfs_reparse(vp, cr))
114 va.va_type = VLNK;
115
116 /* overflow error if time or size is out of range */
117 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
118 if (error)
119 goto out;
120 resp->status = NFS3_OK;
121
122 DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
123 cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
124
125 VN_RELE(vp);
126
127 return;
128 }
129
130 out:
131 if (curthread->t_flag & T_WOULDBLOCK) {
132 curthread->t_flag &= ~T_WOULDBLOCK;
133 resp->status = NFS3ERR_JUKEBOX;
134 } else
135 resp->status = puterrno3(error);
136
137 DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
138 cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
139
140 if (vp != NULL)
141 VN_RELE(vp);
142 }
143
144 void *
145 rfs3_getattr_getfh(GETATTR3args *args)
146 {
147
148 return (&args->object);
149 }
150
151 void
152 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
153 struct svc_req *req, cred_t *cr, bool_t ro)
154 {
155 int error;
156 vnode_t *vp;
157 struct vattr *bvap;
158 struct vattr bva;
159 struct vattr *avap;
160 struct vattr ava;
161 int flag;
162 int in_crit = 0;
163 struct flock64 bf;
164 caller_context_t ct;
165
166 bvap = NULL;
167 avap = NULL;
168
169 vp = nfs3_fhtovp(&args->object, exi);
170
171 DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
172 cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
173
174 if (vp == NULL) {
175 error = ESTALE;
176 goto out;
177 }
178
179 error = sattr3_to_vattr(&args->new_attributes, &ava);
180 if (error)
181 goto out;
182
183 if (is_system_labeled()) {
184 bslabel_t *clabel = req->rq_label;
185
186 ASSERT(clabel != NULL);
187 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
188 "got client label from request(1)", struct svc_req *, req);
189
190 if (!blequal(&l_admin_low->tsl_label, clabel)) {
191 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
192 exi)) {
313 goto out1;
314 }
315
316 ava.va_mask = AT_ALL;
317 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
318
319 /*
320 * Force modified metadata out to stable storage.
321 */
322 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
323
324 if (error)
325 goto out;
326
327 if (in_crit)
328 nbl_end_crit(vp);
329
330 resp->status = NFS3_OK;
331 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
332
333 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
334 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
335
336 VN_RELE(vp);
337
338 return;
339
340 out:
341 if (curthread->t_flag & T_WOULDBLOCK) {
342 curthread->t_flag &= ~T_WOULDBLOCK;
343 resp->status = NFS3ERR_JUKEBOX;
344 } else
345 resp->status = puterrno3(error);
346 out1:
347 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
348 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
349
350 if (vp != NULL) {
351 if (in_crit)
352 nbl_end_crit(vp);
353 VN_RELE(vp);
354 }
355 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
356 }
357
358 void *
359 rfs3_setattr_getfh(SETATTR3args *args)
360 {
361
362 return (&args->object);
363 }
364
365 /* ARGSUSED */
366 void
367 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
368 struct svc_req *req, cred_t *cr, bool_t ro)
373 struct vattr *vap;
374 struct vattr va;
375 struct vattr *dvap;
376 struct vattr dva;
377 nfs_fh3 *fhp;
378 struct sec_ol sec = {0, 0};
379 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
380 struct sockaddr *ca;
381 char *name = NULL;
382
383 dvap = NULL;
384
385 if (exi != NULL)
386 exi_hold(exi);
387
388 /*
389 * Allow lookups from the root - the default
390 * location of the public filehandle.
391 */
392 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
393 dvp = rootdir;
394 VN_HOLD(dvp);
395
396 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
397 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
398 } else {
399 dvp = nfs3_fhtovp(&args->what.dir, exi);
400
401 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
402 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
403
404 if (dvp == NULL) {
405 error = ESTALE;
406 goto out;
407 }
408 }
409
410 dva.va_mask = AT_ALL;
411 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
412
413 if (args->what.name == nfs3nametoolong) {
414 resp->status = NFS3ERR_NAMETOOLONG;
415 goto out1;
416 }
417
418 if (args->what.name == NULL || *(args->what.name) == '\0') {
419 resp->status = NFS3ERR_ACCES;
420 goto out1;
421 }
422
423 fhp = &args->what.dir;
424 if (strcmp(args->what.name, "..") == 0 &&
425 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
426 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
427 (dvp->v_flag & VROOT)) {
428 /*
429 * special case for ".." and 'nohide'exported root
430 */
431 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435 } else {
436 resp->status = NFS3ERR_NOENT;
437 goto out1;
438 }
439 }
440
441 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
442 name = nfscmd_convname(ca, exi, args->what.name,
443 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
444
445 if (name == NULL) {
446 resp->status = NFS3ERR_ACCES;
447 goto out1;
448 }
449
450 /*
451 * If the public filehandle is used then allow
452 * a multi-component lookup
453 */
454 if (PUBLIC_FH3(&args->what.dir)) {
455 publicfh_flag = TRUE;
456
457 exi_rele(exi);
458
459 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
460 &exi, &sec);
461
462 /*
463 * Since WebNFS may bypass MOUNT, we need to ensure this
464 * request didn't come from an unlabeled admin_low client.
465 */
466 if (is_system_labeled() && error == 0) {
467 int addr_type;
468 void *ipaddr;
469 tsol_tpc_t *tp;
470
471 if (ca->sa_family == AF_INET) {
472 addr_type = IPV4_VERSION;
473 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
474 } else if (ca->sa_family == AF_INET6) {
475 addr_type = IPV6_VERSION;
476 ipaddr = &((struct sockaddr_in6 *)
477 ca)->sin6_addr;
521
522 if (error)
523 goto out;
524
525 if (sec.sec_flags & SEC_QUERY) {
526 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
527 } else {
528 error = makefh3(&resp->resok.object, vp, exi);
529 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
530 auth_weak = TRUE;
531 }
532
533 if (error) {
534 VN_RELE(vp);
535 goto out;
536 }
537
538 va.va_mask = AT_ALL;
539 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
540
541 exi_rele(exi);
542 VN_RELE(vp);
543
544 resp->status = NFS3_OK;
545 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
546 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
547
548 /*
549 * If it's public fh, no 0x81, and client's flavor is
550 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
551 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
552 */
553 if (auth_weak)
554 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
555
556 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
557 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
558 VN_RELE(dvp);
559
560 return;
561
562 out:
563 if (curthread->t_flag & T_WOULDBLOCK) {
564 curthread->t_flag &= ~T_WOULDBLOCK;
565 resp->status = NFS3ERR_JUKEBOX;
566 } else
567 resp->status = puterrno3(error);
568 out1:
569 if (exi != NULL)
570 exi_rele(exi);
571
572 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
573 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
574
575 if (dvp != NULL)
576 VN_RELE(dvp);
577 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
578
579 }
580
581 void *
582 rfs3_lookup_getfh(LOOKUP3args *args)
583 {
584
585 return (&args->what.dir);
586 }
587
588 /* ARGSUSED */
589 void
590 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
591 struct svc_req *req, cred_t *cr, bool_t ro)
592 {
593 int error;
594 vnode_t *vp;
595 struct vattr *vap;
596 struct vattr va;
597 int checkwriteperm;
598 boolean_t dominant_label = B_FALSE;
599 boolean_t equal_label = B_FALSE;
600 boolean_t admin_low_client;
601
602 vap = NULL;
603
604 vp = nfs3_fhtovp(&args->object, exi);
605
606 DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
607 cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
608
609 if (vp == NULL) {
610 error = ESTALE;
611 goto out;
612 }
613
614 /*
615 * If the file system is exported read only, it is not appropriate
616 * to check write permissions for regular files and directories.
617 * Special files are interpreted by the client, so the underlying
618 * permissions are sent back to the client for interpretation.
619 */
620 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
621 checkwriteperm = 0;
622 else
623 checkwriteperm = 1;
624
625 /*
626 * We need the mode so that we can correctly determine access
627 * permissions relative to a mandatory lock file. Access to
697 equal_label)
698 resp->resok.access |= ACCESS3_DELETE;
699 }
700 if (args->access & ACCESS3_EXECUTE) {
701 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
702 if (error) {
703 if (curthread->t_flag & T_WOULDBLOCK)
704 goto out;
705 } else if (!MANDLOCK(vp, va.va_mode) &&
706 (!is_system_labeled() || admin_low_client ||
707 dominant_label))
708 resp->resok.access |= ACCESS3_EXECUTE;
709 }
710
711 va.va_mask = AT_ALL;
712 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
713
714 resp->status = NFS3_OK;
715 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
716
717 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
718 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
719
720 VN_RELE(vp);
721
722 return;
723
724 out:
725 if (curthread->t_flag & T_WOULDBLOCK) {
726 curthread->t_flag &= ~T_WOULDBLOCK;
727 resp->status = NFS3ERR_JUKEBOX;
728 } else
729 resp->status = puterrno3(error);
730 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
731 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
732 if (vp != NULL)
733 VN_RELE(vp);
734 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
735 }
736
737 void *
738 rfs3_access_getfh(ACCESS3args *args)
739 {
740
741 return (&args->object);
742 }
743
744 /* ARGSUSED */
745 void
746 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
747 struct svc_req *req, cred_t *cr, bool_t ro)
748 {
749 int error;
750 vnode_t *vp;
751 struct vattr *vap;
752 struct vattr va;
753 struct iovec iov;
754 struct uio uio;
755 char *data;
756 struct sockaddr *ca;
757 char *name = NULL;
758 int is_referral = 0;
759
760 vap = NULL;
761
762 vp = nfs3_fhtovp(&args->symlink, exi);
763
764 DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
765 cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
766
767 if (vp == NULL) {
768 error = ESTALE;
769 goto out;
770 }
771
772 va.va_mask = AT_ALL;
773 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
774 if (error)
775 goto out;
776
777 vap = &va;
778
779 /* We lied about the object type for a referral */
780 if (vn_is_nfs_reparse(vp, cr))
781 is_referral = 1;
782
783 if (vp->v_type != VLNK && !is_referral) {
784 resp->status = NFS3ERR_INVAL;
785 goto out1;
794 bslabel_t *clabel = req->rq_label;
795
796 ASSERT(clabel != NULL);
797 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
798 "got client label from request(1)", struct svc_req *, req);
799
800 if (!blequal(&l_admin_low->tsl_label, clabel)) {
801 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
802 exi)) {
803 resp->status = NFS3ERR_ACCES;
804 goto out1;
805 }
806 }
807 }
808
809 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
810
811 if (is_referral) {
812 char *s;
813 size_t strsz;
814
815 /* Get an artificial symlink based on a referral */
816 s = build_symlink(vp, cr, &strsz);
817 global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
818 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
819 vnode_t *, vp, char *, s);
820 if (s == NULL)
821 error = EINVAL;
822 else {
823 error = 0;
824 (void) strlcpy(data, s, MAXPATHLEN + 1);
825 kmem_free(s, strsz);
826 }
827
828 } else {
829
830 iov.iov_base = data;
831 iov.iov_len = MAXPATHLEN;
832 uio.uio_iov = &iov;
833 uio.uio_iovcnt = 1;
834 uio.uio_segflg = UIO_SYSSPACE;
835 uio.uio_extflg = UIO_COPY_CACHED;
836 uio.uio_loffset = 0;
837 uio.uio_resid = MAXPATHLEN;
865 kmem_free(data, MAXPATHLEN + 1);
866 goto out;
867 }
868
869 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
870 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
871 MAXPATHLEN + 1);
872
873 if (name == NULL) {
874 /*
875 * Even though the conversion failed, we return
876 * something. We just don't translate it.
877 */
878 name = data;
879 }
880
881 resp->status = NFS3_OK;
882 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
883 resp->resok.data = name;
884
885 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
886 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
887 VN_RELE(vp);
888
889 if (name != data)
890 kmem_free(data, MAXPATHLEN + 1);
891
892 return;
893
894 out:
895 if (curthread->t_flag & T_WOULDBLOCK) {
896 curthread->t_flag &= ~T_WOULDBLOCK;
897 resp->status = NFS3ERR_JUKEBOX;
898 } else
899 resp->status = puterrno3(error);
900 out1:
901 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
902 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
903 if (vp != NULL)
904 VN_RELE(vp);
905 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
906 }
907
908 void *
909 rfs3_readlink_getfh(READLINK3args *args)
910 {
911
912 return (&args->symlink);
913 }
914
915 void
916 rfs3_readlink_free(READLINK3res *resp)
917 {
918
919 if (resp->status == NFS3_OK)
920 kmem_free(resp->resok.data, MAXPATHLEN + 1);
921 }
922
932 int error;
933 vnode_t *vp;
934 struct vattr *vap;
935 struct vattr va;
936 struct iovec iov, *iovp = NULL;
937 int iovcnt;
938 struct uio uio;
939 u_offset_t offset;
940 mblk_t *mp = NULL;
941 int in_crit = 0;
942 int need_rwunlock = 0;
943 caller_context_t ct;
944 int rdma_used = 0;
945 int loaned_buffers;
946 struct uio *uiop;
947
948 vap = NULL;
949
950 vp = nfs3_fhtovp(&args->file, exi);
951
952 DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
953 cred_t *, cr, vnode_t *, vp, READ3args *, args);
954
955 if (vp == NULL) {
956 error = ESTALE;
957 goto out;
958 }
959
960 if (args->wlist) {
961 if (args->count > clist_len(args->wlist)) {
962 error = EINVAL;
963 goto out;
964 }
965 rdma_used = 1;
966 }
967
968 /* use loaned buffers for TCP */
969 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
970
971 if (is_system_labeled()) {
972 bslabel_t *clabel = req->rq_label;
973
974 ASSERT(clabel != NULL);
1188 resp->resok.eof = FALSE;
1189 resp->resok.data.data_len = resp->resok.count;
1190
1191 if (mp)
1192 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1193
1194 resp->resok.data.mp = mp;
1195 resp->resok.size = (uint_t)args->count;
1196
1197 if (rdma_used) {
1198 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1199 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1200 resp->status = NFS3ERR_INVAL;
1201 }
1202 } else {
1203 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1204 (resp->resok).wlist = NULL;
1205 }
1206
1207 done:
1208 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1209 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1210
1211 VN_RELE(vp);
1212
1213 if (iovp != NULL)
1214 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1215
1216 return;
1217
1218 out:
1219 if (curthread->t_flag & T_WOULDBLOCK) {
1220 curthread->t_flag &= ~T_WOULDBLOCK;
1221 resp->status = NFS3ERR_JUKEBOX;
1222 } else
1223 resp->status = puterrno3(error);
1224 out1:
1225 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1226 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1227
1228 if (vp != NULL) {
1229 if (need_rwunlock)
1230 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1231 if (in_crit)
1232 nbl_end_crit(vp);
1233 VN_RELE(vp);
1234 }
1235 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1236
1237 if (iovp != NULL)
1238 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1239 }
1240
1241 void
1242 rfs3_read_free(READ3res *resp)
1243 {
1244 mblk_t *mp;
1245
1246 if (resp->status == NFS3_OK) {
1251 }
1252
1253 void *
1254 rfs3_read_getfh(READ3args *args)
1255 {
1256
1257 return (&args->file);
1258 }
1259
1260 #define MAX_IOVECS 12
1261
1262 #ifdef DEBUG
1263 static int rfs3_write_hits = 0;
1264 static int rfs3_write_misses = 0;
1265 #endif
1266
1267 void
1268 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1269 struct svc_req *req, cred_t *cr, bool_t ro)
1270 {
1271 int error;
1272 vnode_t *vp;
1273 struct vattr *bvap = NULL;
1274 struct vattr bva;
1275 struct vattr *avap = NULL;
1276 struct vattr ava;
1277 u_offset_t rlimit;
1278 struct uio uio;
1279 struct iovec iov[MAX_IOVECS];
1280 mblk_t *m;
1281 struct iovec *iovp;
1282 int iovcnt;
1283 int ioflag;
1284 cred_t *savecred;
1285 int in_crit = 0;
1286 int rwlock_ret = -1;
1287 caller_context_t ct;
1288
1289 vp = nfs3_fhtovp(&args->file, exi);
1290
1291 DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1292 cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1293
1294 if (vp == NULL) {
1295 error = ESTALE;
1296 goto err;
1297 }
1298
1299 if (is_system_labeled()) {
1300 bslabel_t *clabel = req->rq_label;
1301
1302 ASSERT(clabel != NULL);
1303 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1304 "got client label from request(1)", struct svc_req *, req);
1305
1306 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1307 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1308 exi)) {
1309 resp->status = NFS3ERR_ACCES;
1310 goto err1;
1311 }
1312 }
1313 }
1314
1315 ct.cc_sysid = 0;
1316 ct.cc_pid = 0;
1317 ct.cc_caller_id = nfs3_srv_caller_id;
1318 ct.cc_flags = CC_DONTBLOCK;
1366
1367 if (vp->v_type != VREG) {
1368 resp->status = NFS3ERR_INVAL;
1369 goto err1;
1370 }
1371
1372 if (crgetuid(cr) != bva.va_uid &&
1373 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1374 goto err;
1375
1376 if (MANDLOCK(vp, bva.va_mode)) {
1377 resp->status = NFS3ERR_ACCES;
1378 goto err1;
1379 }
1380
1381 if (args->count == 0) {
1382 resp->status = NFS3_OK;
1383 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1384 resp->resok.count = 0;
1385 resp->resok.committed = args->stable;
1386 resp->resok.verf = write3verf;
1387 goto out;
1388 }
1389
1390 if (args->mblk != NULL) {
1391 iovcnt = 0;
1392 for (m = args->mblk; m != NULL; m = m->b_cont)
1393 iovcnt++;
1394 if (iovcnt <= MAX_IOVECS) {
1395 #ifdef DEBUG
1396 rfs3_write_hits++;
1397 #endif
1398 iovp = iov;
1399 } else {
1400 #ifdef DEBUG
1401 rfs3_write_misses++;
1402 #endif
1403 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1404 }
1405 mblk_to_iov(args->mblk, iovcnt, iovp);
1406
1468
1469 /*
1470 * If we were unable to get the V_WRITELOCK_TRUE, then we
1471 * may not have accurate after attrs, so check if
1472 * we have both attributes, they have a non-zero va_seq, and
1473 * va_seq has changed by exactly one,
1474 * if not, turn off the before attr.
1475 */
1476 if (rwlock_ret != V_WRITELOCK_TRUE) {
1477 if (bvap == NULL || avap == NULL ||
1478 bvap->va_seq == 0 || avap->va_seq == 0 ||
1479 avap->va_seq != (bvap->va_seq + 1)) {
1480 bvap = NULL;
1481 }
1482 }
1483
1484 resp->status = NFS3_OK;
1485 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1486 resp->resok.count = args->count - uio.uio_resid;
1487 resp->resok.committed = args->stable;
1488 resp->resok.verf = write3verf;
1489 goto out;
1490
1491 err:
1492 if (curthread->t_flag & T_WOULDBLOCK) {
1493 curthread->t_flag &= ~T_WOULDBLOCK;
1494 resp->status = NFS3ERR_JUKEBOX;
1495 } else
1496 resp->status = puterrno3(error);
1497 err1:
1498 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1499 out:
1500 DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1501 cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1502
1503 if (vp != NULL) {
1504 if (rwlock_ret != -1)
1505 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1506 if (in_crit)
1507 nbl_end_crit(vp);
1508 VN_RELE(vp);
1509 }
1510 }
1511
1512 void *
1513 rfs3_write_getfh(WRITE3args *args)
1514 {
1515
1516 return (&args->file);
1517 }
1518
1519 void
1520 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1521 struct svc_req *req, cred_t *cr, bool_t ro)
1526 vnode_t *tvp = NULL;
1527 vnode_t *dvp;
1528 struct vattr *vap;
1529 struct vattr va;
1530 struct vattr *dbvap;
1531 struct vattr dbva;
1532 struct vattr *davap;
1533 struct vattr dava;
1534 enum vcexcl excl;
1535 nfstime3 *mtime;
1536 len_t reqsize;
1537 bool_t trunc;
1538 struct sockaddr *ca;
1539 char *name = NULL;
1540
1541 dbvap = NULL;
1542 davap = NULL;
1543
1544 dvp = nfs3_fhtovp(&args->where.dir, exi);
1545
1546 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1547 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1548
1549 if (dvp == NULL) {
1550 error = ESTALE;
1551 goto out;
1552 }
1553
1554 dbva.va_mask = AT_ALL;
1555 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1556 davap = dbvap;
1557
1558 if (args->where.name == nfs3nametoolong) {
1559 resp->status = NFS3ERR_NAMETOOLONG;
1560 goto out1;
1561 }
1562
1563 if (args->where.name == NULL || *(args->where.name) == '\0') {
1564 resp->status = NFS3ERR_ACCES;
1565 goto out1;
1566 }
1567
1826 else
1827 resp->resok.obj.handle_follows = TRUE;
1828
1829 /*
1830 * Force modified data and metadata out to stable storage.
1831 */
1832 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1833 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1834
1835 VN_RELE(vp);
1836 if (tvp != NULL) {
1837 if (in_crit)
1838 nbl_end_crit(tvp);
1839 VN_RELE(tvp);
1840 }
1841
1842 resp->status = NFS3_OK;
1843 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1844 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1845
1846 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848
1849 VN_RELE(dvp);
1850 return;
1851
1852 out:
1853 if (curthread->t_flag & T_WOULDBLOCK) {
1854 curthread->t_flag &= ~T_WOULDBLOCK;
1855 resp->status = NFS3ERR_JUKEBOX;
1856 } else
1857 resp->status = puterrno3(error);
1858 out1:
1859 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1860 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1861
1862 if (name != NULL && name != args->where.name)
1863 kmem_free(name, MAXPATHLEN + 1);
1864
1865 if (tvp != NULL) {
1866 if (in_crit)
1867 nbl_end_crit(tvp);
1868 VN_RELE(tvp);
1869 }
1870 if (dvp != NULL)
1871 VN_RELE(dvp);
1872 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1873 }
1874
1875 void *
1876 rfs3_create_getfh(CREATE3args *args)
1877 {
1878
1879 return (&args->where.dir);
1880 }
1883 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1884 struct svc_req *req, cred_t *cr, bool_t ro)
1885 {
1886 int error;
1887 vnode_t *vp = NULL;
1888 vnode_t *dvp;
1889 struct vattr *vap;
1890 struct vattr va;
1891 struct vattr *dbvap;
1892 struct vattr dbva;
1893 struct vattr *davap;
1894 struct vattr dava;
1895 struct sockaddr *ca;
1896 char *name = NULL;
1897
1898 dbvap = NULL;
1899 davap = NULL;
1900
1901 dvp = nfs3_fhtovp(&args->where.dir, exi);
1902
1903 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1904 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1905
1906 if (dvp == NULL) {
1907 error = ESTALE;
1908 goto out;
1909 }
1910
1911 dbva.va_mask = AT_ALL;
1912 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1913 davap = dbvap;
1914
1915 if (args->where.name == nfs3nametoolong) {
1916 resp->status = NFS3ERR_NAMETOOLONG;
1917 goto out1;
1918 }
1919
1920 if (args->where.name == NULL || *(args->where.name) == '\0') {
1921 resp->status = NFS3ERR_ACCES;
1922 goto out1;
1923 }
1924
1983 error = makefh3(&resp->resok.obj.handle, vp, exi);
1984 if (error)
1985 resp->resok.obj.handle_follows = FALSE;
1986 else
1987 resp->resok.obj.handle_follows = TRUE;
1988
1989 va.va_mask = AT_ALL;
1990 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1991
1992 /*
1993 * Force modified data and metadata out to stable storage.
1994 */
1995 (void) VOP_FSYNC(vp, 0, cr, NULL);
1996
1997 VN_RELE(vp);
1998
1999 resp->status = NFS3_OK;
2000 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2001 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2002
2003 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2005 VN_RELE(dvp);
2006
2007 return;
2008
2009 out:
2010 if (curthread->t_flag & T_WOULDBLOCK) {
2011 curthread->t_flag &= ~T_WOULDBLOCK;
2012 resp->status = NFS3ERR_JUKEBOX;
2013 } else
2014 resp->status = puterrno3(error);
2015 out1:
2016 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2017 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2018 if (dvp != NULL)
2019 VN_RELE(dvp);
2020 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2021 }
2022
2023 void *
2024 rfs3_mkdir_getfh(MKDIR3args *args)
2025 {
2026
2027 return (&args->where.dir);
2028 }
2029
2030 void
2031 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2032 struct svc_req *req, cred_t *cr, bool_t ro)
2033 {
2034 int error;
2035 vnode_t *vp;
2036 vnode_t *dvp;
2037 struct vattr *vap;
2038 struct vattr va;
2039 struct vattr *dbvap;
2040 struct vattr dbva;
2041 struct vattr *davap;
2042 struct vattr dava;
2043 struct sockaddr *ca;
2044 char *name = NULL;
2045 char *symdata = NULL;
2046
2047 dbvap = NULL;
2048 davap = NULL;
2049
2050 dvp = nfs3_fhtovp(&args->where.dir, exi);
2051
2052 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2053 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2054
2055 if (dvp == NULL) {
2056 error = ESTALE;
2057 goto err;
2058 }
2059
2060 dbva.va_mask = AT_ALL;
2061 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2062 davap = dbvap;
2063
2064 if (args->where.name == nfs3nametoolong) {
2065 resp->status = NFS3ERR_NAMETOOLONG;
2066 goto err1;
2067 }
2068
2069 if (args->where.name == NULL || *(args->where.name) == '\0') {
2070 resp->status = NFS3ERR_ACCES;
2071 goto err1;
2072 }
2073
2170 VN_RELE(vp);
2171
2172 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2173 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2174 goto out;
2175
2176 err:
2177 if (curthread->t_flag & T_WOULDBLOCK) {
2178 curthread->t_flag &= ~T_WOULDBLOCK;
2179 resp->status = NFS3ERR_JUKEBOX;
2180 } else
2181 resp->status = puterrno3(error);
2182 err1:
2183 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2184 out:
2185 if (name != NULL && name != args->where.name)
2186 kmem_free(name, MAXPATHLEN + 1);
2187 if (symdata != NULL && symdata != args->symlink.symlink_data)
2188 kmem_free(symdata, MAXPATHLEN + 1);
2189
2190 DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2191 cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2192
2193 if (dvp != NULL)
2194 VN_RELE(dvp);
2195 }
2196
2197 void *
2198 rfs3_symlink_getfh(SYMLINK3args *args)
2199 {
2200
2201 return (&args->where.dir);
2202 }
2203
2204 void
2205 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2206 struct svc_req *req, cred_t *cr, bool_t ro)
2207 {
2208 int error;
2209 vnode_t *vp;
2210 vnode_t *realvp;
2211 vnode_t *dvp;
2212 struct vattr *vap;
2213 struct vattr va;
2214 struct vattr *dbvap;
2215 struct vattr dbva;
2216 struct vattr *davap;
2217 struct vattr dava;
2218 int mode;
2219 enum vcexcl excl;
2220 struct sockaddr *ca;
2221 char *name = NULL;
2222
2223 dbvap = NULL;
2224 davap = NULL;
2225
2226 dvp = nfs3_fhtovp(&args->where.dir, exi);
2227
2228 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2229 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2230
2231 if (dvp == NULL) {
2232 error = ESTALE;
2233 goto out;
2234 }
2235
2236 dbva.va_mask = AT_ALL;
2237 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2238 davap = dbvap;
2239
2240 if (args->where.name == nfs3nametoolong) {
2241 resp->status = NFS3ERR_NAMETOOLONG;
2242 goto out1;
2243 }
2244
2245 if (args->where.name == NULL || *(args->where.name) == '\0') {
2246 resp->status = NFS3ERR_ACCES;
2247 goto out1;
2248 }
2249
2355 else
2356 resp->resok.obj.handle_follows = TRUE;
2357
2358 va.va_mask = AT_ALL;
2359 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2360
2361 /*
2362 * Force modified metadata out to stable storage.
2363 *
2364 * if a underlying vp exists, pass it to VOP_FSYNC
2365 */
2366 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2367 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2368 else
2369 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2370
2371 VN_RELE(vp);
2372
2373 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2374 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2375 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2376 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2377 VN_RELE(dvp);
2378 return;
2379
2380 out:
2381 if (curthread->t_flag & T_WOULDBLOCK) {
2382 curthread->t_flag &= ~T_WOULDBLOCK;
2383 resp->status = NFS3ERR_JUKEBOX;
2384 } else
2385 resp->status = puterrno3(error);
2386 out1:
2387 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2388 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2389 if (dvp != NULL)
2390 VN_RELE(dvp);
2391 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2392 }
2393
2394 void *
2395 rfs3_mknod_getfh(MKNOD3args *args)
2396 {
2397
2398 return (&args->where.dir);
2399 }
2400
2401 void
2402 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2403 struct svc_req *req, cred_t *cr, bool_t ro)
2404 {
2405 int error = 0;
2406 vnode_t *vp;
2407 struct vattr *bvap;
2408 struct vattr bva;
2409 struct vattr *avap;
2410 struct vattr ava;
2411 vnode_t *targvp = NULL;
2412 struct sockaddr *ca;
2413 char *name = NULL;
2414
2415 bvap = NULL;
2416 avap = NULL;
2417
2418 vp = nfs3_fhtovp(&args->object.dir, exi);
2419
2420 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2421 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2422
2423 if (vp == NULL) {
2424 error = ESTALE;
2425 goto err;
2426 }
2427
2428 bva.va_mask = AT_ALL;
2429 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2430 avap = bvap;
2431
2432 if (vp->v_type != VDIR) {
2433 resp->status = NFS3ERR_NOTDIR;
2434 goto err1;
2435 }
2436
2437 if (args->object.name == nfs3nametoolong) {
2438 resp->status = NFS3ERR_NAMETOOLONG;
2439 goto err1;
2440 }
2441
2509 * Force modified data and metadata out to stable storage.
2510 */
2511 (void) VOP_FSYNC(vp, 0, cr, NULL);
2512
2513 if (error)
2514 goto err;
2515
2516 resp->status = NFS3_OK;
2517 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2518 goto out;
2519
2520 err:
2521 if (curthread->t_flag & T_WOULDBLOCK) {
2522 curthread->t_flag &= ~T_WOULDBLOCK;
2523 resp->status = NFS3ERR_JUKEBOX;
2524 } else
2525 resp->status = puterrno3(error);
2526 err1:
2527 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2528 out:
2529 DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2530 cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2531
2532 if (name != NULL && name != args->object.name)
2533 kmem_free(name, MAXPATHLEN + 1);
2534
2535 if (vp != NULL)
2536 VN_RELE(vp);
2537 }
2538
2539 void *
2540 rfs3_remove_getfh(REMOVE3args *args)
2541 {
2542
2543 return (&args->object.dir);
2544 }
2545
2546 void
2547 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2548 struct svc_req *req, cred_t *cr, bool_t ro)
2549 {
2550 int error;
2551 vnode_t *vp;
2552 struct vattr *bvap;
2553 struct vattr bva;
2554 struct vattr *avap;
2555 struct vattr ava;
2556 struct sockaddr *ca;
2557 char *name = NULL;
2558
2559 bvap = NULL;
2560 avap = NULL;
2561
2562 vp = nfs3_fhtovp(&args->object.dir, exi);
2563
2564 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2565 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2566
2567 if (vp == NULL) {
2568 error = ESTALE;
2569 goto err;
2570 }
2571
2572 bva.va_mask = AT_ALL;
2573 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2574 avap = bvap;
2575
2576 if (vp->v_type != VDIR) {
2577 resp->status = NFS3ERR_NOTDIR;
2578 goto err1;
2579 }
2580
2581 if (args->object.name == nfs3nametoolong) {
2582 resp->status = NFS3ERR_NAMETOOLONG;
2583 goto err1;
2584 }
2585
2601 "got client label from request(1)", struct svc_req *, req);
2602
2603 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2604 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2605 exi)) {
2606 resp->status = NFS3ERR_ACCES;
2607 goto err1;
2608 }
2609 }
2610 }
2611
2612 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2613 name = nfscmd_convname(ca, exi, args->object.name,
2614 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2615
2616 if (name == NULL) {
2617 resp->status = NFS3ERR_INVAL;
2618 goto err1;
2619 }
2620
2621 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2622
2623 if (name != args->object.name)
2624 kmem_free(name, MAXPATHLEN + 1);
2625
2626 ava.va_mask = AT_ALL;
2627 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2628
2629 /*
2630 * Force modified data and metadata out to stable storage.
2631 */
2632 (void) VOP_FSYNC(vp, 0, cr, NULL);
2633
2634 if (error) {
2635 /*
2636 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2637 * if the directory is not empty. A System V NFS server
2638 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2639 * over the wire.
2640 */
2641 if (error == EEXIST)
2642 error = ENOTEMPTY;
2643 goto err;
2644 }
2645
2646 resp->status = NFS3_OK;
2647 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2648 goto out;
2649
2650 err:
2651 if (curthread->t_flag & T_WOULDBLOCK) {
2652 curthread->t_flag &= ~T_WOULDBLOCK;
2653 resp->status = NFS3ERR_JUKEBOX;
2654 } else
2655 resp->status = puterrno3(error);
2656 err1:
2657 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2658 out:
2659 DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2660 cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2661 if (vp != NULL)
2662 VN_RELE(vp);
2663
2664 }
2665
2666 void *
2667 rfs3_rmdir_getfh(RMDIR3args *args)
2668 {
2669
2670 return (&args->object.dir);
2671 }
2672
2673 void
2674 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2675 struct svc_req *req, cred_t *cr, bool_t ro)
2676 {
2677 int error = 0;
2678 vnode_t *fvp;
2679 vnode_t *tvp;
2680 vnode_t *targvp;
2685 struct vattr *tbvap;
2686 struct vattr tbva;
2687 struct vattr *tavap;
2688 struct vattr tava;
2689 nfs_fh3 *fh3;
2690 struct exportinfo *to_exi;
2691 vnode_t *srcvp = NULL;
2692 bslabel_t *clabel;
2693 struct sockaddr *ca;
2694 char *name = NULL;
2695 char *toname = NULL;
2696
2697 fbvap = NULL;
2698 favap = NULL;
2699 tbvap = NULL;
2700 tavap = NULL;
2701 tvp = NULL;
2702
2703 fvp = nfs3_fhtovp(&args->from.dir, exi);
2704
2705 DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2706 cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2707
2708 if (fvp == NULL) {
2709 error = ESTALE;
2710 goto err;
2711 }
2712
2713 if (is_system_labeled()) {
2714 clabel = req->rq_label;
2715 ASSERT(clabel != NULL);
2716 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2717 "got client label from request(1)", struct svc_req *, req);
2718
2719 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2720 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2721 exi)) {
2722 resp->status = NFS3ERR_ACCES;
2723 goto err1;
2724 }
2725 }
2726 }
2803 /*
2804 * Check for a conflict with a non-blocking mandatory share
2805 * reservation or V4 delegations.
2806 */
2807 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2808 NULL, cr, NULL, NULL, NULL);
2809 if (error != 0)
2810 goto err;
2811
2812 /*
2813 * If we rename a delegated file we should recall the
2814 * delegation, since future opens should fail or would
2815 * refer to a new file.
2816 */
2817 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2818 resp->status = NFS3ERR_JUKEBOX;
2819 goto err1;
2820 }
2821
2822 /*
2823 * Check for renaming over a delegated file. Check rfs4_deleg_policy
2824 * first to avoid VOP_LOOKUP if possible.
2825 */
2826 if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2827 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2828 NULL, NULL, NULL) == 0) {
2829
2830 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2831 VN_RELE(targvp);
2832 resp->status = NFS3ERR_JUKEBOX;
2833 goto err1;
2834 }
2835 VN_RELE(targvp);
2836 }
2837
2838 if (!nbl_need_check(srcvp)) {
2839 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2840 } else {
2841 nbl_start_crit(srcvp, RW_READER);
2842 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2843 error = EACCES;
2844 else
2845 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2846 nbl_end_crit(srcvp);
2870 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2871 goto out;
2872
2873 err:
2874 if (curthread->t_flag & T_WOULDBLOCK) {
2875 curthread->t_flag &= ~T_WOULDBLOCK;
2876 resp->status = NFS3ERR_JUKEBOX;
2877 } else {
2878 resp->status = puterrno3(error);
2879 }
2880 err1:
2881 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2882 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2883
2884 out:
2885 if (name != NULL && name != args->from.name)
2886 kmem_free(name, MAXPATHLEN + 1);
2887 if (toname != NULL && toname != args->to.name)
2888 kmem_free(toname, MAXPATHLEN + 1);
2889
2890 DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2891 cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
2892 if (fvp != NULL)
2893 VN_RELE(fvp);
2894 if (tvp != NULL)
2895 VN_RELE(tvp);
2896 }
2897
2898 void *
2899 rfs3_rename_getfh(RENAME3args *args)
2900 {
2901
2902 return (&args->from.dir);
2903 }
2904
2905 void
2906 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2907 struct svc_req *req, cred_t *cr, bool_t ro)
2908 {
2909 int error;
2910 vnode_t *vp;
2911 vnode_t *dvp;
2912 struct vattr *vap;
2913 struct vattr va;
2914 struct vattr *bvap;
2915 struct vattr bva;
2916 struct vattr *avap;
2917 struct vattr ava;
2918 nfs_fh3 *fh3;
2919 struct exportinfo *to_exi;
2920 bslabel_t *clabel;
2921 struct sockaddr *ca;
2922 char *name = NULL;
2923
2924 vap = NULL;
2925 bvap = NULL;
2926 avap = NULL;
2927 dvp = NULL;
2928
2929 vp = nfs3_fhtovp(&args->file, exi);
2930
2931 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2932 cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2933
2934 if (vp == NULL) {
2935 error = ESTALE;
2936 goto out;
2937 }
2938
2939 va.va_mask = AT_ALL;
2940 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2941
2942 fh3 = &args->link.dir;
2943 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2944 if (to_exi == NULL) {
2945 resp->status = NFS3ERR_ACCES;
2946 goto out1;
2947 }
2948 exi_rele(to_exi);
2949
2950 if (to_exi != exi) {
2951 resp->status = NFS3ERR_XDEV;
2952 goto out1;
3024 va.va_mask = AT_ALL;
3025 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3026 ava.va_mask = AT_ALL;
3027 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3028
3029 /*
3030 * Force modified data and metadata out to stable storage.
3031 */
3032 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3033 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3034
3035 if (error)
3036 goto out;
3037
3038 VN_RELE(dvp);
3039
3040 resp->status = NFS3_OK;
3041 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3042 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3043
3044 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3045 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3046
3047 VN_RELE(vp);
3048
3049 return;
3050
3051 out:
3052 if (curthread->t_flag & T_WOULDBLOCK) {
3053 curthread->t_flag &= ~T_WOULDBLOCK;
3054 resp->status = NFS3ERR_JUKEBOX;
3055 } else
3056 resp->status = puterrno3(error);
3057 out1:
3058 if (name != NULL && name != args->link.name)
3059 kmem_free(name, MAXPATHLEN + 1);
3060
3061 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3062 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3063
3064 if (vp != NULL)
3065 VN_RELE(vp);
3066 if (dvp != NULL)
3067 VN_RELE(dvp);
3068 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3069 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3070 }
3071
3072 void *
3073 rfs3_link_getfh(LINK3args *args)
3074 {
3075
3076 return (&args->file);
3077 }
3078
3079 /*
3080 * This macro defines the size of a response which contains attribute
3081 * information and one directory entry (whose length is specified by
3082 * the macro parameter). If the incoming request is larger than this,
3110 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3111 struct svc_req *req, cred_t *cr, bool_t ro)
3112 {
3113 int error;
3114 vnode_t *vp;
3115 struct vattr *vap;
3116 struct vattr va;
3117 struct iovec iov;
3118 struct uio uio;
3119 char *data;
3120 int iseof;
3121 int bufsize;
3122 int namlen;
3123 uint_t count;
3124 struct sockaddr *ca;
3125
3126 vap = NULL;
3127
3128 vp = nfs3_fhtovp(&args->dir, exi);
3129
3130 DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3131 cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3132
3133 if (vp == NULL) {
3134 error = ESTALE;
3135 goto out;
3136 }
3137
3138 if (is_system_labeled()) {
3139 bslabel_t *clabel = req->rq_label;
3140
3141 ASSERT(clabel != NULL);
3142 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3143 "got client label from request(1)", struct svc_req *, req);
3144
3145 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3146 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3147 exi)) {
3148 resp->status = NFS3ERR_ACCES;
3149 goto out1;
3150 }
3151 }
3275 /*
3276 * Don't do this. It causes local disk writes when just
3277 * reading the file and the overhead is deemed larger
3278 * than the benefit.
3279 */
3280 /*
3281 * Force modified metadata out to stable storage.
3282 */
3283 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3284 #endif
3285
3286 resp->status = NFS3_OK;
3287 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3288 resp->resok.cookieverf = 0;
3289 resp->resok.reply.entries = (entry3 *)data;
3290 resp->resok.reply.eof = iseof;
3291 resp->resok.size = count - uio.uio_resid;
3292 resp->resok.count = args->count;
3293 resp->resok.freecount = count;
3294
3295 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3296 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3297
3298 VN_RELE(vp);
3299
3300 return;
3301
3302 out:
3303 if (curthread->t_flag & T_WOULDBLOCK) {
3304 curthread->t_flag &= ~T_WOULDBLOCK;
3305 resp->status = NFS3ERR_JUKEBOX;
3306 } else
3307 resp->status = puterrno3(error);
3308 out1:
3309 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3310 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3311
3312 if (vp != NULL) {
3313 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3314 VN_RELE(vp);
3315 }
3316 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3317 }
3318
3319 void *
3320 rfs3_readdir_getfh(READDIR3args *args)
3321 {
3322
3323 return (&args->dir);
3324 }
3325
3326 void
3327 rfs3_readdir_free(READDIR3res *resp)
3328 {
3329
3330 if (resp->status == NFS3_OK)
3331 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3381 struct vattr nva;
3382 entryplus3_info *infop = NULL;
3383 int size = 0;
3384 int nents = 0;
3385 int bufsize = 0;
3386 int entrysize = 0;
3387 int tofit = 0;
3388 int rd_unit = rfs3_readdir_unit;
3389 int prev_len;
3390 int space_left;
3391 int i;
3392 uint_t *namlen = NULL;
3393 char *ndata = NULL;
3394 struct sockaddr *ca;
3395 size_t ret;
3396
3397 vap = NULL;
3398
3399 vp = nfs3_fhtovp(&args->dir, exi);
3400
3401 DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3402 cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3403
3404 if (vp == NULL) {
3405 error = ESTALE;
3406 goto out;
3407 }
3408
3409 if (is_system_labeled()) {
3410 bslabel_t *clabel = req->rq_label;
3411
3412 ASSERT(clabel != NULL);
3413 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3414 char *, "got client label from request(1)",
3415 struct svc_req *, req);
3416
3417 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3418 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3419 exi)) {
3420 resp->status = NFS3ERR_ACCES;
3421 goto out1;
3422 }
3664 * reading the file and the overhead is deemed larger
3665 * than the benefit.
3666 */
3667 /*
3668 * Force modified metadata out to stable storage.
3669 */
3670 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3671 #endif
3672
3673 kmem_free(namlen, args->dircount);
3674
3675 resp->status = NFS3_OK;
3676 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3677 resp->resok.cookieverf = 0;
3678 resp->resok.reply.entries = (entryplus3 *)ndata;
3679 resp->resok.reply.eof = iseof;
3680 resp->resok.size = nents;
3681 resp->resok.count = args->dircount - ret;
3682 resp->resok.maxcount = args->maxcount;
3683
3684 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686 if (ndata != data)
3687 kmem_free(data, args->dircount);
3688
3689
3690 VN_RELE(vp);
3691
3692 return;
3693
3694 out:
3695 if (curthread->t_flag & T_WOULDBLOCK) {
3696 curthread->t_flag &= ~T_WOULDBLOCK;
3697 resp->status = NFS3ERR_JUKEBOX;
3698 } else {
3699 resp->status = puterrno3(error);
3700 }
3701 out1:
3702 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3703 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3704
3705 if (vp != NULL) {
3706 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3707 VN_RELE(vp);
3708 }
3709
3710 if (namlen != NULL)
3711 kmem_free(namlen, args->dircount);
3712
3713 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3714 }
3715
3716 void *
3717 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3718 {
3719
3720 return (&args->dir);
3721 }
3722
3723 void
3724 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3729 kmem_free(resp->resok.infop,
3730 resp->resok.size * sizeof (struct entryplus3_info));
3731 }
3732 }
3733
3734 /* ARGSUSED */
3735 void
3736 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3737 struct svc_req *req, cred_t *cr, bool_t ro)
3738 {
3739 int error;
3740 vnode_t *vp;
3741 struct vattr *vap;
3742 struct vattr va;
3743 struct statvfs64 sb;
3744
3745 vap = NULL;
3746
3747 vp = nfs3_fhtovp(&args->fsroot, exi);
3748
3749 DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3750 cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3751
3752 if (vp == NULL) {
3753 error = ESTALE;
3754 goto out;
3755 }
3756
3757 if (is_system_labeled()) {
3758 bslabel_t *clabel = req->rq_label;
3759
3760 ASSERT(clabel != NULL);
3761 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3762 "got client label from request(1)", struct svc_req *, req);
3763
3764 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3765 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3766 exi)) {
3767 resp->status = NFS3ERR_ACCES;
3768 goto out1;
3769 }
3770 }
3780
3781 resp->status = NFS3_OK;
3782 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3783 if (sb.f_blocks != (fsblkcnt64_t)-1)
3784 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3785 else
3786 resp->resok.tbytes = (size3)sb.f_blocks;
3787 if (sb.f_bfree != (fsblkcnt64_t)-1)
3788 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3789 else
3790 resp->resok.fbytes = (size3)sb.f_bfree;
3791 if (sb.f_bavail != (fsblkcnt64_t)-1)
3792 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3793 else
3794 resp->resok.abytes = (size3)sb.f_bavail;
3795 resp->resok.tfiles = (size3)sb.f_files;
3796 resp->resok.ffiles = (size3)sb.f_ffree;
3797 resp->resok.afiles = (size3)sb.f_favail;
3798 resp->resok.invarsec = 0;
3799
3800 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3801 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3802 VN_RELE(vp);
3803
3804 return;
3805
3806 out:
3807 if (curthread->t_flag & T_WOULDBLOCK) {
3808 curthread->t_flag &= ~T_WOULDBLOCK;
3809 resp->status = NFS3ERR_JUKEBOX;
3810 } else
3811 resp->status = puterrno3(error);
3812 out1:
3813 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3814 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3815
3816 if (vp != NULL)
3817 VN_RELE(vp);
3818 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3819 }
3820
3821 void *
3822 rfs3_fsstat_getfh(FSSTAT3args *args)
3823 {
3824
3825 return (&args->fsroot);
3826 }
3827
3828 /* ARGSUSED */
3829 void
3830 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3831 struct svc_req *req, cred_t *cr, bool_t ro)
3832 {
3833 vnode_t *vp;
3834 struct vattr *vap;
3835 struct vattr va;
3836 uint32_t xfer_size;
3837 ulong_t l = 0;
3838 int error;
3839
3840 vp = nfs3_fhtovp(&args->fsroot, exi);
3841
3842 DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3843 cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3844
3845 if (vp == NULL) {
3846 if (curthread->t_flag & T_WOULDBLOCK) {
3847 curthread->t_flag &= ~T_WOULDBLOCK;
3848 resp->status = NFS3ERR_JUKEBOX;
3849 } else
3850 resp->status = NFS3ERR_STALE;
3851 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3852 goto out;
3853 }
3854
3855 if (is_system_labeled()) {
3856 bslabel_t *clabel = req->rq_label;
3857
3858 ASSERT(clabel != NULL);
3859 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3860 "got client label from request(1)", struct svc_req *, req);
3861
3862 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3863 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3897 /*
3898 * If the underlying file system does not support _PC_FILESIZEBITS,
3899 * return a reasonable default. Note that error code on VOP_PATHCONF
3900 * will be 0, even if the underlying file system does not support
3901 * _PC_FILESIZEBITS.
3902 */
3903 if (l == (ulong_t)-1) {
3904 resp->resok.maxfilesize = MAXOFF32_T;
3905 } else {
3906 if (l >= (sizeof (uint64_t) * 8))
3907 resp->resok.maxfilesize = INT64_MAX;
3908 else
3909 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3910 }
3911
3912 resp->resok.time_delta.seconds = 0;
3913 resp->resok.time_delta.nseconds = 1000;
3914 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3915 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3916
3917 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3918 cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3919
3920 VN_RELE(vp);
3921
3922 return;
3923
3924 out:
3925 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3926 cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3927 if (vp != NULL)
3928 VN_RELE(vp);
3929 }
3930
3931 void *
3932 rfs3_fsinfo_getfh(FSINFO3args *args)
3933 {
3934 return (&args->fsroot);
3935 }
3936
3937 /* ARGSUSED */
3938 void
3939 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3940 struct svc_req *req, cred_t *cr, bool_t ro)
3941 {
3942 int error;
3943 vnode_t *vp;
3944 struct vattr *vap;
3945 struct vattr va;
3946 ulong_t val;
3947
3948 vap = NULL;
3949
3950 vp = nfs3_fhtovp(&args->object, exi);
3951
3952 DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3953 cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3954
3955 if (vp == NULL) {
3956 error = ESTALE;
3957 goto out;
3958 }
3959
3960 if (is_system_labeled()) {
3961 bslabel_t *clabel = req->rq_label;
3962
3963 ASSERT(clabel != NULL);
3964 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3965 "got client label from request(1)", struct svc_req *, req);
3966
3967 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3968 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3969 exi)) {
3970 resp->status = NFS3ERR_ACCES;
3971 goto out1;
3972 }
3973 }
3989 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3990 if (error)
3991 goto out;
3992 if (val == 1)
3993 resp->resok.info.no_trunc = TRUE;
3994 else
3995 resp->resok.info.no_trunc = FALSE;
3996
3997 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3998 if (error)
3999 goto out;
4000 if (val == 1)
4001 resp->resok.info.chown_restricted = TRUE;
4002 else
4003 resp->resok.info.chown_restricted = FALSE;
4004
4005 resp->status = NFS3_OK;
4006 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4007 resp->resok.info.case_insensitive = FALSE;
4008 resp->resok.info.case_preserving = TRUE;
4009 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4010 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4011 VN_RELE(vp);
4012 return;
4013
4014 out:
4015 if (curthread->t_flag & T_WOULDBLOCK) {
4016 curthread->t_flag &= ~T_WOULDBLOCK;
4017 resp->status = NFS3ERR_JUKEBOX;
4018 } else
4019 resp->status = puterrno3(error);
4020 out1:
4021 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4022 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4023 if (vp != NULL)
4024 VN_RELE(vp);
4025 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4026 }
4027
4028 void *
4029 rfs3_pathconf_getfh(PATHCONF3args *args)
4030 {
4031
4032 return (&args->object);
4033 }
4034
4035 void
4036 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4037 struct svc_req *req, cred_t *cr, bool_t ro)
4038 {
4039 int error;
4040 vnode_t *vp;
4041 struct vattr *bvap;
4042 struct vattr bva;
4043 struct vattr *avap;
4044 struct vattr ava;
4045
4046 bvap = NULL;
4047 avap = NULL;
4048
4049 vp = nfs3_fhtovp(&args->file, exi);
4050
4051 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4052 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4053
4054 if (vp == NULL) {
4055 error = ESTALE;
4056 goto out;
4057 }
4058
4059 bva.va_mask = AT_ALL;
4060 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4061
4062 /*
4063 * If we can't get the attributes, then we can't do the
4064 * right access checking. So, we'll fail the request.
4065 */
4066 if (error)
4067 goto out;
4068
4069 bvap = &bva;
4070
4071 if (rdonly(ro, vp)) {
4072 resp->status = NFS3ERR_ROFS;
4073 goto out1;
4074 }
4075
4076 if (vp->v_type != VREG) {
4077 resp->status = NFS3ERR_INVAL;
4078 goto out1;
4091 resp->status = NFS3ERR_ACCES;
4092 goto out1;
4093 }
4094 }
4095 }
4096
4097 if (crgetuid(cr) != bva.va_uid &&
4098 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4099 goto out;
4100
4101 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4102
4103 ava.va_mask = AT_ALL;
4104 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4105
4106 if (error)
4107 goto out;
4108
4109 resp->status = NFS3_OK;
4110 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4111 resp->resok.verf = write3verf;
4112
4113 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4114 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4115
4116 VN_RELE(vp);
4117
4118 return;
4119
4120 out:
4121 if (curthread->t_flag & T_WOULDBLOCK) {
4122 curthread->t_flag &= ~T_WOULDBLOCK;
4123 resp->status = NFS3ERR_JUKEBOX;
4124 } else
4125 resp->status = puterrno3(error);
4126 out1:
4127 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4128 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4129
4130 if (vp != NULL)
4131 VN_RELE(vp);
4132 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4133 }
4134
4135 void *
4136 rfs3_commit_getfh(COMMIT3args *args)
4137 {
4138
4139 return (&args->file);
4140 }
4141
4142 static int
4143 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4144 {
4145
4146 vap->va_mask = 0;
4147
4148 if (sap->mode.set_it) {
4186 /* check time validity */
4187 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4188 return (EOVERFLOW);
4189 #endif
4190 /*
4191 * nfs protocol defines times as unsigned so don't extend sign,
4192 * unless sysadmin set nfs_allow_preepoch_time.
4193 */
4194 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4195 sap->mtime.mtime.seconds);
4196 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4197 vap->va_mask |= AT_MTIME;
4198 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4199 gethrestime(&vap->va_mtime);
4200 vap->va_mask |= AT_MTIME;
4201 }
4202
4203 return (0);
4204 }
4205
4206 static ftype3 vt_to_nf3[] = {
4207 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4208 };
4209
4210 static int
4211 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4212 {
4213
4214 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4215 /* Return error if time or size overflow */
4216 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4217 return (EOVERFLOW);
4218 }
4219 fap->type = vt_to_nf3[vap->va_type];
4220 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4221 fap->nlink = (uint32)vap->va_nlink;
4222 if (vap->va_uid == UID_NOBODY)
4223 fap->uid = (uid3)NFS_UID_NOBODY;
4224 else
4225 fap->uid = (uid3)vap->va_uid;
4226 if (vap->va_gid == GID_NOBODY)
4268 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4269 poap->attributes = TRUE;
4270 } else
4271 poap->attributes = FALSE;
4272 }
4273
4274 void
4275 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4276 {
4277
4278 /* don't return attrs if time overflow */
4279 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4280 poap->attributes = TRUE;
4281 } else
4282 poap->attributes = FALSE;
4283 }
4284
4285 static void
4286 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4287 {
4288
4289 vattr_to_pre_op_attr(bvap, &wccp->before);
4290 vattr_to_post_op_attr(avap, &wccp->after);
4291 }
4292
4293 void
4294 rfs3_srvrinit(void)
4295 {
4296 struct rfs3_verf_overlay {
4297 uint_t id; /* a "unique" identifier */
4298 int ts; /* a unique timestamp */
4299 } *verfp;
4300 timestruc_t now;
4301
4302 /*
4303 * The following algorithm attempts to find a unique verifier
4304 * to be used as the write verifier returned from the server
4305 * to the client. It is important that this verifier change
4306 * whenever the server reboots. Of secondary importance, it
4307 * is important for the verifier to be unique between two
4308 * different servers.
4309 *
4310 * Thus, an attempt is made to use the system hostid and the
4311 * current time in seconds when the nfssrv kernel module is
4312 * loaded. It is assumed that an NFS server will not be able
4313 * to boot and then to reboot in less than a second. If the
4314 * hostid has not been set, then the current high resolution
4315 * time is used. This will ensure different verifiers each
4316 * time the server reboots and minimize the chances that two
4317 * different servers will have the same verifier.
4318 */
4319
4320 #ifndef lint
4321 /*
4322 * We ASSERT that this constant logic expression is
4323 * always true because in the past, it wasn't.
4324 */
4325 ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4326 #endif
4327
4328 gethrestime(&now);
4329 verfp = (struct rfs3_verf_overlay *)&write3verf;
4330 verfp->ts = (int)now.tv_sec;
4331 verfp->id = zone_get_hostid(NULL);
4332
4333 if (verfp->id == 0)
4334 verfp->id = (uint_t)now.tv_nsec;
4335
4336 nfs3_srv_caller_id = fs_new_caller_id();
4337
4338 }
4339
4340 static int
4341 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4342 {
4343 struct clist *wcl;
4344 int wlist_len;
4345 count3 count = rok->count;
4346
4347 wcl = args->wlist;
4348 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4349 return (FALSE);
4350 }
4351
4352 wcl = args->wlist;
4353 rok->wlist_len = wlist_len;
4354 rok->wlist = wcl;
4355 return (TRUE);
4356 }
4357
4358 void
4359 rfs3_srvrfini(void)
4360 {
4361 /* Nothing to do */
4362 }
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2018 Nexenta Systems, Inc.
24 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/cred.h>
36 #include <sys/buf.h>
37 #include <sys/vfs.h>
38 #include <sys/vnode.h>
39 #include <sys/uio.h>
40 #include <sys/errno.h>
41 #include <sys/sysmacros.h>
42 #include <sys/statvfs.h>
43 #include <sys/kmem.h>
44 #include <sys/dirent.h>
45 #include <sys/cmn_err.h>
46 #include <sys/debug.h>
47 #include <sys/systeminfo.h>
48 #include <sys/flock.h>
49 #include <sys/nbmlock.h>
50 #include <sys/policy.h>
51 #include <sys/sdt.h>
52
53 #include <rpc/types.h>
54 #include <rpc/auth.h>
55 #include <rpc/svc.h>
56 #include <rpc/rpc_rdma.h>
57
58 #include <nfs/nfs.h>
59 #include <nfs/export.h>
60 #include <nfs/nfs_cmd.h>
61
62 #include <sys/strsubr.h>
63 #include <sys/tsol/label.h>
64 #include <sys/tsol/tndb.h>
65
66 #include <sys/zone.h>
67
68 #include <inet/ip.h>
69 #include <inet/ip6.h>
70
71 /*
72 * Zone global variables of NFSv3 server
73 */
74 typedef struct nfs3_srv {
75 writeverf3 write3verf;
76 } nfs3_srv_t;
77
78 /*
79 * These are the interface routines for the server side of the
80 * Network File System. See the NFS version 3 protocol specification
81 * for a description of this interface.
82 */
83
84 static int sattr3_to_vattr(sattr3 *, struct vattr *);
85 static int vattr_to_fattr3(struct vattr *, fattr3 *);
86 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
87 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
88 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
89 static int rdma_setup_read_data3(READ3args *, READ3resok *);
90
91 extern int nfs_loaned_buffers;
92
93 u_longlong_t nfs3_srv_caller_id;
94
95 static nfs3_srv_t *
96 nfs3_get_srv(void)
97 {
98 nfs_globals_t *ng = nfs_srv_getzg();
99 nfs3_srv_t *srv = ng->nfs3_srv;
100 ASSERT(srv != NULL);
101 return (srv);
102 }
103
104 /* ARGSUSED */
105 void
106 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
107 struct svc_req *req, cred_t *cr, bool_t ro)
108 {
109 int error;
110 vnode_t *vp;
111 struct vattr va;
112
113 vp = nfs3_fhtovp(&args->object, exi);
114
115 DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
116 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
117 GETATTR3args *, args);
118
119 if (vp == NULL) {
120 error = ESTALE;
121 goto out;
122 }
123
124 va.va_mask = AT_ALL;
125 error = rfs4_delegated_getattr(vp, &va, 0, cr);
126
127 if (!error) {
128 /* Lie about the object type for a referral */
129 if (vn_is_nfs_reparse(vp, cr))
130 va.va_type = VLNK;
131
132 /* overflow error if time or size is out of range */
133 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
134 if (error)
135 goto out;
136 resp->status = NFS3_OK;
137
138 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
139 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
140 GETATTR3res *, resp);
141
142 VN_RELE(vp);
143
144 return;
145 }
146
147 out:
148 if (curthread->t_flag & T_WOULDBLOCK) {
149 curthread->t_flag &= ~T_WOULDBLOCK;
150 resp->status = NFS3ERR_JUKEBOX;
151 } else
152 resp->status = puterrno3(error);
153
154 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
155 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
156 GETATTR3res *, resp);
157
158 if (vp != NULL)
159 VN_RELE(vp);
160 }
161
162 void *
163 rfs3_getattr_getfh(GETATTR3args *args)
164 {
165
166 return (&args->object);
167 }
168
169 void
170 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
171 struct svc_req *req, cred_t *cr, bool_t ro)
172 {
173 int error;
174 vnode_t *vp;
175 struct vattr *bvap;
176 struct vattr bva;
177 struct vattr *avap;
178 struct vattr ava;
179 int flag;
180 int in_crit = 0;
181 struct flock64 bf;
182 caller_context_t ct;
183
184 bvap = NULL;
185 avap = NULL;
186
187 vp = nfs3_fhtovp(&args->object, exi);
188
189 DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
190 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
191 SETATTR3args *, args);
192
193 if (vp == NULL) {
194 error = ESTALE;
195 goto out;
196 }
197
198 error = sattr3_to_vattr(&args->new_attributes, &ava);
199 if (error)
200 goto out;
201
202 if (is_system_labeled()) {
203 bslabel_t *clabel = req->rq_label;
204
205 ASSERT(clabel != NULL);
206 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
207 "got client label from request(1)", struct svc_req *, req);
208
209 if (!blequal(&l_admin_low->tsl_label, clabel)) {
210 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
211 exi)) {
332 goto out1;
333 }
334
335 ava.va_mask = AT_ALL;
336 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
337
338 /*
339 * Force modified metadata out to stable storage.
340 */
341 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
342
343 if (error)
344 goto out;
345
346 if (in_crit)
347 nbl_end_crit(vp);
348
349 resp->status = NFS3_OK;
350 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
351
352 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
353 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
354 SETATTR3res *, resp);
355
356 VN_RELE(vp);
357
358 return;
359
360 out:
361 if (curthread->t_flag & T_WOULDBLOCK) {
362 curthread->t_flag &= ~T_WOULDBLOCK;
363 resp->status = NFS3ERR_JUKEBOX;
364 } else
365 resp->status = puterrno3(error);
366 out1:
367 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
368 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
369 SETATTR3res *, resp);
370
371 if (vp != NULL) {
372 if (in_crit)
373 nbl_end_crit(vp);
374 VN_RELE(vp);
375 }
376 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
377 }
378
379 void *
380 rfs3_setattr_getfh(SETATTR3args *args)
381 {
382
383 return (&args->object);
384 }
385
386 /* ARGSUSED */
387 void
388 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
389 struct svc_req *req, cred_t *cr, bool_t ro)
394 struct vattr *vap;
395 struct vattr va;
396 struct vattr *dvap;
397 struct vattr dva;
398 nfs_fh3 *fhp;
399 struct sec_ol sec = {0, 0};
400 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
401 struct sockaddr *ca;
402 char *name = NULL;
403
404 dvap = NULL;
405
406 if (exi != NULL)
407 exi_hold(exi);
408
409 /*
410 * Allow lookups from the root - the default
411 * location of the public filehandle.
412 */
413 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
414 ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
415 dvp = ZONE_ROOTVP();
416 VN_HOLD(dvp);
417
418 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
419 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
420 LOOKUP3args *, args);
421 } else {
422 dvp = nfs3_fhtovp(&args->what.dir, exi);
423
424 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
425 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
426 LOOKUP3args *, args);
427
428 if (dvp == NULL) {
429 error = ESTALE;
430 goto out;
431 }
432 }
433
434 dva.va_mask = AT_ALL;
435 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
436
437 if (args->what.name == nfs3nametoolong) {
438 resp->status = NFS3ERR_NAMETOOLONG;
439 goto out1;
440 }
441
442 if (args->what.name == NULL || *(args->what.name) == '\0') {
443 resp->status = NFS3ERR_ACCES;
444 goto out1;
445 }
446
447 fhp = &args->what.dir;
448 ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL */
449 if (strcmp(args->what.name, "..") == 0 &&
450 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
451 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
452 ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
453 /*
454 * special case for ".." and 'nohide'exported root
455 */
456 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
457 resp->status = NFS3ERR_ACCES;
458 goto out1;
459 }
460 } else {
461 resp->status = NFS3ERR_NOENT;
462 goto out1;
463 }
464 }
465
466 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
467 name = nfscmd_convname(ca, exi, args->what.name,
468 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
469
470 if (name == NULL) {
471 resp->status = NFS3ERR_ACCES;
472 goto out1;
473 }
474
475 /*
476 * If the public filehandle is used then allow
477 * a multi-component lookup
478 */
479 if (PUBLIC_FH3(&args->what.dir)) {
480 publicfh_flag = TRUE;
481
482 exi_rele(exi);
483 exi = NULL;
484
485 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
486 &exi, &sec);
487
488 /*
489 * Since WebNFS may bypass MOUNT, we need to ensure this
490 * request didn't come from an unlabeled admin_low client.
491 */
492 if (is_system_labeled() && error == 0) {
493 int addr_type;
494 void *ipaddr;
495 tsol_tpc_t *tp;
496
497 if (ca->sa_family == AF_INET) {
498 addr_type = IPV4_VERSION;
499 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
500 } else if (ca->sa_family == AF_INET6) {
501 addr_type = IPV6_VERSION;
502 ipaddr = &((struct sockaddr_in6 *)
503 ca)->sin6_addr;
547
548 if (error)
549 goto out;
550
551 if (sec.sec_flags & SEC_QUERY) {
552 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
553 } else {
554 error = makefh3(&resp->resok.object, vp, exi);
555 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
556 auth_weak = TRUE;
557 }
558
559 if (error) {
560 VN_RELE(vp);
561 goto out;
562 }
563
564 va.va_mask = AT_ALL;
565 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
566
567 VN_RELE(vp);
568
569 resp->status = NFS3_OK;
570 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
571 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
572
573 /*
574 * If it's public fh, no 0x81, and client's flavor is
575 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
576 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
577 */
578 if (auth_weak)
579 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
580
581 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
582 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
583 LOOKUP3res *, resp);
584 VN_RELE(dvp);
585 exi_rele(exi);
586
587 return;
588
589 out:
590 if (curthread->t_flag & T_WOULDBLOCK) {
591 curthread->t_flag &= ~T_WOULDBLOCK;
592 resp->status = NFS3ERR_JUKEBOX;
593 } else
594 resp->status = puterrno3(error);
595 out1:
596 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
597 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
598 LOOKUP3res *, resp);
599
600 if (exi != NULL)
601 exi_rele(exi);
602
603 if (dvp != NULL)
604 VN_RELE(dvp);
605 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
606
607 }
608
609 void *
610 rfs3_lookup_getfh(LOOKUP3args *args)
611 {
612
613 return (&args->what.dir);
614 }
615
616 /* ARGSUSED */
617 void
618 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
619 struct svc_req *req, cred_t *cr, bool_t ro)
620 {
621 int error;
622 vnode_t *vp;
623 struct vattr *vap;
624 struct vattr va;
625 int checkwriteperm;
626 boolean_t dominant_label = B_FALSE;
627 boolean_t equal_label = B_FALSE;
628 boolean_t admin_low_client;
629
630 vap = NULL;
631
632 vp = nfs3_fhtovp(&args->object, exi);
633
634 DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
635 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
636 ACCESS3args *, args);
637
638 if (vp == NULL) {
639 error = ESTALE;
640 goto out;
641 }
642
643 /*
644 * If the file system is exported read only, it is not appropriate
645 * to check write permissions for regular files and directories.
646 * Special files are interpreted by the client, so the underlying
647 * permissions are sent back to the client for interpretation.
648 */
649 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
650 checkwriteperm = 0;
651 else
652 checkwriteperm = 1;
653
654 /*
655 * We need the mode so that we can correctly determine access
656 * permissions relative to a mandatory lock file. Access to
726 equal_label)
727 resp->resok.access |= ACCESS3_DELETE;
728 }
729 if (args->access & ACCESS3_EXECUTE) {
730 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
731 if (error) {
732 if (curthread->t_flag & T_WOULDBLOCK)
733 goto out;
734 } else if (!MANDLOCK(vp, va.va_mode) &&
735 (!is_system_labeled() || admin_low_client ||
736 dominant_label))
737 resp->resok.access |= ACCESS3_EXECUTE;
738 }
739
740 va.va_mask = AT_ALL;
741 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
742
743 resp->status = NFS3_OK;
744 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
745
746 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
747 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
748 ACCESS3res *, resp);
749
750 VN_RELE(vp);
751
752 return;
753
754 out:
755 if (curthread->t_flag & T_WOULDBLOCK) {
756 curthread->t_flag &= ~T_WOULDBLOCK;
757 resp->status = NFS3ERR_JUKEBOX;
758 } else
759 resp->status = puterrno3(error);
760 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
761 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
762 ACCESS3res *, resp);
763 if (vp != NULL)
764 VN_RELE(vp);
765 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
766 }
767
768 void *
769 rfs3_access_getfh(ACCESS3args *args)
770 {
771
772 return (&args->object);
773 }
774
775 /* ARGSUSED */
776 void
777 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
778 struct svc_req *req, cred_t *cr, bool_t ro)
779 {
780 int error;
781 vnode_t *vp;
782 struct vattr *vap;
783 struct vattr va;
784 struct iovec iov;
785 struct uio uio;
786 char *data;
787 struct sockaddr *ca;
788 char *name = NULL;
789 int is_referral = 0;
790
791 vap = NULL;
792
793 vp = nfs3_fhtovp(&args->symlink, exi);
794
795 DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
796 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
797 READLINK3args *, args);
798
799 if (vp == NULL) {
800 error = ESTALE;
801 goto out;
802 }
803
804 va.va_mask = AT_ALL;
805 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
806 if (error)
807 goto out;
808
809 vap = &va;
810
811 /* We lied about the object type for a referral */
812 if (vn_is_nfs_reparse(vp, cr))
813 is_referral = 1;
814
815 if (vp->v_type != VLNK && !is_referral) {
816 resp->status = NFS3ERR_INVAL;
817 goto out1;
826 bslabel_t *clabel = req->rq_label;
827
828 ASSERT(clabel != NULL);
829 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
830 "got client label from request(1)", struct svc_req *, req);
831
832 if (!blequal(&l_admin_low->tsl_label, clabel)) {
833 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
834 exi)) {
835 resp->status = NFS3ERR_ACCES;
836 goto out1;
837 }
838 }
839 }
840
841 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
842
843 if (is_referral) {
844 char *s;
845 size_t strsz;
846 kstat_named_t *stat = exi->exi_ne->ne_globals->svstat[NFS_V3];
847
848 /* Get an artificial symlink based on a referral */
849 s = build_symlink(vp, cr, &strsz);
850 stat[NFS_REFERLINKS].value.ui64++;
851 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
852 vnode_t *, vp, char *, s);
853 if (s == NULL)
854 error = EINVAL;
855 else {
856 error = 0;
857 (void) strlcpy(data, s, MAXPATHLEN + 1);
858 kmem_free(s, strsz);
859 }
860
861 } else {
862
863 iov.iov_base = data;
864 iov.iov_len = MAXPATHLEN;
865 uio.uio_iov = &iov;
866 uio.uio_iovcnt = 1;
867 uio.uio_segflg = UIO_SYSSPACE;
868 uio.uio_extflg = UIO_COPY_CACHED;
869 uio.uio_loffset = 0;
870 uio.uio_resid = MAXPATHLEN;
898 kmem_free(data, MAXPATHLEN + 1);
899 goto out;
900 }
901
902 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
903 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
904 MAXPATHLEN + 1);
905
906 if (name == NULL) {
907 /*
908 * Even though the conversion failed, we return
909 * something. We just don't translate it.
910 */
911 name = data;
912 }
913
914 resp->status = NFS3_OK;
915 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
916 resp->resok.data = name;
917
918 DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
919 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
920 READLINK3res *, resp);
921 VN_RELE(vp);
922
923 if (name != data)
924 kmem_free(data, MAXPATHLEN + 1);
925
926 return;
927
928 out:
929 if (curthread->t_flag & T_WOULDBLOCK) {
930 curthread->t_flag &= ~T_WOULDBLOCK;
931 resp->status = NFS3ERR_JUKEBOX;
932 } else
933 resp->status = puterrno3(error);
934 out1:
935 DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
936 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
937 READLINK3res *, resp);
938 if (vp != NULL)
939 VN_RELE(vp);
940 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
941 }
942
943 void *
944 rfs3_readlink_getfh(READLINK3args *args)
945 {
946
947 return (&args->symlink);
948 }
949
950 void
951 rfs3_readlink_free(READLINK3res *resp)
952 {
953
954 if (resp->status == NFS3_OK)
955 kmem_free(resp->resok.data, MAXPATHLEN + 1);
956 }
957
967 int error;
968 vnode_t *vp;
969 struct vattr *vap;
970 struct vattr va;
971 struct iovec iov, *iovp = NULL;
972 int iovcnt;
973 struct uio uio;
974 u_offset_t offset;
975 mblk_t *mp = NULL;
976 int in_crit = 0;
977 int need_rwunlock = 0;
978 caller_context_t ct;
979 int rdma_used = 0;
980 int loaned_buffers;
981 struct uio *uiop;
982
983 vap = NULL;
984
985 vp = nfs3_fhtovp(&args->file, exi);
986
987 DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
988 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
989 READ3args *, args);
990
991
992 if (vp == NULL) {
993 error = ESTALE;
994 goto out;
995 }
996
997 if (args->wlist) {
998 if (args->count > clist_len(args->wlist)) {
999 error = EINVAL;
1000 goto out;
1001 }
1002 rdma_used = 1;
1003 }
1004
1005 /* use loaned buffers for TCP */
1006 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
1007
1008 if (is_system_labeled()) {
1009 bslabel_t *clabel = req->rq_label;
1010
1011 ASSERT(clabel != NULL);
1225 resp->resok.eof = FALSE;
1226 resp->resok.data.data_len = resp->resok.count;
1227
1228 if (mp)
1229 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1230
1231 resp->resok.data.mp = mp;
1232 resp->resok.size = (uint_t)args->count;
1233
1234 if (rdma_used) {
1235 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1236 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1237 resp->status = NFS3ERR_INVAL;
1238 }
1239 } else {
1240 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1241 (resp->resok).wlist = NULL;
1242 }
1243
1244 done:
1245 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1246 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1247 READ3res *, resp);
1248
1249 VN_RELE(vp);
1250
1251 if (iovp != NULL)
1252 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1253
1254 return;
1255
1256 out:
1257 if (curthread->t_flag & T_WOULDBLOCK) {
1258 curthread->t_flag &= ~T_WOULDBLOCK;
1259 resp->status = NFS3ERR_JUKEBOX;
1260 } else
1261 resp->status = puterrno3(error);
1262 out1:
1263 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1264 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1265 READ3res *, resp);
1266
1267 if (vp != NULL) {
1268 if (need_rwunlock)
1269 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1270 if (in_crit)
1271 nbl_end_crit(vp);
1272 VN_RELE(vp);
1273 }
1274 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1275
1276 if (iovp != NULL)
1277 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1278 }
1279
1280 void
1281 rfs3_read_free(READ3res *resp)
1282 {
1283 mblk_t *mp;
1284
1285 if (resp->status == NFS3_OK) {
1290 }
1291
1292 void *
1293 rfs3_read_getfh(READ3args *args)
1294 {
1295
1296 return (&args->file);
1297 }
1298
1299 #define MAX_IOVECS 12
1300
1301 #ifdef DEBUG
1302 static int rfs3_write_hits = 0;
1303 static int rfs3_write_misses = 0;
1304 #endif
1305
1306 void
1307 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1308 struct svc_req *req, cred_t *cr, bool_t ro)
1309 {
1310 nfs3_srv_t *ns;
1311 int error;
1312 vnode_t *vp;
1313 struct vattr *bvap = NULL;
1314 struct vattr bva;
1315 struct vattr *avap = NULL;
1316 struct vattr ava;
1317 u_offset_t rlimit;
1318 struct uio uio;
1319 struct iovec iov[MAX_IOVECS];
1320 mblk_t *m;
1321 struct iovec *iovp;
1322 int iovcnt;
1323 int ioflag;
1324 cred_t *savecred;
1325 int in_crit = 0;
1326 int rwlock_ret = -1;
1327 caller_context_t ct;
1328
1329 vp = nfs3_fhtovp(&args->file, exi);
1330
1331 DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1332 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1333 WRITE3args *, args);
1334
1335 if (vp == NULL) {
1336 error = ESTALE;
1337 goto err;
1338 }
1339
1340 ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
1341 ns = nfs3_get_srv();
1342
1343 if (is_system_labeled()) {
1344 bslabel_t *clabel = req->rq_label;
1345
1346 ASSERT(clabel != NULL);
1347 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1348 "got client label from request(1)", struct svc_req *, req);
1349
1350 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1351 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1352 exi)) {
1353 resp->status = NFS3ERR_ACCES;
1354 goto err1;
1355 }
1356 }
1357 }
1358
1359 ct.cc_sysid = 0;
1360 ct.cc_pid = 0;
1361 ct.cc_caller_id = nfs3_srv_caller_id;
1362 ct.cc_flags = CC_DONTBLOCK;
1410
1411 if (vp->v_type != VREG) {
1412 resp->status = NFS3ERR_INVAL;
1413 goto err1;
1414 }
1415
1416 if (crgetuid(cr) != bva.va_uid &&
1417 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1418 goto err;
1419
1420 if (MANDLOCK(vp, bva.va_mode)) {
1421 resp->status = NFS3ERR_ACCES;
1422 goto err1;
1423 }
1424
1425 if (args->count == 0) {
1426 resp->status = NFS3_OK;
1427 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1428 resp->resok.count = 0;
1429 resp->resok.committed = args->stable;
1430 resp->resok.verf = ns->write3verf;
1431 goto out;
1432 }
1433
1434 if (args->mblk != NULL) {
1435 iovcnt = 0;
1436 for (m = args->mblk; m != NULL; m = m->b_cont)
1437 iovcnt++;
1438 if (iovcnt <= MAX_IOVECS) {
1439 #ifdef DEBUG
1440 rfs3_write_hits++;
1441 #endif
1442 iovp = iov;
1443 } else {
1444 #ifdef DEBUG
1445 rfs3_write_misses++;
1446 #endif
1447 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1448 }
1449 mblk_to_iov(args->mblk, iovcnt, iovp);
1450
1512
1513 /*
1514 * If we were unable to get the V_WRITELOCK_TRUE, then we
1515 * may not have accurate after attrs, so check if
1516 * we have both attributes, they have a non-zero va_seq, and
1517 * va_seq has changed by exactly one,
1518 * if not, turn off the before attr.
1519 */
1520 if (rwlock_ret != V_WRITELOCK_TRUE) {
1521 if (bvap == NULL || avap == NULL ||
1522 bvap->va_seq == 0 || avap->va_seq == 0 ||
1523 avap->va_seq != (bvap->va_seq + 1)) {
1524 bvap = NULL;
1525 }
1526 }
1527
1528 resp->status = NFS3_OK;
1529 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1530 resp->resok.count = args->count - uio.uio_resid;
1531 resp->resok.committed = args->stable;
1532 resp->resok.verf = ns->write3verf;
1533 goto out;
1534
1535 err:
1536 if (curthread->t_flag & T_WOULDBLOCK) {
1537 curthread->t_flag &= ~T_WOULDBLOCK;
1538 resp->status = NFS3ERR_JUKEBOX;
1539 } else
1540 resp->status = puterrno3(error);
1541 err1:
1542 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1543 out:
1544 DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1545 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1546 WRITE3res *, resp);
1547
1548 if (vp != NULL) {
1549 if (rwlock_ret != -1)
1550 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1551 if (in_crit)
1552 nbl_end_crit(vp);
1553 VN_RELE(vp);
1554 }
1555 }
1556
1557 void *
1558 rfs3_write_getfh(WRITE3args *args)
1559 {
1560
1561 return (&args->file);
1562 }
1563
1564 void
1565 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1566 struct svc_req *req, cred_t *cr, bool_t ro)
1571 vnode_t *tvp = NULL;
1572 vnode_t *dvp;
1573 struct vattr *vap;
1574 struct vattr va;
1575 struct vattr *dbvap;
1576 struct vattr dbva;
1577 struct vattr *davap;
1578 struct vattr dava;
1579 enum vcexcl excl;
1580 nfstime3 *mtime;
1581 len_t reqsize;
1582 bool_t trunc;
1583 struct sockaddr *ca;
1584 char *name = NULL;
1585
1586 dbvap = NULL;
1587 davap = NULL;
1588
1589 dvp = nfs3_fhtovp(&args->where.dir, exi);
1590
1591 DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1592 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1593 CREATE3args *, args);
1594
1595 if (dvp == NULL) {
1596 error = ESTALE;
1597 goto out;
1598 }
1599
1600 dbva.va_mask = AT_ALL;
1601 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1602 davap = dbvap;
1603
1604 if (args->where.name == nfs3nametoolong) {
1605 resp->status = NFS3ERR_NAMETOOLONG;
1606 goto out1;
1607 }
1608
1609 if (args->where.name == NULL || *(args->where.name) == '\0') {
1610 resp->status = NFS3ERR_ACCES;
1611 goto out1;
1612 }
1613
1872 else
1873 resp->resok.obj.handle_follows = TRUE;
1874
1875 /*
1876 * Force modified data and metadata out to stable storage.
1877 */
1878 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1879 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1880
1881 VN_RELE(vp);
1882 if (tvp != NULL) {
1883 if (in_crit)
1884 nbl_end_crit(tvp);
1885 VN_RELE(tvp);
1886 }
1887
1888 resp->status = NFS3_OK;
1889 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1890 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1891
1892 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1893 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1894 CREATE3res *, resp);
1895
1896 VN_RELE(dvp);
1897 return;
1898
1899 out:
1900 if (curthread->t_flag & T_WOULDBLOCK) {
1901 curthread->t_flag &= ~T_WOULDBLOCK;
1902 resp->status = NFS3ERR_JUKEBOX;
1903 } else
1904 resp->status = puterrno3(error);
1905 out1:
1906 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1907 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1908 CREATE3res *, resp);
1909
1910 if (name != NULL && name != args->where.name)
1911 kmem_free(name, MAXPATHLEN + 1);
1912
1913 if (tvp != NULL) {
1914 if (in_crit)
1915 nbl_end_crit(tvp);
1916 VN_RELE(tvp);
1917 }
1918 if (dvp != NULL)
1919 VN_RELE(dvp);
1920 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1921 }
1922
1923 void *
1924 rfs3_create_getfh(CREATE3args *args)
1925 {
1926
1927 return (&args->where.dir);
1928 }
1931 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1932 struct svc_req *req, cred_t *cr, bool_t ro)
1933 {
1934 int error;
1935 vnode_t *vp = NULL;
1936 vnode_t *dvp;
1937 struct vattr *vap;
1938 struct vattr va;
1939 struct vattr *dbvap;
1940 struct vattr dbva;
1941 struct vattr *davap;
1942 struct vattr dava;
1943 struct sockaddr *ca;
1944 char *name = NULL;
1945
1946 dbvap = NULL;
1947 davap = NULL;
1948
1949 dvp = nfs3_fhtovp(&args->where.dir, exi);
1950
1951 DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1952 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1953 MKDIR3args *, args);
1954
1955 if (dvp == NULL) {
1956 error = ESTALE;
1957 goto out;
1958 }
1959
1960 dbva.va_mask = AT_ALL;
1961 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1962 davap = dbvap;
1963
1964 if (args->where.name == nfs3nametoolong) {
1965 resp->status = NFS3ERR_NAMETOOLONG;
1966 goto out1;
1967 }
1968
1969 if (args->where.name == NULL || *(args->where.name) == '\0') {
1970 resp->status = NFS3ERR_ACCES;
1971 goto out1;
1972 }
1973
2032 error = makefh3(&resp->resok.obj.handle, vp, exi);
2033 if (error)
2034 resp->resok.obj.handle_follows = FALSE;
2035 else
2036 resp->resok.obj.handle_follows = TRUE;
2037
2038 va.va_mask = AT_ALL;
2039 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2040
2041 /*
2042 * Force modified data and metadata out to stable storage.
2043 */
2044 (void) VOP_FSYNC(vp, 0, cr, NULL);
2045
2046 VN_RELE(vp);
2047
2048 resp->status = NFS3_OK;
2049 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2050 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2051
2052 DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2053 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2054 MKDIR3res *, resp);
2055 VN_RELE(dvp);
2056
2057 return;
2058
2059 out:
2060 if (curthread->t_flag & T_WOULDBLOCK) {
2061 curthread->t_flag &= ~T_WOULDBLOCK;
2062 resp->status = NFS3ERR_JUKEBOX;
2063 } else
2064 resp->status = puterrno3(error);
2065 out1:
2066 DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2067 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2068 MKDIR3res *, resp);
2069 if (dvp != NULL)
2070 VN_RELE(dvp);
2071 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2072 }
2073
2074 void *
2075 rfs3_mkdir_getfh(MKDIR3args *args)
2076 {
2077
2078 return (&args->where.dir);
2079 }
2080
2081 void
2082 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2083 struct svc_req *req, cred_t *cr, bool_t ro)
2084 {
2085 int error;
2086 vnode_t *vp;
2087 vnode_t *dvp;
2088 struct vattr *vap;
2089 struct vattr va;
2090 struct vattr *dbvap;
2091 struct vattr dbva;
2092 struct vattr *davap;
2093 struct vattr dava;
2094 struct sockaddr *ca;
2095 char *name = NULL;
2096 char *symdata = NULL;
2097
2098 dbvap = NULL;
2099 davap = NULL;
2100
2101 dvp = nfs3_fhtovp(&args->where.dir, exi);
2102
2103 DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2104 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2105 SYMLINK3args *, args);
2106
2107 if (dvp == NULL) {
2108 error = ESTALE;
2109 goto err;
2110 }
2111
2112 dbva.va_mask = AT_ALL;
2113 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2114 davap = dbvap;
2115
2116 if (args->where.name == nfs3nametoolong) {
2117 resp->status = NFS3ERR_NAMETOOLONG;
2118 goto err1;
2119 }
2120
2121 if (args->where.name == NULL || *(args->where.name) == '\0') {
2122 resp->status = NFS3ERR_ACCES;
2123 goto err1;
2124 }
2125
2222 VN_RELE(vp);
2223
2224 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2225 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2226 goto out;
2227
2228 err:
2229 if (curthread->t_flag & T_WOULDBLOCK) {
2230 curthread->t_flag &= ~T_WOULDBLOCK;
2231 resp->status = NFS3ERR_JUKEBOX;
2232 } else
2233 resp->status = puterrno3(error);
2234 err1:
2235 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2236 out:
2237 if (name != NULL && name != args->where.name)
2238 kmem_free(name, MAXPATHLEN + 1);
2239 if (symdata != NULL && symdata != args->symlink.symlink_data)
2240 kmem_free(symdata, MAXPATHLEN + 1);
2241
2242 DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2243 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2244 SYMLINK3res *, resp);
2245
2246 if (dvp != NULL)
2247 VN_RELE(dvp);
2248 }
2249
2250 void *
2251 rfs3_symlink_getfh(SYMLINK3args *args)
2252 {
2253
2254 return (&args->where.dir);
2255 }
2256
2257 void
2258 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2259 struct svc_req *req, cred_t *cr, bool_t ro)
2260 {
2261 int error;
2262 vnode_t *vp;
2263 vnode_t *realvp;
2264 vnode_t *dvp;
2265 struct vattr *vap;
2266 struct vattr va;
2267 struct vattr *dbvap;
2268 struct vattr dbva;
2269 struct vattr *davap;
2270 struct vattr dava;
2271 int mode;
2272 enum vcexcl excl;
2273 struct sockaddr *ca;
2274 char *name = NULL;
2275
2276 dbvap = NULL;
2277 davap = NULL;
2278
2279 dvp = nfs3_fhtovp(&args->where.dir, exi);
2280
2281 DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2282 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2283 MKNOD3args *, args);
2284
2285 if (dvp == NULL) {
2286 error = ESTALE;
2287 goto out;
2288 }
2289
2290 dbva.va_mask = AT_ALL;
2291 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2292 davap = dbvap;
2293
2294 if (args->where.name == nfs3nametoolong) {
2295 resp->status = NFS3ERR_NAMETOOLONG;
2296 goto out1;
2297 }
2298
2299 if (args->where.name == NULL || *(args->where.name) == '\0') {
2300 resp->status = NFS3ERR_ACCES;
2301 goto out1;
2302 }
2303
2409 else
2410 resp->resok.obj.handle_follows = TRUE;
2411
2412 va.va_mask = AT_ALL;
2413 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2414
2415 /*
2416 * Force modified metadata out to stable storage.
2417 *
2418 * if a underlying vp exists, pass it to VOP_FSYNC
2419 */
2420 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2421 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2422 else
2423 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2424
2425 VN_RELE(vp);
2426
2427 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2428 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2429 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2430 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2431 MKNOD3res *, resp);
2432 VN_RELE(dvp);
2433 return;
2434
2435 out:
2436 if (curthread->t_flag & T_WOULDBLOCK) {
2437 curthread->t_flag &= ~T_WOULDBLOCK;
2438 resp->status = NFS3ERR_JUKEBOX;
2439 } else
2440 resp->status = puterrno3(error);
2441 out1:
2442 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2443 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2444 MKNOD3res *, resp);
2445 if (dvp != NULL)
2446 VN_RELE(dvp);
2447 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2448 }
2449
2450 void *
2451 rfs3_mknod_getfh(MKNOD3args *args)
2452 {
2453
2454 return (&args->where.dir);
2455 }
2456
2457 void
2458 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2459 struct svc_req *req, cred_t *cr, bool_t ro)
2460 {
2461 int error = 0;
2462 vnode_t *vp;
2463 struct vattr *bvap;
2464 struct vattr bva;
2465 struct vattr *avap;
2466 struct vattr ava;
2467 vnode_t *targvp = NULL;
2468 struct sockaddr *ca;
2469 char *name = NULL;
2470
2471 bvap = NULL;
2472 avap = NULL;
2473
2474 vp = nfs3_fhtovp(&args->object.dir, exi);
2475
2476 DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2477 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2478 REMOVE3args *, args);
2479
2480 if (vp == NULL) {
2481 error = ESTALE;
2482 goto err;
2483 }
2484
2485 bva.va_mask = AT_ALL;
2486 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2487 avap = bvap;
2488
2489 if (vp->v_type != VDIR) {
2490 resp->status = NFS3ERR_NOTDIR;
2491 goto err1;
2492 }
2493
2494 if (args->object.name == nfs3nametoolong) {
2495 resp->status = NFS3ERR_NAMETOOLONG;
2496 goto err1;
2497 }
2498
2566 * Force modified data and metadata out to stable storage.
2567 */
2568 (void) VOP_FSYNC(vp, 0, cr, NULL);
2569
2570 if (error)
2571 goto err;
2572
2573 resp->status = NFS3_OK;
2574 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2575 goto out;
2576
2577 err:
2578 if (curthread->t_flag & T_WOULDBLOCK) {
2579 curthread->t_flag &= ~T_WOULDBLOCK;
2580 resp->status = NFS3ERR_JUKEBOX;
2581 } else
2582 resp->status = puterrno3(error);
2583 err1:
2584 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2585 out:
2586 DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2587 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2588 REMOVE3res *, resp);
2589
2590 if (name != NULL && name != args->object.name)
2591 kmem_free(name, MAXPATHLEN + 1);
2592
2593 if (vp != NULL)
2594 VN_RELE(vp);
2595 }
2596
2597 void *
2598 rfs3_remove_getfh(REMOVE3args *args)
2599 {
2600
2601 return (&args->object.dir);
2602 }
2603
2604 void
2605 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2606 struct svc_req *req, cred_t *cr, bool_t ro)
2607 {
2608 int error;
2609 vnode_t *vp;
2610 struct vattr *bvap;
2611 struct vattr bva;
2612 struct vattr *avap;
2613 struct vattr ava;
2614 struct sockaddr *ca;
2615 char *name = NULL;
2616
2617 bvap = NULL;
2618 avap = NULL;
2619
2620 vp = nfs3_fhtovp(&args->object.dir, exi);
2621
2622 DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2623 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2624 RMDIR3args *, args);
2625
2626 if (vp == NULL) {
2627 error = ESTALE;
2628 goto err;
2629 }
2630
2631 bva.va_mask = AT_ALL;
2632 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2633 avap = bvap;
2634
2635 if (vp->v_type != VDIR) {
2636 resp->status = NFS3ERR_NOTDIR;
2637 goto err1;
2638 }
2639
2640 if (args->object.name == nfs3nametoolong) {
2641 resp->status = NFS3ERR_NAMETOOLONG;
2642 goto err1;
2643 }
2644
2660 "got client label from request(1)", struct svc_req *, req);
2661
2662 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2663 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2664 exi)) {
2665 resp->status = NFS3ERR_ACCES;
2666 goto err1;
2667 }
2668 }
2669 }
2670
2671 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2672 name = nfscmd_convname(ca, exi, args->object.name,
2673 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2674
2675 if (name == NULL) {
2676 resp->status = NFS3ERR_INVAL;
2677 goto err1;
2678 }
2679
2680 ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
2681 error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2682
2683 if (name != args->object.name)
2684 kmem_free(name, MAXPATHLEN + 1);
2685
2686 ava.va_mask = AT_ALL;
2687 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2688
2689 /*
2690 * Force modified data and metadata out to stable storage.
2691 */
2692 (void) VOP_FSYNC(vp, 0, cr, NULL);
2693
2694 if (error) {
2695 /*
2696 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2697 * if the directory is not empty. A System V NFS server
2698 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2699 * over the wire.
2700 */
2701 if (error == EEXIST)
2702 error = ENOTEMPTY;
2703 goto err;
2704 }
2705
2706 resp->status = NFS3_OK;
2707 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2708 goto out;
2709
2710 err:
2711 if (curthread->t_flag & T_WOULDBLOCK) {
2712 curthread->t_flag &= ~T_WOULDBLOCK;
2713 resp->status = NFS3ERR_JUKEBOX;
2714 } else
2715 resp->status = puterrno3(error);
2716 err1:
2717 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2718 out:
2719 DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2720 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2721 RMDIR3res *, resp);
2722 if (vp != NULL)
2723 VN_RELE(vp);
2724
2725 }
2726
2727 void *
2728 rfs3_rmdir_getfh(RMDIR3args *args)
2729 {
2730
2731 return (&args->object.dir);
2732 }
2733
2734 void
2735 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2736 struct svc_req *req, cred_t *cr, bool_t ro)
2737 {
2738 int error = 0;
2739 vnode_t *fvp;
2740 vnode_t *tvp;
2741 vnode_t *targvp;
2746 struct vattr *tbvap;
2747 struct vattr tbva;
2748 struct vattr *tavap;
2749 struct vattr tava;
2750 nfs_fh3 *fh3;
2751 struct exportinfo *to_exi;
2752 vnode_t *srcvp = NULL;
2753 bslabel_t *clabel;
2754 struct sockaddr *ca;
2755 char *name = NULL;
2756 char *toname = NULL;
2757
2758 fbvap = NULL;
2759 favap = NULL;
2760 tbvap = NULL;
2761 tavap = NULL;
2762 tvp = NULL;
2763
2764 fvp = nfs3_fhtovp(&args->from.dir, exi);
2765
2766 DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2767 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2768 RENAME3args *, args);
2769
2770 if (fvp == NULL) {
2771 error = ESTALE;
2772 goto err;
2773 }
2774
2775 if (is_system_labeled()) {
2776 clabel = req->rq_label;
2777 ASSERT(clabel != NULL);
2778 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2779 "got client label from request(1)", struct svc_req *, req);
2780
2781 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2782 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2783 exi)) {
2784 resp->status = NFS3ERR_ACCES;
2785 goto err1;
2786 }
2787 }
2788 }
2865 /*
2866 * Check for a conflict with a non-blocking mandatory share
2867 * reservation or V4 delegations.
2868 */
2869 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2870 NULL, cr, NULL, NULL, NULL);
2871 if (error != 0)
2872 goto err;
2873
2874 /*
2875 * If we rename a delegated file we should recall the
2876 * delegation, since future opens should fail or would
2877 * refer to a new file.
2878 */
2879 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2880 resp->status = NFS3ERR_JUKEBOX;
2881 goto err1;
2882 }
2883
2884 /*
2885 * Check for renaming over a delegated file. Check nfs4_deleg_policy
2886 * first to avoid VOP_LOOKUP if possible.
2887 */
2888 if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2889 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2890 NULL, NULL, NULL) == 0) {
2891
2892 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2893 VN_RELE(targvp);
2894 resp->status = NFS3ERR_JUKEBOX;
2895 goto err1;
2896 }
2897 VN_RELE(targvp);
2898 }
2899
2900 if (!nbl_need_check(srcvp)) {
2901 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2902 } else {
2903 nbl_start_crit(srcvp, RW_READER);
2904 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2905 error = EACCES;
2906 else
2907 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2908 nbl_end_crit(srcvp);
2932 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2933 goto out;
2934
2935 err:
2936 if (curthread->t_flag & T_WOULDBLOCK) {
2937 curthread->t_flag &= ~T_WOULDBLOCK;
2938 resp->status = NFS3ERR_JUKEBOX;
2939 } else {
2940 resp->status = puterrno3(error);
2941 }
2942 err1:
2943 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2944 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2945
2946 out:
2947 if (name != NULL && name != args->from.name)
2948 kmem_free(name, MAXPATHLEN + 1);
2949 if (toname != NULL && toname != args->to.name)
2950 kmem_free(toname, MAXPATHLEN + 1);
2951
2952 DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2953 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2954 RENAME3res *, resp);
2955 if (fvp != NULL)
2956 VN_RELE(fvp);
2957 if (tvp != NULL)
2958 VN_RELE(tvp);
2959 }
2960
2961 void *
2962 rfs3_rename_getfh(RENAME3args *args)
2963 {
2964
2965 return (&args->from.dir);
2966 }
2967
2968 void
2969 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2970 struct svc_req *req, cred_t *cr, bool_t ro)
2971 {
2972 int error;
2973 vnode_t *vp;
2974 vnode_t *dvp;
2975 struct vattr *vap;
2976 struct vattr va;
2977 struct vattr *bvap;
2978 struct vattr bva;
2979 struct vattr *avap;
2980 struct vattr ava;
2981 nfs_fh3 *fh3;
2982 struct exportinfo *to_exi;
2983 bslabel_t *clabel;
2984 struct sockaddr *ca;
2985 char *name = NULL;
2986
2987 vap = NULL;
2988 bvap = NULL;
2989 avap = NULL;
2990 dvp = NULL;
2991
2992 vp = nfs3_fhtovp(&args->file, exi);
2993
2994 DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2995 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2996 LINK3args *, args);
2997
2998 if (vp == NULL) {
2999 error = ESTALE;
3000 goto out;
3001 }
3002
3003 va.va_mask = AT_ALL;
3004 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3005
3006 fh3 = &args->link.dir;
3007 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3008 if (to_exi == NULL) {
3009 resp->status = NFS3ERR_ACCES;
3010 goto out1;
3011 }
3012 exi_rele(to_exi);
3013
3014 if (to_exi != exi) {
3015 resp->status = NFS3ERR_XDEV;
3016 goto out1;
3088 va.va_mask = AT_ALL;
3089 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3090 ava.va_mask = AT_ALL;
3091 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3092
3093 /*
3094 * Force modified data and metadata out to stable storage.
3095 */
3096 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3097 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3098
3099 if (error)
3100 goto out;
3101
3102 VN_RELE(dvp);
3103
3104 resp->status = NFS3_OK;
3105 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3106 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3107
3108 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3109 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3110 LINK3res *, resp);
3111
3112 VN_RELE(vp);
3113
3114 return;
3115
3116 out:
3117 if (curthread->t_flag & T_WOULDBLOCK) {
3118 curthread->t_flag &= ~T_WOULDBLOCK;
3119 resp->status = NFS3ERR_JUKEBOX;
3120 } else
3121 resp->status = puterrno3(error);
3122 out1:
3123 if (name != NULL && name != args->link.name)
3124 kmem_free(name, MAXPATHLEN + 1);
3125
3126 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3127 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3128 LINK3res *, resp);
3129
3130 if (vp != NULL)
3131 VN_RELE(vp);
3132 if (dvp != NULL)
3133 VN_RELE(dvp);
3134 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3135 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3136 }
3137
3138 void *
3139 rfs3_link_getfh(LINK3args *args)
3140 {
3141
3142 return (&args->file);
3143 }
3144
3145 /*
3146 * This macro defines the size of a response which contains attribute
3147 * information and one directory entry (whose length is specified by
3148 * the macro parameter). If the incoming request is larger than this,
3176 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3177 struct svc_req *req, cred_t *cr, bool_t ro)
3178 {
3179 int error;
3180 vnode_t *vp;
3181 struct vattr *vap;
3182 struct vattr va;
3183 struct iovec iov;
3184 struct uio uio;
3185 char *data;
3186 int iseof;
3187 int bufsize;
3188 int namlen;
3189 uint_t count;
3190 struct sockaddr *ca;
3191
3192 vap = NULL;
3193
3194 vp = nfs3_fhtovp(&args->dir, exi);
3195
3196 DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3197 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3198 READDIR3args *, args);
3199
3200 if (vp == NULL) {
3201 error = ESTALE;
3202 goto out;
3203 }
3204
3205 if (is_system_labeled()) {
3206 bslabel_t *clabel = req->rq_label;
3207
3208 ASSERT(clabel != NULL);
3209 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3210 "got client label from request(1)", struct svc_req *, req);
3211
3212 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3213 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3214 exi)) {
3215 resp->status = NFS3ERR_ACCES;
3216 goto out1;
3217 }
3218 }
3342 /*
3343 * Don't do this. It causes local disk writes when just
3344 * reading the file and the overhead is deemed larger
3345 * than the benefit.
3346 */
3347 /*
3348 * Force modified metadata out to stable storage.
3349 */
3350 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3351 #endif
3352
3353 resp->status = NFS3_OK;
3354 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3355 resp->resok.cookieverf = 0;
3356 resp->resok.reply.entries = (entry3 *)data;
3357 resp->resok.reply.eof = iseof;
3358 resp->resok.size = count - uio.uio_resid;
3359 resp->resok.count = args->count;
3360 resp->resok.freecount = count;
3361
3362 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3363 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3364 READDIR3res *, resp);
3365
3366 VN_RELE(vp);
3367
3368 return;
3369
3370 out:
3371 if (curthread->t_flag & T_WOULDBLOCK) {
3372 curthread->t_flag &= ~T_WOULDBLOCK;
3373 resp->status = NFS3ERR_JUKEBOX;
3374 } else
3375 resp->status = puterrno3(error);
3376 out1:
3377 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3378
3379 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3380 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3381 READDIR3res *, resp);
3382
3383 if (vp != NULL) {
3384 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3385 VN_RELE(vp);
3386 }
3387 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3388 }
3389
3390 void *
3391 rfs3_readdir_getfh(READDIR3args *args)
3392 {
3393
3394 return (&args->dir);
3395 }
3396
3397 void
3398 rfs3_readdir_free(READDIR3res *resp)
3399 {
3400
3401 if (resp->status == NFS3_OK)
3402 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3452 struct vattr nva;
3453 entryplus3_info *infop = NULL;
3454 int size = 0;
3455 int nents = 0;
3456 int bufsize = 0;
3457 int entrysize = 0;
3458 int tofit = 0;
3459 int rd_unit = rfs3_readdir_unit;
3460 int prev_len;
3461 int space_left;
3462 int i;
3463 uint_t *namlen = NULL;
3464 char *ndata = NULL;
3465 struct sockaddr *ca;
3466 size_t ret;
3467
3468 vap = NULL;
3469
3470 vp = nfs3_fhtovp(&args->dir, exi);
3471
3472 DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3473 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3474 READDIRPLUS3args *, args);
3475
3476 if (vp == NULL) {
3477 error = ESTALE;
3478 goto out;
3479 }
3480
3481 if (is_system_labeled()) {
3482 bslabel_t *clabel = req->rq_label;
3483
3484 ASSERT(clabel != NULL);
3485 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3486 char *, "got client label from request(1)",
3487 struct svc_req *, req);
3488
3489 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3490 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3491 exi)) {
3492 resp->status = NFS3ERR_ACCES;
3493 goto out1;
3494 }
3736 * reading the file and the overhead is deemed larger
3737 * than the benefit.
3738 */
3739 /*
3740 * Force modified metadata out to stable storage.
3741 */
3742 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3743 #endif
3744
3745 kmem_free(namlen, args->dircount);
3746
3747 resp->status = NFS3_OK;
3748 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3749 resp->resok.cookieverf = 0;
3750 resp->resok.reply.entries = (entryplus3 *)ndata;
3751 resp->resok.reply.eof = iseof;
3752 resp->resok.size = nents;
3753 resp->resok.count = args->dircount - ret;
3754 resp->resok.maxcount = args->maxcount;
3755
3756 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3757 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3758 READDIRPLUS3res *, resp);
3759
3760 VN_RELE(vp);
3761
3762 return;
3763
3764 out:
3765 if (curthread->t_flag & T_WOULDBLOCK) {
3766 curthread->t_flag &= ~T_WOULDBLOCK;
3767 resp->status = NFS3ERR_JUKEBOX;
3768 } else {
3769 resp->status = puterrno3(error);
3770 }
3771 out1:
3772 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3773
3774 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3775 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3776 READDIRPLUS3res *, resp);
3777
3778 if (vp != NULL) {
3779 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3780 VN_RELE(vp);
3781 }
3782
3783 if (namlen != NULL)
3784 kmem_free(namlen, args->dircount);
3785
3786 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3787 }
3788
3789 void *
3790 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3791 {
3792
3793 return (&args->dir);
3794 }
3795
3796 void
3797 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3802 kmem_free(resp->resok.infop,
3803 resp->resok.size * sizeof (struct entryplus3_info));
3804 }
3805 }
3806
3807 /* ARGSUSED */
3808 void
3809 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3810 struct svc_req *req, cred_t *cr, bool_t ro)
3811 {
3812 int error;
3813 vnode_t *vp;
3814 struct vattr *vap;
3815 struct vattr va;
3816 struct statvfs64 sb;
3817
3818 vap = NULL;
3819
3820 vp = nfs3_fhtovp(&args->fsroot, exi);
3821
3822 DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3823 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3824 FSSTAT3args *, args);
3825
3826 if (vp == NULL) {
3827 error = ESTALE;
3828 goto out;
3829 }
3830
3831 if (is_system_labeled()) {
3832 bslabel_t *clabel = req->rq_label;
3833
3834 ASSERT(clabel != NULL);
3835 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3836 "got client label from request(1)", struct svc_req *, req);
3837
3838 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3839 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3840 exi)) {
3841 resp->status = NFS3ERR_ACCES;
3842 goto out1;
3843 }
3844 }
3854
3855 resp->status = NFS3_OK;
3856 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3857 if (sb.f_blocks != (fsblkcnt64_t)-1)
3858 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3859 else
3860 resp->resok.tbytes = (size3)sb.f_blocks;
3861 if (sb.f_bfree != (fsblkcnt64_t)-1)
3862 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3863 else
3864 resp->resok.fbytes = (size3)sb.f_bfree;
3865 if (sb.f_bavail != (fsblkcnt64_t)-1)
3866 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3867 else
3868 resp->resok.abytes = (size3)sb.f_bavail;
3869 resp->resok.tfiles = (size3)sb.f_files;
3870 resp->resok.ffiles = (size3)sb.f_ffree;
3871 resp->resok.afiles = (size3)sb.f_favail;
3872 resp->resok.invarsec = 0;
3873
3874 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3875 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3876 FSSTAT3res *, resp);
3877 VN_RELE(vp);
3878
3879 return;
3880
3881 out:
3882 if (curthread->t_flag & T_WOULDBLOCK) {
3883 curthread->t_flag &= ~T_WOULDBLOCK;
3884 resp->status = NFS3ERR_JUKEBOX;
3885 } else
3886 resp->status = puterrno3(error);
3887 out1:
3888 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3889 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3890 FSSTAT3res *, resp);
3891
3892 if (vp != NULL)
3893 VN_RELE(vp);
3894 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3895 }
3896
3897 void *
3898 rfs3_fsstat_getfh(FSSTAT3args *args)
3899 {
3900
3901 return (&args->fsroot);
3902 }
3903
3904 /* ARGSUSED */
3905 void
3906 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3907 struct svc_req *req, cred_t *cr, bool_t ro)
3908 {
3909 vnode_t *vp;
3910 struct vattr *vap;
3911 struct vattr va;
3912 uint32_t xfer_size;
3913 ulong_t l = 0;
3914 int error;
3915
3916 vp = nfs3_fhtovp(&args->fsroot, exi);
3917
3918 DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3919 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3920 FSINFO3args *, args);
3921
3922 if (vp == NULL) {
3923 if (curthread->t_flag & T_WOULDBLOCK) {
3924 curthread->t_flag &= ~T_WOULDBLOCK;
3925 resp->status = NFS3ERR_JUKEBOX;
3926 } else
3927 resp->status = NFS3ERR_STALE;
3928 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3929 goto out;
3930 }
3931
3932 if (is_system_labeled()) {
3933 bslabel_t *clabel = req->rq_label;
3934
3935 ASSERT(clabel != NULL);
3936 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3937 "got client label from request(1)", struct svc_req *, req);
3938
3939 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3940 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3974 /*
3975 * If the underlying file system does not support _PC_FILESIZEBITS,
3976 * return a reasonable default. Note that error code on VOP_PATHCONF
3977 * will be 0, even if the underlying file system does not support
3978 * _PC_FILESIZEBITS.
3979 */
3980 if (l == (ulong_t)-1) {
3981 resp->resok.maxfilesize = MAXOFF32_T;
3982 } else {
3983 if (l >= (sizeof (uint64_t) * 8))
3984 resp->resok.maxfilesize = INT64_MAX;
3985 else
3986 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3987 }
3988
3989 resp->resok.time_delta.seconds = 0;
3990 resp->resok.time_delta.nseconds = 1000;
3991 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3992 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3993
3994 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3995 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3996 FSINFO3res *, resp);
3997
3998 VN_RELE(vp);
3999
4000 return;
4001
4002 out:
4003 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
4004 cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
4005 FSINFO3res *, resp);
4006 if (vp != NULL)
4007 VN_RELE(vp);
4008 }
4009
4010 void *
4011 rfs3_fsinfo_getfh(FSINFO3args *args)
4012 {
4013 return (&args->fsroot);
4014 }
4015
4016 /* ARGSUSED */
4017 void
4018 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
4019 struct svc_req *req, cred_t *cr, bool_t ro)
4020 {
4021 int error;
4022 vnode_t *vp;
4023 struct vattr *vap;
4024 struct vattr va;
4025 ulong_t val;
4026
4027 vap = NULL;
4028
4029 vp = nfs3_fhtovp(&args->object, exi);
4030
4031 DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4032 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4033 PATHCONF3args *, args);
4034
4035 if (vp == NULL) {
4036 error = ESTALE;
4037 goto out;
4038 }
4039
4040 if (is_system_labeled()) {
4041 bslabel_t *clabel = req->rq_label;
4042
4043 ASSERT(clabel != NULL);
4044 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4045 "got client label from request(1)", struct svc_req *, req);
4046
4047 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4048 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4049 exi)) {
4050 resp->status = NFS3ERR_ACCES;
4051 goto out1;
4052 }
4053 }
4069 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4070 if (error)
4071 goto out;
4072 if (val == 1)
4073 resp->resok.info.no_trunc = TRUE;
4074 else
4075 resp->resok.info.no_trunc = FALSE;
4076
4077 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4078 if (error)
4079 goto out;
4080 if (val == 1)
4081 resp->resok.info.chown_restricted = TRUE;
4082 else
4083 resp->resok.info.chown_restricted = FALSE;
4084
4085 resp->status = NFS3_OK;
4086 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4087 resp->resok.info.case_insensitive = FALSE;
4088 resp->resok.info.case_preserving = TRUE;
4089 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4090 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4091 PATHCONF3res *, resp);
4092 VN_RELE(vp);
4093 return;
4094
4095 out:
4096 if (curthread->t_flag & T_WOULDBLOCK) {
4097 curthread->t_flag &= ~T_WOULDBLOCK;
4098 resp->status = NFS3ERR_JUKEBOX;
4099 } else
4100 resp->status = puterrno3(error);
4101 out1:
4102 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4103 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4104 PATHCONF3res *, resp);
4105 if (vp != NULL)
4106 VN_RELE(vp);
4107 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4108 }
4109
4110 void *
4111 rfs3_pathconf_getfh(PATHCONF3args *args)
4112 {
4113
4114 return (&args->object);
4115 }
4116
4117 void
4118 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4119 struct svc_req *req, cred_t *cr, bool_t ro)
4120 {
4121 nfs3_srv_t *ns;
4122 int error;
4123 vnode_t *vp;
4124 struct vattr *bvap;
4125 struct vattr bva;
4126 struct vattr *avap;
4127 struct vattr ava;
4128
4129 bvap = NULL;
4130 avap = NULL;
4131
4132 vp = nfs3_fhtovp(&args->file, exi);
4133
4134 DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4135 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4136 COMMIT3args *, args);
4137
4138 if (vp == NULL) {
4139 error = ESTALE;
4140 goto out;
4141 }
4142
4143 ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
4144 ns = nfs3_get_srv();
4145 bva.va_mask = AT_ALL;
4146 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4147
4148 /*
4149 * If we can't get the attributes, then we can't do the
4150 * right access checking. So, we'll fail the request.
4151 */
4152 if (error)
4153 goto out;
4154
4155 bvap = &bva;
4156
4157 if (rdonly(ro, vp)) {
4158 resp->status = NFS3ERR_ROFS;
4159 goto out1;
4160 }
4161
4162 if (vp->v_type != VREG) {
4163 resp->status = NFS3ERR_INVAL;
4164 goto out1;
4177 resp->status = NFS3ERR_ACCES;
4178 goto out1;
4179 }
4180 }
4181 }
4182
4183 if (crgetuid(cr) != bva.va_uid &&
4184 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4185 goto out;
4186
4187 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4188
4189 ava.va_mask = AT_ALL;
4190 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4191
4192 if (error)
4193 goto out;
4194
4195 resp->status = NFS3_OK;
4196 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4197 resp->resok.verf = ns->write3verf;
4198
4199 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4200 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4201 COMMIT3res *, resp);
4202
4203 VN_RELE(vp);
4204
4205 return;
4206
4207 out:
4208 if (curthread->t_flag & T_WOULDBLOCK) {
4209 curthread->t_flag &= ~T_WOULDBLOCK;
4210 resp->status = NFS3ERR_JUKEBOX;
4211 } else
4212 resp->status = puterrno3(error);
4213 out1:
4214 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4215 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4216 COMMIT3res *, resp);
4217
4218 if (vp != NULL)
4219 VN_RELE(vp);
4220 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4221 }
4222
4223 void *
4224 rfs3_commit_getfh(COMMIT3args *args)
4225 {
4226
4227 return (&args->file);
4228 }
4229
4230 static int
4231 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4232 {
4233
4234 vap->va_mask = 0;
4235
4236 if (sap->mode.set_it) {
4274 /* check time validity */
4275 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4276 return (EOVERFLOW);
4277 #endif
4278 /*
4279 * nfs protocol defines times as unsigned so don't extend sign,
4280 * unless sysadmin set nfs_allow_preepoch_time.
4281 */
4282 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4283 sap->mtime.mtime.seconds);
4284 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4285 vap->va_mask |= AT_MTIME;
4286 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4287 gethrestime(&vap->va_mtime);
4288 vap->va_mask |= AT_MTIME;
4289 }
4290
4291 return (0);
4292 }
4293
4294 static const ftype3 vt_to_nf3[] = {
4295 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4296 };
4297
4298 static int
4299 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4300 {
4301
4302 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4303 /* Return error if time or size overflow */
4304 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4305 return (EOVERFLOW);
4306 }
4307 fap->type = vt_to_nf3[vap->va_type];
4308 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4309 fap->nlink = (uint32)vap->va_nlink;
4310 if (vap->va_uid == UID_NOBODY)
4311 fap->uid = (uid3)NFS_UID_NOBODY;
4312 else
4313 fap->uid = (uid3)vap->va_uid;
4314 if (vap->va_gid == GID_NOBODY)
4356 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4357 poap->attributes = TRUE;
4358 } else
4359 poap->attributes = FALSE;
4360 }
4361
4362 void
4363 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4364 {
4365
4366 /* don't return attrs if time overflow */
4367 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4368 poap->attributes = TRUE;
4369 } else
4370 poap->attributes = FALSE;
4371 }
4372
4373 static void
4374 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4375 {
4376 vattr_to_pre_op_attr(bvap, &wccp->before);
4377 vattr_to_post_op_attr(avap, &wccp->after);
4378 }
4379
4380 static int
4381 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4382 {
4383 struct clist *wcl;
4384 int wlist_len;
4385 count3 count = rok->count;
4386
4387 wcl = args->wlist;
4388 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4389 return (FALSE);
4390
4391 wcl = args->wlist;
4392 rok->wlist_len = wlist_len;
4393 rok->wlist = wcl;
4394 return (TRUE);
4395 }
4396
4397 void
4398 rfs3_srv_zone_init(nfs_globals_t *ng)
4399 {
4400 nfs3_srv_t *ns;
4401 struct rfs3_verf_overlay {
4402 uint_t id; /* a "unique" identifier */
4403 int ts; /* a unique timestamp */
4404 } *verfp;
4405 timestruc_t now;
4406
4407 ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4408
4409 /*
4410 * The following algorithm attempts to find a unique verifier
4411 * to be used as the write verifier returned from the server
4412 * to the client. It is important that this verifier change
4413 * whenever the server reboots. Of secondary importance, it
4414 * is important for the verifier to be unique between two
4415 * different servers.
4416 *
4417 * Thus, an attempt is made to use the system hostid and the
4418 * current time in seconds when the nfssrv kernel module is
4419 * loaded. It is assumed that an NFS server will not be able
4420 * to boot and then to reboot in less than a second. If the
4421 * hostid has not been set, then the current high resolution
4422 * time is used. This will ensure different verifiers each
4423 * time the server reboots and minimize the chances that two
4424 * different servers will have the same verifier.
4425 */
4426
4427 #ifndef lint
4428 /*
4429 * We ASSERT that this constant logic expression is
4430 * always true because in the past, it wasn't.
4431 */
4432 ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
4433 #endif
4434
4435 gethrestime(&now);
4436 verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4437 verfp->ts = (int)now.tv_sec;
4438 verfp->id = zone_get_hostid(NULL);
4439
4440 if (verfp->id == 0)
4441 verfp->id = (uint_t)now.tv_nsec;
4442
4443 ng->nfs3_srv = ns;
4444 }
4445
4446 void
4447 rfs3_srv_zone_fini(nfs_globals_t *ng)
4448 {
4449 nfs3_srv_t *ns = ng->nfs3_srv;
4450
4451 ng->nfs3_srv = NULL;
4452
4453 kmem_free(ns, sizeof (*ns));
4454 }
4455
4456 void
4457 rfs3_srvrinit(void)
4458 {
4459 nfs3_srv_caller_id = fs_new_caller_id();
4460 }
4461
4462 void
4463 rfs3_srvrfini(void)
4464 {
4465 /* Nothing to do */
4466 }
|