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)
369 {
370 int error;
371 vnode_t *vp;
372 vnode_t *dvp;
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 /*
386 * Allow lookups from the root - the default
387 * location of the public filehandle.
388 */
389 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
390 dvp = rootdir;
391 VN_HOLD(dvp);
392
393 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
394 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
395 } else {
396 dvp = nfs3_fhtovp(&args->what.dir, exi);
397
398 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
399 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
400
401 if (dvp == NULL) {
402 error = ESTALE;
403 goto out;
404 }
405 }
406
407 dva.va_mask = AT_ALL;
408 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
409
410 if (args->what.name == nfs3nametoolong) {
411 resp->status = NFS3ERR_NAMETOOLONG;
412 goto out1;
413 }
414
415 if (args->what.name == NULL || *(args->what.name) == '\0') {
416 resp->status = NFS3ERR_ACCES;
417 goto out1;
418 }
419
420 fhp = &args->what.dir;
421 if (strcmp(args->what.name, "..") == 0 &&
422 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
423 resp->status = NFS3ERR_NOENT;
424 goto out1;
425 }
426
427 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
428 name = nfscmd_convname(ca, exi, args->what.name,
429 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
430
431 if (name == NULL) {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435
436 /*
437 * If the public filehandle is used then allow
438 * a multi-component lookup
439 */
440 if (PUBLIC_FH3(&args->what.dir)) {
441 publicfh_flag = TRUE;
442 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
443 &exi, &sec);
444 if (error && exi != NULL)
445 exi_rele(exi); /* See comment below Re: publicfh_flag */
446 /*
447 * Since WebNFS may bypass MOUNT, we need to ensure this
448 * request didn't come from an unlabeled admin_low client.
449 */
450 if (is_system_labeled() && error == 0) {
451 int addr_type;
452 void *ipaddr;
453 tsol_tpc_t *tp;
454
455 if (ca->sa_family == AF_INET) {
456 addr_type = IPV4_VERSION;
457 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
458 } else if (ca->sa_family == AF_INET6) {
459 addr_type = IPV6_VERSION;
460 ipaddr = &((struct sockaddr_in6 *)
461 ca)->sin6_addr;
462 }
463 tp = find_tpc(ipaddr, addr_type, B_FALSE);
464 if (tp == NULL || tp->tpc_tp.tp_doi !=
465 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
466 SUN_CIPSO) {
467 if (exi != NULL)
468 exi_rele(exi);
469 VN_RELE(vp);
470 error = EACCES;
471 }
472 if (tp != NULL)
473 TPC_RELE(tp);
474 }
475 } else {
476 error = VOP_LOOKUP(dvp, name, &vp,
477 NULL, 0, NULL, cr, NULL, NULL, NULL);
478 }
479
480 if (name != args->what.name)
481 kmem_free(name, MAXPATHLEN + 1);
482
483 if (is_system_labeled() && error == 0) {
484 bslabel_t *clabel = req->rq_label;
485
486 ASSERT(clabel != NULL);
487 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
488 "got client label from request(1)", struct svc_req *, req);
489
490 if (!blequal(&l_admin_low->tsl_label, clabel)) {
491 if (!do_rfs_label_check(clabel, dvp,
492 DOMINANCE_CHECK, exi)) {
493 if (publicfh_flag && exi != NULL)
494 exi_rele(exi);
495 VN_RELE(vp);
496 error = EACCES;
497 }
498 }
499 }
500
501 dva.va_mask = AT_ALL;
502 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
503
504 if (error)
505 goto out;
506
507 if (sec.sec_flags & SEC_QUERY) {
508 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
509 } else {
510 error = makefh3(&resp->resok.object, vp, exi);
511 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
512 auth_weak = TRUE;
513 }
514
515 /*
516 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
517 * and have obtained a new exportinfo in exi which needs to be
518 * released. Note that the original exportinfo pointed to by exi
519 * will be released by the caller, common_dispatch.
520 */
521 if (publicfh_flag)
522 exi_rele(exi);
523
524 if (error) {
525 VN_RELE(vp);
526 goto out;
527 }
528
529 va.va_mask = AT_ALL;
530 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
531
532 VN_RELE(vp);
533
534 resp->status = NFS3_OK;
535 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
536 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
537
538 /*
539 * If it's public fh, no 0x81, and client's flavor is
540 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
541 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
542 */
543 if (auth_weak)
544 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
545
546 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
547 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
548 VN_RELE(dvp);
549
550 return;
551
552 out:
553 if (curthread->t_flag & T_WOULDBLOCK) {
554 curthread->t_flag &= ~T_WOULDBLOCK;
555 resp->status = NFS3ERR_JUKEBOX;
556 } else
557 resp->status = puterrno3(error);
558 out1:
559 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
560 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
561
562 if (dvp != NULL)
563 VN_RELE(dvp);
564 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
565
566 }
567
568 void *
569 rfs3_lookup_getfh(LOOKUP3args *args)
570 {
571
572 return (&args->what.dir);
573 }
574
575 /* ARGSUSED */
576 void
577 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
578 struct svc_req *req, cred_t *cr, bool_t ro)
579 {
580 int error;
581 vnode_t *vp;
582 struct vattr *vap;
583 struct vattr va;
584 int checkwriteperm;
585 boolean_t dominant_label = B_FALSE;
586 boolean_t equal_label = B_FALSE;
587 boolean_t admin_low_client;
588
589 vap = NULL;
590
591 vp = nfs3_fhtovp(&args->object, exi);
592
593 DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
594 cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
595
596 if (vp == NULL) {
597 error = ESTALE;
598 goto out;
599 }
600
601 /*
602 * If the file system is exported read only, it is not appropriate
603 * to check write permissions for regular files and directories.
604 * Special files are interpreted by the client, so the underlying
605 * permissions are sent back to the client for interpretation.
606 */
607 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
608 checkwriteperm = 0;
609 else
610 checkwriteperm = 1;
611
612 /*
613 * We need the mode so that we can correctly determine access
614 * permissions relative to a mandatory lock file. Access to
684 equal_label)
685 resp->resok.access |= ACCESS3_DELETE;
686 }
687 if (args->access & ACCESS3_EXECUTE) {
688 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
689 if (error) {
690 if (curthread->t_flag & T_WOULDBLOCK)
691 goto out;
692 } else if (!MANDLOCK(vp, va.va_mode) &&
693 (!is_system_labeled() || admin_low_client ||
694 dominant_label))
695 resp->resok.access |= ACCESS3_EXECUTE;
696 }
697
698 va.va_mask = AT_ALL;
699 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
700
701 resp->status = NFS3_OK;
702 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
703
704 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
705 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
706
707 VN_RELE(vp);
708
709 return;
710
711 out:
712 if (curthread->t_flag & T_WOULDBLOCK) {
713 curthread->t_flag &= ~T_WOULDBLOCK;
714 resp->status = NFS3ERR_JUKEBOX;
715 } else
716 resp->status = puterrno3(error);
717 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
718 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
719 if (vp != NULL)
720 VN_RELE(vp);
721 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
722 }
723
724 void *
725 rfs3_access_getfh(ACCESS3args *args)
726 {
727
728 return (&args->object);
729 }
730
731 /* ARGSUSED */
732 void
733 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
734 struct svc_req *req, cred_t *cr, bool_t ro)
735 {
736 int error;
737 vnode_t *vp;
738 struct vattr *vap;
739 struct vattr va;
740 struct iovec iov;
741 struct uio uio;
742 char *data;
743 struct sockaddr *ca;
744 char *name = NULL;
745 int is_referral = 0;
746
747 vap = NULL;
748
749 vp = nfs3_fhtovp(&args->symlink, exi);
750
751 DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
752 cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
753
754 if (vp == NULL) {
755 error = ESTALE;
756 goto out;
757 }
758
759 va.va_mask = AT_ALL;
760 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
761 if (error)
762 goto out;
763
764 vap = &va;
765
766 /* We lied about the object type for a referral */
767 if (vn_is_nfs_reparse(vp, cr))
768 is_referral = 1;
769
770 if (vp->v_type != VLNK && !is_referral) {
771 resp->status = NFS3ERR_INVAL;
772 goto out1;
852 kmem_free(data, MAXPATHLEN + 1);
853 goto out;
854 }
855
856 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
857 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
858 MAXPATHLEN + 1);
859
860 if (name == NULL) {
861 /*
862 * Even though the conversion failed, we return
863 * something. We just don't translate it.
864 */
865 name = data;
866 }
867
868 resp->status = NFS3_OK;
869 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
870 resp->resok.data = name;
871
872 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
873 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
874 VN_RELE(vp);
875
876 if (name != data)
877 kmem_free(data, MAXPATHLEN + 1);
878
879 return;
880
881 out:
882 if (curthread->t_flag & T_WOULDBLOCK) {
883 curthread->t_flag &= ~T_WOULDBLOCK;
884 resp->status = NFS3ERR_JUKEBOX;
885 } else
886 resp->status = puterrno3(error);
887 out1:
888 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
889 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
890 if (vp != NULL)
891 VN_RELE(vp);
892 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
893 }
894
895 void *
896 rfs3_readlink_getfh(READLINK3args *args)
897 {
898
899 return (&args->symlink);
900 }
901
902 void
903 rfs3_readlink_free(READLINK3res *resp)
904 {
905
906 if (resp->status == NFS3_OK)
907 kmem_free(resp->resok.data, MAXPATHLEN + 1);
908 }
909
910 /*
911 * Server routine to handle read
912 * May handle RDMA data as well as mblks
913 */
914 /* ARGSUSED */
915 void
916 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
917 struct svc_req *req, cred_t *cr, bool_t ro)
918 {
919 int error;
920 vnode_t *vp;
921 struct vattr *vap;
922 struct vattr va;
923 struct iovec iov, *iovp = NULL;
924 int iovcnt;
925 struct uio uio;
926 u_offset_t offset;
927 mblk_t *mp = NULL;
928 int in_crit = 0;
929 int need_rwunlock = 0;
930 caller_context_t ct;
931 int rdma_used = 0;
932 int loaned_buffers;
933 struct uio *uiop;
934
935 vap = NULL;
936
937 vp = nfs3_fhtovp(&args->file, exi);
938
939 DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
940 cred_t *, cr, vnode_t *, vp, READ3args *, args);
941
942 if (vp == NULL) {
943 error = ESTALE;
944 goto out;
945 }
946
947 if (args->wlist) {
948 if (args->count > clist_len(args->wlist)) {
949 error = EINVAL;
950 goto out;
951 }
952 rdma_used = 1;
953 }
954
955 /* use loaned buffers for TCP */
956 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
957
958 if (is_system_labeled()) {
959 bslabel_t *clabel = req->rq_label;
960
961 ASSERT(clabel != NULL);
1175 resp->resok.eof = FALSE;
1176 resp->resok.data.data_len = resp->resok.count;
1177
1178 if (mp)
1179 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1180
1181 resp->resok.data.mp = mp;
1182 resp->resok.size = (uint_t)args->count;
1183
1184 if (rdma_used) {
1185 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1186 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1187 resp->status = NFS3ERR_INVAL;
1188 }
1189 } else {
1190 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1191 (resp->resok).wlist = NULL;
1192 }
1193
1194 done:
1195 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1196 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1197
1198 VN_RELE(vp);
1199
1200 if (iovp != NULL)
1201 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1202
1203 return;
1204
1205 out:
1206 if (curthread->t_flag & T_WOULDBLOCK) {
1207 curthread->t_flag &= ~T_WOULDBLOCK;
1208 resp->status = NFS3ERR_JUKEBOX;
1209 } else
1210 resp->status = puterrno3(error);
1211 out1:
1212 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1213 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1214
1215 if (vp != NULL) {
1216 if (need_rwunlock)
1217 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1218 if (in_crit)
1219 nbl_end_crit(vp);
1220 VN_RELE(vp);
1221 }
1222 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1223
1224 if (iovp != NULL)
1225 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1226 }
1227
1228 void
1229 rfs3_read_free(READ3res *resp)
1230 {
1231 mblk_t *mp;
1232
1233 if (resp->status == NFS3_OK) {
1234 mp = resp->resok.data.mp;
1235 if (mp != NULL)
1236 freemsg(mp);
1237 }
1238 }
1239
1240 void *
1241 rfs3_read_getfh(READ3args *args)
1242 {
1243
1244 return (&args->file);
1245 }
1246
1247 #define MAX_IOVECS 12
1248
1249 #ifdef DEBUG
1250 static int rfs3_write_hits = 0;
1251 static int rfs3_write_misses = 0;
1252 #endif
1253
1254 void
1255 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1256 struct svc_req *req, cred_t *cr, bool_t ro)
1257 {
1258 int error;
1259 vnode_t *vp;
1260 struct vattr *bvap = NULL;
1261 struct vattr bva;
1262 struct vattr *avap = NULL;
1263 struct vattr ava;
1264 u_offset_t rlimit;
1265 struct uio uio;
1266 struct iovec iov[MAX_IOVECS];
1267 mblk_t *m;
1268 struct iovec *iovp;
1269 int iovcnt;
1270 int ioflag;
1271 cred_t *savecred;
1272 int in_crit = 0;
1273 int rwlock_ret = -1;
1274 caller_context_t ct;
1275
1276 vp = nfs3_fhtovp(&args->file, exi);
1277
1278 DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1279 cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1280
1281 if (vp == NULL) {
1282 error = ESTALE;
1283 goto err;
1284 }
1285
1286 if (is_system_labeled()) {
1287 bslabel_t *clabel = req->rq_label;
1288
1289 ASSERT(clabel != NULL);
1290 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1291 "got client label from request(1)", struct svc_req *, req);
1292
1293 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1294 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1295 exi)) {
1296 resp->status = NFS3ERR_ACCES;
1297 goto err1;
1298 }
1299 }
1300 }
1301
1302 ct.cc_sysid = 0;
1303 ct.cc_pid = 0;
1304 ct.cc_caller_id = nfs3_srv_caller_id;
1305 ct.cc_flags = CC_DONTBLOCK;
1353
1354 if (vp->v_type != VREG) {
1355 resp->status = NFS3ERR_INVAL;
1356 goto err1;
1357 }
1358
1359 if (crgetuid(cr) != bva.va_uid &&
1360 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1361 goto err;
1362
1363 if (MANDLOCK(vp, bva.va_mode)) {
1364 resp->status = NFS3ERR_ACCES;
1365 goto err1;
1366 }
1367
1368 if (args->count == 0) {
1369 resp->status = NFS3_OK;
1370 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1371 resp->resok.count = 0;
1372 resp->resok.committed = args->stable;
1373 resp->resok.verf = write3verf;
1374 goto out;
1375 }
1376
1377 if (args->mblk != NULL) {
1378 iovcnt = 0;
1379 for (m = args->mblk; m != NULL; m = m->b_cont)
1380 iovcnt++;
1381 if (iovcnt <= MAX_IOVECS) {
1382 #ifdef DEBUG
1383 rfs3_write_hits++;
1384 #endif
1385 iovp = iov;
1386 } else {
1387 #ifdef DEBUG
1388 rfs3_write_misses++;
1389 #endif
1390 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1391 }
1392 mblk_to_iov(args->mblk, iovcnt, iovp);
1393
1455
1456 /*
1457 * If we were unable to get the V_WRITELOCK_TRUE, then we
1458 * may not have accurate after attrs, so check if
1459 * we have both attributes, they have a non-zero va_seq, and
1460 * va_seq has changed by exactly one,
1461 * if not, turn off the before attr.
1462 */
1463 if (rwlock_ret != V_WRITELOCK_TRUE) {
1464 if (bvap == NULL || avap == NULL ||
1465 bvap->va_seq == 0 || avap->va_seq == 0 ||
1466 avap->va_seq != (bvap->va_seq + 1)) {
1467 bvap = NULL;
1468 }
1469 }
1470
1471 resp->status = NFS3_OK;
1472 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1473 resp->resok.count = args->count - uio.uio_resid;
1474 resp->resok.committed = args->stable;
1475 resp->resok.verf = write3verf;
1476 goto out;
1477
1478 err:
1479 if (curthread->t_flag & T_WOULDBLOCK) {
1480 curthread->t_flag &= ~T_WOULDBLOCK;
1481 resp->status = NFS3ERR_JUKEBOX;
1482 } else
1483 resp->status = puterrno3(error);
1484 err1:
1485 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1486 out:
1487 DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1488 cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1489
1490 if (vp != NULL) {
1491 if (rwlock_ret != -1)
1492 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1493 if (in_crit)
1494 nbl_end_crit(vp);
1495 VN_RELE(vp);
1496 }
1497 }
1498
1499 void *
1500 rfs3_write_getfh(WRITE3args *args)
1501 {
1502
1503 return (&args->file);
1504 }
1505
1506 void
1507 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1508 struct svc_req *req, cred_t *cr, bool_t ro)
1509 {
1510 int error;
1511 int in_crit = 0;
1512 vnode_t *vp;
1513 vnode_t *tvp = NULL;
1514 vnode_t *dvp;
1515 struct vattr *vap;
1516 struct vattr va;
1517 struct vattr *dbvap;
1518 struct vattr dbva;
1519 struct vattr *davap;
1520 struct vattr dava;
1521 enum vcexcl excl;
1522 nfstime3 *mtime;
1523 len_t reqsize;
1524 bool_t trunc;
1525 struct sockaddr *ca;
1526 char *name = NULL;
1527
1528 dbvap = NULL;
1529 davap = NULL;
1530
1531 dvp = nfs3_fhtovp(&args->where.dir, exi);
1532
1533 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1534 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1535
1536 if (dvp == NULL) {
1537 error = ESTALE;
1538 goto out;
1539 }
1540
1541 dbva.va_mask = AT_ALL;
1542 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1543 davap = dbvap;
1544
1545 if (args->where.name == nfs3nametoolong) {
1546 resp->status = NFS3ERR_NAMETOOLONG;
1547 goto out1;
1548 }
1549
1550 if (args->where.name == NULL || *(args->where.name) == '\0') {
1551 resp->status = NFS3ERR_ACCES;
1552 goto out1;
1553 }
1554
1555 if (rdonly(ro, dvp)) {
1556 resp->status = NFS3ERR_ROFS;
1557 goto out1;
1558 }
1559
1560 if (is_system_labeled()) {
1561 bslabel_t *clabel = req->rq_label;
1562
1563 ASSERT(clabel != NULL);
1564 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1565 "got client label from request(1)", struct svc_req *, req);
1566
1567 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1568 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1569 exi)) {
1570 resp->status = NFS3ERR_ACCES;
1571 goto out1;
1572 }
1573 }
1574 }
1575
1576 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1577 name = nfscmd_convname(ca, exi, args->where.name,
1578 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1579
1813 else
1814 resp->resok.obj.handle_follows = TRUE;
1815
1816 /*
1817 * Force modified data and metadata out to stable storage.
1818 */
1819 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1820 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1821
1822 VN_RELE(vp);
1823 if (tvp != NULL) {
1824 if (in_crit)
1825 nbl_end_crit(tvp);
1826 VN_RELE(tvp);
1827 }
1828
1829 resp->status = NFS3_OK;
1830 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1831 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1832
1833 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1834 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1835
1836 VN_RELE(dvp);
1837 return;
1838
1839 out:
1840 if (curthread->t_flag & T_WOULDBLOCK) {
1841 curthread->t_flag &= ~T_WOULDBLOCK;
1842 resp->status = NFS3ERR_JUKEBOX;
1843 } else
1844 resp->status = puterrno3(error);
1845 out1:
1846 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848
1849 if (name != NULL && name != args->where.name)
1850 kmem_free(name, MAXPATHLEN + 1);
1851
1852 if (tvp != NULL) {
1853 if (in_crit)
1854 nbl_end_crit(tvp);
1855 VN_RELE(tvp);
1856 }
1857 if (dvp != NULL)
1858 VN_RELE(dvp);
1859 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1860 }
1861
1862 void *
1863 rfs3_create_getfh(CREATE3args *args)
1864 {
1865
1866 return (&args->where.dir);
1867 }
1868
1869 void
1870 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1871 struct svc_req *req, cred_t *cr, bool_t ro)
1872 {
1873 int error;
1874 vnode_t *vp = NULL;
1875 vnode_t *dvp;
1876 struct vattr *vap;
1877 struct vattr va;
1878 struct vattr *dbvap;
1879 struct vattr dbva;
1880 struct vattr *davap;
1881 struct vattr dava;
1882 struct sockaddr *ca;
1883 char *name = NULL;
1884
1885 dbvap = NULL;
1886 davap = NULL;
1887
1888 dvp = nfs3_fhtovp(&args->where.dir, exi);
1889
1890 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1891 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1892
1893 if (dvp == NULL) {
1894 error = ESTALE;
1895 goto out;
1896 }
1897
1898 dbva.va_mask = AT_ALL;
1899 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1900 davap = dbvap;
1901
1902 if (args->where.name == nfs3nametoolong) {
1903 resp->status = NFS3ERR_NAMETOOLONG;
1904 goto out1;
1905 }
1906
1907 if (args->where.name == NULL || *(args->where.name) == '\0') {
1908 resp->status = NFS3ERR_ACCES;
1909 goto out1;
1910 }
1911
1912 if (rdonly(ro, dvp)) {
1913 resp->status = NFS3ERR_ROFS;
1914 goto out1;
1915 }
1916
1917 if (is_system_labeled()) {
1918 bslabel_t *clabel = req->rq_label;
1919
1920 ASSERT(clabel != NULL);
1921 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1922 "got client label from request(1)", struct svc_req *, req);
1923
1924 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1925 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1926 exi)) {
1927 resp->status = NFS3ERR_ACCES;
1928 goto out1;
1929 }
1930 }
1931 }
1932
1933 error = sattr3_to_vattr(&args->attributes, &va);
1934 if (error)
1935 goto out;
1936
1970 error = makefh3(&resp->resok.obj.handle, vp, exi);
1971 if (error)
1972 resp->resok.obj.handle_follows = FALSE;
1973 else
1974 resp->resok.obj.handle_follows = TRUE;
1975
1976 va.va_mask = AT_ALL;
1977 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1978
1979 /*
1980 * Force modified data and metadata out to stable storage.
1981 */
1982 (void) VOP_FSYNC(vp, 0, cr, NULL);
1983
1984 VN_RELE(vp);
1985
1986 resp->status = NFS3_OK;
1987 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1988 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1989
1990 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
1991 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
1992 VN_RELE(dvp);
1993
1994 return;
1995
1996 out:
1997 if (curthread->t_flag & T_WOULDBLOCK) {
1998 curthread->t_flag &= ~T_WOULDBLOCK;
1999 resp->status = NFS3ERR_JUKEBOX;
2000 } else
2001 resp->status = puterrno3(error);
2002 out1:
2003 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2005 if (dvp != NULL)
2006 VN_RELE(dvp);
2007 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2008 }
2009
2010 void *
2011 rfs3_mkdir_getfh(MKDIR3args *args)
2012 {
2013
2014 return (&args->where.dir);
2015 }
2016
2017 void
2018 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2019 struct svc_req *req, cred_t *cr, bool_t ro)
2020 {
2021 int error;
2022 vnode_t *vp;
2023 vnode_t *dvp;
2024 struct vattr *vap;
2025 struct vattr va;
2026 struct vattr *dbvap;
2027 struct vattr dbva;
2028 struct vattr *davap;
2029 struct vattr dava;
2030 struct sockaddr *ca;
2031 char *name = NULL;
2032 char *symdata = NULL;
2033
2034 dbvap = NULL;
2035 davap = NULL;
2036
2037 dvp = nfs3_fhtovp(&args->where.dir, exi);
2038
2039 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2040 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2041
2042 if (dvp == NULL) {
2043 error = ESTALE;
2044 goto err;
2045 }
2046
2047 dbva.va_mask = AT_ALL;
2048 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2049 davap = dbvap;
2050
2051 if (args->where.name == nfs3nametoolong) {
2052 resp->status = NFS3ERR_NAMETOOLONG;
2053 goto err1;
2054 }
2055
2056 if (args->where.name == NULL || *(args->where.name) == '\0') {
2057 resp->status = NFS3ERR_ACCES;
2058 goto err1;
2059 }
2060
2061 if (rdonly(ro, dvp)) {
2062 resp->status = NFS3ERR_ROFS;
2063 goto err1;
2064 }
2065
2066 if (is_system_labeled()) {
2067 bslabel_t *clabel = req->rq_label;
2068
2069 ASSERT(clabel != NULL);
2070 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2071 "got client label from request(1)", struct svc_req *, req);
2072
2073 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2074 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2075 exi)) {
2076 resp->status = NFS3ERR_ACCES;
2077 goto err1;
2078 }
2079 }
2080 }
2081
2082 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2083 if (error)
2084 goto err;
2085
2157 VN_RELE(vp);
2158
2159 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2160 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2161 goto out;
2162
2163 err:
2164 if (curthread->t_flag & T_WOULDBLOCK) {
2165 curthread->t_flag &= ~T_WOULDBLOCK;
2166 resp->status = NFS3ERR_JUKEBOX;
2167 } else
2168 resp->status = puterrno3(error);
2169 err1:
2170 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2171 out:
2172 if (name != NULL && name != args->where.name)
2173 kmem_free(name, MAXPATHLEN + 1);
2174 if (symdata != NULL && symdata != args->symlink.symlink_data)
2175 kmem_free(symdata, MAXPATHLEN + 1);
2176
2177 DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2178 cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2179
2180 if (dvp != NULL)
2181 VN_RELE(dvp);
2182 }
2183
2184 void *
2185 rfs3_symlink_getfh(SYMLINK3args *args)
2186 {
2187
2188 return (&args->where.dir);
2189 }
2190
2191 void
2192 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2193 struct svc_req *req, cred_t *cr, bool_t ro)
2194 {
2195 int error;
2196 vnode_t *vp;
2197 vnode_t *realvp;
2198 vnode_t *dvp;
2199 struct vattr *vap;
2200 struct vattr va;
2201 struct vattr *dbvap;
2202 struct vattr dbva;
2203 struct vattr *davap;
2204 struct vattr dava;
2205 int mode;
2206 enum vcexcl excl;
2207 struct sockaddr *ca;
2208 char *name = NULL;
2209
2210 dbvap = NULL;
2211 davap = NULL;
2212
2213 dvp = nfs3_fhtovp(&args->where.dir, exi);
2214
2215 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2216 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2217
2218 if (dvp == NULL) {
2219 error = ESTALE;
2220 goto out;
2221 }
2222
2223 dbva.va_mask = AT_ALL;
2224 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2225 davap = dbvap;
2226
2227 if (args->where.name == nfs3nametoolong) {
2228 resp->status = NFS3ERR_NAMETOOLONG;
2229 goto out1;
2230 }
2231
2232 if (args->where.name == NULL || *(args->where.name) == '\0') {
2233 resp->status = NFS3ERR_ACCES;
2234 goto out1;
2235 }
2236
2237 if (rdonly(ro, dvp)) {
2238 resp->status = NFS3ERR_ROFS;
2239 goto out1;
2240 }
2241
2242 if (is_system_labeled()) {
2243 bslabel_t *clabel = req->rq_label;
2244
2245 ASSERT(clabel != NULL);
2246 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2247 "got client label from request(1)", struct svc_req *, req);
2248
2249 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2250 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2251 exi)) {
2252 resp->status = NFS3ERR_ACCES;
2253 goto out1;
2254 }
2255 }
2256 }
2257
2258 switch (args->what.type) {
2259 case NF3CHR:
2260 case NF3BLK:
2261 error = sattr3_to_vattr(
2342 else
2343 resp->resok.obj.handle_follows = TRUE;
2344
2345 va.va_mask = AT_ALL;
2346 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2347
2348 /*
2349 * Force modified metadata out to stable storage.
2350 *
2351 * if a underlying vp exists, pass it to VOP_FSYNC
2352 */
2353 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2354 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2355 else
2356 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2357
2358 VN_RELE(vp);
2359
2360 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2361 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2362 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2363 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2364 VN_RELE(dvp);
2365 return;
2366
2367 out:
2368 if (curthread->t_flag & T_WOULDBLOCK) {
2369 curthread->t_flag &= ~T_WOULDBLOCK;
2370 resp->status = NFS3ERR_JUKEBOX;
2371 } else
2372 resp->status = puterrno3(error);
2373 out1:
2374 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2375 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2376 if (dvp != NULL)
2377 VN_RELE(dvp);
2378 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2379 }
2380
2381 void *
2382 rfs3_mknod_getfh(MKNOD3args *args)
2383 {
2384
2385 return (&args->where.dir);
2386 }
2387
2388 void
2389 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2390 struct svc_req *req, cred_t *cr, bool_t ro)
2391 {
2392 int error = 0;
2393 vnode_t *vp;
2394 struct vattr *bvap;
2395 struct vattr bva;
2396 struct vattr *avap;
2397 struct vattr ava;
2398 vnode_t *targvp = NULL;
2399 struct sockaddr *ca;
2400 char *name = NULL;
2401
2402 bvap = NULL;
2403 avap = NULL;
2404
2405 vp = nfs3_fhtovp(&args->object.dir, exi);
2406
2407 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2408 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2409
2410 if (vp == NULL) {
2411 error = ESTALE;
2412 goto err;
2413 }
2414
2415 bva.va_mask = AT_ALL;
2416 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2417 avap = bvap;
2418
2419 if (vp->v_type != VDIR) {
2420 resp->status = NFS3ERR_NOTDIR;
2421 goto err1;
2422 }
2423
2424 if (args->object.name == nfs3nametoolong) {
2425 resp->status = NFS3ERR_NAMETOOLONG;
2426 goto err1;
2427 }
2428
2496 * Force modified data and metadata out to stable storage.
2497 */
2498 (void) VOP_FSYNC(vp, 0, cr, NULL);
2499
2500 if (error)
2501 goto err;
2502
2503 resp->status = NFS3_OK;
2504 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2505 goto out;
2506
2507 err:
2508 if (curthread->t_flag & T_WOULDBLOCK) {
2509 curthread->t_flag &= ~T_WOULDBLOCK;
2510 resp->status = NFS3ERR_JUKEBOX;
2511 } else
2512 resp->status = puterrno3(error);
2513 err1:
2514 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2515 out:
2516 DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2517 cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2518
2519 if (name != NULL && name != args->object.name)
2520 kmem_free(name, MAXPATHLEN + 1);
2521
2522 if (vp != NULL)
2523 VN_RELE(vp);
2524 }
2525
2526 void *
2527 rfs3_remove_getfh(REMOVE3args *args)
2528 {
2529
2530 return (&args->object.dir);
2531 }
2532
2533 void
2534 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2535 struct svc_req *req, cred_t *cr, bool_t ro)
2536 {
2537 int error;
2538 vnode_t *vp;
2539 struct vattr *bvap;
2540 struct vattr bva;
2541 struct vattr *avap;
2542 struct vattr ava;
2543 struct sockaddr *ca;
2544 char *name = NULL;
2545
2546 bvap = NULL;
2547 avap = NULL;
2548
2549 vp = nfs3_fhtovp(&args->object.dir, exi);
2550
2551 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2552 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2553
2554 if (vp == NULL) {
2555 error = ESTALE;
2556 goto err;
2557 }
2558
2559 bva.va_mask = AT_ALL;
2560 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2561 avap = bvap;
2562
2563 if (vp->v_type != VDIR) {
2564 resp->status = NFS3ERR_NOTDIR;
2565 goto err1;
2566 }
2567
2568 if (args->object.name == nfs3nametoolong) {
2569 resp->status = NFS3ERR_NAMETOOLONG;
2570 goto err1;
2571 }
2572
2588 "got client label from request(1)", struct svc_req *, req);
2589
2590 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2591 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2592 exi)) {
2593 resp->status = NFS3ERR_ACCES;
2594 goto err1;
2595 }
2596 }
2597 }
2598
2599 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2600 name = nfscmd_convname(ca, exi, args->object.name,
2601 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2602
2603 if (name == NULL) {
2604 resp->status = NFS3ERR_INVAL;
2605 goto err1;
2606 }
2607
2608 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2609
2610 if (name != args->object.name)
2611 kmem_free(name, MAXPATHLEN + 1);
2612
2613 ava.va_mask = AT_ALL;
2614 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2615
2616 /*
2617 * Force modified data and metadata out to stable storage.
2618 */
2619 (void) VOP_FSYNC(vp, 0, cr, NULL);
2620
2621 if (error) {
2622 /*
2623 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2624 * if the directory is not empty. A System V NFS server
2625 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2626 * over the wire.
2627 */
2628 if (error == EEXIST)
2629 error = ENOTEMPTY;
2630 goto err;
2631 }
2632
2633 resp->status = NFS3_OK;
2634 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2635 goto out;
2636
2637 err:
2638 if (curthread->t_flag & T_WOULDBLOCK) {
2639 curthread->t_flag &= ~T_WOULDBLOCK;
2640 resp->status = NFS3ERR_JUKEBOX;
2641 } else
2642 resp->status = puterrno3(error);
2643 err1:
2644 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2645 out:
2646 DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2647 cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2648 if (vp != NULL)
2649 VN_RELE(vp);
2650
2651 }
2652
2653 void *
2654 rfs3_rmdir_getfh(RMDIR3args *args)
2655 {
2656
2657 return (&args->object.dir);
2658 }
2659
2660 void
2661 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2662 struct svc_req *req, cred_t *cr, bool_t ro)
2663 {
2664 int error = 0;
2665 vnode_t *fvp;
2666 vnode_t *tvp;
2667 vnode_t *targvp;
2668 struct vattr *fbvap;
2669 struct vattr fbva;
2670 struct vattr *favap;
2671 struct vattr fava;
2672 struct vattr *tbvap;
2673 struct vattr tbva;
2674 struct vattr *tavap;
2675 struct vattr tava;
2676 nfs_fh3 *fh3;
2677 struct exportinfo *to_exi;
2678 vnode_t *srcvp = NULL;
2679 bslabel_t *clabel;
2680 struct sockaddr *ca;
2681 char *name = NULL;
2682 char *toname = NULL;
2683
2684 fbvap = NULL;
2685 favap = NULL;
2686 tbvap = NULL;
2687 tavap = NULL;
2688 tvp = NULL;
2689
2690 fvp = nfs3_fhtovp(&args->from.dir, exi);
2691
2692 DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2693 cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2694
2695 if (fvp == NULL) {
2696 error = ESTALE;
2697 goto err;
2698 }
2699
2700 if (is_system_labeled()) {
2701 clabel = req->rq_label;
2702 ASSERT(clabel != NULL);
2703 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2704 "got client label from request(1)", struct svc_req *, req);
2705
2706 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2707 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2708 exi)) {
2709 resp->status = NFS3ERR_ACCES;
2710 goto err1;
2711 }
2712 }
2713 }
2714
2715 fbva.va_mask = AT_ALL;
2716 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2717 favap = fbvap;
2718
2719 fh3 = &args->to.dir;
2720 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2721 if (to_exi == NULL) {
2722 resp->status = NFS3ERR_ACCES;
2723 goto err1;
2724 }
2725 exi_rele(to_exi);
2726
2727 if (to_exi != exi) {
2728 resp->status = NFS3ERR_XDEV;
2729 goto err1;
2730 }
2731
2732 tvp = nfs3_fhtovp(&args->to.dir, exi);
2733 if (tvp == NULL) {
2734 error = ESTALE;
2735 goto err;
2736 }
2737
2738 tbva.va_mask = AT_ALL;
2739 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2740 tavap = tbvap;
2741
2742 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2743 resp->status = NFS3ERR_NOTDIR;
2744 goto err1;
2745 }
2746
2747 if (args->from.name == nfs3nametoolong ||
2748 args->to.name == nfs3nametoolong) {
2749 resp->status = NFS3ERR_NAMETOOLONG;
2750 goto err1;
2751 }
2752 if (args->from.name == NULL || *(args->from.name) == '\0' ||
2753 args->to.name == NULL || *(args->to.name) == '\0') {
2754 resp->status = NFS3ERR_ACCES;
2755 goto err1;
2756 }
2757
2758 if (rdonly(ro, tvp)) {
2759 resp->status = NFS3ERR_ROFS;
2760 goto err1;
2761 }
2762
2763 if (is_system_labeled()) {
2764 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2765 if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2766 exi)) {
2767 resp->status = NFS3ERR_ACCES;
2768 goto err1;
2769 }
2770 }
2771 }
2772
2773 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2774 name = nfscmd_convname(ca, exi, args->from.name,
2775 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2776
2777 if (name == NULL) {
2778 resp->status = NFS3ERR_INVAL;
2779 goto err1;
2780 }
2781
2782 toname = nfscmd_convname(ca, exi, args->to.name,
2790 /*
2791 * Check for a conflict with a non-blocking mandatory share
2792 * reservation or V4 delegations.
2793 */
2794 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2795 NULL, cr, NULL, NULL, NULL);
2796 if (error != 0)
2797 goto err;
2798
2799 /*
2800 * If we rename a delegated file we should recall the
2801 * delegation, since future opens should fail or would
2802 * refer to a new file.
2803 */
2804 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2805 resp->status = NFS3ERR_JUKEBOX;
2806 goto err1;
2807 }
2808
2809 /*
2810 * Check for renaming over a delegated file. Check rfs4_deleg_policy
2811 * first to avoid VOP_LOOKUP if possible.
2812 */
2813 if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2814 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2815 NULL, NULL, NULL) == 0) {
2816
2817 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2818 VN_RELE(targvp);
2819 resp->status = NFS3ERR_JUKEBOX;
2820 goto err1;
2821 }
2822 VN_RELE(targvp);
2823 }
2824
2825 if (!nbl_need_check(srcvp)) {
2826 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2827 } else {
2828 nbl_start_crit(srcvp, RW_READER);
2829 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2830 error = EACCES;
2831 else
2832 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2833 nbl_end_crit(srcvp);
2857 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2858 goto out;
2859
2860 err:
2861 if (curthread->t_flag & T_WOULDBLOCK) {
2862 curthread->t_flag &= ~T_WOULDBLOCK;
2863 resp->status = NFS3ERR_JUKEBOX;
2864 } else {
2865 resp->status = puterrno3(error);
2866 }
2867 err1:
2868 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2869 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2870
2871 out:
2872 if (name != NULL && name != args->from.name)
2873 kmem_free(name, MAXPATHLEN + 1);
2874 if (toname != NULL && toname != args->to.name)
2875 kmem_free(toname, MAXPATHLEN + 1);
2876
2877 DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2878 cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
2879 if (fvp != NULL)
2880 VN_RELE(fvp);
2881 if (tvp != NULL)
2882 VN_RELE(tvp);
2883 }
2884
2885 void *
2886 rfs3_rename_getfh(RENAME3args *args)
2887 {
2888
2889 return (&args->from.dir);
2890 }
2891
2892 void
2893 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2894 struct svc_req *req, cred_t *cr, bool_t ro)
2895 {
2896 int error;
2897 vnode_t *vp;
2898 vnode_t *dvp;
2899 struct vattr *vap;
2900 struct vattr va;
2901 struct vattr *bvap;
2902 struct vattr bva;
2903 struct vattr *avap;
2904 struct vattr ava;
2905 nfs_fh3 *fh3;
2906 struct exportinfo *to_exi;
2907 bslabel_t *clabel;
2908 struct sockaddr *ca;
2909 char *name = NULL;
2910
2911 vap = NULL;
2912 bvap = NULL;
2913 avap = NULL;
2914 dvp = NULL;
2915
2916 vp = nfs3_fhtovp(&args->file, exi);
2917
2918 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2919 cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2920
2921 if (vp == NULL) {
2922 error = ESTALE;
2923 goto out;
2924 }
2925
2926 va.va_mask = AT_ALL;
2927 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2928
2929 fh3 = &args->link.dir;
2930 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2931 if (to_exi == NULL) {
2932 resp->status = NFS3ERR_ACCES;
2933 goto out1;
2934 }
2935 exi_rele(to_exi);
2936
2937 if (to_exi != exi) {
2938 resp->status = NFS3ERR_XDEV;
2939 goto out1;
2940 }
2941
2942 if (is_system_labeled()) {
2943 clabel = req->rq_label;
2944
2945 ASSERT(clabel != NULL);
2946 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
2947 "got client label from request(1)", struct svc_req *, req);
2948
2949 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2950 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2951 exi)) {
2952 resp->status = NFS3ERR_ACCES;
2953 goto out1;
2954 }
2955 }
2967 if (dvp->v_type != VDIR) {
2968 resp->status = NFS3ERR_NOTDIR;
2969 goto out1;
2970 }
2971
2972 if (args->link.name == nfs3nametoolong) {
2973 resp->status = NFS3ERR_NAMETOOLONG;
2974 goto out1;
2975 }
2976
2977 if (args->link.name == NULL || *(args->link.name) == '\0') {
2978 resp->status = NFS3ERR_ACCES;
2979 goto out1;
2980 }
2981
2982 if (rdonly(ro, dvp)) {
2983 resp->status = NFS3ERR_ROFS;
2984 goto out1;
2985 }
2986
2987 if (is_system_labeled()) {
2988 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
2989 "got client label from request(1)", struct svc_req *, req);
2990
2991 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2992 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2993 exi)) {
2994 resp->status = NFS3ERR_ACCES;
2995 goto out1;
2996 }
2997 }
2998 }
2999
3000 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3001 name = nfscmd_convname(ca, exi, args->link.name,
3002 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3003
3004 if (name == NULL) {
3005 resp->status = NFS3ERR_SERVERFAULT;
3006 goto out1;
3011 va.va_mask = AT_ALL;
3012 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3013 ava.va_mask = AT_ALL;
3014 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3015
3016 /*
3017 * Force modified data and metadata out to stable storage.
3018 */
3019 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3020 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3021
3022 if (error)
3023 goto out;
3024
3025 VN_RELE(dvp);
3026
3027 resp->status = NFS3_OK;
3028 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3029 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3030
3031 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3032 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3033
3034 VN_RELE(vp);
3035
3036 return;
3037
3038 out:
3039 if (curthread->t_flag & T_WOULDBLOCK) {
3040 curthread->t_flag &= ~T_WOULDBLOCK;
3041 resp->status = NFS3ERR_JUKEBOX;
3042 } else
3043 resp->status = puterrno3(error);
3044 out1:
3045 if (name != NULL && name != args->link.name)
3046 kmem_free(name, MAXPATHLEN + 1);
3047
3048 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3049 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3050
3051 if (vp != NULL)
3052 VN_RELE(vp);
3053 if (dvp != NULL)
3054 VN_RELE(dvp);
3055 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3056 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3057 }
3058
3059 void *
3060 rfs3_link_getfh(LINK3args *args)
3061 {
3062
3063 return (&args->file);
3064 }
3065
3066 /*
3067 * This macro defines the size of a response which contains attribute
3068 * information and one directory entry (whose length is specified by
3069 * the macro parameter). If the incoming request is larger than this,
3070 * then we are guaranteed to be able to return at one directory entry
3071 * if one exists. Therefore, we do not need to check for
3072 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it
3073 * is not, then we need to check to make sure that this error does not
3074 * need to be returned.
3075 *
3076 * NFS3_READDIR_MIN_COUNT is comprised of following :
3077 *
3078 * status - 1 * BYTES_PER_XDR_UNIT
3079 * attr. flag - 1 * BYTES_PER_XDR_UNIT
3080 * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3081 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3082 * boolean - 1 * BYTES_PER_XDR_UNIT
3083 * file id - 2 * BYTES_PER_XDR_UNIT
3084 * directory name length - 1 * BYTES_PER_XDR_UNIT
3085 * cookie - 2 * BYTES_PER_XDR_UNIT
3086 * end of list - 1 * BYTES_PER_XDR_UNIT
3087 * end of file - 1 * BYTES_PER_XDR_UNIT
3088 * Name length of directory to the nearest byte
3089 */
3090
3091 #define NFS3_READDIR_MIN_COUNT(length) \
3092 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3093 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3094
3095 /* ARGSUSED */
3096 void
3097 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3098 struct svc_req *req, cred_t *cr, bool_t ro)
3099 {
3100 int error;
3101 vnode_t *vp;
3102 struct vattr *vap;
3103 struct vattr va;
3104 struct iovec iov;
3105 struct uio uio;
3106 char *data;
3107 int iseof;
3108 int bufsize;
3109 int namlen;
3110 uint_t count;
3111 struct sockaddr *ca;
3112
3113 vap = NULL;
3114
3115 vp = nfs3_fhtovp(&args->dir, exi);
3116
3117 DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3118 cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3119
3120 if (vp == NULL) {
3121 error = ESTALE;
3122 goto out;
3123 }
3124
3125 if (is_system_labeled()) {
3126 bslabel_t *clabel = req->rq_label;
3127
3128 ASSERT(clabel != NULL);
3129 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3130 "got client label from request(1)", struct svc_req *, req);
3131
3132 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3133 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3134 exi)) {
3135 resp->status = NFS3ERR_ACCES;
3136 goto out1;
3137 }
3138 }
3139 }
3140
3141 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3142
3143 va.va_mask = AT_ALL;
3144 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3145
3146 if (vp->v_type != VDIR) {
3147 resp->status = NFS3ERR_NOTDIR;
3148 goto out1;
3149 }
3150
3151 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3152 if (error)
3153 goto out;
3154
3155 /*
3156 * Now don't allow arbitrary count to alloc;
3157 * allow the maximum not to exceed rfs3_tsize()
3158 */
3159 if (args->count > rfs3_tsize(req))
3160 args->count = rfs3_tsize(req);
3161
3162 /*
3163 * Make sure that there is room to read at least one entry
3164 * if any are available.
3165 */
3166 if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3167 count = DIRENT64_RECLEN(MAXNAMELEN);
3168 else
3169 count = args->count;
3170
3171 data = kmem_alloc(count, KM_SLEEP);
3172
3173 iov.iov_base = data;
3174 iov.iov_len = count;
3175 uio.uio_iov = &iov;
3176 uio.uio_iovcnt = 1;
3177 uio.uio_segflg = UIO_SYSSPACE;
3178 uio.uio_extflg = UIO_COPY_CACHED;
3179 uio.uio_loffset = (offset_t)args->cookie;
3180 uio.uio_resid = count;
3181
3182 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3183
3184 va.va_mask = AT_ALL;
3185 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3186
3187 if (error) {
3188 kmem_free(data, count);
3189 goto out;
3190 }
3191
3192 /*
3193 * If the count was not large enough to be able to guarantee
3194 * to be able to return at least one entry, then need to
3195 * check to see if NFS3ERR_TOOSMALL should be returned.
3196 */
3197 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3198 /*
3199 * bufsize is used to keep track of the size of the response.
3200 * It is primed with:
3201 * 1 for the status +
3202 * 1 for the dir_attributes.attributes boolean +
3203 * 2 for the cookie verifier
3204 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3205 * to bytes. If there are directory attributes to be
3206 * returned, then:
3207 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3208 * time BYTES_PER_XDR_UNIT is added to account for them.
3209 */
3210 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3211 if (vap != NULL)
3212 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3213 /*
3214 * An entry is composed of:
3215 * 1 for the true/false list indicator +
3216 * 2 for the fileid +
3217 * 1 for the length of the name +
3218 * 2 for the cookie +
3219 * all times BYTES_PER_XDR_UNIT to convert from
3220 * XDR units to bytes, plus the length of the name
3221 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3222 */
3223 if (count != uio.uio_resid) {
3224 namlen = strlen(((struct dirent64 *)data)->d_name);
3225 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3226 roundup(namlen, BYTES_PER_XDR_UNIT);
3227 }
3228 /*
3229 * We need to check to see if the number of bytes left
3230 * to go into the buffer will actually fit into the
3231 * buffer. This is calculated as the size of this
3232 * entry plus:
3233 * 1 for the true/false list indicator +
3234 * 1 for the eof indicator
3235 * times BYTES_PER_XDR_UNIT to convert from from
3236 * XDR units to bytes.
3237 */
3238 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3239 if (bufsize > args->count) {
3240 kmem_free(data, count);
3241 resp->status = NFS3ERR_TOOSMALL;
3242 goto out1;
3243 }
3244 }
3245
3246 /*
3247 * Have a valid readir buffer for the native character
3248 * set. Need to check if a conversion is necessary and
3249 * potentially rewrite the whole buffer. Note that if the
3250 * conversion expands names enough, the structure may not
3251 * fit. In this case, we need to drop entries until if fits
3252 * and patch the counts in order that the next readdir will
3253 * get the correct entries.
3254 */
3255 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3256 data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3257
3258
3259 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3260
3261 #if 0 /* notyet */
3262 /*
3263 * Don't do this. It causes local disk writes when just
3264 * reading the file and the overhead is deemed larger
3265 * than the benefit.
3266 */
3267 /*
3268 * Force modified metadata out to stable storage.
3269 */
3270 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3271 #endif
3272
3273 resp->status = NFS3_OK;
3274 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3275 resp->resok.cookieverf = 0;
3276 resp->resok.reply.entries = (entry3 *)data;
3277 resp->resok.reply.eof = iseof;
3278 resp->resok.size = count - uio.uio_resid;
3279 resp->resok.count = args->count;
3280 resp->resok.freecount = count;
3281
3282 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3283 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3284
3285 VN_RELE(vp);
3286
3287 return;
3288
3289 out:
3290 if (curthread->t_flag & T_WOULDBLOCK) {
3291 curthread->t_flag &= ~T_WOULDBLOCK;
3292 resp->status = NFS3ERR_JUKEBOX;
3293 } else
3294 resp->status = puterrno3(error);
3295 out1:
3296 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3297 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3298
3299 if (vp != NULL) {
3300 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3301 VN_RELE(vp);
3302 }
3303 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3304 }
3305
3306 void *
3307 rfs3_readdir_getfh(READDIR3args *args)
3308 {
3309
3310 return (&args->dir);
3311 }
3312
3313 void
3314 rfs3_readdir_free(READDIR3res *resp)
3315 {
3316
3317 if (resp->status == NFS3_OK)
3318 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3319 }
3320
3321 #ifdef nextdp
3322 #undef nextdp
3323 #endif
3324 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3325
3326 /*
3327 * This macro computes the size of a response which contains
3328 * one directory entry including the attributes as well as file handle.
3329 * If the incoming request is larger than this, then we are guaranteed to be
3330 * able to return at least one more directory entry if one exists.
3331 *
3332 * NFS3_READDIRPLUS_ENTRY is made up of the following:
3333 *
3334 * boolean - 1 * BYTES_PER_XDR_UNIT
3335 * file id - 2 * BYTES_PER_XDR_UNIT
3336 * directory name length - 1 * BYTES_PER_XDR_UNIT
3337 * cookie - 2 * BYTES_PER_XDR_UNIT
3338 * attribute flag - 1 * BYTES_PER_XDR_UNIT
3339 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3340 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT
3341 * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3342 * Maximum length of a file handle (NFS3_MAXFHSIZE)
3343 * name length of the entry to the nearest bytes
3344 */
3345 #define NFS3_READDIRPLUS_ENTRY(namelen) \
3346 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3347 BYTES_PER_XDR_UNIT + \
3348 NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3349
3350 static int rfs3_readdir_unit = MAXBSIZE;
3351
3352 /* ARGSUSED */
3353 void
3354 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3355 struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3356 {
3357 int error;
3358 vnode_t *vp;
3359 struct vattr *vap;
3360 struct vattr va;
3361 struct iovec iov;
3362 struct uio uio;
3363 char *data;
3364 int iseof;
3365 struct dirent64 *dp;
3366 vnode_t *nvp;
3367 struct vattr *nvap;
3368 struct vattr nva;
3369 entryplus3_info *infop = NULL;
3370 int size = 0;
3371 int nents = 0;
3372 int bufsize = 0;
3373 int entrysize = 0;
3374 int tofit = 0;
3375 int rd_unit = rfs3_readdir_unit;
3376 int prev_len;
3377 int space_left;
3378 int i;
3379 uint_t *namlen = NULL;
3380 char *ndata = NULL;
3381 struct sockaddr *ca;
3382 size_t ret;
3383
3384 vap = NULL;
3385
3386 vp = nfs3_fhtovp(&args->dir, exi);
3387
3388 DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3389 cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3390
3391 if (vp == NULL) {
3392 error = ESTALE;
3393 goto out;
3394 }
3395
3396 if (is_system_labeled()) {
3397 bslabel_t *clabel = req->rq_label;
3398
3399 ASSERT(clabel != NULL);
3400 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3401 char *, "got client label from request(1)",
3402 struct svc_req *, req);
3403
3404 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3405 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3406 exi)) {
3407 resp->status = NFS3ERR_ACCES;
3408 goto out1;
3409 }
3410 }
3411 }
3412
3413 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3414
3415 va.va_mask = AT_ALL;
3416 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3417
3418 if (vp->v_type != VDIR) {
3419 error = ENOTDIR;
3420 goto out;
3421 }
3422
3423 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3424 if (error)
3425 goto out;
3426
3427 /*
3428 * Don't allow arbitrary counts for allocation
3429 */
3430 if (args->maxcount > rfs3_tsize(req))
3431 args->maxcount = rfs3_tsize(req);
3432
3433 /*
3434 * Make sure that there is room to read at least one entry
3435 * if any are available
3436 */
3437 args->dircount = MIN(args->dircount, args->maxcount);
3438
3439 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3440 args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3441
3442 /*
3443 * This allocation relies on a minimum directory entry
3444 * being roughly 24 bytes. Therefore, the namlen array
3445 * will have enough space based on the maximum number of
3446 * entries to read.
3447 */
3448 namlen = kmem_alloc(args->dircount, KM_SLEEP);
3449
3450 space_left = args->dircount;
3451 data = kmem_alloc(args->dircount, KM_SLEEP);
3452 dp = (struct dirent64 *)data;
3453 uio.uio_iov = &iov;
3454 uio.uio_iovcnt = 1;
3455 uio.uio_segflg = UIO_SYSSPACE;
3456 uio.uio_extflg = UIO_COPY_CACHED;
3457 uio.uio_loffset = (offset_t)args->cookie;
3458
3459 /*
3460 * bufsize is used to keep track of the size of the response as we
3461 * get post op attributes and filehandles for each entry. This is
3462 * an optimization as the server may have read more entries than will
3463 * fit in the buffer specified by maxcount. We stop calculating
3464 * post op attributes and filehandles once we have exceeded maxcount.
3465 * This will minimize the effect of truncation.
3466 *
3467 * It is primed with:
3468 * 1 for the status +
3469 * 1 for the dir_attributes.attributes boolean +
3470 * 2 for the cookie verifier
3471 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3472 * to bytes. If there are directory attributes to be
3473 * returned, then:
3474 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3475 * time BYTES_PER_XDR_UNIT is added to account for them.
3476 */
3477 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3478 if (vap != NULL)
3479 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3480
3481 getmoredents:
3482 /*
3483 * Here we make a check so that our read unit is not larger than
3484 * the space left in the buffer.
3485 */
3486 rd_unit = MIN(rd_unit, space_left);
3487 iov.iov_base = (char *)dp;
3488 iov.iov_len = rd_unit;
3489 uio.uio_resid = rd_unit;
3490 prev_len = rd_unit;
3491
3492 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3493
3494 if (error) {
3495 kmem_free(data, args->dircount);
3496 goto out;
3497 }
3498
3499 if (uio.uio_resid == prev_len && !iseof) {
3500 if (nents == 0) {
3501 kmem_free(data, args->dircount);
3502 resp->status = NFS3ERR_TOOSMALL;
3503 goto out1;
3504 }
3505
3506 /*
3507 * We could not get any more entries, so get the attributes
3508 * and filehandle for the entries already obtained.
3509 */
3510 goto good;
3511 }
3512
3513 /*
3514 * We estimate the size of the response by assuming the
3515 * entry exists and attributes and filehandle are also valid
3516 */
3517 for (size = prev_len - uio.uio_resid;
3518 size > 0;
3519 size -= dp->d_reclen, dp = nextdp(dp)) {
3520
3521 if (dp->d_ino == 0) {
3522 nents++;
3523 continue;
3524 }
3525
3526 namlen[nents] = strlen(dp->d_name);
3527 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3528
3529 /*
3530 * We need to check to see if the number of bytes left
3531 * to go into the buffer will actually fit into the
3532 * buffer. This is calculated as the size of this
3533 * entry plus:
3534 * 1 for the true/false list indicator +
3535 * 1 for the eof indicator
3536 * times BYTES_PER_XDR_UNIT to convert from XDR units
3537 * to bytes.
3538 *
3539 * Also check the dircount limit against the first entry read
3540 *
3541 */
3542 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3543 if (bufsize + tofit > args->maxcount) {
3544 /*
3545 * We make a check here to see if this was the
3546 * first entry being measured. If so, then maxcount
3547 * was too small to begin with and so we need to
3548 * return with NFS3ERR_TOOSMALL.
3549 */
3550 if (nents == 0) {
3551 kmem_free(data, args->dircount);
3552 resp->status = NFS3ERR_TOOSMALL;
3553 goto out1;
3554 }
3555 iseof = FALSE;
3556 goto good;
3557 }
3558 bufsize += entrysize;
3559 nents++;
3560 }
3561
3562 /*
3563 * If there is enough room to fit at least 1 more entry including
3564 * post op attributes and filehandle in the buffer AND that we haven't
3565 * exceeded dircount then go back and get some more.
3566 */
3567 if (!iseof &&
3568 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3569 space_left -= (prev_len - uio.uio_resid);
3570 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3571 goto getmoredents;
3572
3573 /* else, fall through */
3574 }
3575 good:
3576 va.va_mask = AT_ALL;
3577 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3578
3579 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3580
3581 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3582 resp->resok.infop = infop;
3583
3584 dp = (struct dirent64 *)data;
3585 for (i = 0; i < nents; i++) {
3586
3587 if (dp->d_ino == 0) {
3588 infop[i].attr.attributes = FALSE;
3589 infop[i].fh.handle_follows = FALSE;
3590 dp = nextdp(dp);
3591 continue;
3592 }
3593
3594 infop[i].namelen = namlen[i];
3595
3596 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3597 NULL, NULL, NULL);
3598 if (error) {
3599 infop[i].attr.attributes = FALSE;
3600 infop[i].fh.handle_follows = FALSE;
3601 dp = nextdp(dp);
3602 continue;
3603 }
3604
3605 nva.va_mask = AT_ALL;
3606 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3607
3608 /* Lie about the object type for a referral */
3609 if (vn_is_nfs_reparse(nvp, cr))
3610 nvap->va_type = VLNK;
3611
3612 vattr_to_post_op_attr(nvap, &infop[i].attr);
3613
3614 error = makefh3(&infop[i].fh.handle, nvp, exi);
3615 if (!error)
3616 infop[i].fh.handle_follows = TRUE;
3617 else
3618 infop[i].fh.handle_follows = FALSE;
3619
3620 VN_RELE(nvp);
3621 dp = nextdp(dp);
3622 }
3623
3624 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626 if (ndata == NULL)
3627 ndata = data;
3628
3629 if (ret > 0) {
3630 /*
3631 * We had to drop one or more entries in order to fit
3632 * during the character conversion. We need to patch
3633 * up the size and eof info.
3634 */
3635 if (iseof)
3636 iseof = FALSE;
3637
3638 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3639 nents, ret);
3640 }
3641
3642
3643 #if 0 /* notyet */
3644 /*
3645 * Don't do this. It causes local disk writes when just
3646 * reading the file and the overhead is deemed larger
3647 * than the benefit.
3648 */
3649 /*
3650 * Force modified metadata out to stable storage.
3651 */
3652 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3653 #endif
3654
3655 kmem_free(namlen, args->dircount);
3656
3657 resp->status = NFS3_OK;
3658 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3659 resp->resok.cookieverf = 0;
3660 resp->resok.reply.entries = (entryplus3 *)ndata;
3661 resp->resok.reply.eof = iseof;
3662 resp->resok.size = nents;
3663 resp->resok.count = args->dircount - ret;
3664 resp->resok.maxcount = args->maxcount;
3665
3666 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3667 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3668 if (ndata != data)
3669 kmem_free(data, args->dircount);
3670
3671
3672 VN_RELE(vp);
3673
3674 return;
3675
3676 out:
3677 if (curthread->t_flag & T_WOULDBLOCK) {
3678 curthread->t_flag &= ~T_WOULDBLOCK;
3679 resp->status = NFS3ERR_JUKEBOX;
3680 } else {
3681 resp->status = puterrno3(error);
3682 }
3683 out1:
3684 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686
3687 if (vp != NULL) {
3688 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3689 VN_RELE(vp);
3690 }
3691
3692 if (namlen != NULL)
3693 kmem_free(namlen, args->dircount);
3694
3695 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3696 }
3697
3698 void *
3699 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3700 {
3701
3702 return (&args->dir);
3703 }
3704
3705 void
3706 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3707 {
3708
3709 if (resp->status == NFS3_OK) {
3710 kmem_free(resp->resok.reply.entries, resp->resok.count);
3711 kmem_free(resp->resok.infop,
3712 resp->resok.size * sizeof (struct entryplus3_info));
3713 }
3714 }
3715
3716 /* ARGSUSED */
3717 void
3718 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3719 struct svc_req *req, cred_t *cr, bool_t ro)
3720 {
3721 int error;
3722 vnode_t *vp;
3723 struct vattr *vap;
3724 struct vattr va;
3725 struct statvfs64 sb;
3726
3727 vap = NULL;
3728
3729 vp = nfs3_fhtovp(&args->fsroot, exi);
3730
3731 DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3732 cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3733
3734 if (vp == NULL) {
3735 error = ESTALE;
3736 goto out;
3737 }
3738
3739 if (is_system_labeled()) {
3740 bslabel_t *clabel = req->rq_label;
3741
3742 ASSERT(clabel != NULL);
3743 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3744 "got client label from request(1)", struct svc_req *, req);
3745
3746 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3747 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3748 exi)) {
3749 resp->status = NFS3ERR_ACCES;
3750 goto out1;
3751 }
3752 }
3762
3763 resp->status = NFS3_OK;
3764 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3765 if (sb.f_blocks != (fsblkcnt64_t)-1)
3766 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3767 else
3768 resp->resok.tbytes = (size3)sb.f_blocks;
3769 if (sb.f_bfree != (fsblkcnt64_t)-1)
3770 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3771 else
3772 resp->resok.fbytes = (size3)sb.f_bfree;
3773 if (sb.f_bavail != (fsblkcnt64_t)-1)
3774 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3775 else
3776 resp->resok.abytes = (size3)sb.f_bavail;
3777 resp->resok.tfiles = (size3)sb.f_files;
3778 resp->resok.ffiles = (size3)sb.f_ffree;
3779 resp->resok.afiles = (size3)sb.f_favail;
3780 resp->resok.invarsec = 0;
3781
3782 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3783 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3784 VN_RELE(vp);
3785
3786 return;
3787
3788 out:
3789 if (curthread->t_flag & T_WOULDBLOCK) {
3790 curthread->t_flag &= ~T_WOULDBLOCK;
3791 resp->status = NFS3ERR_JUKEBOX;
3792 } else
3793 resp->status = puterrno3(error);
3794 out1:
3795 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3796 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3797
3798 if (vp != NULL)
3799 VN_RELE(vp);
3800 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3801 }
3802
3803 void *
3804 rfs3_fsstat_getfh(FSSTAT3args *args)
3805 {
3806
3807 return (&args->fsroot);
3808 }
3809
3810 /* ARGSUSED */
3811 void
3812 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3813 struct svc_req *req, cred_t *cr, bool_t ro)
3814 {
3815 vnode_t *vp;
3816 struct vattr *vap;
3817 struct vattr va;
3818 uint32_t xfer_size;
3819 ulong_t l = 0;
3820 int error;
3821
3822 vp = nfs3_fhtovp(&args->fsroot, exi);
3823
3824 DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3825 cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3826
3827 if (vp == NULL) {
3828 if (curthread->t_flag & T_WOULDBLOCK) {
3829 curthread->t_flag &= ~T_WOULDBLOCK;
3830 resp->status = NFS3ERR_JUKEBOX;
3831 } else
3832 resp->status = NFS3ERR_STALE;
3833 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3834 goto out;
3835 }
3836
3837 if (is_system_labeled()) {
3838 bslabel_t *clabel = req->rq_label;
3839
3840 ASSERT(clabel != NULL);
3841 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3842 "got client label from request(1)", struct svc_req *, req);
3843
3844 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3845 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3879 /*
3880 * If the underlying file system does not support _PC_FILESIZEBITS,
3881 * return a reasonable default. Note that error code on VOP_PATHCONF
3882 * will be 0, even if the underlying file system does not support
3883 * _PC_FILESIZEBITS.
3884 */
3885 if (l == (ulong_t)-1) {
3886 resp->resok.maxfilesize = MAXOFF32_T;
3887 } else {
3888 if (l >= (sizeof (uint64_t) * 8))
3889 resp->resok.maxfilesize = INT64_MAX;
3890 else
3891 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3892 }
3893
3894 resp->resok.time_delta.seconds = 0;
3895 resp->resok.time_delta.nseconds = 1000;
3896 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3897 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3898
3899 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3900 cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3901
3902 VN_RELE(vp);
3903
3904 return;
3905
3906 out:
3907 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3908 cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3909 if (vp != NULL)
3910 VN_RELE(vp);
3911 }
3912
3913 void *
3914 rfs3_fsinfo_getfh(FSINFO3args *args)
3915 {
3916 return (&args->fsroot);
3917 }
3918
3919 /* ARGSUSED */
3920 void
3921 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3922 struct svc_req *req, cred_t *cr, bool_t ro)
3923 {
3924 int error;
3925 vnode_t *vp;
3926 struct vattr *vap;
3927 struct vattr va;
3928 ulong_t val;
3929
3930 vap = NULL;
3931
3932 vp = nfs3_fhtovp(&args->object, exi);
3933
3934 DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3935 cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3936
3937 if (vp == NULL) {
3938 error = ESTALE;
3939 goto out;
3940 }
3941
3942 if (is_system_labeled()) {
3943 bslabel_t *clabel = req->rq_label;
3944
3945 ASSERT(clabel != NULL);
3946 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3947 "got client label from request(1)", struct svc_req *, req);
3948
3949 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3950 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3951 exi)) {
3952 resp->status = NFS3ERR_ACCES;
3953 goto out1;
3954 }
3955 }
3971 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3972 if (error)
3973 goto out;
3974 if (val == 1)
3975 resp->resok.info.no_trunc = TRUE;
3976 else
3977 resp->resok.info.no_trunc = FALSE;
3978
3979 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3980 if (error)
3981 goto out;
3982 if (val == 1)
3983 resp->resok.info.chown_restricted = TRUE;
3984 else
3985 resp->resok.info.chown_restricted = FALSE;
3986
3987 resp->status = NFS3_OK;
3988 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3989 resp->resok.info.case_insensitive = FALSE;
3990 resp->resok.info.case_preserving = TRUE;
3991 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
3992 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
3993 VN_RELE(vp);
3994 return;
3995
3996 out:
3997 if (curthread->t_flag & T_WOULDBLOCK) {
3998 curthread->t_flag &= ~T_WOULDBLOCK;
3999 resp->status = NFS3ERR_JUKEBOX;
4000 } else
4001 resp->status = puterrno3(error);
4002 out1:
4003 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4004 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4005 if (vp != NULL)
4006 VN_RELE(vp);
4007 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4008 }
4009
4010 void *
4011 rfs3_pathconf_getfh(PATHCONF3args *args)
4012 {
4013
4014 return (&args->object);
4015 }
4016
4017 void
4018 rfs3_commit(COMMIT3args *args, COMMIT3res *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 *bvap;
4024 struct vattr bva;
4025 struct vattr *avap;
4026 struct vattr ava;
4027
4028 bvap = NULL;
4029 avap = NULL;
4030
4031 vp = nfs3_fhtovp(&args->file, exi);
4032
4033 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4034 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4035
4036 if (vp == NULL) {
4037 error = ESTALE;
4038 goto out;
4039 }
4040
4041 bva.va_mask = AT_ALL;
4042 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4043
4044 /*
4045 * If we can't get the attributes, then we can't do the
4046 * right access checking. So, we'll fail the request.
4047 */
4048 if (error)
4049 goto out;
4050
4051 bvap = &bva;
4052
4053 if (rdonly(ro, vp)) {
4054 resp->status = NFS3ERR_ROFS;
4055 goto out1;
4056 }
4057
4058 if (vp->v_type != VREG) {
4059 resp->status = NFS3ERR_INVAL;
4060 goto out1;
4073 resp->status = NFS3ERR_ACCES;
4074 goto out1;
4075 }
4076 }
4077 }
4078
4079 if (crgetuid(cr) != bva.va_uid &&
4080 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4081 goto out;
4082
4083 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4084
4085 ava.va_mask = AT_ALL;
4086 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4087
4088 if (error)
4089 goto out;
4090
4091 resp->status = NFS3_OK;
4092 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4093 resp->resok.verf = write3verf;
4094
4095 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4096 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4097
4098 VN_RELE(vp);
4099
4100 return;
4101
4102 out:
4103 if (curthread->t_flag & T_WOULDBLOCK) {
4104 curthread->t_flag &= ~T_WOULDBLOCK;
4105 resp->status = NFS3ERR_JUKEBOX;
4106 } else
4107 resp->status = puterrno3(error);
4108 out1:
4109 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4110 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4111
4112 if (vp != NULL)
4113 VN_RELE(vp);
4114 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4115 }
4116
4117 void *
4118 rfs3_commit_getfh(COMMIT3args *args)
4119 {
4120
4121 return (&args->file);
4122 }
4123
4124 static int
4125 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4126 {
4127
4128 vap->va_mask = 0;
4129
4130 if (sap->mode.set_it) {
4131 vap->va_mode = (mode_t)sap->mode.mode;
4132 vap->va_mask |= AT_MODE;
4133 }
4134 if (sap->uid.set_it) {
4135 vap->va_uid = (uid_t)sap->uid.uid;
4136 vap->va_mask |= AT_UID;
4137 }
4138 if (sap->gid.set_it) {
4139 vap->va_gid = (gid_t)sap->gid.gid;
4140 vap->va_mask |= AT_GID;
4168 /* check time validity */
4169 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4170 return (EOVERFLOW);
4171 #endif
4172 /*
4173 * nfs protocol defines times as unsigned so don't extend sign,
4174 * unless sysadmin set nfs_allow_preepoch_time.
4175 */
4176 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4177 sap->mtime.mtime.seconds);
4178 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4179 vap->va_mask |= AT_MTIME;
4180 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4181 gethrestime(&vap->va_mtime);
4182 vap->va_mask |= AT_MTIME;
4183 }
4184
4185 return (0);
4186 }
4187
4188 static ftype3 vt_to_nf3[] = {
4189 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4190 };
4191
4192 static int
4193 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4194 {
4195
4196 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4197 /* Return error if time or size overflow */
4198 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4199 return (EOVERFLOW);
4200 }
4201 fap->type = vt_to_nf3[vap->va_type];
4202 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4203 fap->nlink = (uint32)vap->va_nlink;
4204 if (vap->va_uid == UID_NOBODY)
4205 fap->uid = (uid3)NFS_UID_NOBODY;
4206 else
4207 fap->uid = (uid3)vap->va_uid;
4208 if (vap->va_gid == GID_NOBODY)
4250 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4251 poap->attributes = TRUE;
4252 } else
4253 poap->attributes = FALSE;
4254 }
4255
4256 void
4257 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4258 {
4259
4260 /* don't return attrs if time overflow */
4261 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4262 poap->attributes = TRUE;
4263 } else
4264 poap->attributes = FALSE;
4265 }
4266
4267 static void
4268 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4269 {
4270
4271 vattr_to_pre_op_attr(bvap, &wccp->before);
4272 vattr_to_post_op_attr(avap, &wccp->after);
4273 }
4274
4275 void
4276 rfs3_srvrinit(void)
4277 {
4278 struct rfs3_verf_overlay {
4279 uint_t id; /* a "unique" identifier */
4280 int ts; /* a unique timestamp */
4281 } *verfp;
4282 timestruc_t now;
4283
4284 /*
4285 * The following algorithm attempts to find a unique verifier
4286 * to be used as the write verifier returned from the server
4287 * to the client. It is important that this verifier change
4288 * whenever the server reboots. Of secondary importance, it
4289 * is important for the verifier to be unique between two
4290 * different servers.
4291 *
4292 * Thus, an attempt is made to use the system hostid and the
4293 * current time in seconds when the nfssrv kernel module is
4294 * loaded. It is assumed that an NFS server will not be able
4295 * to boot and then to reboot in less than a second. If the
4296 * hostid has not been set, then the current high resolution
4297 * time is used. This will ensure different verifiers each
4298 * time the server reboots and minimize the chances that two
4299 * different servers will have the same verifier.
4300 */
4301
4302 #ifndef lint
4303 /*
4304 * We ASSERT that this constant logic expression is
4305 * always true because in the past, it wasn't.
4306 */
4307 ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4308 #endif
4309
4310 gethrestime(&now);
4311 verfp = (struct rfs3_verf_overlay *)&write3verf;
4312 verfp->ts = (int)now.tv_sec;
4313 verfp->id = zone_get_hostid(NULL);
4314
4315 if (verfp->id == 0)
4316 verfp->id = (uint_t)now.tv_nsec;
4317
4318 nfs3_srv_caller_id = fs_new_caller_id();
4319
4320 }
4321
4322 static int
4323 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4324 {
4325 struct clist *wcl;
4326 int wlist_len;
4327 count3 count = rok->count;
4328
4329 wcl = args->wlist;
4330 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4331 return (FALSE);
4332 }
4333
4334 wcl = args->wlist;
4335 rok->wlist_len = wlist_len;
4336 rok->wlist = wcl;
4337 return (TRUE);
4338 }
4339
4340 void
4341 rfs3_srvrfini(void)
4342 {
4343 /* Nothing to do */
4344 }
|
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 static zone_key_t rfs3_zone_key;
95
96 /* ARGSUSED */
97 void
98 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
99 struct svc_req *req, cred_t *cr, bool_t ro)
100 {
101 int error;
102 vnode_t *vp;
103 struct vattr va;
104
105 vp = nfs3_fhtovp(&args->object, exi);
106
107 DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
108 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
109 GETATTR3args *, args);
110
111 if (vp == NULL) {
112 error = ESTALE;
113 goto out;
114 }
115
116 va.va_mask = AT_ALL;
117 error = rfs4_delegated_getattr(vp, &va, 0, cr);
118
119 if (!error) {
120 /* Lie about the object type for a referral */
121 if (vn_is_nfs_reparse(vp, cr))
122 va.va_type = VLNK;
123
124 /* overflow error if time or size is out of range */
125 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
126 if (error)
127 goto out;
128 resp->status = NFS3_OK;
129
130 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
131 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
132 GETATTR3res *, resp);
133
134 VN_RELE(vp);
135
136 return;
137 }
138
139 out:
140 if (curthread->t_flag & T_WOULDBLOCK) {
141 curthread->t_flag &= ~T_WOULDBLOCK;
142 resp->status = NFS3ERR_JUKEBOX;
143 } else
144 resp->status = puterrno3(error);
145
146 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
147 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
148 GETATTR3res *, resp);
149
150 if (vp != NULL)
151 VN_RELE(vp);
152 }
153
154 void *
155 rfs3_getattr_getfh(GETATTR3args *args)
156 {
157 return (&args->object);
158 }
159
160 void
161 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
162 struct svc_req *req, cred_t *cr, bool_t ro)
163 {
164 int error;
165 vnode_t *vp;
166 struct vattr *bvap;
167 struct vattr bva;
168 struct vattr *avap;
169 struct vattr ava;
170 int flag;
171 int in_crit = 0;
172 struct flock64 bf;
173 caller_context_t ct;
174
175 bvap = NULL;
176 avap = NULL;
177
178 vp = nfs3_fhtovp(&args->object, exi);
179
180 DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
181 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
182 SETATTR3args *, args);
183
184 if (vp == NULL) {
185 error = ESTALE;
186 goto out;
187 }
188
189 error = sattr3_to_vattr(&args->new_attributes, &ava);
190 if (error)
191 goto out;
192
193 if (is_system_labeled()) {
194 bslabel_t *clabel = req->rq_label;
195
196 ASSERT(clabel != NULL);
197 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
198 "got client label from request(1)", struct svc_req *, req);
199
200 if (!blequal(&l_admin_low->tsl_label, clabel)) {
201 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
202 exi)) {
323 goto out1;
324 }
325
326 ava.va_mask = AT_ALL;
327 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
328
329 /*
330 * Force modified metadata out to stable storage.
331 */
332 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
333
334 if (error)
335 goto out;
336
337 if (in_crit)
338 nbl_end_crit(vp);
339
340 resp->status = NFS3_OK;
341 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
342
343 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
344 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
345 SETATTR3res *, resp);
346
347 VN_RELE(vp);
348
349 return;
350
351 out:
352 if (curthread->t_flag & T_WOULDBLOCK) {
353 curthread->t_flag &= ~T_WOULDBLOCK;
354 resp->status = NFS3ERR_JUKEBOX;
355 } else
356 resp->status = puterrno3(error);
357 out1:
358 DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
359 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
360 SETATTR3res *, resp);
361
362 if (vp != NULL) {
363 if (in_crit)
364 nbl_end_crit(vp);
365 VN_RELE(vp);
366 }
367 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
368 }
369
370 void *
371 rfs3_setattr_getfh(SETATTR3args *args)
372 {
373 return (&args->object);
374 }
375
376 /* ARGSUSED */
377 void
378 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
379 struct svc_req *req, cred_t *cr, bool_t ro)
380 {
381 int error;
382 vnode_t *vp;
383 vnode_t *dvp;
384 struct vattr *vap;
385 struct vattr va;
386 struct vattr *dvap;
387 struct vattr dva;
388 nfs_fh3 *fhp;
389 struct sec_ol sec = {0, 0};
390 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
391 struct sockaddr *ca;
392 char *name = NULL;
393
394 dvap = NULL;
395
396 if (exi != NULL)
397 exi_hold(exi);
398
399 /*
400 * Allow lookups from the root - the default
401 * location of the public filehandle.
402 */
403 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
404 dvp = ZONE_ROOTVP();
405 VN_HOLD(dvp);
406
407 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
408 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
409 LOOKUP3args *, args);
410 } else {
411 dvp = nfs3_fhtovp(&args->what.dir, exi);
412
413 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
414 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
415 LOOKUP3args *, args);
416
417 if (dvp == NULL) {
418 error = ESTALE;
419 goto out;
420 }
421 }
422
423 dva.va_mask = AT_ALL;
424 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
425
426 if (args->what.name == nfs3nametoolong) {
427 resp->status = NFS3ERR_NAMETOOLONG;
428 goto out1;
429 }
430
431 if (args->what.name == NULL || *(args->what.name) == '\0') {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435
436 fhp = &args->what.dir;
437 if (strcmp(args->what.name, "..") == 0 &&
438 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
439 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
440 (dvp->v_flag & VROOT)) {
441 /*
442 * special case for ".." and 'nohide'exported root
443 */
444 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
445 resp->status = NFS3ERR_ACCES;
446 goto out1;
447 }
448 } else {
449 resp->status = NFS3ERR_NOENT;
450 goto out1;
451 }
452 }
453
454 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
455 name = nfscmd_convname(ca, exi, args->what.name,
456 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
457
458 if (name == NULL) {
459 resp->status = NFS3ERR_ACCES;
460 goto out1;
461 }
462
463 /*
464 * If the public filehandle is used then allow
465 * a multi-component lookup
466 */
467 if (PUBLIC_FH3(&args->what.dir)) {
468 publicfh_flag = TRUE;
469
470 exi_rele(&exi);
471
472 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
473 &exi, &sec);
474
475 /*
476 * Since WebNFS may bypass MOUNT, we need to ensure this
477 * request didn't come from an unlabeled admin_low client.
478 */
479 if (is_system_labeled() && error == 0) {
480 int addr_type;
481 void *ipaddr;
482 tsol_tpc_t *tp;
483
484 if (ca->sa_family == AF_INET) {
485 addr_type = IPV4_VERSION;
486 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
487 } else if (ca->sa_family == AF_INET6) {
488 addr_type = IPV6_VERSION;
489 ipaddr = &((struct sockaddr_in6 *)
490 ca)->sin6_addr;
491 }
492 tp = find_tpc(ipaddr, addr_type, B_FALSE);
493 if (tp == NULL || tp->tpc_tp.tp_doi !=
494 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
495 SUN_CIPSO) {
496 VN_RELE(vp);
497 error = EACCES;
498 }
499 if (tp != NULL)
500 TPC_RELE(tp);
501 }
502 } else {
503 error = VOP_LOOKUP(dvp, name, &vp,
504 NULL, 0, NULL, cr, NULL, NULL, NULL);
505 }
506
507 if (name != args->what.name)
508 kmem_free(name, MAXPATHLEN + 1);
509
510 if (error == 0 && vn_ismntpt(vp)) {
511 error = rfs_cross_mnt(&vp, &exi);
512 if (error)
513 VN_RELE(vp);
514 }
515
516 if (is_system_labeled() && error == 0) {
517 bslabel_t *clabel = req->rq_label;
518
519 ASSERT(clabel != NULL);
520 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
521 "got client label from request(1)", struct svc_req *, req);
522
523 if (!blequal(&l_admin_low->tsl_label, clabel)) {
524 if (!do_rfs_label_check(clabel, dvp,
525 DOMINANCE_CHECK, exi)) {
526 VN_RELE(vp);
527 error = EACCES;
528 }
529 }
530 }
531
532 dva.va_mask = AT_ALL;
533 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
534
535 if (error)
536 goto out;
537
538 if (sec.sec_flags & SEC_QUERY) {
539 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
540 } else {
541 error = makefh3(&resp->resok.object, vp, exi);
542 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
543 auth_weak = TRUE;
544 }
545
546 if (error) {
547 VN_RELE(vp);
548 goto out;
549 }
550
551 va.va_mask = AT_ALL;
552 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
553
554 exi_rele(&exi);
555 VN_RELE(vp);
556
557 resp->status = NFS3_OK;
558 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
559 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
560
561 /*
562 * If it's public fh, no 0x81, and client's flavor is
563 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
564 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
565 */
566 if (auth_weak)
567 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
568
569 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
570 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
571 LOOKUP3res *, resp);
572 VN_RELE(dvp);
573
574 return;
575
576 out:
577 if (curthread->t_flag & T_WOULDBLOCK) {
578 curthread->t_flag &= ~T_WOULDBLOCK;
579 resp->status = NFS3ERR_JUKEBOX;
580 } else
581 resp->status = puterrno3(error);
582 out1:
583 if (exi != NULL)
584 exi_rele(&exi);
585
586 DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
587 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
588 LOOKUP3res *, resp);
589
590 if (dvp != NULL)
591 VN_RELE(dvp);
592 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
593
594 }
595
596 void *
597 rfs3_lookup_getfh(LOOKUP3args *args)
598 {
599 return (&args->what.dir);
600 }
601
602 void
603 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
604 struct svc_req *req, cred_t *cr, bool_t ro)
605 {
606 int error;
607 vnode_t *vp;
608 struct vattr *vap;
609 struct vattr va;
610 int checkwriteperm;
611 boolean_t dominant_label = B_FALSE;
612 boolean_t equal_label = B_FALSE;
613 boolean_t admin_low_client;
614
615 vap = NULL;
616
617 vp = nfs3_fhtovp(&args->object, exi);
618
619 DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
620 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
621 ACCESS3args *, args);
622
623 if (vp == NULL) {
624 error = ESTALE;
625 goto out;
626 }
627
628 /*
629 * If the file system is exported read only, it is not appropriate
630 * to check write permissions for regular files and directories.
631 * Special files are interpreted by the client, so the underlying
632 * permissions are sent back to the client for interpretation.
633 */
634 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
635 checkwriteperm = 0;
636 else
637 checkwriteperm = 1;
638
639 /*
640 * We need the mode so that we can correctly determine access
641 * permissions relative to a mandatory lock file. Access to
711 equal_label)
712 resp->resok.access |= ACCESS3_DELETE;
713 }
714 if (args->access & ACCESS3_EXECUTE) {
715 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
716 if (error) {
717 if (curthread->t_flag & T_WOULDBLOCK)
718 goto out;
719 } else if (!MANDLOCK(vp, va.va_mode) &&
720 (!is_system_labeled() || admin_low_client ||
721 dominant_label))
722 resp->resok.access |= ACCESS3_EXECUTE;
723 }
724
725 va.va_mask = AT_ALL;
726 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
727
728 resp->status = NFS3_OK;
729 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
730
731 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
732 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
733 ACCESS3res *, resp);
734
735 VN_RELE(vp);
736
737 return;
738
739 out:
740 if (curthread->t_flag & T_WOULDBLOCK) {
741 curthread->t_flag &= ~T_WOULDBLOCK;
742 resp->status = NFS3ERR_JUKEBOX;
743 } else
744 resp->status = puterrno3(error);
745 DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
746 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
747 ACCESS3res *, resp);
748 if (vp != NULL)
749 VN_RELE(vp);
750 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
751 }
752
753 void *
754 rfs3_access_getfh(ACCESS3args *args)
755 {
756 return (&args->object);
757 }
758
759 /* ARGSUSED */
760 void
761 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
762 struct svc_req *req, cred_t *cr, bool_t ro)
763 {
764 int error;
765 vnode_t *vp;
766 struct vattr *vap;
767 struct vattr va;
768 struct iovec iov;
769 struct uio uio;
770 char *data;
771 struct sockaddr *ca;
772 char *name = NULL;
773 int is_referral = 0;
774
775 vap = NULL;
776
777 vp = nfs3_fhtovp(&args->symlink, exi);
778
779 DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
780 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
781 READLINK3args *, args);
782
783 if (vp == NULL) {
784 error = ESTALE;
785 goto out;
786 }
787
788 va.va_mask = AT_ALL;
789 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
790 if (error)
791 goto out;
792
793 vap = &va;
794
795 /* We lied about the object type for a referral */
796 if (vn_is_nfs_reparse(vp, cr))
797 is_referral = 1;
798
799 if (vp->v_type != VLNK && !is_referral) {
800 resp->status = NFS3ERR_INVAL;
801 goto out1;
881 kmem_free(data, MAXPATHLEN + 1);
882 goto out;
883 }
884
885 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
886 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
887 MAXPATHLEN + 1);
888
889 if (name == NULL) {
890 /*
891 * Even though the conversion failed, we return
892 * something. We just don't translate it.
893 */
894 name = data;
895 }
896
897 resp->status = NFS3_OK;
898 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
899 resp->resok.data = name;
900
901 DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
902 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
903 READLINK3res *, resp);
904 VN_RELE(vp);
905
906 if (name != data)
907 kmem_free(data, MAXPATHLEN + 1);
908
909 return;
910
911 out:
912 if (curthread->t_flag & T_WOULDBLOCK) {
913 curthread->t_flag &= ~T_WOULDBLOCK;
914 resp->status = NFS3ERR_JUKEBOX;
915 } else
916 resp->status = puterrno3(error);
917 out1:
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 if (vp != NULL)
922 VN_RELE(vp);
923 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
924 }
925
926 void *
927 rfs3_readlink_getfh(READLINK3args *args)
928 {
929 return (&args->symlink);
930 }
931
932 void
933 rfs3_readlink_free(READLINK3res *resp)
934 {
935 if (resp->status == NFS3_OK)
936 kmem_free(resp->resok.data, MAXPATHLEN + 1);
937 }
938
939 /*
940 * Server routine to handle read
941 * May handle RDMA data as well as mblks
942 */
943 /* ARGSUSED */
944 void
945 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
946 struct svc_req *req, cred_t *cr, bool_t ro)
947 {
948 int error;
949 vnode_t *vp;
950 struct vattr *vap;
951 struct vattr va;
952 struct iovec iov, *iovp = NULL;
953 int iovcnt;
954 struct uio uio;
955 u_offset_t offset;
956 mblk_t *mp = NULL;
957 int in_crit = 0;
958 int need_rwunlock = 0;
959 caller_context_t ct;
960 int rdma_used = 0;
961 int loaned_buffers;
962 struct uio *uiop;
963
964 vap = NULL;
965
966 vp = nfs3_fhtovp(&args->file, exi);
967
968 DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
969 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
970 READ3args *, args);
971
972
973 if (vp == NULL) {
974 error = ESTALE;
975 goto out;
976 }
977
978 if (args->wlist) {
979 if (args->count > clist_len(args->wlist)) {
980 error = EINVAL;
981 goto out;
982 }
983 rdma_used = 1;
984 }
985
986 /* use loaned buffers for TCP */
987 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
988
989 if (is_system_labeled()) {
990 bslabel_t *clabel = req->rq_label;
991
992 ASSERT(clabel != NULL);
1206 resp->resok.eof = FALSE;
1207 resp->resok.data.data_len = resp->resok.count;
1208
1209 if (mp)
1210 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1211
1212 resp->resok.data.mp = mp;
1213 resp->resok.size = (uint_t)args->count;
1214
1215 if (rdma_used) {
1216 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1217 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1218 resp->status = NFS3ERR_INVAL;
1219 }
1220 } else {
1221 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1222 (resp->resok).wlist = NULL;
1223 }
1224
1225 done:
1226 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1227 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1228 READ3res *, resp);
1229
1230 VN_RELE(vp);
1231
1232 if (iovp != NULL)
1233 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1234
1235 return;
1236
1237 out:
1238 if (curthread->t_flag & T_WOULDBLOCK) {
1239 curthread->t_flag &= ~T_WOULDBLOCK;
1240 resp->status = NFS3ERR_JUKEBOX;
1241 } else
1242 resp->status = puterrno3(error);
1243 out1:
1244 DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1245 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1246 READ3res *, resp);
1247
1248 if (vp != NULL) {
1249 if (need_rwunlock)
1250 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1251 if (in_crit)
1252 nbl_end_crit(vp);
1253 VN_RELE(vp);
1254 }
1255 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1256
1257 if (iovp != NULL)
1258 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1259 }
1260
1261 void
1262 rfs3_read_free(READ3res *resp)
1263 {
1264 mblk_t *mp;
1265
1266 if (resp->status == NFS3_OK) {
1267 mp = resp->resok.data.mp;
1268 if (mp != NULL)
1269 freemsg(mp);
1270 }
1271 }
1272
1273 void *
1274 rfs3_read_getfh(READ3args *args)
1275 {
1276 return (&args->file);
1277 }
1278
1279 #define MAX_IOVECS 12
1280
1281 #ifdef DEBUG
1282 static int rfs3_write_hits = 0;
1283 static int rfs3_write_misses = 0;
1284 #endif
1285
1286 void
1287 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1288 struct svc_req *req, cred_t *cr, bool_t ro)
1289 {
1290 nfs3_srv_t *ns;
1291 int error;
1292 vnode_t *vp;
1293 struct vattr *bvap = NULL;
1294 struct vattr bva;
1295 struct vattr *avap = NULL;
1296 struct vattr ava;
1297 u_offset_t rlimit;
1298 struct uio uio;
1299 struct iovec iov[MAX_IOVECS];
1300 mblk_t *m;
1301 struct iovec *iovp;
1302 int iovcnt;
1303 int ioflag;
1304 cred_t *savecred;
1305 int in_crit = 0;
1306 int rwlock_ret = -1;
1307 caller_context_t ct;
1308
1309 vp = nfs3_fhtovp(&args->file, exi);
1310
1311 DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1312 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1313 WRITE3args *, args);
1314
1315 if (vp == NULL) {
1316 error = ESTALE;
1317 goto err;
1318 }
1319
1320 ns = zone_getspecific(rfs3_zone_key, curzone);
1321 if (is_system_labeled()) {
1322 bslabel_t *clabel = req->rq_label;
1323
1324 ASSERT(clabel != NULL);
1325 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1326 "got client label from request(1)", struct svc_req *, req);
1327
1328 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1329 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1330 exi)) {
1331 resp->status = NFS3ERR_ACCES;
1332 goto err1;
1333 }
1334 }
1335 }
1336
1337 ct.cc_sysid = 0;
1338 ct.cc_pid = 0;
1339 ct.cc_caller_id = nfs3_srv_caller_id;
1340 ct.cc_flags = CC_DONTBLOCK;
1388
1389 if (vp->v_type != VREG) {
1390 resp->status = NFS3ERR_INVAL;
1391 goto err1;
1392 }
1393
1394 if (crgetuid(cr) != bva.va_uid &&
1395 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1396 goto err;
1397
1398 if (MANDLOCK(vp, bva.va_mode)) {
1399 resp->status = NFS3ERR_ACCES;
1400 goto err1;
1401 }
1402
1403 if (args->count == 0) {
1404 resp->status = NFS3_OK;
1405 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1406 resp->resok.count = 0;
1407 resp->resok.committed = args->stable;
1408 resp->resok.verf = ns->write3verf;
1409 goto out;
1410 }
1411
1412 if (args->mblk != NULL) {
1413 iovcnt = 0;
1414 for (m = args->mblk; m != NULL; m = m->b_cont)
1415 iovcnt++;
1416 if (iovcnt <= MAX_IOVECS) {
1417 #ifdef DEBUG
1418 rfs3_write_hits++;
1419 #endif
1420 iovp = iov;
1421 } else {
1422 #ifdef DEBUG
1423 rfs3_write_misses++;
1424 #endif
1425 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1426 }
1427 mblk_to_iov(args->mblk, iovcnt, iovp);
1428
1490
1491 /*
1492 * If we were unable to get the V_WRITELOCK_TRUE, then we
1493 * may not have accurate after attrs, so check if
1494 * we have both attributes, they have a non-zero va_seq, and
1495 * va_seq has changed by exactly one,
1496 * if not, turn off the before attr.
1497 */
1498 if (rwlock_ret != V_WRITELOCK_TRUE) {
1499 if (bvap == NULL || avap == NULL ||
1500 bvap->va_seq == 0 || avap->va_seq == 0 ||
1501 avap->va_seq != (bvap->va_seq + 1)) {
1502 bvap = NULL;
1503 }
1504 }
1505
1506 resp->status = NFS3_OK;
1507 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1508 resp->resok.count = args->count - uio.uio_resid;
1509 resp->resok.committed = args->stable;
1510 resp->resok.verf = ns->write3verf;
1511 goto out;
1512
1513 err:
1514 if (curthread->t_flag & T_WOULDBLOCK) {
1515 curthread->t_flag &= ~T_WOULDBLOCK;
1516 resp->status = NFS3ERR_JUKEBOX;
1517 } else
1518 resp->status = puterrno3(error);
1519 err1:
1520 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1521 out:
1522 DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1523 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1524 WRITE3res *, resp);
1525
1526 if (vp != NULL) {
1527 if (rwlock_ret != -1)
1528 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1529 if (in_crit)
1530 nbl_end_crit(vp);
1531 VN_RELE(vp);
1532 }
1533 }
1534
1535 void *
1536 rfs3_write_getfh(WRITE3args *args)
1537 {
1538 return (&args->file);
1539 }
1540
1541 void
1542 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1543 struct svc_req *req, cred_t *cr, bool_t ro)
1544 {
1545 int error;
1546 int in_crit = 0;
1547 vnode_t *vp;
1548 vnode_t *tvp = NULL;
1549 vnode_t *dvp;
1550 struct vattr *vap;
1551 struct vattr va;
1552 struct vattr *dbvap;
1553 struct vattr dbva;
1554 struct vattr *davap;
1555 struct vattr dava;
1556 enum vcexcl excl;
1557 nfstime3 *mtime;
1558 len_t reqsize;
1559 bool_t trunc;
1560 struct sockaddr *ca;
1561 char *name = NULL;
1562
1563 dbvap = NULL;
1564 davap = NULL;
1565
1566 dvp = nfs3_fhtovp(&args->where.dir, exi);
1567
1568 DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1569 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1570 CREATE3args *, args);
1571
1572 if (dvp == NULL) {
1573 error = ESTALE;
1574 goto out;
1575 }
1576
1577 dbva.va_mask = AT_ALL;
1578 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1579 davap = dbvap;
1580
1581 if (args->where.name == nfs3nametoolong) {
1582 resp->status = NFS3ERR_NAMETOOLONG;
1583 goto out1;
1584 }
1585
1586 if (args->where.name == NULL || *(args->where.name) == '\0') {
1587 resp->status = NFS3ERR_ACCES;
1588 goto out1;
1589 }
1590
1591 if (rdonly(ro, dvp)) {
1592 resp->status = NFS3ERR_ROFS;
1593 goto out1;
1594 }
1595
1596 if (protect_zfs_mntpt(dvp) != 0) {
1597 resp->status = NFS3ERR_ACCES;
1598 goto out1;
1599 }
1600
1601 if (is_system_labeled()) {
1602 bslabel_t *clabel = req->rq_label;
1603
1604 ASSERT(clabel != NULL);
1605 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1606 "got client label from request(1)", struct svc_req *, req);
1607
1608 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1609 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1610 exi)) {
1611 resp->status = NFS3ERR_ACCES;
1612 goto out1;
1613 }
1614 }
1615 }
1616
1617 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1618 name = nfscmd_convname(ca, exi, args->where.name,
1619 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1620
1854 else
1855 resp->resok.obj.handle_follows = TRUE;
1856
1857 /*
1858 * Force modified data and metadata out to stable storage.
1859 */
1860 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1861 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1862
1863 VN_RELE(vp);
1864 if (tvp != NULL) {
1865 if (in_crit)
1866 nbl_end_crit(tvp);
1867 VN_RELE(tvp);
1868 }
1869
1870 resp->status = NFS3_OK;
1871 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1872 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1873
1874 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1875 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1876 CREATE3res *, resp);
1877
1878 VN_RELE(dvp);
1879 return;
1880
1881 out:
1882 if (curthread->t_flag & T_WOULDBLOCK) {
1883 curthread->t_flag &= ~T_WOULDBLOCK;
1884 resp->status = NFS3ERR_JUKEBOX;
1885 } else
1886 resp->status = puterrno3(error);
1887 out1:
1888 DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1889 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1890 CREATE3res *, resp);
1891
1892 if (name != NULL && name != args->where.name)
1893 kmem_free(name, MAXPATHLEN + 1);
1894
1895 if (tvp != NULL) {
1896 if (in_crit)
1897 nbl_end_crit(tvp);
1898 VN_RELE(tvp);
1899 }
1900 if (dvp != NULL)
1901 VN_RELE(dvp);
1902 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1903 }
1904
1905 void *
1906 rfs3_create_getfh(CREATE3args *args)
1907 {
1908 return (&args->where.dir);
1909 }
1910
1911 void
1912 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1913 struct svc_req *req, cred_t *cr, bool_t ro)
1914 {
1915 int error;
1916 vnode_t *vp = NULL;
1917 vnode_t *dvp;
1918 struct vattr *vap;
1919 struct vattr va;
1920 struct vattr *dbvap;
1921 struct vattr dbva;
1922 struct vattr *davap;
1923 struct vattr dava;
1924 struct sockaddr *ca;
1925 char *name = NULL;
1926
1927 dbvap = NULL;
1928 davap = NULL;
1929
1930 dvp = nfs3_fhtovp(&args->where.dir, exi);
1931
1932 DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1933 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1934 MKDIR3args *, args);
1935
1936 if (dvp == NULL) {
1937 error = ESTALE;
1938 goto out;
1939 }
1940
1941 dbva.va_mask = AT_ALL;
1942 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1943 davap = dbvap;
1944
1945 if (args->where.name == nfs3nametoolong) {
1946 resp->status = NFS3ERR_NAMETOOLONG;
1947 goto out1;
1948 }
1949
1950 if (args->where.name == NULL || *(args->where.name) == '\0') {
1951 resp->status = NFS3ERR_ACCES;
1952 goto out1;
1953 }
1954
1955 if (rdonly(ro, dvp)) {
1956 resp->status = NFS3ERR_ROFS;
1957 goto out1;
1958 }
1959
1960 if (protect_zfs_mntpt(dvp) != 0) {
1961 resp->status = NFS3ERR_ACCES;
1962 goto out1;
1963 }
1964
1965 if (is_system_labeled()) {
1966 bslabel_t *clabel = req->rq_label;
1967
1968 ASSERT(clabel != NULL);
1969 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1970 "got client label from request(1)", struct svc_req *, req);
1971
1972 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1973 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1974 exi)) {
1975 resp->status = NFS3ERR_ACCES;
1976 goto out1;
1977 }
1978 }
1979 }
1980
1981 error = sattr3_to_vattr(&args->attributes, &va);
1982 if (error)
1983 goto out;
1984
2018 error = makefh3(&resp->resok.obj.handle, vp, exi);
2019 if (error)
2020 resp->resok.obj.handle_follows = FALSE;
2021 else
2022 resp->resok.obj.handle_follows = TRUE;
2023
2024 va.va_mask = AT_ALL;
2025 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2026
2027 /*
2028 * Force modified data and metadata out to stable storage.
2029 */
2030 (void) VOP_FSYNC(vp, 0, cr, NULL);
2031
2032 VN_RELE(vp);
2033
2034 resp->status = NFS3_OK;
2035 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2036 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2037
2038 DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2039 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2040 MKDIR3res *, resp);
2041 VN_RELE(dvp);
2042
2043 return;
2044
2045 out:
2046 if (curthread->t_flag & T_WOULDBLOCK) {
2047 curthread->t_flag &= ~T_WOULDBLOCK;
2048 resp->status = NFS3ERR_JUKEBOX;
2049 } else
2050 resp->status = puterrno3(error);
2051 out1:
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 if (dvp != NULL)
2056 VN_RELE(dvp);
2057 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2058 }
2059
2060 void *
2061 rfs3_mkdir_getfh(MKDIR3args *args)
2062 {
2063 return (&args->where.dir);
2064 }
2065
2066 void
2067 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2068 struct svc_req *req, cred_t *cr, bool_t ro)
2069 {
2070 int error;
2071 vnode_t *vp;
2072 vnode_t *dvp;
2073 struct vattr *vap;
2074 struct vattr va;
2075 struct vattr *dbvap;
2076 struct vattr dbva;
2077 struct vattr *davap;
2078 struct vattr dava;
2079 struct sockaddr *ca;
2080 char *name = NULL;
2081 char *symdata = NULL;
2082
2083 dbvap = NULL;
2084 davap = NULL;
2085
2086 dvp = nfs3_fhtovp(&args->where.dir, exi);
2087
2088 DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2089 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2090 SYMLINK3args *, args);
2091
2092 if (dvp == NULL) {
2093 error = ESTALE;
2094 goto err;
2095 }
2096
2097 dbva.va_mask = AT_ALL;
2098 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2099 davap = dbvap;
2100
2101 if (args->where.name == nfs3nametoolong) {
2102 resp->status = NFS3ERR_NAMETOOLONG;
2103 goto err1;
2104 }
2105
2106 if (args->where.name == NULL || *(args->where.name) == '\0') {
2107 resp->status = NFS3ERR_ACCES;
2108 goto err1;
2109 }
2110
2111 if (rdonly(ro, dvp)) {
2112 resp->status = NFS3ERR_ROFS;
2113 goto err1;
2114 }
2115
2116 if (protect_zfs_mntpt(dvp) != 0) {
2117 resp->status = NFS3ERR_ACCES;
2118 goto err1;
2119 }
2120
2121 if (is_system_labeled()) {
2122 bslabel_t *clabel = req->rq_label;
2123
2124 ASSERT(clabel != NULL);
2125 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2126 "got client label from request(1)", struct svc_req *, req);
2127
2128 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2129 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2130 exi)) {
2131 resp->status = NFS3ERR_ACCES;
2132 goto err1;
2133 }
2134 }
2135 }
2136
2137 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2138 if (error)
2139 goto err;
2140
2212 VN_RELE(vp);
2213
2214 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2215 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2216 goto out;
2217
2218 err:
2219 if (curthread->t_flag & T_WOULDBLOCK) {
2220 curthread->t_flag &= ~T_WOULDBLOCK;
2221 resp->status = NFS3ERR_JUKEBOX;
2222 } else
2223 resp->status = puterrno3(error);
2224 err1:
2225 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2226 out:
2227 if (name != NULL && name != args->where.name)
2228 kmem_free(name, MAXPATHLEN + 1);
2229 if (symdata != NULL && symdata != args->symlink.symlink_data)
2230 kmem_free(symdata, MAXPATHLEN + 1);
2231
2232 DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2233 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2234 SYMLINK3res *, resp);
2235
2236 if (dvp != NULL)
2237 VN_RELE(dvp);
2238 }
2239
2240 void *
2241 rfs3_symlink_getfh(SYMLINK3args *args)
2242 {
2243 return (&args->where.dir);
2244 }
2245
2246 void
2247 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2248 struct svc_req *req, cred_t *cr, bool_t ro)
2249 {
2250 int error;
2251 vnode_t *vp;
2252 vnode_t *realvp;
2253 vnode_t *dvp;
2254 struct vattr *vap;
2255 struct vattr va;
2256 struct vattr *dbvap;
2257 struct vattr dbva;
2258 struct vattr *davap;
2259 struct vattr dava;
2260 int mode;
2261 enum vcexcl excl;
2262 struct sockaddr *ca;
2263 char *name = NULL;
2264
2265 dbvap = NULL;
2266 davap = NULL;
2267
2268 dvp = nfs3_fhtovp(&args->where.dir, exi);
2269
2270 DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2271 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2272 MKNOD3args *, args);
2273
2274 if (dvp == NULL) {
2275 error = ESTALE;
2276 goto out;
2277 }
2278
2279 dbva.va_mask = AT_ALL;
2280 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2281 davap = dbvap;
2282
2283 if (args->where.name == nfs3nametoolong) {
2284 resp->status = NFS3ERR_NAMETOOLONG;
2285 goto out1;
2286 }
2287
2288 if (args->where.name == NULL || *(args->where.name) == '\0') {
2289 resp->status = NFS3ERR_ACCES;
2290 goto out1;
2291 }
2292
2293 if (rdonly(ro, dvp)) {
2294 resp->status = NFS3ERR_ROFS;
2295 goto out1;
2296 }
2297
2298 if (protect_zfs_mntpt(dvp) != 0) {
2299 resp->status = NFS3ERR_ACCES;
2300 goto out1;
2301 }
2302
2303 if (is_system_labeled()) {
2304 bslabel_t *clabel = req->rq_label;
2305
2306 ASSERT(clabel != NULL);
2307 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2308 "got client label from request(1)", struct svc_req *, req);
2309
2310 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2311 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2312 exi)) {
2313 resp->status = NFS3ERR_ACCES;
2314 goto out1;
2315 }
2316 }
2317 }
2318
2319 switch (args->what.type) {
2320 case NF3CHR:
2321 case NF3BLK:
2322 error = sattr3_to_vattr(
2403 else
2404 resp->resok.obj.handle_follows = TRUE;
2405
2406 va.va_mask = AT_ALL;
2407 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2408
2409 /*
2410 * Force modified metadata out to stable storage.
2411 *
2412 * if a underlying vp exists, pass it to VOP_FSYNC
2413 */
2414 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2415 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2416 else
2417 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2418
2419 VN_RELE(vp);
2420
2421 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2422 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2423 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2424 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2425 MKNOD3res *, resp);
2426 VN_RELE(dvp);
2427 return;
2428
2429 out:
2430 if (curthread->t_flag & T_WOULDBLOCK) {
2431 curthread->t_flag &= ~T_WOULDBLOCK;
2432 resp->status = NFS3ERR_JUKEBOX;
2433 } else
2434 resp->status = puterrno3(error);
2435 out1:
2436 DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2437 cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2438 MKNOD3res *, resp);
2439 if (dvp != NULL)
2440 VN_RELE(dvp);
2441 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2442 }
2443
2444 void *
2445 rfs3_mknod_getfh(MKNOD3args *args)
2446 {
2447 return (&args->where.dir);
2448 }
2449
2450 void
2451 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2452 struct svc_req *req, cred_t *cr, bool_t ro)
2453 {
2454 int error = 0;
2455 vnode_t *vp;
2456 struct vattr *bvap;
2457 struct vattr bva;
2458 struct vattr *avap;
2459 struct vattr ava;
2460 vnode_t *targvp = NULL;
2461 struct sockaddr *ca;
2462 char *name = NULL;
2463
2464 bvap = NULL;
2465 avap = NULL;
2466
2467 vp = nfs3_fhtovp(&args->object.dir, exi);
2468
2469 DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2470 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2471 REMOVE3args *, args);
2472
2473 if (vp == NULL) {
2474 error = ESTALE;
2475 goto err;
2476 }
2477
2478 bva.va_mask = AT_ALL;
2479 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2480 avap = bvap;
2481
2482 if (vp->v_type != VDIR) {
2483 resp->status = NFS3ERR_NOTDIR;
2484 goto err1;
2485 }
2486
2487 if (args->object.name == nfs3nametoolong) {
2488 resp->status = NFS3ERR_NAMETOOLONG;
2489 goto err1;
2490 }
2491
2559 * Force modified data and metadata out to stable storage.
2560 */
2561 (void) VOP_FSYNC(vp, 0, cr, NULL);
2562
2563 if (error)
2564 goto err;
2565
2566 resp->status = NFS3_OK;
2567 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2568 goto out;
2569
2570 err:
2571 if (curthread->t_flag & T_WOULDBLOCK) {
2572 curthread->t_flag &= ~T_WOULDBLOCK;
2573 resp->status = NFS3ERR_JUKEBOX;
2574 } else
2575 resp->status = puterrno3(error);
2576 err1:
2577 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2578 out:
2579 DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2580 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2581 REMOVE3res *, resp);
2582
2583 if (name != NULL && name != args->object.name)
2584 kmem_free(name, MAXPATHLEN + 1);
2585
2586 if (vp != NULL)
2587 VN_RELE(vp);
2588 }
2589
2590 void *
2591 rfs3_remove_getfh(REMOVE3args *args)
2592 {
2593 return (&args->object.dir);
2594 }
2595
2596 void
2597 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2598 struct svc_req *req, cred_t *cr, bool_t ro)
2599 {
2600 int error;
2601 vnode_t *vp;
2602 struct vattr *bvap;
2603 struct vattr bva;
2604 struct vattr *avap;
2605 struct vattr ava;
2606 struct sockaddr *ca;
2607 char *name = NULL;
2608
2609 bvap = NULL;
2610 avap = NULL;
2611
2612 vp = nfs3_fhtovp(&args->object.dir, exi);
2613
2614 DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2615 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2616 RMDIR3args *, args);
2617
2618 if (vp == NULL) {
2619 error = ESTALE;
2620 goto err;
2621 }
2622
2623 bva.va_mask = AT_ALL;
2624 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2625 avap = bvap;
2626
2627 if (vp->v_type != VDIR) {
2628 resp->status = NFS3ERR_NOTDIR;
2629 goto err1;
2630 }
2631
2632 if (args->object.name == nfs3nametoolong) {
2633 resp->status = NFS3ERR_NAMETOOLONG;
2634 goto err1;
2635 }
2636
2652 "got client label from request(1)", struct svc_req *, req);
2653
2654 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2655 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2656 exi)) {
2657 resp->status = NFS3ERR_ACCES;
2658 goto err1;
2659 }
2660 }
2661 }
2662
2663 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2664 name = nfscmd_convname(ca, exi, args->object.name,
2665 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2666
2667 if (name == NULL) {
2668 resp->status = NFS3ERR_INVAL;
2669 goto err1;
2670 }
2671
2672 error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2673
2674 if (name != args->object.name)
2675 kmem_free(name, MAXPATHLEN + 1);
2676
2677 ava.va_mask = AT_ALL;
2678 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2679
2680 /*
2681 * Force modified data and metadata out to stable storage.
2682 */
2683 (void) VOP_FSYNC(vp, 0, cr, NULL);
2684
2685 if (error) {
2686 /*
2687 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2688 * if the directory is not empty. A System V NFS server
2689 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2690 * over the wire.
2691 */
2692 if (error == EEXIST)
2693 error = ENOTEMPTY;
2694 goto err;
2695 }
2696
2697 resp->status = NFS3_OK;
2698 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2699 goto out;
2700
2701 err:
2702 if (curthread->t_flag & T_WOULDBLOCK) {
2703 curthread->t_flag &= ~T_WOULDBLOCK;
2704 resp->status = NFS3ERR_JUKEBOX;
2705 } else
2706 resp->status = puterrno3(error);
2707 err1:
2708 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2709 out:
2710 DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2711 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2712 RMDIR3res *, resp);
2713 if (vp != NULL)
2714 VN_RELE(vp);
2715
2716 }
2717
2718 void *
2719 rfs3_rmdir_getfh(RMDIR3args *args)
2720 {
2721 return (&args->object.dir);
2722 }
2723
2724 void
2725 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2726 struct svc_req *req, cred_t *cr, bool_t ro)
2727 {
2728 int error = 0;
2729 vnode_t *fvp;
2730 vnode_t *tvp;
2731 vnode_t *targvp;
2732 struct vattr *fbvap;
2733 struct vattr fbva;
2734 struct vattr *favap;
2735 struct vattr fava;
2736 struct vattr *tbvap;
2737 struct vattr tbva;
2738 struct vattr *tavap;
2739 struct vattr tava;
2740 nfs_fh3 *fh3;
2741 struct exportinfo *to_exi;
2742 vnode_t *srcvp = NULL;
2743 bslabel_t *clabel;
2744 struct sockaddr *ca;
2745 char *name = NULL;
2746 char *toname = NULL;
2747
2748 fbvap = NULL;
2749 favap = NULL;
2750 tbvap = NULL;
2751 tavap = NULL;
2752 tvp = NULL;
2753
2754 fvp = nfs3_fhtovp(&args->from.dir, exi);
2755
2756 DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2757 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2758 RENAME3args *, args);
2759
2760 if (fvp == NULL) {
2761 error = ESTALE;
2762 goto err;
2763 }
2764
2765 if (is_system_labeled()) {
2766 clabel = req->rq_label;
2767 ASSERT(clabel != NULL);
2768 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2769 "got client label from request(1)", struct svc_req *, req);
2770
2771 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2772 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2773 exi)) {
2774 resp->status = NFS3ERR_ACCES;
2775 goto err1;
2776 }
2777 }
2778 }
2779
2780 fbva.va_mask = AT_ALL;
2781 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2782 favap = fbvap;
2783
2784 fh3 = &args->to.dir;
2785 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2786 if (to_exi == NULL) {
2787 resp->status = NFS3ERR_ACCES;
2788 goto err1;
2789 }
2790 exi_rele(&to_exi);
2791
2792 if (to_exi != exi) {
2793 resp->status = NFS3ERR_XDEV;
2794 goto err1;
2795 }
2796
2797 tvp = nfs3_fhtovp(&args->to.dir, exi);
2798 if (tvp == NULL) {
2799 error = ESTALE;
2800 goto err;
2801 }
2802
2803 tbva.va_mask = AT_ALL;
2804 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2805 tavap = tbvap;
2806
2807 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2808 resp->status = NFS3ERR_NOTDIR;
2809 goto err1;
2810 }
2811
2812 if (args->from.name == nfs3nametoolong ||
2813 args->to.name == nfs3nametoolong) {
2814 resp->status = NFS3ERR_NAMETOOLONG;
2815 goto err1;
2816 }
2817 if (args->from.name == NULL || *(args->from.name) == '\0' ||
2818 args->to.name == NULL || *(args->to.name) == '\0') {
2819 resp->status = NFS3ERR_ACCES;
2820 goto err1;
2821 }
2822
2823 if (rdonly(ro, tvp)) {
2824 resp->status = NFS3ERR_ROFS;
2825 goto err1;
2826 }
2827
2828 if (protect_zfs_mntpt(tvp) != 0) {
2829 resp->status = NFS3ERR_ACCES;
2830 goto err1;
2831 }
2832
2833 if (is_system_labeled()) {
2834 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2835 if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2836 exi)) {
2837 resp->status = NFS3ERR_ACCES;
2838 goto err1;
2839 }
2840 }
2841 }
2842
2843 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2844 name = nfscmd_convname(ca, exi, args->from.name,
2845 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2846
2847 if (name == NULL) {
2848 resp->status = NFS3ERR_INVAL;
2849 goto err1;
2850 }
2851
2852 toname = nfscmd_convname(ca, exi, args->to.name,
2860 /*
2861 * Check for a conflict with a non-blocking mandatory share
2862 * reservation or V4 delegations.
2863 */
2864 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2865 NULL, cr, NULL, NULL, NULL);
2866 if (error != 0)
2867 goto err;
2868
2869 /*
2870 * If we rename a delegated file we should recall the
2871 * delegation, since future opens should fail or would
2872 * refer to a new file.
2873 */
2874 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2875 resp->status = NFS3ERR_JUKEBOX;
2876 goto err1;
2877 }
2878
2879 /*
2880 * Check for renaming over a delegated file. Check nfs4_deleg_policy
2881 * first to avoid VOP_LOOKUP if possible.
2882 */
2883 if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2884 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2885 NULL, NULL, NULL) == 0) {
2886
2887 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2888 VN_RELE(targvp);
2889 resp->status = NFS3ERR_JUKEBOX;
2890 goto err1;
2891 }
2892 VN_RELE(targvp);
2893 }
2894
2895 if (!nbl_need_check(srcvp)) {
2896 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2897 } else {
2898 nbl_start_crit(srcvp, RW_READER);
2899 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2900 error = EACCES;
2901 else
2902 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2903 nbl_end_crit(srcvp);
2927 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2928 goto out;
2929
2930 err:
2931 if (curthread->t_flag & T_WOULDBLOCK) {
2932 curthread->t_flag &= ~T_WOULDBLOCK;
2933 resp->status = NFS3ERR_JUKEBOX;
2934 } else {
2935 resp->status = puterrno3(error);
2936 }
2937 err1:
2938 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2939 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2940
2941 out:
2942 if (name != NULL && name != args->from.name)
2943 kmem_free(name, MAXPATHLEN + 1);
2944 if (toname != NULL && toname != args->to.name)
2945 kmem_free(toname, MAXPATHLEN + 1);
2946
2947 DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2948 cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2949 RENAME3res *, resp);
2950 if (fvp != NULL)
2951 VN_RELE(fvp);
2952 if (tvp != NULL)
2953 VN_RELE(tvp);
2954 }
2955
2956 void *
2957 rfs3_rename_getfh(RENAME3args *args)
2958 {
2959 return (&args->from.dir);
2960 }
2961
2962 void
2963 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2964 struct svc_req *req, cred_t *cr, bool_t ro)
2965 {
2966 int error;
2967 vnode_t *vp;
2968 vnode_t *dvp;
2969 struct vattr *vap;
2970 struct vattr va;
2971 struct vattr *bvap;
2972 struct vattr bva;
2973 struct vattr *avap;
2974 struct vattr ava;
2975 nfs_fh3 *fh3;
2976 struct exportinfo *to_exi;
2977 bslabel_t *clabel;
2978 struct sockaddr *ca;
2979 char *name = NULL;
2980
2981 vap = NULL;
2982 bvap = NULL;
2983 avap = NULL;
2984 dvp = NULL;
2985
2986 vp = nfs3_fhtovp(&args->file, exi);
2987
2988 DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2989 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2990 LINK3args *, args);
2991
2992 if (vp == NULL) {
2993 error = ESTALE;
2994 goto out;
2995 }
2996
2997 va.va_mask = AT_ALL;
2998 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2999
3000 fh3 = &args->link.dir;
3001 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3002 if (to_exi == NULL) {
3003 resp->status = NFS3ERR_ACCES;
3004 goto out1;
3005 }
3006 exi_rele(&to_exi);
3007
3008 if (to_exi != exi) {
3009 resp->status = NFS3ERR_XDEV;
3010 goto out1;
3011 }
3012
3013 if (is_system_labeled()) {
3014 clabel = req->rq_label;
3015
3016 ASSERT(clabel != NULL);
3017 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3018 "got client label from request(1)", struct svc_req *, req);
3019
3020 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3021 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3022 exi)) {
3023 resp->status = NFS3ERR_ACCES;
3024 goto out1;
3025 }
3026 }
3038 if (dvp->v_type != VDIR) {
3039 resp->status = NFS3ERR_NOTDIR;
3040 goto out1;
3041 }
3042
3043 if (args->link.name == nfs3nametoolong) {
3044 resp->status = NFS3ERR_NAMETOOLONG;
3045 goto out1;
3046 }
3047
3048 if (args->link.name == NULL || *(args->link.name) == '\0') {
3049 resp->status = NFS3ERR_ACCES;
3050 goto out1;
3051 }
3052
3053 if (rdonly(ro, dvp)) {
3054 resp->status = NFS3ERR_ROFS;
3055 goto out1;
3056 }
3057
3058 if (protect_zfs_mntpt(dvp) != 0) {
3059 resp->status = NFS3ERR_ACCES;
3060 goto out1;
3061 }
3062
3063 if (is_system_labeled()) {
3064 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3065 "got client label from request(1)", struct svc_req *, req);
3066
3067 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3068 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3069 exi)) {
3070 resp->status = NFS3ERR_ACCES;
3071 goto out1;
3072 }
3073 }
3074 }
3075
3076 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3077 name = nfscmd_convname(ca, exi, args->link.name,
3078 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3079
3080 if (name == NULL) {
3081 resp->status = NFS3ERR_SERVERFAULT;
3082 goto out1;
3087 va.va_mask = AT_ALL;
3088 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3089 ava.va_mask = AT_ALL;
3090 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3091
3092 /*
3093 * Force modified data and metadata out to stable storage.
3094 */
3095 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3096 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3097
3098 if (error)
3099 goto out;
3100
3101 VN_RELE(dvp);
3102
3103 resp->status = NFS3_OK;
3104 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3105 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3106
3107 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3108 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3109 LINK3res *, resp);
3110
3111 VN_RELE(vp);
3112
3113 return;
3114
3115 out:
3116 if (curthread->t_flag & T_WOULDBLOCK) {
3117 curthread->t_flag &= ~T_WOULDBLOCK;
3118 resp->status = NFS3ERR_JUKEBOX;
3119 } else
3120 resp->status = puterrno3(error);
3121 out1:
3122 if (name != NULL && name != args->link.name)
3123 kmem_free(name, MAXPATHLEN + 1);
3124
3125 DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3126 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3127 LINK3res *, resp);
3128
3129 if (vp != NULL)
3130 VN_RELE(vp);
3131 if (dvp != NULL)
3132 VN_RELE(dvp);
3133 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3134 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3135 }
3136
3137 void *
3138 rfs3_link_getfh(LINK3args *args)
3139 {
3140 return (&args->file);
3141 }
3142
3143 #ifdef nextdp
3144 #undef nextdp
3145 #endif
3146 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3147
3148 /* ARGSUSED */
3149 void
3150 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3151 struct svc_req *req, cred_t *cr, bool_t ro)
3152 {
3153 int error;
3154 vnode_t *vp;
3155 struct vattr *vap;
3156 struct vattr va;
3157 struct iovec iov;
3158 struct uio uio;
3159 int iseof;
3160
3161 count3 count = args->count;
3162 count3 size; /* size of the READDIR3resok structure */
3163
3164 size_t datasz;
3165 char *data = NULL;
3166 dirent64_t *dp;
3167
3168 struct sockaddr *ca;
3169 entry3 **eptr;
3170 entry3 *entry;
3171
3172 vp = nfs3_fhtovp(&args->dir, exi);
3173
3174 DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3175 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3176 READDIR3args *, args);
3177
3178 if (vp == NULL) {
3179 resp->status = NFS3ERR_STALE;
3180 vap = NULL;
3181 goto out1;
3182 }
3183
3184 if (vp->v_type != VDIR) {
3185 resp->status = NFS3ERR_NOTDIR;
3186 vap = NULL;
3187 goto out1;
3188 }
3189
3190 if (is_system_labeled()) {
3191 bslabel_t *clabel = req->rq_label;
3192
3193 ASSERT(clabel != NULL);
3194 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3195 "got client label from request(1)", struct svc_req *, req);
3196
3197 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3198 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3199 exi)) {
3200 resp->status = NFS3ERR_ACCES;
3201 vap = NULL;
3202 goto out1;
3203 }
3204 }
3205 }
3206
3207 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3208
3209 va.va_mask = AT_ALL;
3210 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3211
3212 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3213 if (error)
3214 goto out;
3215
3216 /*
3217 * Don't allow arbitrary counts for allocation
3218 */
3219 if (count > rfs3_tsize(req))
3220 count = rfs3_tsize(req);
3221
3222 /*
3223 * struct READDIR3resok:
3224 * dir_attributes: 1 + NFS3_SIZEOF_FATTR3
3225 * cookieverf: 2
3226 * entries (bool): 1
3227 * eof: 1
3228 */
3229 size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
3230
3231 if (size > count) {
3232 resp->status = NFS3ERR_TOOSMALL;
3233 goto out1;
3234 }
3235
3236 /*
3237 * This is simplification. The dirent64_t size is not the same as the
3238 * size of XDR representation of entry3, but the sizes are similar so
3239 * we'll assume they are same. This assumption should not cause any
3240 * harm. In worst case we will need to issue VOP_READDIR() once more.
3241 */
3242 datasz = count;
3243
3244 /*
3245 * Make sure that there is room to read at least one entry
3246 * if any are available.
3247 */
3248 if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
3249 datasz = DIRENT64_RECLEN(MAXNAMELEN);
3250
3251 data = kmem_alloc(datasz, KM_NOSLEEP);
3252 if (data == NULL) {
3253 /* The allocation failed; downsize and wait for it this time */
3254 if (datasz > MAXBSIZE)
3255 datasz = MAXBSIZE;
3256 data = kmem_alloc(datasz, KM_SLEEP);
3257 }
3258
3259 uio.uio_iov = &iov;
3260 uio.uio_iovcnt = 1;
3261 uio.uio_segflg = UIO_SYSSPACE;
3262 uio.uio_extflg = UIO_COPY_CACHED;
3263 uio.uio_loffset = (offset_t)args->cookie;
3264 uio.uio_resid = datasz;
3265
3266 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3267 eptr = &resp->resok.reply.entries;
3268 entry = NULL;
3269
3270 getmoredents:
3271 iov.iov_base = data;
3272 iov.iov_len = datasz;
3273
3274 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3275 if (error) {
3276 iseof = 0;
3277 goto done;
3278 }
3279
3280 if (iov.iov_len == datasz)
3281 goto done;
3282
3283 for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
3284 dp = nextdp(dp)) {
3285 char *name;
3286 count3 esize;
3287
3288 if (dp->d_ino == 0) {
3289 if (entry != NULL)
3290 entry->cookie = (cookie3)dp->d_off;
3291 continue;
3292 }
3293
3294 name = nfscmd_convname(ca, exi, dp->d_name,
3295 NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
3296 if (name == NULL) {
3297 if (entry != NULL)
3298 entry->cookie = (cookie3)dp->d_off;
3299 continue;
3300 }
3301
3302 /*
3303 * struct entry3:
3304 * fileid: 2
3305 * name (length): 1
3306 * name (data): length (rounded up)
3307 * cookie: 2
3308 * nextentry (bool): 1
3309 */
3310 esize = (2 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT +
3311 RNDUP(strlen(name));
3312
3313 /* If the new entry does not fit, discard it */
3314 if (esize > count - size) {
3315 if (name != dp->d_name)
3316 kmem_free(name, MAXPATHLEN + 1);
3317 iseof = 0;
3318 goto done;
3319 }
3320
3321 entry = kmem_alloc(sizeof (entry3), KM_SLEEP);
3322
3323 entry->fileid = (fileid3)dp->d_ino;
3324 entry->name = strdup(name);
3325 if (name != dp->d_name)
3326 kmem_free(name, MAXPATHLEN + 1);
3327 entry->cookie = (cookie3)dp->d_off;
3328
3329 size += esize;
3330
3331 /* Add the entry to the linked list */
3332 *eptr = entry;
3333 eptr = &entry->nextentry;
3334 }
3335
3336 if (!iseof && size < count) {
3337 uio.uio_resid = MIN(datasz, MAXBSIZE);
3338 goto getmoredents;
3339 }
3340
3341 done:
3342 *eptr = NULL;
3343
3344 va.va_mask = AT_ALL;
3345 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3346
3347 if (!iseof && resp->resok.reply.entries == NULL) {
3348 if (error)
3349 goto out;
3350 resp->status = NFS3ERR_TOOSMALL;
3351 goto out1;
3352 }
3353
3354 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3355
3356 #if 0 /* notyet */
3357 /*
3358 * Don't do this. It causes local disk writes when just
3359 * reading the file and the overhead is deemed larger
3360 * than the benefit.
3361 */
3362 /*
3363 * Force modified metadata out to stable storage.
3364 */
3365 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3366 #endif
3367
3368 resp->status = NFS3_OK;
3369 resp->resok.cookieverf = 0;
3370 resp->resok.reply.eof = iseof ? TRUE : FALSE;
3371
3372 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3373
3374 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3375 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3376 READDIR3res *, resp);
3377
3378 VN_RELE(vp);
3379
3380 if (data != NULL)
3381 kmem_free(data, datasz);
3382
3383 return;
3384
3385 out:
3386 if (curthread->t_flag & T_WOULDBLOCK) {
3387 curthread->t_flag &= ~T_WOULDBLOCK;
3388 resp->status = NFS3ERR_JUKEBOX;
3389 } else
3390 resp->status = puterrno3(error);
3391 out1:
3392 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3393
3394 DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3395 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3396 READDIR3res *, resp);
3397
3398 if (vp != NULL) {
3399 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3400 VN_RELE(vp);
3401 }
3402
3403 if (data != NULL)
3404 kmem_free(data, datasz);
3405 }
3406
3407 void *
3408 rfs3_readdir_getfh(READDIR3args *args)
3409 {
3410 return (&args->dir);
3411 }
3412
3413 void
3414 rfs3_readdir_free(READDIR3res *resp)
3415 {
3416 if (resp->status == NFS3_OK) {
3417 entry3 *entry, *nentry;
3418
3419 for (entry = resp->resok.reply.entries; entry != NULL;
3420 entry = nentry) {
3421 nentry = entry->nextentry;
3422 strfree(entry->name);
3423 kmem_free(entry, sizeof (entry3));
3424 }
3425 }
3426 }
3427
3428 #ifdef nextdp
3429 #undef nextdp
3430 #endif
3431 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3432
3433 /* ARGSUSED */
3434 void
3435 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3436 struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3437 {
3438 int error;
3439 vnode_t *vp;
3440 struct vattr *vap;
3441 struct vattr va;
3442 struct iovec iov;
3443 struct uio uio;
3444 int iseof;
3445
3446 count3 dircount = args->dircount;
3447 count3 maxcount = args->maxcount;
3448 count3 dirsize = 0;
3449 count3 size; /* size of the READDIRPLUS3resok structure */
3450
3451 size_t datasz;
3452 char *data = NULL;
3453 dirent64_t *dp;
3454
3455 struct sockaddr *ca;
3456 entryplus3 **eptr;
3457 entryplus3 *entry;
3458
3459 vp = nfs3_fhtovp(&args->dir, exi);
3460
3461 DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3462 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3463 READDIRPLUS3args *, args);
3464
3465 if (vp == NULL) {
3466 resp->status = NFS3ERR_STALE;
3467 vap = NULL;
3468 goto out1;
3469 }
3470
3471 if (vp->v_type != VDIR) {
3472 resp->status = NFS3ERR_NOTDIR;
3473 vap = NULL;
3474 goto out1;
3475 }
3476
3477 if (is_system_labeled()) {
3478 bslabel_t *clabel = req->rq_label;
3479
3480 ASSERT(clabel != NULL);
3481 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3482 char *, "got client label from request(1)",
3483 struct svc_req *, req);
3484
3485 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3486 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3487 exi)) {
3488 resp->status = NFS3ERR_ACCES;
3489 vap = NULL;
3490 goto out1;
3491 }
3492 }
3493 }
3494
3495 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3496
3497 va.va_mask = AT_ALL;
3498 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3499
3500 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3501 if (error)
3502 goto out;
3503
3504 /*
3505 * Don't allow arbitrary counts for allocation
3506 */
3507 if (maxcount > rfs3_tsize(req))
3508 maxcount = rfs3_tsize(req);
3509
3510 /*
3511 * struct READDIRPLUS3resok:
3512 * dir_attributes: 1 + NFS3_SIZEOF_FATTR3
3513 * cookieverf: 2
3514 * entries (bool): 1
3515 * eof: 1
3516 */
3517 size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
3518
3519 if (size > maxcount) {
3520 resp->status = NFS3ERR_TOOSMALL;
3521 goto out1;
3522 }
3523
3524 /*
3525 * This is simplification. The dirent64_t size is not the same as the
3526 * size of XDR representation of entryplus3 (excluding attributes and
3527 * handle), but the sizes are similar so we'll assume they are same.
3528 * This assumption should not cause any harm. In worst case we will
3529 * need to issue VOP_READDIR() once more.
3530 */
3531
3532 datasz = MIN(dircount, maxcount);
3533
3534 /*
3535 * Make sure that there is room to read at least one entry
3536 * if any are available.
3537 */
3538 if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
3539 datasz = DIRENT64_RECLEN(MAXNAMELEN);
3540
3541 data = kmem_alloc(datasz, KM_NOSLEEP);
3542 if (data == NULL) {
3543 /* The allocation failed; downsize and wait for it this time */
3544 if (datasz > MAXBSIZE)
3545 datasz = MAXBSIZE;
3546 data = kmem_alloc(datasz, KM_SLEEP);
3547 }
3548
3549 uio.uio_iov = &iov;
3550 uio.uio_iovcnt = 1;
3551 uio.uio_segflg = UIO_SYSSPACE;
3552 uio.uio_extflg = UIO_COPY_CACHED;
3553 uio.uio_loffset = (offset_t)args->cookie;
3554 uio.uio_resid = datasz;
3555
3556 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3557 eptr = &resp->resok.reply.entries;
3558 entry = NULL;
3559
3560 getmoredents:
3561 iov.iov_base = data;
3562 iov.iov_len = datasz;
3563
3564 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3565 if (error) {
3566 iseof = 0;
3567 goto done;
3568 }
3569
3570 if (iov.iov_len == datasz)
3571 goto done;
3572
3573 for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
3574 dp = nextdp(dp)) {
3575 char *name;
3576 vnode_t *nvp;
3577 count3 edirsize;
3578 count3 esize;
3579
3580 if (dp->d_ino == 0) {
3581 if (entry != NULL)
3582 entry->cookie = (cookie3)dp->d_off;
3583 continue;
3584 }
3585
3586 name = nfscmd_convname(ca, exi, dp->d_name,
3587 NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
3588 if (name == NULL) {
3589 if (entry != NULL)
3590 entry->cookie = (cookie3)dp->d_off;
3591 continue;
3592 }
3593
3594 /*
3595 * struct entryplus3:
3596 * fileid: 2
3597 * name (length): 1
3598 * name (data): length (rounded up)
3599 * cookie: 2
3600 */
3601 edirsize = (2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3602 RNDUP(strlen(name));
3603
3604 /*
3605 * struct entryplus3:
3606 * attributes_follow: 1
3607 * handle_follows: 1
3608 * nextentry (bool): 1
3609 */
3610 esize = edirsize + (1 + 1 + 1) * BYTES_PER_XDR_UNIT;
3611
3612 /* If the new entry does not fit, we are done */
3613 if (edirsize > dircount - dirsize || esize > maxcount - size) {
3614 if (name != dp->d_name)
3615 kmem_free(name, MAXPATHLEN + 1);
3616 iseof = 0;
3617 error = 0;
3618 goto done;
3619 }
3620
3621 entry = kmem_alloc(sizeof (entryplus3), KM_SLEEP);
3622
3623 entry->fileid = (fileid3)dp->d_ino;
3624 entry->name = strdup(name);
3625 if (name != dp->d_name)
3626 kmem_free(name, MAXPATHLEN + 1);
3627 entry->cookie = (cookie3)dp->d_off;
3628
3629 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3630 NULL, NULL, NULL);
3631 if (error) {
3632 entry->name_attributes.attributes = FALSE;
3633 entry->name_handle.handle_follows = FALSE;
3634 } else {
3635 struct vattr nva;
3636 struct vattr *nvap;
3637
3638 nva.va_mask = AT_ALL;
3639 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL :
3640 &nva;
3641
3642 /* Lie about the object type for a referral */
3643 if (nvap != NULL && vn_is_nfs_reparse(nvp, cr))
3644 nvap->va_type = VLNK;
3645
3646 if (vn_ismntpt(nvp)) {
3647 entry->name_attributes.attributes = FALSE;
3648 entry->name_handle.handle_follows = FALSE;
3649 } else {
3650 vattr_to_post_op_attr(nvap,
3651 &entry->name_attributes);
3652
3653 error = makefh3(&entry->name_handle.handle, nvp,
3654 exi);
3655 if (!error)
3656 entry->name_handle.handle_follows =
3657 TRUE;
3658 else
3659 entry->name_handle.handle_follows =
3660 FALSE;
3661 }
3662
3663 VN_RELE(nvp);
3664 }
3665
3666 /*
3667 * struct entryplus3 (optionally):
3668 * attributes: NFS3_SIZEOF_FATTR3
3669 * handle length: 1
3670 * handle data: length (rounded up)
3671 */
3672 if (entry->name_attributes.attributes == TRUE)
3673 esize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3674 if (entry->name_handle.handle_follows == TRUE)
3675 esize += 1 * BYTES_PER_XDR_UNIT +
3676 RNDUP(entry->name_handle.handle.fh3_length);
3677
3678 /* If the new entry does not fit, discard it */
3679 if (esize > maxcount - size) {
3680 strfree(entry->name);
3681 kmem_free(entry, sizeof (entryplus3));
3682 iseof = 0;
3683 error = 0;
3684 goto done;
3685 }
3686
3687 dirsize += edirsize;
3688 size += esize;
3689
3690 /* Add the entry to the linked list */
3691 *eptr = entry;
3692 eptr = &entry->nextentry;
3693 }
3694
3695 if (!iseof && dirsize < dircount && size < maxcount) {
3696 uio.uio_resid = MIN(datasz, MAXBSIZE);
3697 goto getmoredents;
3698 }
3699
3700 done:
3701 *eptr = NULL;
3702
3703 va.va_mask = AT_ALL;
3704 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3705
3706 if (!iseof && resp->resok.reply.entries == NULL) {
3707 if (error)
3708 goto out;
3709 resp->status = NFS3ERR_TOOSMALL;
3710 goto out1;
3711 }
3712
3713 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3714
3715 #if 0 /* notyet */
3716 /*
3717 * Don't do this. It causes local disk writes when just
3718 * reading the file and the overhead is deemed larger
3719 * than the benefit.
3720 */
3721 /*
3722 * Force modified metadata out to stable storage.
3723 */
3724 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3725 #endif
3726
3727 resp->status = NFS3_OK;
3728 resp->resok.cookieverf = 0;
3729 resp->resok.reply.eof = iseof ? TRUE : FALSE;
3730
3731 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3732
3733 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3734 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3735 READDIRPLUS3res *, resp);
3736
3737 VN_RELE(vp);
3738
3739 if (data != NULL)
3740 kmem_free(data, datasz);
3741
3742 return;
3743
3744 out:
3745 if (curthread->t_flag & T_WOULDBLOCK) {
3746 curthread->t_flag &= ~T_WOULDBLOCK;
3747 resp->status = NFS3ERR_JUKEBOX;
3748 } else {
3749 resp->status = puterrno3(error);
3750 }
3751 out1:
3752 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3753
3754 DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3755 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3756 READDIRPLUS3res *, resp);
3757
3758 if (vp != NULL) {
3759 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3760 VN_RELE(vp);
3761 }
3762
3763 if (data != NULL)
3764 kmem_free(data, datasz);
3765 }
3766
3767 void *
3768 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3769 {
3770 return (&args->dir);
3771 }
3772
3773 void
3774 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3775 {
3776 if (resp->status == NFS3_OK) {
3777 entryplus3 *entry, *nentry;
3778
3779 for (entry = resp->resok.reply.entries; entry != NULL;
3780 entry = nentry) {
3781 nentry = entry->nextentry;
3782 strfree(entry->name);
3783 kmem_free(entry, sizeof (entryplus3));
3784 }
3785 }
3786 }
3787
3788 /* ARGSUSED */
3789 void
3790 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3791 struct svc_req *req, cred_t *cr, bool_t ro)
3792 {
3793 int error;
3794 vnode_t *vp;
3795 struct vattr *vap;
3796 struct vattr va;
3797 struct statvfs64 sb;
3798
3799 vap = NULL;
3800
3801 vp = nfs3_fhtovp(&args->fsroot, exi);
3802
3803 DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3804 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3805 FSSTAT3args *, args);
3806
3807 if (vp == NULL) {
3808 error = ESTALE;
3809 goto out;
3810 }
3811
3812 if (is_system_labeled()) {
3813 bslabel_t *clabel = req->rq_label;
3814
3815 ASSERT(clabel != NULL);
3816 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3817 "got client label from request(1)", struct svc_req *, req);
3818
3819 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3820 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3821 exi)) {
3822 resp->status = NFS3ERR_ACCES;
3823 goto out1;
3824 }
3825 }
3835
3836 resp->status = NFS3_OK;
3837 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3838 if (sb.f_blocks != (fsblkcnt64_t)-1)
3839 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3840 else
3841 resp->resok.tbytes = (size3)sb.f_blocks;
3842 if (sb.f_bfree != (fsblkcnt64_t)-1)
3843 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3844 else
3845 resp->resok.fbytes = (size3)sb.f_bfree;
3846 if (sb.f_bavail != (fsblkcnt64_t)-1)
3847 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3848 else
3849 resp->resok.abytes = (size3)sb.f_bavail;
3850 resp->resok.tfiles = (size3)sb.f_files;
3851 resp->resok.ffiles = (size3)sb.f_ffree;
3852 resp->resok.afiles = (size3)sb.f_favail;
3853 resp->resok.invarsec = 0;
3854
3855 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3856 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3857 FSSTAT3res *, resp);
3858 VN_RELE(vp);
3859
3860 return;
3861
3862 out:
3863 if (curthread->t_flag & T_WOULDBLOCK) {
3864 curthread->t_flag &= ~T_WOULDBLOCK;
3865 resp->status = NFS3ERR_JUKEBOX;
3866 } else
3867 resp->status = puterrno3(error);
3868 out1:
3869 DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3870 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3871 FSSTAT3res *, resp);
3872
3873 if (vp != NULL)
3874 VN_RELE(vp);
3875 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3876 }
3877
3878 void *
3879 rfs3_fsstat_getfh(FSSTAT3args *args)
3880 {
3881 return (&args->fsroot);
3882 }
3883
3884 /* ARGSUSED */
3885 void
3886 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3887 struct svc_req *req, cred_t *cr, bool_t ro)
3888 {
3889 vnode_t *vp;
3890 struct vattr *vap;
3891 struct vattr va;
3892 uint32_t xfer_size;
3893 ulong_t l = 0;
3894 int error;
3895
3896 vp = nfs3_fhtovp(&args->fsroot, exi);
3897
3898 DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3899 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3900 FSINFO3args *, args);
3901
3902 if (vp == NULL) {
3903 if (curthread->t_flag & T_WOULDBLOCK) {
3904 curthread->t_flag &= ~T_WOULDBLOCK;
3905 resp->status = NFS3ERR_JUKEBOX;
3906 } else
3907 resp->status = NFS3ERR_STALE;
3908 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3909 goto out;
3910 }
3911
3912 if (is_system_labeled()) {
3913 bslabel_t *clabel = req->rq_label;
3914
3915 ASSERT(clabel != NULL);
3916 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3917 "got client label from request(1)", struct svc_req *, req);
3918
3919 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3920 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3954 /*
3955 * If the underlying file system does not support _PC_FILESIZEBITS,
3956 * return a reasonable default. Note that error code on VOP_PATHCONF
3957 * will be 0, even if the underlying file system does not support
3958 * _PC_FILESIZEBITS.
3959 */
3960 if (l == (ulong_t)-1) {
3961 resp->resok.maxfilesize = MAXOFF32_T;
3962 } else {
3963 if (l >= (sizeof (uint64_t) * 8))
3964 resp->resok.maxfilesize = INT64_MAX;
3965 else
3966 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3967 }
3968
3969 resp->resok.time_delta.seconds = 0;
3970 resp->resok.time_delta.nseconds = 1000;
3971 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3972 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3973
3974 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3975 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3976 FSINFO3res *, resp);
3977
3978 VN_RELE(vp);
3979
3980 return;
3981
3982 out:
3983 DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3984 cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
3985 FSINFO3res *, resp);
3986 if (vp != NULL)
3987 VN_RELE(vp);
3988 }
3989
3990 void *
3991 rfs3_fsinfo_getfh(FSINFO3args *args)
3992 {
3993 return (&args->fsroot);
3994 }
3995
3996 /* ARGSUSED */
3997 void
3998 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3999 struct svc_req *req, cred_t *cr, bool_t ro)
4000 {
4001 int error;
4002 vnode_t *vp;
4003 struct vattr *vap;
4004 struct vattr va;
4005 ulong_t val;
4006
4007 vap = NULL;
4008
4009 vp = nfs3_fhtovp(&args->object, exi);
4010
4011 DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4012 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4013 PATHCONF3args *, args);
4014
4015 if (vp == NULL) {
4016 error = ESTALE;
4017 goto out;
4018 }
4019
4020 if (is_system_labeled()) {
4021 bslabel_t *clabel = req->rq_label;
4022
4023 ASSERT(clabel != NULL);
4024 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4025 "got client label from request(1)", struct svc_req *, req);
4026
4027 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4028 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4029 exi)) {
4030 resp->status = NFS3ERR_ACCES;
4031 goto out1;
4032 }
4033 }
4049 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4050 if (error)
4051 goto out;
4052 if (val == 1)
4053 resp->resok.info.no_trunc = TRUE;
4054 else
4055 resp->resok.info.no_trunc = FALSE;
4056
4057 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4058 if (error)
4059 goto out;
4060 if (val == 1)
4061 resp->resok.info.chown_restricted = TRUE;
4062 else
4063 resp->resok.info.chown_restricted = FALSE;
4064
4065 resp->status = NFS3_OK;
4066 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4067 resp->resok.info.case_insensitive = FALSE;
4068 resp->resok.info.case_preserving = TRUE;
4069 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4070 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4071 PATHCONF3res *, resp);
4072 VN_RELE(vp);
4073 return;
4074
4075 out:
4076 if (curthread->t_flag & T_WOULDBLOCK) {
4077 curthread->t_flag &= ~T_WOULDBLOCK;
4078 resp->status = NFS3ERR_JUKEBOX;
4079 } else
4080 resp->status = puterrno3(error);
4081 out1:
4082 DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4083 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4084 PATHCONF3res *, resp);
4085 if (vp != NULL)
4086 VN_RELE(vp);
4087 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4088 }
4089
4090 void *
4091 rfs3_pathconf_getfh(PATHCONF3args *args)
4092 {
4093 return (&args->object);
4094 }
4095
4096 void
4097 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4098 struct svc_req *req, cred_t *cr, bool_t ro)
4099 {
4100 nfs3_srv_t *ns;
4101 int error;
4102 vnode_t *vp;
4103 struct vattr *bvap;
4104 struct vattr bva;
4105 struct vattr *avap;
4106 struct vattr ava;
4107
4108 bvap = NULL;
4109 avap = NULL;
4110
4111 vp = nfs3_fhtovp(&args->file, exi);
4112
4113 DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4114 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4115 COMMIT3args *, args);
4116
4117 if (vp == NULL) {
4118 error = ESTALE;
4119 goto out;
4120 }
4121
4122 ns = zone_getspecific(rfs3_zone_key, curzone);
4123 bva.va_mask = AT_ALL;
4124 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4125
4126 /*
4127 * If we can't get the attributes, then we can't do the
4128 * right access checking. So, we'll fail the request.
4129 */
4130 if (error)
4131 goto out;
4132
4133 bvap = &bva;
4134
4135 if (rdonly(ro, vp)) {
4136 resp->status = NFS3ERR_ROFS;
4137 goto out1;
4138 }
4139
4140 if (vp->v_type != VREG) {
4141 resp->status = NFS3ERR_INVAL;
4142 goto out1;
4155 resp->status = NFS3ERR_ACCES;
4156 goto out1;
4157 }
4158 }
4159 }
4160
4161 if (crgetuid(cr) != bva.va_uid &&
4162 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4163 goto out;
4164
4165 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4166
4167 ava.va_mask = AT_ALL;
4168 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4169
4170 if (error)
4171 goto out;
4172
4173 resp->status = NFS3_OK;
4174 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4175 resp->resok.verf = ns->write3verf;
4176
4177 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4178 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4179 COMMIT3res *, resp);
4180
4181 VN_RELE(vp);
4182
4183 return;
4184
4185 out:
4186 if (curthread->t_flag & T_WOULDBLOCK) {
4187 curthread->t_flag &= ~T_WOULDBLOCK;
4188 resp->status = NFS3ERR_JUKEBOX;
4189 } else
4190 resp->status = puterrno3(error);
4191 out1:
4192 DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4193 cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4194 COMMIT3res *, resp);
4195
4196 if (vp != NULL)
4197 VN_RELE(vp);
4198 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4199 }
4200
4201 void *
4202 rfs3_commit_getfh(COMMIT3args *args)
4203 {
4204 return (&args->file);
4205 }
4206
4207 static int
4208 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4209 {
4210
4211 vap->va_mask = 0;
4212
4213 if (sap->mode.set_it) {
4214 vap->va_mode = (mode_t)sap->mode.mode;
4215 vap->va_mask |= AT_MODE;
4216 }
4217 if (sap->uid.set_it) {
4218 vap->va_uid = (uid_t)sap->uid.uid;
4219 vap->va_mask |= AT_UID;
4220 }
4221 if (sap->gid.set_it) {
4222 vap->va_gid = (gid_t)sap->gid.gid;
4223 vap->va_mask |= AT_GID;
4251 /* check time validity */
4252 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4253 return (EOVERFLOW);
4254 #endif
4255 /*
4256 * nfs protocol defines times as unsigned so don't extend sign,
4257 * unless sysadmin set nfs_allow_preepoch_time.
4258 */
4259 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4260 sap->mtime.mtime.seconds);
4261 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4262 vap->va_mask |= AT_MTIME;
4263 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4264 gethrestime(&vap->va_mtime);
4265 vap->va_mask |= AT_MTIME;
4266 }
4267
4268 return (0);
4269 }
4270
4271 static const ftype3 vt_to_nf3[] = {
4272 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4273 };
4274
4275 static int
4276 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4277 {
4278
4279 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4280 /* Return error if time or size overflow */
4281 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4282 return (EOVERFLOW);
4283 }
4284 fap->type = vt_to_nf3[vap->va_type];
4285 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4286 fap->nlink = (uint32)vap->va_nlink;
4287 if (vap->va_uid == UID_NOBODY)
4288 fap->uid = (uid3)NFS_UID_NOBODY;
4289 else
4290 fap->uid = (uid3)vap->va_uid;
4291 if (vap->va_gid == GID_NOBODY)
4333 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4334 poap->attributes = TRUE;
4335 } else
4336 poap->attributes = FALSE;
4337 }
4338
4339 void
4340 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4341 {
4342
4343 /* don't return attrs if time overflow */
4344 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4345 poap->attributes = TRUE;
4346 } else
4347 poap->attributes = FALSE;
4348 }
4349
4350 static void
4351 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4352 {
4353 vattr_to_pre_op_attr(bvap, &wccp->before);
4354 vattr_to_post_op_attr(avap, &wccp->after);
4355 }
4356
4357 static int
4358 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4359 {
4360 struct clist *wcl;
4361 int wlist_len;
4362 count3 count = rok->count;
4363
4364 wcl = args->wlist;
4365 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4366 return (FALSE);
4367
4368 wcl = args->wlist;
4369 rok->wlist_len = wlist_len;
4370 rok->wlist = wcl;
4371 return (TRUE);
4372 }
4373
4374 /* ARGSUSED */
4375 static void *
4376 rfs3_zone_init(zoneid_t zoneid)
4377 {
4378 nfs3_srv_t *ns;
4379 struct rfs3_verf_overlay {
4380 uint_t id; /* a "unique" identifier */
4381 int ts; /* a unique timestamp */
4382 } *verfp;
4383 timestruc_t now;
4384
4385 ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4386
4387 /*
4388 * The following algorithm attempts to find a unique verifier
4389 * to be used as the write verifier returned from the server
4390 * to the client. It is important that this verifier change
4391 * whenever the server reboots. Of secondary importance, it
4392 * is important for the verifier to be unique between two
4393 * different servers.
4394 *
4395 * Thus, an attempt is made to use the system hostid and the
4396 * current time in seconds when the nfssrv kernel module is
4397 * loaded. It is assumed that an NFS server will not be able
4398 * to boot and then to reboot in less than a second. If the
4399 * hostid has not been set, then the current high resolution
4400 * time is used. This will ensure different verifiers each
4401 * time the server reboots and minimize the chances that two
4402 * different servers will have the same verifier.
4403 */
4404
4405 #ifndef lint
4406 /*
4407 * We ASSERT that this constant logic expression is
4408 * always true because in the past, it wasn't.
4409 */
4410 ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
4411 #endif
4412
4413 gethrestime(&now);
4414 verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4415 verfp->ts = (int)now.tv_sec;
4416 verfp->id = zone_get_hostid(NULL);
4417
4418 if (verfp->id == 0)
4419 verfp->id = (uint_t)now.tv_nsec;
4420
4421 return (ns);
4422 }
4423
4424 /* ARGSUSED */
4425 static void
4426 rfs3_zone_fini(zoneid_t zoneid, void *data)
4427 {
4428 nfs3_srv_t *ns = data;
4429
4430 kmem_free(ns, sizeof (*ns));
4431 }
4432
4433 void
4434 rfs3_srvrinit(void)
4435 {
4436 nfs3_srv_caller_id = fs_new_caller_id();
4437 zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini);
4438 }
4439
4440 void
4441 rfs3_srvrfini(void)
4442 {
4443 /* Nothing to do */
4444 }
|