54 #include <nfs/nfs.h>
55 #include <nfs/export.h>
56 #include <nfs/nfs_cmd.h>
57
58 #include <sys/strsubr.h>
59
60 #include <sys/tsol/label.h>
61 #include <sys/tsol/tndb.h>
62
63 #include <sys/zone.h>
64
65 #include <inet/ip.h>
66 #include <inet/ip6.h>
67
68 /*
69 * These are the interface routines for the server side of the
70 * Network File System. See the NFS version 3 protocol specification
71 * for a description of this interface.
72 */
73
74 #ifdef DEBUG
75 int rfs3_do_pre_op_attr = 1;
76 int rfs3_do_post_op_attr = 1;
77 int rfs3_do_post_op_fh3 = 1;
78 #endif
79
80 static writeverf3 write3verf;
81
82 static int sattr3_to_vattr(sattr3 *, struct vattr *);
83 static int vattr_to_fattr3(struct vattr *, fattr3 *);
84 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
85 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
86 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
87 static int rdma_setup_read_data3(READ3args *, READ3resok *);
88
89 extern int nfs_loaned_buffers;
90
91 u_longlong_t nfs3_srv_caller_id;
92
93 /* ARGSUSED */
94 void
95 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
96 struct svc_req *req, cred_t *cr)
97 {
98 int error;
99 vnode_t *vp;
210 * delegated this file. If so, then we return JUKEBOX to
211 * allow the client to retrasmit its request.
212 */
213 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
214 if (nbl_need_check(vp)) {
215 nbl_start_crit(vp, RW_READER);
216 in_crit = 1;
217 }
218 }
219
220 bva.va_mask = AT_ALL;
221 error = rfs4_delegated_getattr(vp, &bva, 0, cr);
222
223 /*
224 * If we can't get the attributes, then we can't do the
225 * right access checking. So, we'll fail the request.
226 */
227 if (error)
228 goto out;
229
230 #ifdef DEBUG
231 if (rfs3_do_pre_op_attr)
232 bvap = &bva;
233 #else
234 bvap = &bva;
235 #endif
236
237 if (rdonly(exi, req) || vn_is_readonly(vp)) {
238 resp->status = NFS3ERR_ROFS;
239 goto out1;
240 }
241
242 if (args->guard.check &&
243 (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
244 args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
245 resp->status = NFS3ERR_NOT_SYNC;
246 goto out1;
247 }
248
249 if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
250 flag = ATTR_UTIME;
251 else
252 flag = 0;
253
254 /*
255 * If the filesystem is exported with nosuid, then mask off
305 bf.l_type = F_WRLCK;
306 bf.l_whence = 0;
307 bf.l_start = (off64_t)ava.va_size;
308 bf.l_len = 0;
309 bf.l_sysid = 0;
310 bf.l_pid = 0;
311 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
312 (offset_t)ava.va_size, cr, &ct);
313 }
314 }
315
316 if (!error && ava.va_mask)
317 error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
318
319 /* check if a monitor detected a delegation conflict */
320 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
321 resp->status = NFS3ERR_JUKEBOX;
322 goto out1;
323 }
324
325 #ifdef DEBUG
326 if (rfs3_do_post_op_attr) {
327 ava.va_mask = AT_ALL;
328 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
329 } else
330 avap = NULL;
331 #else
332 ava.va_mask = AT_ALL;
333 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
334 #endif
335
336 /*
337 * Force modified metadata out to stable storage.
338 */
339 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
340
341 if (error)
342 goto out;
343
344 if (in_crit)
345 nbl_end_crit(vp);
346
347 resp->status = NFS3_OK;
348 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
349
350 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
351 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
352
353 VN_RELE(vp);
354
404 * location of the public filehandle.
405 */
406 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
407 dvp = rootdir;
408 VN_HOLD(dvp);
409
410 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
411 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
412 } else {
413 dvp = nfs3_fhtovp(&args->what.dir, exi);
414
415 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
416 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
417
418 if (dvp == NULL) {
419 error = ESTALE;
420 goto out;
421 }
422 }
423
424 #ifdef DEBUG
425 if (rfs3_do_pre_op_attr) {
426 dva.va_mask = AT_ALL;
427 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
428 }
429 #else
430 dva.va_mask = AT_ALL;
431 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
432 #endif
433
434 if (args->what.name == nfs3nametoolong) {
435 resp->status = NFS3ERR_NAMETOOLONG;
436 goto out1;
437 }
438
439 if (args->what.name == NULL || *(args->what.name) == '\0') {
440 resp->status = NFS3ERR_ACCES;
441 goto out1;
442 }
443
444 fhp = &args->what.dir;
445 if (strcmp(args->what.name, "..") == 0 &&
446 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
447 resp->status = NFS3ERR_NOENT;
448 goto out1;
449 }
450
451 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
452 name = nfscmd_convname(ca, exi, args->what.name,
453 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
454
455 if (name == NULL) {
456 resp->status = NFS3ERR_ACCES;
457 goto out1;
458 }
459
460 /*
461 * If the public filehandle is used then allow
462 * a multi-component lookup
463 */
464 if (PUBLIC_FH3(&args->what.dir)) {
465 publicfh_flag = TRUE;
466 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
467 &exi, &sec);
468 if (error && exi != NULL)
469 exi_rele(exi); /* See comment below Re: publicfh_flag */
470 /*
471 * Since WebNFS may bypass MOUNT, we need to ensure this
472 * request didn't come from an unlabeled admin_low client.
473 */
474 if (is_system_labeled() && error == 0) {
475 int addr_type;
476 void *ipaddr;
477 tsol_tpc_t *tp;
478
479 if (ca->sa_family == AF_INET) {
480 addr_type = IPV4_VERSION;
481 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
482 } else if (ca->sa_family == AF_INET6) {
483 addr_type = IPV6_VERSION;
484 ipaddr = &((struct sockaddr_in6 *)
485 ca)->sin6_addr;
486 }
487 tp = find_tpc(ipaddr, addr_type, B_FALSE);
488 if (tp == NULL || tp->tpc_tp.tp_doi !=
489 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
490 SUN_CIPSO) {
491 if (exi != NULL)
492 exi_rele(exi);
493 VN_RELE(vp);
494 resp->status = NFS3ERR_ACCES;
495 error = 1;
496 }
497 if (tp != NULL)
498 TPC_RELE(tp);
499 }
500 } else {
501 error = VOP_LOOKUP(dvp, name, &vp,
502 NULL, 0, NULL, cr, NULL, NULL, NULL);
503 }
504
505 if (name != args->what.name)
506 kmem_free(name, MAXPATHLEN + 1);
507
508 if (is_system_labeled() && error == 0) {
509 bslabel_t *clabel = req->rq_label;
510
511 ASSERT(clabel != NULL);
512 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
513 "got client label from request(1)", struct svc_req *, req);
514
515 if (!blequal(&l_admin_low->tsl_label, clabel)) {
516 if (!do_rfs_label_check(clabel, dvp,
517 DOMINANCE_CHECK, exi)) {
518 if (publicfh_flag && exi != NULL)
519 exi_rele(exi);
520 VN_RELE(vp);
521 resp->status = NFS3ERR_ACCES;
522 error = 1;
523 }
524 }
525 }
526
527 #ifdef DEBUG
528 if (rfs3_do_post_op_attr) {
529 dva.va_mask = AT_ALL;
530 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
531 } else
532 dvap = NULL;
533 #else
534 dva.va_mask = AT_ALL;
535 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
536 #endif
537
538 if (error)
539 goto out;
540
541 if (sec.sec_flags & SEC_QUERY) {
542 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
543 } else {
544 error = makefh3(&resp->resok.object, vp, exi);
545 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
546 auth_weak = TRUE;
547 }
548
549 if (error) {
550 VN_RELE(vp);
551 goto out;
552 }
553
554 /*
555 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
556 * and have obtained a new exportinfo in exi which needs to be
557 * released. Note the the original exportinfo pointed to by exi
558 * will be released by the caller, common_dispatch.
559 */
560 if (publicfh_flag)
561 exi_rele(exi);
562
563 #ifdef DEBUG
564 if (rfs3_do_post_op_attr) {
565 va.va_mask = AT_ALL;
566 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
567 } else
568 vap = NULL;
569 #else
570 va.va_mask = AT_ALL;
571 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
572 #endif
573
574 VN_RELE(vp);
575
576 resp->status = NFS3_OK;
577 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
578 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
579
580 /*
581 * If it's public fh, no 0x81, and client's flavor is
582 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
583 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
584 */
585 if (auth_weak)
586 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
587
588 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
589 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
590 VN_RELE(dvp);
591
592 return;
593
594 out:
595 if (curthread->t_flag & T_WOULDBLOCK) {
596 curthread->t_flag &= ~T_WOULDBLOCK;
597 resp->status = NFS3ERR_JUKEBOX;
598 } else
599 resp->status = puterrno3(error);
600 out1:
601 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
602 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
603
604 if (dvp != NULL)
605 VN_RELE(dvp);
606 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
607
608 }
609
610 void *
611 rfs3_lookup_getfh(LOOKUP3args *args)
612 {
613
614 return (&args->what.dir);
645 * to check write permissions for regular files and directories.
646 * Special files are interpreted by the client, so the underlying
647 * permissions are sent back to the client for interpretation.
648 */
649 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
650 checkwriteperm = 0;
651 else
652 checkwriteperm = 1;
653
654 /*
655 * We need the mode so that we can correctly determine access
656 * permissions relative to a mandatory lock file. Access to
657 * mandatory lock files is denied on the server, so it might
658 * as well be reflected to the server during the open.
659 */
660 va.va_mask = AT_MODE;
661 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
662 if (error)
663 goto out;
664
665 #ifdef DEBUG
666 if (rfs3_do_post_op_attr)
667 vap = &va;
668 #else
669 vap = &va;
670 #endif
671
672 resp->resok.access = 0;
673
674 if (is_system_labeled()) {
675 bslabel_t *clabel = req->rq_label;
676
677 ASSERT(clabel != NULL);
678 DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
679 "got client label from request(1)", struct svc_req *, req);
680
681 if (!blequal(&l_admin_low->tsl_label, clabel)) {
682 if ((equal_label = do_rfs_label_check(clabel, vp,
683 EQUALITY_CHECK, exi)) == B_FALSE) {
684 dominant_label = do_rfs_label_check(clabel,
685 vp, DOMINANCE_CHECK, exi);
686 } else
687 dominant_label = B_TRUE;
688 admin_low_client = B_FALSE;
689 } else
690 admin_low_client = B_TRUE;
725 (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
726 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
727 if (error) {
728 if (curthread->t_flag & T_WOULDBLOCK)
729 goto out;
730 } else if (!is_system_labeled() || admin_low_client ||
731 equal_label)
732 resp->resok.access |= ACCESS3_DELETE;
733 }
734 if (args->access & ACCESS3_EXECUTE) {
735 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
736 if (error) {
737 if (curthread->t_flag & T_WOULDBLOCK)
738 goto out;
739 } else if (!MANDLOCK(vp, va.va_mode) &&
740 (!is_system_labeled() || admin_low_client ||
741 dominant_label))
742 resp->resok.access |= ACCESS3_EXECUTE;
743 }
744
745 #ifdef DEBUG
746 if (rfs3_do_post_op_attr) {
747 va.va_mask = AT_ALL;
748 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
749 } else
750 vap = NULL;
751 #else
752 va.va_mask = AT_ALL;
753 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
754 #endif
755
756 resp->status = NFS3_OK;
757 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
758
759 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
760 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
761
762 VN_RELE(vp);
763
764 return;
765
766 out:
767 if (curthread->t_flag & T_WOULDBLOCK) {
768 curthread->t_flag &= ~T_WOULDBLOCK;
769 resp->status = NFS3ERR_JUKEBOX;
770 } else
771 resp->status = puterrno3(error);
772 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
773 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
774 if (vp != NULL)
799 char *name = NULL;
800 int is_referral = 0;
801
802 vap = NULL;
803
804 vp = nfs3_fhtovp(&args->symlink, exi);
805
806 DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
807 cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
808
809 if (vp == NULL) {
810 error = ESTALE;
811 goto out;
812 }
813
814 va.va_mask = AT_ALL;
815 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
816 if (error)
817 goto out;
818
819 #ifdef DEBUG
820 if (rfs3_do_post_op_attr)
821 vap = &va;
822 #else
823 vap = &va;
824 #endif
825
826 /* We lied about the object type for a referral */
827 if (vn_is_nfs_reparse(vp, cr))
828 is_referral = 1;
829
830 if (vp->v_type != VLNK && !is_referral) {
831 resp->status = NFS3ERR_INVAL;
832 goto out1;
833 }
834
835 if (MANDLOCK(vp, va.va_mode)) {
836 resp->status = NFS3ERR_ACCES;
837 goto out1;
838 }
839
840 if (is_system_labeled()) {
841 bslabel_t *clabel = req->rq_label;
842
843 ASSERT(clabel != NULL);
844 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
872 kmem_free(s, strsz);
873 }
874
875 } else {
876
877 iov.iov_base = data;
878 iov.iov_len = MAXPATHLEN;
879 uio.uio_iov = &iov;
880 uio.uio_iovcnt = 1;
881 uio.uio_segflg = UIO_SYSSPACE;
882 uio.uio_extflg = UIO_COPY_CACHED;
883 uio.uio_loffset = 0;
884 uio.uio_resid = MAXPATHLEN;
885
886 error = VOP_READLINK(vp, &uio, cr, NULL);
887
888 if (!error)
889 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
890 }
891
892 #ifdef DEBUG
893 if (rfs3_do_post_op_attr) {
894 va.va_mask = AT_ALL;
895 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
896 } else
897 vap = NULL;
898 #else
899 va.va_mask = AT_ALL;
900 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
901 #endif
902 /* Lie about object type again just to be consistent */
903 if (is_referral && vap != NULL)
904 vap->va_type = VLNK;
905
906 #if 0 /* notyet */
907 /*
908 * Don't do this. It causes local disk writes when just
909 * reading the file and the overhead is deemed larger
910 * than the benefit.
911 */
912 /*
913 * Force modified metadata out to stable storage.
914 */
915 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
916 #endif
917
918 if (error) {
919 kmem_free(data, MAXPATHLEN + 1);
920 goto out;
921 }
1060 error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1061
1062 /* check if a monitor detected a delegation conflict */
1063 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1064 resp->status = NFS3ERR_JUKEBOX;
1065 goto out1;
1066 }
1067
1068 need_rwunlock = 1;
1069
1070 va.va_mask = AT_ALL;
1071 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1072
1073 /*
1074 * If we can't get the attributes, then we can't do the
1075 * right access checking. So, we'll fail the request.
1076 */
1077 if (error)
1078 goto out;
1079
1080 #ifdef DEBUG
1081 if (rfs3_do_post_op_attr)
1082 vap = &va;
1083 #else
1084 vap = &va;
1085 #endif
1086
1087 if (vp->v_type != VREG) {
1088 resp->status = NFS3ERR_INVAL;
1089 goto out1;
1090 }
1091
1092 if (crgetuid(cr) != va.va_uid) {
1093 error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
1094 if (error) {
1095 if (curthread->t_flag & T_WOULDBLOCK)
1096 goto out;
1097 error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
1098 if (error)
1099 goto out;
1100 }
1101 }
1102
1103 if (MANDLOCK(vp, va.va_mode)) {
1104 resp->status = NFS3ERR_ACCES;
1105 goto out1;
1215 if (error) {
1216 if (mp)
1217 freemsg(mp);
1218 /* check if a monitor detected a delegation conflict */
1219 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1220 resp->status = NFS3ERR_JUKEBOX;
1221 goto out1;
1222 }
1223 goto out;
1224 }
1225
1226 /* make mblk using zc buffers */
1227 if (loaned_buffers) {
1228 mp = uio_to_mblk(uiop);
1229 ASSERT(mp != NULL);
1230 }
1231
1232 va.va_mask = AT_ALL;
1233 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1234
1235 #ifdef DEBUG
1236 if (rfs3_do_post_op_attr) {
1237 if (error)
1238 vap = NULL;
1239 else
1240 vap = &va;
1241 } else
1242 vap = NULL;
1243 #else
1244 if (error)
1245 vap = NULL;
1246 else
1247 vap = &va;
1248 #endif
1249
1250 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1251
1252 if (in_crit)
1253 nbl_end_crit(vp);
1254
1255 resp->status = NFS3_OK;
1256 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1257 resp->resok.count = args->count - uiop->uio_resid;
1258 if (!error && offset + resp->resok.count == va.va_size)
1259 resp->resok.eof = TRUE;
1260 else
1261 resp->resok.eof = FALSE;
1262 resp->resok.data.data_len = resp->resok.count;
1263
1264 if (mp)
1265 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1266
1267 resp->resok.data.mp = mp;
1268 resp->resok.size = (uint_t)args->count;
1402
1403 /* check if a monitor detected a delegation conflict */
1404 if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1405 resp->status = NFS3ERR_JUKEBOX;
1406 rwlock_ret = -1;
1407 goto err1;
1408 }
1409
1410
1411 bva.va_mask = AT_ALL;
1412 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1413
1414 /*
1415 * If we can't get the attributes, then we can't do the
1416 * right access checking. So, we'll fail the request.
1417 */
1418 if (error)
1419 goto err;
1420
1421 bvap = &bva;
1422 #ifdef DEBUG
1423 if (!rfs3_do_pre_op_attr)
1424 bvap = NULL;
1425 #endif
1426 avap = bvap;
1427
1428 if (args->count != args->data.data_len) {
1429 resp->status = NFS3ERR_INVAL;
1430 goto err1;
1431 }
1432
1433 if (rdonly(exi, req)) {
1434 resp->status = NFS3ERR_ROFS;
1435 goto err1;
1436 }
1437
1438 if (vp->v_type != VREG) {
1439 resp->status = NFS3ERR_INVAL;
1440 goto err1;
1441 }
1442
1443 if (crgetuid(cr) != bva.va_uid &&
1444 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1445 goto err;
1517 * the cred of the current thread to be used if quota
1518 * checking is enabled.
1519 */
1520 savecred = curthread->t_cred;
1521 curthread->t_cred = cr;
1522 error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1523 curthread->t_cred = savecred;
1524
1525 if (iovp != iov)
1526 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1527
1528 /* check if a monitor detected a delegation conflict */
1529 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1530 resp->status = NFS3ERR_JUKEBOX;
1531 goto err1;
1532 }
1533
1534 ava.va_mask = AT_ALL;
1535 avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1536
1537 #ifdef DEBUG
1538 if (!rfs3_do_post_op_attr)
1539 avap = NULL;
1540 #endif
1541
1542 if (error)
1543 goto err;
1544
1545 /*
1546 * If we were unable to get the V_WRITELOCK_TRUE, then we
1547 * may not have accurate after attrs, so check if
1548 * we have both attributes, they have a non-zero va_seq, and
1549 * va_seq has changed by exactly one,
1550 * if not, turn off the before attr.
1551 */
1552 if (rwlock_ret != V_WRITELOCK_TRUE) {
1553 if (bvap == NULL || avap == NULL ||
1554 bvap->va_seq == 0 || avap->va_seq == 0 ||
1555 avap->va_seq != (bvap->va_seq + 1)) {
1556 bvap = NULL;
1557 }
1558 }
1559
1560 resp->status = NFS3_OK;
1561 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1610 enum vcexcl excl;
1611 nfstime3 *mtime;
1612 len_t reqsize;
1613 bool_t trunc;
1614 struct sockaddr *ca;
1615 char *name = NULL;
1616
1617 dbvap = NULL;
1618 davap = NULL;
1619
1620 dvp = nfs3_fhtovp(&args->where.dir, exi);
1621
1622 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1623 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1624
1625 if (dvp == NULL) {
1626 error = ESTALE;
1627 goto out;
1628 }
1629
1630 #ifdef DEBUG
1631 if (rfs3_do_pre_op_attr) {
1632 dbva.va_mask = AT_ALL;
1633 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1634 } else
1635 dbvap = NULL;
1636 #else
1637 dbva.va_mask = AT_ALL;
1638 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1639 #endif
1640 davap = dbvap;
1641
1642 if (args->where.name == nfs3nametoolong) {
1643 resp->status = NFS3ERR_NAMETOOLONG;
1644 goto out1;
1645 }
1646
1647 if (args->where.name == NULL || *(args->where.name) == '\0') {
1648 resp->status = NFS3ERR_ACCES;
1649 goto out1;
1650 }
1651
1652 if (rdonly(exi, req)) {
1653 resp->status = NFS3ERR_ROFS;
1654 goto out1;
1655 }
1656
1657 if (is_system_labeled()) {
1658 bslabel_t *clabel = req->rq_label;
1659
1782 goto out1;
1783 }
1784
1785 /*
1786 * If the filesystem is exported with nosuid, then mask off
1787 * the setuid and setgid bits.
1788 */
1789 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1790 va.va_mode &= ~(VSUID | VSGID);
1791
1792 tryagain:
1793 /*
1794 * The file open mode used is VWRITE. If the client needs
1795 * some other semantic, then it should do the access checking
1796 * itself. It would have been nice to have the file open mode
1797 * passed as part of the arguments.
1798 */
1799 error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1800 &vp, cr, 0, NULL, NULL);
1801
1802 #ifdef DEBUG
1803 if (rfs3_do_post_op_attr) {
1804 dava.va_mask = AT_ALL;
1805 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1806 } else
1807 davap = NULL;
1808 #else
1809 dava.va_mask = AT_ALL;
1810 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1811 #endif
1812
1813 if (error) {
1814 /*
1815 * If we got something other than file already exists
1816 * then just return this error. Otherwise, we got
1817 * EEXIST. If we were doing a GUARDED create, then
1818 * just return this error. Otherwise, we need to
1819 * make sure that this wasn't a duplicate of an
1820 * exclusive create request.
1821 *
1822 * The assumption is made that a non-exclusive create
1823 * request will never return EEXIST.
1824 */
1825 if (error != EEXIST || args->how.mode == GUARDED)
1826 goto out;
1827 /*
1828 * Lookup the file so that we can get a vnode for it.
1829 */
1830 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1831 NULL, cr, NULL, NULL, NULL);
1895 * still recover by checking the size of the file
1896 * after it has created it and then issue a setattr
1897 * request of its own to set the size of the file.
1898 */
1899 if (vap != NULL &&
1900 (args->how.mode == UNCHECKED ||
1901 args->how.mode == GUARDED) &&
1902 args->how.createhow3_u.obj_attributes.size.set_it &&
1903 vap->va_size != reqsize) {
1904 va.va_mask = AT_SIZE;
1905 va.va_size = reqsize;
1906 (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1907 va.va_mask = AT_ALL;
1908 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1909 }
1910 }
1911
1912 if (name != args->where.name)
1913 kmem_free(name, MAXPATHLEN + 1);
1914
1915 #ifdef DEBUG
1916 if (!rfs3_do_post_op_attr)
1917 vap = NULL;
1918 #endif
1919
1920 #ifdef DEBUG
1921 if (!rfs3_do_post_op_fh3)
1922 resp->resok.obj.handle_follows = FALSE;
1923 else {
1924 #endif
1925 error = makefh3(&resp->resok.obj.handle, vp, exi);
1926 if (error)
1927 resp->resok.obj.handle_follows = FALSE;
1928 else
1929 resp->resok.obj.handle_follows = TRUE;
1930 #ifdef DEBUG
1931 }
1932 #endif
1933
1934 /*
1935 * Force modified data and metadata out to stable storage.
1936 */
1937 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1938 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1939
1940 VN_RELE(vp);
1941 if (tvp != NULL) {
1942 if (in_crit)
1943 nbl_end_crit(tvp);
1944 VN_RELE(tvp);
1945 }
1946
1947 resp->status = NFS3_OK;
1948 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1949 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1950
1951 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1952 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1996 struct vattr *dbvap;
1997 struct vattr dbva;
1998 struct vattr *davap;
1999 struct vattr dava;
2000 struct sockaddr *ca;
2001 char *name = NULL;
2002
2003 dbvap = NULL;
2004 davap = NULL;
2005
2006 dvp = nfs3_fhtovp(&args->where.dir, exi);
2007
2008 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
2009 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
2010
2011 if (dvp == NULL) {
2012 error = ESTALE;
2013 goto out;
2014 }
2015
2016 #ifdef DEBUG
2017 if (rfs3_do_pre_op_attr) {
2018 dbva.va_mask = AT_ALL;
2019 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2020 } else
2021 dbvap = NULL;
2022 #else
2023 dbva.va_mask = AT_ALL;
2024 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2025 #endif
2026 davap = dbvap;
2027
2028 if (args->where.name == nfs3nametoolong) {
2029 resp->status = NFS3ERR_NAMETOOLONG;
2030 goto out1;
2031 }
2032
2033 if (args->where.name == NULL || *(args->where.name) == '\0') {
2034 resp->status = NFS3ERR_ACCES;
2035 goto out1;
2036 }
2037
2038 if (rdonly(exi, req)) {
2039 resp->status = NFS3ERR_ROFS;
2040 goto out1;
2041 }
2042
2043 if (is_system_labeled()) {
2044 bslabel_t *clabel = req->rq_label;
2045
2065 goto out1;
2066 }
2067
2068 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2069 name = nfscmd_convname(ca, exi, args->where.name,
2070 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2071
2072 if (name == NULL) {
2073 resp->status = NFS3ERR_INVAL;
2074 goto out1;
2075 }
2076
2077 va.va_mask |= AT_TYPE;
2078 va.va_type = VDIR;
2079
2080 error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
2081
2082 if (name != args->where.name)
2083 kmem_free(name, MAXPATHLEN + 1);
2084
2085 #ifdef DEBUG
2086 if (rfs3_do_post_op_attr) {
2087 dava.va_mask = AT_ALL;
2088 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2089 } else
2090 davap = NULL;
2091 #else
2092 dava.va_mask = AT_ALL;
2093 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2094 #endif
2095
2096 /*
2097 * Force modified data and metadata out to stable storage.
2098 */
2099 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2100
2101 if (error)
2102 goto out;
2103
2104 #ifdef DEBUG
2105 if (!rfs3_do_post_op_fh3)
2106 resp->resok.obj.handle_follows = FALSE;
2107 else {
2108 #endif
2109 error = makefh3(&resp->resok.obj.handle, vp, exi);
2110 if (error)
2111 resp->resok.obj.handle_follows = FALSE;
2112 else
2113 resp->resok.obj.handle_follows = TRUE;
2114 #ifdef DEBUG
2115 }
2116 #endif
2117
2118 #ifdef DEBUG
2119 if (rfs3_do_post_op_attr) {
2120 va.va_mask = AT_ALL;
2121 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2122 } else
2123 vap = NULL;
2124 #else
2125 va.va_mask = AT_ALL;
2126 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2127 #endif
2128
2129 /*
2130 * Force modified data and metadata out to stable storage.
2131 */
2132 (void) VOP_FSYNC(vp, 0, cr, NULL);
2133
2134 VN_RELE(vp);
2135
2136 resp->status = NFS3_OK;
2137 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2138 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2139
2140 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2141 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2142 VN_RELE(dvp);
2143
2144 return;
2145
2146 out:
2147 if (curthread->t_flag & T_WOULDBLOCK) {
2177 struct vattr dbva;
2178 struct vattr *davap;
2179 struct vattr dava;
2180 struct sockaddr *ca;
2181 char *name = NULL;
2182 char *symdata = NULL;
2183
2184 dbvap = NULL;
2185 davap = NULL;
2186
2187 dvp = nfs3_fhtovp(&args->where.dir, exi);
2188
2189 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2190 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2191
2192 if (dvp == NULL) {
2193 error = ESTALE;
2194 goto err;
2195 }
2196
2197 #ifdef DEBUG
2198 if (rfs3_do_pre_op_attr) {
2199 dbva.va_mask = AT_ALL;
2200 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2201 } else
2202 dbvap = NULL;
2203 #else
2204 dbva.va_mask = AT_ALL;
2205 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2206 #endif
2207 davap = dbvap;
2208
2209 if (args->where.name == nfs3nametoolong) {
2210 resp->status = NFS3ERR_NAMETOOLONG;
2211 goto err1;
2212 }
2213
2214 if (args->where.name == NULL || *(args->where.name) == '\0') {
2215 resp->status = NFS3ERR_ACCES;
2216 goto err1;
2217 }
2218
2219 if (rdonly(exi, req)) {
2220 resp->status = NFS3ERR_ROFS;
2221 goto err1;
2222 }
2223
2224 if (is_system_labeled()) {
2225 bslabel_t *clabel = req->rq_label;
2226
2258 if (name == NULL) {
2259 /* This is really a Solaris EILSEQ */
2260 resp->status = NFS3ERR_INVAL;
2261 goto err1;
2262 }
2263
2264 symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2265 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2266 if (symdata == NULL) {
2267 /* This is really a Solaris EILSEQ */
2268 resp->status = NFS3ERR_INVAL;
2269 goto err1;
2270 }
2271
2272
2273 va.va_mask |= AT_TYPE;
2274 va.va_type = VLNK;
2275
2276 error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2277
2278 #ifdef DEBUG
2279 if (rfs3_do_post_op_attr) {
2280 dava.va_mask = AT_ALL;
2281 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2282 } else
2283 davap = NULL;
2284 #else
2285 dava.va_mask = AT_ALL;
2286 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2287 #endif
2288
2289 if (error)
2290 goto err;
2291
2292 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2293 NULL, NULL, NULL);
2294
2295 /*
2296 * Force modified data and metadata out to stable storage.
2297 */
2298 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2299
2300
2301 resp->status = NFS3_OK;
2302 if (error) {
2303 resp->resok.obj.handle_follows = FALSE;
2304 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2305 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2306 goto out;
2307 }
2308
2309 #ifdef DEBUG
2310 if (!rfs3_do_post_op_fh3)
2311 resp->resok.obj.handle_follows = FALSE;
2312 else {
2313 #endif
2314 error = makefh3(&resp->resok.obj.handle, vp, exi);
2315 if (error)
2316 resp->resok.obj.handle_follows = FALSE;
2317 else
2318 resp->resok.obj.handle_follows = TRUE;
2319 #ifdef DEBUG
2320 }
2321 #endif
2322
2323 #ifdef DEBUG
2324 if (rfs3_do_post_op_attr) {
2325 va.va_mask = AT_ALL;
2326 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2327 } else
2328 vap = NULL;
2329 #else
2330 va.va_mask = AT_ALL;
2331 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2332 #endif
2333
2334 /*
2335 * Force modified data and metadata out to stable storage.
2336 */
2337 (void) VOP_FSYNC(vp, 0, cr, NULL);
2338
2339 VN_RELE(vp);
2340
2341 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2342 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2343 goto out;
2344
2345 err:
2346 if (curthread->t_flag & T_WOULDBLOCK) {
2347 curthread->t_flag &= ~T_WOULDBLOCK;
2348 resp->status = NFS3ERR_JUKEBOX;
2349 } else
2350 resp->status = puterrno3(error);
2351 err1:
2352 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2385 struct vattr *davap;
2386 struct vattr dava;
2387 int mode;
2388 enum vcexcl excl;
2389 struct sockaddr *ca;
2390 char *name = NULL;
2391
2392 dbvap = NULL;
2393 davap = NULL;
2394
2395 dvp = nfs3_fhtovp(&args->where.dir, exi);
2396
2397 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2398 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2399
2400 if (dvp == NULL) {
2401 error = ESTALE;
2402 goto out;
2403 }
2404
2405 #ifdef DEBUG
2406 if (rfs3_do_pre_op_attr) {
2407 dbva.va_mask = AT_ALL;
2408 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2409 } else
2410 dbvap = NULL;
2411 #else
2412 dbva.va_mask = AT_ALL;
2413 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2414 #endif
2415 davap = dbvap;
2416
2417 if (args->where.name == nfs3nametoolong) {
2418 resp->status = NFS3ERR_NAMETOOLONG;
2419 goto out1;
2420 }
2421
2422 if (args->where.name == NULL || *(args->where.name) == '\0') {
2423 resp->status = NFS3ERR_ACCES;
2424 goto out1;
2425 }
2426
2427 if (rdonly(exi, req)) {
2428 resp->status = NFS3ERR_ROFS;
2429 goto out1;
2430 }
2431
2432 if (is_system_labeled()) {
2433 bslabel_t *clabel = req->rq_label;
2434
2496
2497 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2498 name = nfscmd_convname(ca, exi, args->where.name,
2499 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2500
2501 if (name == NULL) {
2502 resp->status = NFS3ERR_INVAL;
2503 goto out1;
2504 }
2505
2506 excl = EXCL;
2507
2508 mode = 0;
2509
2510 error = VOP_CREATE(dvp, name, &va, excl, mode,
2511 &vp, cr, 0, NULL, NULL);
2512
2513 if (name != args->where.name)
2514 kmem_free(name, MAXPATHLEN + 1);
2515
2516 #ifdef DEBUG
2517 if (rfs3_do_post_op_attr) {
2518 dava.va_mask = AT_ALL;
2519 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2520 } else
2521 davap = NULL;
2522 #else
2523 dava.va_mask = AT_ALL;
2524 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2525 #endif
2526
2527 /*
2528 * Force modified data and metadata out to stable storage.
2529 */
2530 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2531
2532 if (error)
2533 goto out;
2534
2535 resp->status = NFS3_OK;
2536
2537 #ifdef DEBUG
2538 if (!rfs3_do_post_op_fh3)
2539 resp->resok.obj.handle_follows = FALSE;
2540 else {
2541 #endif
2542 error = makefh3(&resp->resok.obj.handle, vp, exi);
2543 if (error)
2544 resp->resok.obj.handle_follows = FALSE;
2545 else
2546 resp->resok.obj.handle_follows = TRUE;
2547 #ifdef DEBUG
2548 }
2549 #endif
2550
2551 #ifdef DEBUG
2552 if (rfs3_do_post_op_attr) {
2553 va.va_mask = AT_ALL;
2554 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2555 } else
2556 vap = NULL;
2557 #else
2558 va.va_mask = AT_ALL;
2559 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2560 #endif
2561
2562 /*
2563 * Force modified metadata out to stable storage.
2564 *
2565 * if a underlying vp exists, pass it to VOP_FSYNC
2566 */
2567 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2568 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2569 else
2570 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2571
2572 VN_RELE(vp);
2573
2574 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2575 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2576 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2577 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2578 VN_RELE(dvp);
2579 return;
2580
2609 struct vattr bva;
2610 struct vattr *avap;
2611 struct vattr ava;
2612 vnode_t *targvp = NULL;
2613 struct sockaddr *ca;
2614 char *name = NULL;
2615
2616 bvap = NULL;
2617 avap = NULL;
2618
2619 vp = nfs3_fhtovp(&args->object.dir, exi);
2620
2621 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2622 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2623
2624 if (vp == NULL) {
2625 error = ESTALE;
2626 goto err;
2627 }
2628
2629 #ifdef DEBUG
2630 if (rfs3_do_pre_op_attr) {
2631 bva.va_mask = AT_ALL;
2632 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2633 } else
2634 bvap = NULL;
2635 #else
2636 bva.va_mask = AT_ALL;
2637 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2638 #endif
2639 avap = bvap;
2640
2641 if (vp->v_type != VDIR) {
2642 resp->status = NFS3ERR_NOTDIR;
2643 goto err1;
2644 }
2645
2646 if (args->object.name == nfs3nametoolong) {
2647 resp->status = NFS3ERR_NAMETOOLONG;
2648 goto err1;
2649 }
2650
2651 if (args->object.name == NULL || *(args->object.name) == '\0') {
2652 resp->status = NFS3ERR_ACCES;
2653 goto err1;
2654 }
2655
2656 if (rdonly(exi, req)) {
2657 resp->status = NFS3ERR_ROFS;
2658 goto err1;
2694
2695 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2696 resp->status = NFS3ERR_JUKEBOX;
2697 goto err1;
2698 }
2699
2700 if (!nbl_need_check(targvp)) {
2701 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2702 } else {
2703 nbl_start_crit(targvp, RW_READER);
2704 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2705 error = EACCES;
2706 } else {
2707 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2708 }
2709 nbl_end_crit(targvp);
2710 }
2711 VN_RELE(targvp);
2712 targvp = NULL;
2713
2714 #ifdef DEBUG
2715 if (rfs3_do_post_op_attr) {
2716 ava.va_mask = AT_ALL;
2717 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2718 } else
2719 avap = NULL;
2720 #else
2721 ava.va_mask = AT_ALL;
2722 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2723 #endif
2724
2725 /*
2726 * Force modified data and metadata out to stable storage.
2727 */
2728 (void) VOP_FSYNC(vp, 0, cr, NULL);
2729
2730 if (error)
2731 goto err;
2732
2733 resp->status = NFS3_OK;
2734 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2735 goto out;
2736
2737 err:
2738 if (curthread->t_flag & T_WOULDBLOCK) {
2739 curthread->t_flag &= ~T_WOULDBLOCK;
2740 resp->status = NFS3ERR_JUKEBOX;
2741 } else
2742 resp->status = puterrno3(error);
2743 err1:
2769 struct vattr *bvap;
2770 struct vattr bva;
2771 struct vattr *avap;
2772 struct vattr ava;
2773 struct sockaddr *ca;
2774 char *name = NULL;
2775
2776 bvap = NULL;
2777 avap = NULL;
2778
2779 vp = nfs3_fhtovp(&args->object.dir, exi);
2780
2781 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2782 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2783
2784 if (vp == NULL) {
2785 error = ESTALE;
2786 goto err;
2787 }
2788
2789 #ifdef DEBUG
2790 if (rfs3_do_pre_op_attr) {
2791 bva.va_mask = AT_ALL;
2792 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2793 } else
2794 bvap = NULL;
2795 #else
2796 bva.va_mask = AT_ALL;
2797 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2798 #endif
2799 avap = bvap;
2800
2801 if (vp->v_type != VDIR) {
2802 resp->status = NFS3ERR_NOTDIR;
2803 goto err1;
2804 }
2805
2806 if (args->object.name == nfs3nametoolong) {
2807 resp->status = NFS3ERR_NAMETOOLONG;
2808 goto err1;
2809 }
2810
2811 if (args->object.name == NULL || *(args->object.name) == '\0') {
2812 resp->status = NFS3ERR_ACCES;
2813 goto err1;
2814 }
2815
2816 if (rdonly(exi, req)) {
2817 resp->status = NFS3ERR_ROFS;
2818 goto err1;
2831 resp->status = NFS3ERR_ACCES;
2832 goto err1;
2833 }
2834 }
2835 }
2836
2837 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2838 name = nfscmd_convname(ca, exi, args->object.name,
2839 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2840
2841 if (name == NULL) {
2842 resp->status = NFS3ERR_INVAL;
2843 goto err1;
2844 }
2845
2846 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2847
2848 if (name != args->object.name)
2849 kmem_free(name, MAXPATHLEN + 1);
2850
2851 #ifdef DEBUG
2852 if (rfs3_do_post_op_attr) {
2853 ava.va_mask = AT_ALL;
2854 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2855 } else
2856 avap = NULL;
2857 #else
2858 ava.va_mask = AT_ALL;
2859 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2860 #endif
2861
2862 /*
2863 * Force modified data and metadata out to stable storage.
2864 */
2865 (void) VOP_FSYNC(vp, 0, cr, NULL);
2866
2867 if (error) {
2868 /*
2869 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2870 * if the directory is not empty. A System V NFS server
2871 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2872 * over the wire.
2873 */
2874 if (error == EEXIST)
2875 error = ENOTEMPTY;
2876 goto err;
2877 }
2878
2879 resp->status = NFS3_OK;
2880 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2941 if (fvp == NULL) {
2942 error = ESTALE;
2943 goto err;
2944 }
2945
2946 if (is_system_labeled()) {
2947 clabel = req->rq_label;
2948 ASSERT(clabel != NULL);
2949 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2950 "got client label from request(1)", struct svc_req *, req);
2951
2952 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2953 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2954 exi)) {
2955 resp->status = NFS3ERR_ACCES;
2956 goto err1;
2957 }
2958 }
2959 }
2960
2961 #ifdef DEBUG
2962 if (rfs3_do_pre_op_attr) {
2963 fbva.va_mask = AT_ALL;
2964 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2965 } else
2966 fbvap = NULL;
2967 #else
2968 fbva.va_mask = AT_ALL;
2969 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2970 #endif
2971 favap = fbvap;
2972
2973 fh3 = &args->to.dir;
2974 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2975 if (to_exi == NULL) {
2976 resp->status = NFS3ERR_ACCES;
2977 goto err1;
2978 }
2979 exi_rele(to_exi);
2980
2981 if (to_exi != exi) {
2982 resp->status = NFS3ERR_XDEV;
2983 goto err1;
2984 }
2985
2986 tvp = nfs3_fhtovp(&args->to.dir, exi);
2987 if (tvp == NULL) {
2988 error = ESTALE;
2989 goto err;
2990 }
2991
2992 #ifdef DEBUG
2993 if (rfs3_do_pre_op_attr) {
2994 tbva.va_mask = AT_ALL;
2995 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2996 } else
2997 tbvap = NULL;
2998 #else
2999 tbva.va_mask = AT_ALL;
3000 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
3001 #endif
3002 tavap = tbvap;
3003
3004 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
3005 resp->status = NFS3ERR_NOTDIR;
3006 goto err1;
3007 }
3008
3009 if (args->from.name == nfs3nametoolong ||
3010 args->to.name == nfs3nametoolong) {
3011 resp->status = NFS3ERR_NAMETOOLONG;
3012 goto err1;
3013 }
3014 if (args->from.name == NULL || *(args->from.name) == '\0' ||
3015 args->to.name == NULL || *(args->to.name) == '\0') {
3016 resp->status = NFS3ERR_ACCES;
3017 goto err1;
3018 }
3019
3020 if (rdonly(exi, req)) {
3021 resp->status = NFS3ERR_ROFS;
3083 }
3084 VN_RELE(targvp);
3085 }
3086
3087 if (!nbl_need_check(srcvp)) {
3088 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
3089 } else {
3090 nbl_start_crit(srcvp, RW_READER);
3091 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
3092 error = EACCES;
3093 else
3094 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
3095 nbl_end_crit(srcvp);
3096 }
3097 if (error == 0)
3098 vn_renamepath(tvp, srcvp, args->to.name,
3099 strlen(args->to.name));
3100 VN_RELE(srcvp);
3101 srcvp = NULL;
3102
3103 #ifdef DEBUG
3104 if (rfs3_do_post_op_attr) {
3105 fava.va_mask = AT_ALL;
3106 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
3107 tava.va_mask = AT_ALL;
3108 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
3109 } else {
3110 favap = NULL;
3111 tavap = NULL;
3112 }
3113 #else
3114 fava.va_mask = AT_ALL;
3115 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
3116 tava.va_mask = AT_ALL;
3117 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
3118 #endif
3119
3120 /*
3121 * Force modified data and metadata out to stable storage.
3122 */
3123 (void) VOP_FSYNC(fvp, 0, cr, NULL);
3124 (void) VOP_FSYNC(tvp, 0, cr, NULL);
3125
3126 if (error)
3127 goto err;
3128
3129 resp->status = NFS3_OK;
3130 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
3131 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
3132 goto out;
3133
3134 err:
3135 if (curthread->t_flag & T_WOULDBLOCK) {
3136 curthread->t_flag &= ~T_WOULDBLOCK;
3137 resp->status = NFS3ERR_JUKEBOX;
3138 } else {
3180 struct exportinfo *to_exi;
3181 bslabel_t *clabel;
3182 struct sockaddr *ca;
3183 char *name = NULL;
3184
3185 vap = NULL;
3186 bvap = NULL;
3187 avap = NULL;
3188 dvp = NULL;
3189
3190 vp = nfs3_fhtovp(&args->file, exi);
3191
3192 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
3193 cred_t *, cr, vnode_t *, vp, LINK3args *, args);
3194
3195 if (vp == NULL) {
3196 error = ESTALE;
3197 goto out;
3198 }
3199
3200 #ifdef DEBUG
3201 if (rfs3_do_pre_op_attr) {
3202 va.va_mask = AT_ALL;
3203 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3204 } else
3205 vap = NULL;
3206 #else
3207 va.va_mask = AT_ALL;
3208 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3209 #endif
3210
3211 fh3 = &args->link.dir;
3212 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3213 if (to_exi == NULL) {
3214 resp->status = NFS3ERR_ACCES;
3215 goto out1;
3216 }
3217 exi_rele(to_exi);
3218
3219 if (to_exi != exi) {
3220 resp->status = NFS3ERR_XDEV;
3221 goto out1;
3222 }
3223
3224 if (is_system_labeled()) {
3225 clabel = req->rq_label;
3226
3227 ASSERT(clabel != NULL);
3228 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3229 "got client label from request(1)", struct svc_req *, req);
3230
3231 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3232 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3233 exi)) {
3234 resp->status = NFS3ERR_ACCES;
3235 goto out1;
3236 }
3237 }
3238 }
3239
3240 dvp = nfs3_fhtovp(&args->link.dir, exi);
3241 if (dvp == NULL) {
3242 error = ESTALE;
3243 goto out;
3244 }
3245
3246 #ifdef DEBUG
3247 if (rfs3_do_pre_op_attr) {
3248 bva.va_mask = AT_ALL;
3249 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3250 } else
3251 bvap = NULL;
3252 #else
3253 bva.va_mask = AT_ALL;
3254 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3255 #endif
3256
3257 if (dvp->v_type != VDIR) {
3258 resp->status = NFS3ERR_NOTDIR;
3259 goto out1;
3260 }
3261
3262 if (args->link.name == nfs3nametoolong) {
3263 resp->status = NFS3ERR_NAMETOOLONG;
3264 goto out1;
3265 }
3266
3267 if (args->link.name == NULL || *(args->link.name) == '\0') {
3268 resp->status = NFS3ERR_ACCES;
3269 goto out1;
3270 }
3271
3272 if (rdonly(exi, req)) {
3273 resp->status = NFS3ERR_ROFS;
3274 goto out1;
3275 }
3281 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3282 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3283 exi)) {
3284 resp->status = NFS3ERR_ACCES;
3285 goto out1;
3286 }
3287 }
3288 }
3289
3290 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3291 name = nfscmd_convname(ca, exi, args->link.name,
3292 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3293
3294 if (name == NULL) {
3295 resp->status = NFS3ERR_SERVERFAULT;
3296 goto out1;
3297 }
3298
3299 error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3300
3301 #ifdef DEBUG
3302 if (rfs3_do_post_op_attr) {
3303 va.va_mask = AT_ALL;
3304 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3305 ava.va_mask = AT_ALL;
3306 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3307 } else {
3308 vap = NULL;
3309 avap = NULL;
3310 }
3311 #else
3312 va.va_mask = AT_ALL;
3313 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3314 ava.va_mask = AT_ALL;
3315 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3316 #endif
3317
3318 /*
3319 * Force modified data and metadata out to stable storage.
3320 */
3321 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3322 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3323
3324 if (error)
3325 goto out;
3326
3327 VN_RELE(dvp);
3328
3329 resp->status = NFS3_OK;
3330 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3331 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3332
3333 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3334 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3335
3336 VN_RELE(vp);
3425 }
3426
3427 if (is_system_labeled()) {
3428 bslabel_t *clabel = req->rq_label;
3429
3430 ASSERT(clabel != NULL);
3431 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3432 "got client label from request(1)", struct svc_req *, req);
3433
3434 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3435 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3436 exi)) {
3437 resp->status = NFS3ERR_ACCES;
3438 goto out1;
3439 }
3440 }
3441 }
3442
3443 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3444
3445 #ifdef DEBUG
3446 if (rfs3_do_pre_op_attr) {
3447 va.va_mask = AT_ALL;
3448 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3449 } else
3450 vap = NULL;
3451 #else
3452 va.va_mask = AT_ALL;
3453 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3454 #endif
3455
3456 if (vp->v_type != VDIR) {
3457 resp->status = NFS3ERR_NOTDIR;
3458 goto out1;
3459 }
3460
3461 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3462 if (error)
3463 goto out;
3464
3465 /*
3466 * Now don't allow arbitrary count to alloc;
3467 * allow the maximum not to exceed rfs3_tsize()
3468 */
3469 if (args->count > rfs3_tsize(req))
3470 args->count = rfs3_tsize(req);
3471
3472 /*
3473 * Make sure that there is room to read at least one entry
3474 * if any are available.
3475 */
3476 if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3477 count = DIRENT64_RECLEN(MAXNAMELEN);
3478 else
3479 count = args->count;
3480
3481 data = kmem_alloc(count, KM_SLEEP);
3482
3483 iov.iov_base = data;
3484 iov.iov_len = count;
3485 uio.uio_iov = &iov;
3486 uio.uio_iovcnt = 1;
3487 uio.uio_segflg = UIO_SYSSPACE;
3488 uio.uio_extflg = UIO_COPY_CACHED;
3489 uio.uio_loffset = (offset_t)args->cookie;
3490 uio.uio_resid = count;
3491
3492 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3493
3494 #ifdef DEBUG
3495 if (rfs3_do_post_op_attr) {
3496 va.va_mask = AT_ALL;
3497 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3498 } else
3499 vap = NULL;
3500 #else
3501 va.va_mask = AT_ALL;
3502 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3503 #endif
3504
3505 if (error) {
3506 kmem_free(data, count);
3507 goto out;
3508 }
3509
3510 /*
3511 * If the count was not large enough to be able to guarantee
3512 * to be able to return at least one entry, then need to
3513 * check to see if NFS3ERR_TOOSMALL should be returned.
3514 */
3515 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3516 /*
3517 * bufsize is used to keep track of the size of the response.
3518 * It is primed with:
3519 * 1 for the status +
3520 * 1 for the dir_attributes.attributes boolean +
3521 * 2 for the cookie verifier
3522 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3523 * to bytes. If there are directory attributes to be
3713
3714 if (is_system_labeled()) {
3715 bslabel_t *clabel = req->rq_label;
3716
3717 ASSERT(clabel != NULL);
3718 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3719 char *, "got client label from request(1)",
3720 struct svc_req *, req);
3721
3722 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3723 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3724 exi)) {
3725 resp->status = NFS3ERR_ACCES;
3726 goto out1;
3727 }
3728 }
3729 }
3730
3731 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3732
3733 #ifdef DEBUG
3734 if (rfs3_do_pre_op_attr) {
3735 va.va_mask = AT_ALL;
3736 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3737 } else
3738 vap = NULL;
3739 #else
3740 va.va_mask = AT_ALL;
3741 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3742 #endif
3743
3744 if (vp->v_type != VDIR) {
3745 error = ENOTDIR;
3746 goto out;
3747 }
3748
3749 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3750 if (error)
3751 goto out;
3752
3753 /*
3754 * Don't allow arbitrary counts for allocation
3755 */
3756 if (args->maxcount > rfs3_tsize(req))
3757 args->maxcount = rfs3_tsize(req);
3758
3759 /*
3760 * Make sure that there is room to read at least one entry
3761 * if any are available
3762 */
3881 iseof = FALSE;
3882 goto good;
3883 }
3884 bufsize += entrysize;
3885 nents++;
3886 }
3887
3888 /*
3889 * If there is enough room to fit at least 1 more entry including
3890 * post op attributes and filehandle in the buffer AND that we haven't
3891 * exceeded dircount then go back and get some more.
3892 */
3893 if (!iseof &&
3894 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3895 space_left -= (prev_len - uio.uio_resid);
3896 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3897 goto getmoredents;
3898
3899 /* else, fall through */
3900 }
3901
3902 good:
3903
3904 #ifdef DEBUG
3905 if (rfs3_do_post_op_attr) {
3906 va.va_mask = AT_ALL;
3907 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3908 } else
3909 vap = NULL;
3910 #else
3911 va.va_mask = AT_ALL;
3912 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3913 #endif
3914
3915 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3916
3917 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3918 resp->resok.infop = infop;
3919
3920 dp = (struct dirent64 *)data;
3921 for (i = 0; i < nents; i++) {
3922
3923 if (dp->d_ino == 0) {
3924 infop[i].attr.attributes = FALSE;
3925 infop[i].fh.handle_follows = FALSE;
3926 dp = nextdp(dp);
3927 continue;
3928 }
3929
3930 infop[i].namelen = namlen[i];
3931
3932 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3933 NULL, NULL, NULL);
3934 if (error) {
3935 infop[i].attr.attributes = FALSE;
3936 infop[i].fh.handle_follows = FALSE;
3937 dp = nextdp(dp);
3938 continue;
3939 }
3940
3941 #ifdef DEBUG
3942 if (rfs3_do_post_op_attr) {
3943 nva.va_mask = AT_ALL;
3944 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
3945 NULL : &nva;
3946 } else
3947 nvap = NULL;
3948 #else
3949 nva.va_mask = AT_ALL;
3950 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3951 #endif
3952 /* Lie about the object type for a referral */
3953 if (vn_is_nfs_reparse(nvp, cr))
3954 nvap->va_type = VLNK;
3955
3956 vattr_to_post_op_attr(nvap, &infop[i].attr);
3957
3958 #ifdef DEBUG
3959 if (!rfs3_do_post_op_fh3)
3960 infop[i].fh.handle_follows = FALSE;
3961 else {
3962 #endif
3963 error = makefh3(&infop[i].fh.handle, nvp, exi);
3964 if (!error)
3965 infop[i].fh.handle_follows = TRUE;
3966 else
3967 infop[i].fh.handle_follows = FALSE;
3968 #ifdef DEBUG
3969 }
3970 #endif
3971
3972 VN_RELE(nvp);
3973 dp = nextdp(dp);
3974 }
3975
3976 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3977 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3978 if (ndata == NULL)
3979 ndata = data;
3980
3981 if (ret > 0) {
3982 /*
3983 * We had to drop one or more entries in order to fit
3984 * during the character conversion. We need to patch
3985 * up the size and eof info.
3986 */
3987 if (iseof)
3988 iseof = FALSE;
3989
3990 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
4089 }
4090
4091 if (is_system_labeled()) {
4092 bslabel_t *clabel = req->rq_label;
4093
4094 ASSERT(clabel != NULL);
4095 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
4096 "got client label from request(1)", struct svc_req *, req);
4097
4098 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4099 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4100 exi)) {
4101 resp->status = NFS3ERR_ACCES;
4102 goto out1;
4103 }
4104 }
4105 }
4106
4107 error = VFS_STATVFS(vp->v_vfsp, &sb);
4108
4109 #ifdef DEBUG
4110 if (rfs3_do_post_op_attr) {
4111 va.va_mask = AT_ALL;
4112 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4113 } else
4114 vap = NULL;
4115 #else
4116 va.va_mask = AT_ALL;
4117 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4118 #endif
4119
4120 if (error)
4121 goto out;
4122
4123 resp->status = NFS3_OK;
4124 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4125 if (sb.f_blocks != (fsblkcnt64_t)-1)
4126 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
4127 else
4128 resp->resok.tbytes = (size3)sb.f_blocks;
4129 if (sb.f_bfree != (fsblkcnt64_t)-1)
4130 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
4131 else
4132 resp->resok.fbytes = (size3)sb.f_bfree;
4133 if (sb.f_bavail != (fsblkcnt64_t)-1)
4134 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
4135 else
4136 resp->resok.abytes = (size3)sb.f_bavail;
4137 resp->resok.tfiles = (size3)sb.f_files;
4138 resp->resok.ffiles = (size3)sb.f_ffree;
4194 }
4195
4196 if (is_system_labeled()) {
4197 bslabel_t *clabel = req->rq_label;
4198
4199 ASSERT(clabel != NULL);
4200 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
4201 "got client label from request(1)", struct svc_req *, req);
4202
4203 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4204 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4205 exi)) {
4206 resp->status = NFS3ERR_STALE;
4207 vattr_to_post_op_attr(NULL,
4208 &resp->resfail.obj_attributes);
4209 goto out;
4210 }
4211 }
4212 }
4213
4214 #ifdef DEBUG
4215 if (rfs3_do_post_op_attr) {
4216 va.va_mask = AT_ALL;
4217 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4218 } else
4219 vap = NULL;
4220 #else
4221 va.va_mask = AT_ALL;
4222 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4223 #endif
4224
4225 resp->status = NFS3_OK;
4226 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4227 xfer_size = rfs3_tsize(req);
4228 resp->resok.rtmax = xfer_size;
4229 resp->resok.rtpref = xfer_size;
4230 resp->resok.rtmult = DEV_BSIZE;
4231 resp->resok.wtmax = xfer_size;
4232 resp->resok.wtpref = xfer_size;
4233 resp->resok.wtmult = DEV_BSIZE;
4234 resp->resok.dtpref = MAXBSIZE;
4235
4236 /*
4237 * Large file spec: want maxfilesize based on limit of
4238 * underlying filesystem. We can guess 2^31-1 if need be.
4239 */
4240 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
4241 if (error) {
4242 resp->status = puterrno3(error);
4243 goto out;
4306 error = ESTALE;
4307 goto out;
4308 }
4309
4310 if (is_system_labeled()) {
4311 bslabel_t *clabel = req->rq_label;
4312
4313 ASSERT(clabel != NULL);
4314 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4315 "got client label from request(1)", struct svc_req *, req);
4316
4317 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4318 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4319 exi)) {
4320 resp->status = NFS3ERR_ACCES;
4321 goto out1;
4322 }
4323 }
4324 }
4325
4326 #ifdef DEBUG
4327 if (rfs3_do_post_op_attr) {
4328 va.va_mask = AT_ALL;
4329 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4330 } else
4331 vap = NULL;
4332 #else
4333 va.va_mask = AT_ALL;
4334 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4335 #endif
4336
4337 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
4338 if (error)
4339 goto out;
4340 resp->resok.info.link_max = (uint32)val;
4341
4342 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
4343 if (error)
4344 goto out;
4345 resp->resok.info.name_max = (uint32)val;
4346
4347 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4348 if (error)
4349 goto out;
4350 if (val == 1)
4351 resp->resok.info.no_trunc = TRUE;
4352 else
4353 resp->resok.info.no_trunc = FALSE;
4354
4355 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4407 vp = nfs3_fhtovp(&args->file, exi);
4408
4409 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4410 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4411
4412 if (vp == NULL) {
4413 error = ESTALE;
4414 goto out;
4415 }
4416
4417 bva.va_mask = AT_ALL;
4418 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4419
4420 /*
4421 * If we can't get the attributes, then we can't do the
4422 * right access checking. So, we'll fail the request.
4423 */
4424 if (error)
4425 goto out;
4426
4427 #ifdef DEBUG
4428 if (rfs3_do_pre_op_attr)
4429 bvap = &bva;
4430 else
4431 bvap = NULL;
4432 #else
4433 bvap = &bva;
4434 #endif
4435
4436 if (rdonly(exi, req)) {
4437 resp->status = NFS3ERR_ROFS;
4438 goto out1;
4439 }
4440
4441 if (vp->v_type != VREG) {
4442 resp->status = NFS3ERR_INVAL;
4443 goto out1;
4444 }
4445
4446 if (is_system_labeled()) {
4447 bslabel_t *clabel = req->rq_label;
4448
4449 ASSERT(clabel != NULL);
4450 DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4451 "got client label from request(1)", struct svc_req *, req);
4452
4453 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4454 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4455 exi)) {
4456 resp->status = NFS3ERR_ACCES;
4457 goto out1;
4458 }
4459 }
4460 }
4461
4462 if (crgetuid(cr) != bva.va_uid &&
4463 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4464 goto out;
4465
4466 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4467
4468 #ifdef DEBUG
4469 if (rfs3_do_post_op_attr) {
4470 ava.va_mask = AT_ALL;
4471 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4472 } else
4473 avap = NULL;
4474 #else
4475 ava.va_mask = AT_ALL;
4476 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4477 #endif
4478
4479 if (error)
4480 goto out;
4481
4482 resp->status = NFS3_OK;
4483 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4484 resp->resok.verf = write3verf;
4485
4486 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4487 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4488
4489 VN_RELE(vp);
4490
4491 return;
4492
4493 out:
4494 if (curthread->t_flag & T_WOULDBLOCK) {
4495 curthread->t_flag &= ~T_WOULDBLOCK;
4496 resp->status = NFS3ERR_JUKEBOX;
4497 } else
|
54 #include <nfs/nfs.h>
55 #include <nfs/export.h>
56 #include <nfs/nfs_cmd.h>
57
58 #include <sys/strsubr.h>
59
60 #include <sys/tsol/label.h>
61 #include <sys/tsol/tndb.h>
62
63 #include <sys/zone.h>
64
65 #include <inet/ip.h>
66 #include <inet/ip6.h>
67
68 /*
69 * These are the interface routines for the server side of the
70 * Network File System. See the NFS version 3 protocol specification
71 * for a description of this interface.
72 */
73
74 static writeverf3 write3verf;
75
76 static int sattr3_to_vattr(sattr3 *, struct vattr *);
77 static int vattr_to_fattr3(struct vattr *, fattr3 *);
78 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
79 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
80 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
81 static int rdma_setup_read_data3(READ3args *, READ3resok *);
82
83 extern int nfs_loaned_buffers;
84
85 u_longlong_t nfs3_srv_caller_id;
86
87 /* ARGSUSED */
88 void
89 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
90 struct svc_req *req, cred_t *cr)
91 {
92 int error;
93 vnode_t *vp;
204 * delegated this file. If so, then we return JUKEBOX to
205 * allow the client to retrasmit its request.
206 */
207 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
208 if (nbl_need_check(vp)) {
209 nbl_start_crit(vp, RW_READER);
210 in_crit = 1;
211 }
212 }
213
214 bva.va_mask = AT_ALL;
215 error = rfs4_delegated_getattr(vp, &bva, 0, cr);
216
217 /*
218 * If we can't get the attributes, then we can't do the
219 * right access checking. So, we'll fail the request.
220 */
221 if (error)
222 goto out;
223
224 bvap = &bva;
225
226 if (rdonly(exi, req) || vn_is_readonly(vp)) {
227 resp->status = NFS3ERR_ROFS;
228 goto out1;
229 }
230
231 if (args->guard.check &&
232 (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
233 args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
234 resp->status = NFS3ERR_NOT_SYNC;
235 goto out1;
236 }
237
238 if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
239 flag = ATTR_UTIME;
240 else
241 flag = 0;
242
243 /*
244 * If the filesystem is exported with nosuid, then mask off
294 bf.l_type = F_WRLCK;
295 bf.l_whence = 0;
296 bf.l_start = (off64_t)ava.va_size;
297 bf.l_len = 0;
298 bf.l_sysid = 0;
299 bf.l_pid = 0;
300 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
301 (offset_t)ava.va_size, cr, &ct);
302 }
303 }
304
305 if (!error && ava.va_mask)
306 error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
307
308 /* check if a monitor detected a delegation conflict */
309 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
310 resp->status = NFS3ERR_JUKEBOX;
311 goto out1;
312 }
313
314 ava.va_mask = AT_ALL;
315 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
316
317 /*
318 * Force modified metadata out to stable storage.
319 */
320 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
321
322 if (error)
323 goto out;
324
325 if (in_crit)
326 nbl_end_crit(vp);
327
328 resp->status = NFS3_OK;
329 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
330
331 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
332 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
333
334 VN_RELE(vp);
335
385 * location of the public filehandle.
386 */
387 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
388 dvp = rootdir;
389 VN_HOLD(dvp);
390
391 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
392 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
393 } else {
394 dvp = nfs3_fhtovp(&args->what.dir, exi);
395
396 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
397 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
398
399 if (dvp == NULL) {
400 error = ESTALE;
401 goto out;
402 }
403 }
404
405 dva.va_mask = AT_ALL;
406 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
407
408 if (args->what.name == nfs3nametoolong) {
409 resp->status = NFS3ERR_NAMETOOLONG;
410 goto out1;
411 }
412
413 if (args->what.name == NULL || *(args->what.name) == '\0') {
414 resp->status = NFS3ERR_ACCES;
415 goto out1;
416 }
417
418 fhp = &args->what.dir;
419 if (strcmp(args->what.name, "..") == 0 &&
420 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
421 resp->status = NFS3ERR_NOENT;
422 goto out1;
423 }
424
425 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
426 name = nfscmd_convname(ca, exi, args->what.name,
427 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
428
429 if (name == NULL) {
430 resp->status = NFS3ERR_ACCES;
431 goto out1;
432 }
433
434 exi_hold(exi);
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 struct exportinfo *new;
442
443 publicfh_flag = TRUE;
444
445 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
446 &new, &sec);
447
448 if (error == 0) {
449 exi_rele(exi);
450 exi = new;
451 }
452
453 /*
454 * Since WebNFS may bypass MOUNT, we need to ensure this
455 * request didn't come from an unlabeled admin_low client.
456 */
457 if (is_system_labeled() && error == 0) {
458 int addr_type;
459 void *ipaddr;
460 tsol_tpc_t *tp;
461
462 if (ca->sa_family == AF_INET) {
463 addr_type = IPV4_VERSION;
464 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
465 } else if (ca->sa_family == AF_INET6) {
466 addr_type = IPV6_VERSION;
467 ipaddr = &((struct sockaddr_in6 *)
468 ca)->sin6_addr;
469 }
470 tp = find_tpc(ipaddr, addr_type, B_FALSE);
471 if (tp == NULL || tp->tpc_tp.tp_doi !=
472 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
473 SUN_CIPSO) {
474 VN_RELE(vp);
475 resp->status = NFS3ERR_ACCES;
476 error = 1;
477 }
478 if (tp != NULL)
479 TPC_RELE(tp);
480 }
481 } else {
482 error = VOP_LOOKUP(dvp, name, &vp,
483 NULL, 0, NULL, cr, NULL, NULL, NULL);
484 }
485
486 if (name != args->what.name)
487 kmem_free(name, MAXPATHLEN + 1);
488
489 if (error == 0 && vn_ismntpt(vp)) {
490 error = rfs_cross_mnt(&vp, &exi);
491 if (error)
492 VN_RELE(vp);
493 }
494
495 if (is_system_labeled() && error == 0) {
496 bslabel_t *clabel = req->rq_label;
497
498 ASSERT(clabel != NULL);
499 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
500 "got client label from request(1)", struct svc_req *, req);
501
502 if (!blequal(&l_admin_low->tsl_label, clabel)) {
503 if (!do_rfs_label_check(clabel, dvp,
504 DOMINANCE_CHECK, exi)) {
505 VN_RELE(vp);
506 resp->status = NFS3ERR_ACCES;
507 error = 1;
508 }
509 }
510 }
511
512 dva.va_mask = AT_ALL;
513 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
514
515 if (error)
516 goto out;
517
518 if (sec.sec_flags & SEC_QUERY) {
519 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
520 } else {
521 error = makefh3(&resp->resok.object, vp, exi);
522 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
523 auth_weak = TRUE;
524 }
525
526 if (error) {
527 VN_RELE(vp);
528 goto out;
529 }
530
531 va.va_mask = AT_ALL;
532 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
533
534 exi_rele(exi);
535 VN_RELE(vp);
536
537 resp->status = NFS3_OK;
538 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
539 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
540
541 /*
542 * If it's public fh, no 0x81, and client's flavor is
543 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
544 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
545 */
546 if (auth_weak)
547 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
548
549 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
550 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
551 VN_RELE(dvp);
552
553 return;
554
555 out:
556 /*
557 * The passed argument exportinfo is released by the
558 * caller, common_dispatch
559 */
560 exi_rele(exi);
561
562 if (curthread->t_flag & T_WOULDBLOCK) {
563 curthread->t_flag &= ~T_WOULDBLOCK;
564 resp->status = NFS3ERR_JUKEBOX;
565 } else
566 resp->status = puterrno3(error);
567 out1:
568 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
569 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
570
571 if (dvp != NULL)
572 VN_RELE(dvp);
573 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
574
575 }
576
577 void *
578 rfs3_lookup_getfh(LOOKUP3args *args)
579 {
580
581 return (&args->what.dir);
612 * to check write permissions for regular files and directories.
613 * Special files are interpreted by the client, so the underlying
614 * permissions are sent back to the client for interpretation.
615 */
616 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
617 checkwriteperm = 0;
618 else
619 checkwriteperm = 1;
620
621 /*
622 * We need the mode so that we can correctly determine access
623 * permissions relative to a mandatory lock file. Access to
624 * mandatory lock files is denied on the server, so it might
625 * as well be reflected to the server during the open.
626 */
627 va.va_mask = AT_MODE;
628 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
629 if (error)
630 goto out;
631
632 vap = &va;
633
634 resp->resok.access = 0;
635
636 if (is_system_labeled()) {
637 bslabel_t *clabel = req->rq_label;
638
639 ASSERT(clabel != NULL);
640 DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
641 "got client label from request(1)", struct svc_req *, req);
642
643 if (!blequal(&l_admin_low->tsl_label, clabel)) {
644 if ((equal_label = do_rfs_label_check(clabel, vp,
645 EQUALITY_CHECK, exi)) == B_FALSE) {
646 dominant_label = do_rfs_label_check(clabel,
647 vp, DOMINANCE_CHECK, exi);
648 } else
649 dominant_label = B_TRUE;
650 admin_low_client = B_FALSE;
651 } else
652 admin_low_client = B_TRUE;
687 (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
688 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
689 if (error) {
690 if (curthread->t_flag & T_WOULDBLOCK)
691 goto out;
692 } else if (!is_system_labeled() || admin_low_client ||
693 equal_label)
694 resp->resok.access |= ACCESS3_DELETE;
695 }
696 if (args->access & ACCESS3_EXECUTE) {
697 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
698 if (error) {
699 if (curthread->t_flag & T_WOULDBLOCK)
700 goto out;
701 } else if (!MANDLOCK(vp, va.va_mode) &&
702 (!is_system_labeled() || admin_low_client ||
703 dominant_label))
704 resp->resok.access |= ACCESS3_EXECUTE;
705 }
706
707 va.va_mask = AT_ALL;
708 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
709
710 resp->status = NFS3_OK;
711 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
712
713 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
714 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
715
716 VN_RELE(vp);
717
718 return;
719
720 out:
721 if (curthread->t_flag & T_WOULDBLOCK) {
722 curthread->t_flag &= ~T_WOULDBLOCK;
723 resp->status = NFS3ERR_JUKEBOX;
724 } else
725 resp->status = puterrno3(error);
726 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
727 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
728 if (vp != NULL)
753 char *name = NULL;
754 int is_referral = 0;
755
756 vap = NULL;
757
758 vp = nfs3_fhtovp(&args->symlink, exi);
759
760 DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
761 cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
762
763 if (vp == NULL) {
764 error = ESTALE;
765 goto out;
766 }
767
768 va.va_mask = AT_ALL;
769 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
770 if (error)
771 goto out;
772
773 vap = &va;
774
775 /* We lied about the object type for a referral */
776 if (vn_is_nfs_reparse(vp, cr))
777 is_referral = 1;
778
779 if (vp->v_type != VLNK && !is_referral) {
780 resp->status = NFS3ERR_INVAL;
781 goto out1;
782 }
783
784 if (MANDLOCK(vp, va.va_mode)) {
785 resp->status = NFS3ERR_ACCES;
786 goto out1;
787 }
788
789 if (is_system_labeled()) {
790 bslabel_t *clabel = req->rq_label;
791
792 ASSERT(clabel != NULL);
793 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
821 kmem_free(s, strsz);
822 }
823
824 } else {
825
826 iov.iov_base = data;
827 iov.iov_len = MAXPATHLEN;
828 uio.uio_iov = &iov;
829 uio.uio_iovcnt = 1;
830 uio.uio_segflg = UIO_SYSSPACE;
831 uio.uio_extflg = UIO_COPY_CACHED;
832 uio.uio_loffset = 0;
833 uio.uio_resid = MAXPATHLEN;
834
835 error = VOP_READLINK(vp, &uio, cr, NULL);
836
837 if (!error)
838 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
839 }
840
841 va.va_mask = AT_ALL;
842 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
843
844 /* Lie about object type again just to be consistent */
845 if (is_referral && vap != NULL)
846 vap->va_type = VLNK;
847
848 #if 0 /* notyet */
849 /*
850 * Don't do this. It causes local disk writes when just
851 * reading the file and the overhead is deemed larger
852 * than the benefit.
853 */
854 /*
855 * Force modified metadata out to stable storage.
856 */
857 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
858 #endif
859
860 if (error) {
861 kmem_free(data, MAXPATHLEN + 1);
862 goto out;
863 }
1002 error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1003
1004 /* check if a monitor detected a delegation conflict */
1005 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1006 resp->status = NFS3ERR_JUKEBOX;
1007 goto out1;
1008 }
1009
1010 need_rwunlock = 1;
1011
1012 va.va_mask = AT_ALL;
1013 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1014
1015 /*
1016 * If we can't get the attributes, then we can't do the
1017 * right access checking. So, we'll fail the request.
1018 */
1019 if (error)
1020 goto out;
1021
1022 vap = &va;
1023
1024 if (vp->v_type != VREG) {
1025 resp->status = NFS3ERR_INVAL;
1026 goto out1;
1027 }
1028
1029 if (crgetuid(cr) != va.va_uid) {
1030 error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
1031 if (error) {
1032 if (curthread->t_flag & T_WOULDBLOCK)
1033 goto out;
1034 error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
1035 if (error)
1036 goto out;
1037 }
1038 }
1039
1040 if (MANDLOCK(vp, va.va_mode)) {
1041 resp->status = NFS3ERR_ACCES;
1042 goto out1;
1152 if (error) {
1153 if (mp)
1154 freemsg(mp);
1155 /* check if a monitor detected a delegation conflict */
1156 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1157 resp->status = NFS3ERR_JUKEBOX;
1158 goto out1;
1159 }
1160 goto out;
1161 }
1162
1163 /* make mblk using zc buffers */
1164 if (loaned_buffers) {
1165 mp = uio_to_mblk(uiop);
1166 ASSERT(mp != NULL);
1167 }
1168
1169 va.va_mask = AT_ALL;
1170 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1171
1172 if (error)
1173 vap = NULL;
1174 else
1175 vap = &va;
1176
1177 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1178
1179 if (in_crit)
1180 nbl_end_crit(vp);
1181
1182 resp->status = NFS3_OK;
1183 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1184 resp->resok.count = args->count - uiop->uio_resid;
1185 if (!error && offset + resp->resok.count == va.va_size)
1186 resp->resok.eof = TRUE;
1187 else
1188 resp->resok.eof = FALSE;
1189 resp->resok.data.data_len = resp->resok.count;
1190
1191 if (mp)
1192 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1193
1194 resp->resok.data.mp = mp;
1195 resp->resok.size = (uint_t)args->count;
1329
1330 /* check if a monitor detected a delegation conflict */
1331 if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1332 resp->status = NFS3ERR_JUKEBOX;
1333 rwlock_ret = -1;
1334 goto err1;
1335 }
1336
1337
1338 bva.va_mask = AT_ALL;
1339 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1340
1341 /*
1342 * If we can't get the attributes, then we can't do the
1343 * right access checking. So, we'll fail the request.
1344 */
1345 if (error)
1346 goto err;
1347
1348 bvap = &bva;
1349 avap = bvap;
1350
1351 if (args->count != args->data.data_len) {
1352 resp->status = NFS3ERR_INVAL;
1353 goto err1;
1354 }
1355
1356 if (rdonly(exi, req)) {
1357 resp->status = NFS3ERR_ROFS;
1358 goto err1;
1359 }
1360
1361 if (vp->v_type != VREG) {
1362 resp->status = NFS3ERR_INVAL;
1363 goto err1;
1364 }
1365
1366 if (crgetuid(cr) != bva.va_uid &&
1367 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1368 goto err;
1440 * the cred of the current thread to be used if quota
1441 * checking is enabled.
1442 */
1443 savecred = curthread->t_cred;
1444 curthread->t_cred = cr;
1445 error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1446 curthread->t_cred = savecred;
1447
1448 if (iovp != iov)
1449 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1450
1451 /* check if a monitor detected a delegation conflict */
1452 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1453 resp->status = NFS3ERR_JUKEBOX;
1454 goto err1;
1455 }
1456
1457 ava.va_mask = AT_ALL;
1458 avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1459
1460 if (error)
1461 goto err;
1462
1463 /*
1464 * If we were unable to get the V_WRITELOCK_TRUE, then we
1465 * may not have accurate after attrs, so check if
1466 * we have both attributes, they have a non-zero va_seq, and
1467 * va_seq has changed by exactly one,
1468 * if not, turn off the before attr.
1469 */
1470 if (rwlock_ret != V_WRITELOCK_TRUE) {
1471 if (bvap == NULL || avap == NULL ||
1472 bvap->va_seq == 0 || avap->va_seq == 0 ||
1473 avap->va_seq != (bvap->va_seq + 1)) {
1474 bvap = NULL;
1475 }
1476 }
1477
1478 resp->status = NFS3_OK;
1479 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1528 enum vcexcl excl;
1529 nfstime3 *mtime;
1530 len_t reqsize;
1531 bool_t trunc;
1532 struct sockaddr *ca;
1533 char *name = NULL;
1534
1535 dbvap = NULL;
1536 davap = NULL;
1537
1538 dvp = nfs3_fhtovp(&args->where.dir, exi);
1539
1540 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1541 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1542
1543 if (dvp == NULL) {
1544 error = ESTALE;
1545 goto out;
1546 }
1547
1548 dbva.va_mask = AT_ALL;
1549 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1550 davap = dbvap;
1551
1552 if (args->where.name == nfs3nametoolong) {
1553 resp->status = NFS3ERR_NAMETOOLONG;
1554 goto out1;
1555 }
1556
1557 if (args->where.name == NULL || *(args->where.name) == '\0') {
1558 resp->status = NFS3ERR_ACCES;
1559 goto out1;
1560 }
1561
1562 if (rdonly(exi, req)) {
1563 resp->status = NFS3ERR_ROFS;
1564 goto out1;
1565 }
1566
1567 if (is_system_labeled()) {
1568 bslabel_t *clabel = req->rq_label;
1569
1692 goto out1;
1693 }
1694
1695 /*
1696 * If the filesystem is exported with nosuid, then mask off
1697 * the setuid and setgid bits.
1698 */
1699 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1700 va.va_mode &= ~(VSUID | VSGID);
1701
1702 tryagain:
1703 /*
1704 * The file open mode used is VWRITE. If the client needs
1705 * some other semantic, then it should do the access checking
1706 * itself. It would have been nice to have the file open mode
1707 * passed as part of the arguments.
1708 */
1709 error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1710 &vp, cr, 0, NULL, NULL);
1711
1712 dava.va_mask = AT_ALL;
1713 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1714
1715 if (error) {
1716 /*
1717 * If we got something other than file already exists
1718 * then just return this error. Otherwise, we got
1719 * EEXIST. If we were doing a GUARDED create, then
1720 * just return this error. Otherwise, we need to
1721 * make sure that this wasn't a duplicate of an
1722 * exclusive create request.
1723 *
1724 * The assumption is made that a non-exclusive create
1725 * request will never return EEXIST.
1726 */
1727 if (error != EEXIST || args->how.mode == GUARDED)
1728 goto out;
1729 /*
1730 * Lookup the file so that we can get a vnode for it.
1731 */
1732 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1733 NULL, cr, NULL, NULL, NULL);
1797 * still recover by checking the size of the file
1798 * after it has created it and then issue a setattr
1799 * request of its own to set the size of the file.
1800 */
1801 if (vap != NULL &&
1802 (args->how.mode == UNCHECKED ||
1803 args->how.mode == GUARDED) &&
1804 args->how.createhow3_u.obj_attributes.size.set_it &&
1805 vap->va_size != reqsize) {
1806 va.va_mask = AT_SIZE;
1807 va.va_size = reqsize;
1808 (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1809 va.va_mask = AT_ALL;
1810 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1811 }
1812 }
1813
1814 if (name != args->where.name)
1815 kmem_free(name, MAXPATHLEN + 1);
1816
1817 error = makefh3(&resp->resok.obj.handle, vp, exi);
1818 if (error)
1819 resp->resok.obj.handle_follows = FALSE;
1820 else
1821 resp->resok.obj.handle_follows = TRUE;
1822
1823 /*
1824 * Force modified data and metadata out to stable storage.
1825 */
1826 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1827 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1828
1829 VN_RELE(vp);
1830 if (tvp != NULL) {
1831 if (in_crit)
1832 nbl_end_crit(tvp);
1833 VN_RELE(tvp);
1834 }
1835
1836 resp->status = NFS3_OK;
1837 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1838 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1839
1840 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1841 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1885 struct vattr *dbvap;
1886 struct vattr dbva;
1887 struct vattr *davap;
1888 struct vattr dava;
1889 struct sockaddr *ca;
1890 char *name = NULL;
1891
1892 dbvap = NULL;
1893 davap = NULL;
1894
1895 dvp = nfs3_fhtovp(&args->where.dir, exi);
1896
1897 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1898 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1899
1900 if (dvp == NULL) {
1901 error = ESTALE;
1902 goto out;
1903 }
1904
1905 dbva.va_mask = AT_ALL;
1906 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1907 davap = dbvap;
1908
1909 if (args->where.name == nfs3nametoolong) {
1910 resp->status = NFS3ERR_NAMETOOLONG;
1911 goto out1;
1912 }
1913
1914 if (args->where.name == NULL || *(args->where.name) == '\0') {
1915 resp->status = NFS3ERR_ACCES;
1916 goto out1;
1917 }
1918
1919 if (rdonly(exi, req)) {
1920 resp->status = NFS3ERR_ROFS;
1921 goto out1;
1922 }
1923
1924 if (is_system_labeled()) {
1925 bslabel_t *clabel = req->rq_label;
1926
1946 goto out1;
1947 }
1948
1949 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1950 name = nfscmd_convname(ca, exi, args->where.name,
1951 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1952
1953 if (name == NULL) {
1954 resp->status = NFS3ERR_INVAL;
1955 goto out1;
1956 }
1957
1958 va.va_mask |= AT_TYPE;
1959 va.va_type = VDIR;
1960
1961 error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
1962
1963 if (name != args->where.name)
1964 kmem_free(name, MAXPATHLEN + 1);
1965
1966 dava.va_mask = AT_ALL;
1967 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1968
1969 /*
1970 * Force modified data and metadata out to stable storage.
1971 */
1972 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1973
1974 if (error)
1975 goto out;
1976
1977 error = makefh3(&resp->resok.obj.handle, vp, exi);
1978 if (error)
1979 resp->resok.obj.handle_follows = FALSE;
1980 else
1981 resp->resok.obj.handle_follows = TRUE;
1982
1983 va.va_mask = AT_ALL;
1984 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1985
1986 /*
1987 * Force modified data and metadata out to stable storage.
1988 */
1989 (void) VOP_FSYNC(vp, 0, cr, NULL);
1990
1991 VN_RELE(vp);
1992
1993 resp->status = NFS3_OK;
1994 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1995 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1996
1997 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
1998 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
1999 VN_RELE(dvp);
2000
2001 return;
2002
2003 out:
2004 if (curthread->t_flag & T_WOULDBLOCK) {
2034 struct vattr dbva;
2035 struct vattr *davap;
2036 struct vattr dava;
2037 struct sockaddr *ca;
2038 char *name = NULL;
2039 char *symdata = NULL;
2040
2041 dbvap = NULL;
2042 davap = NULL;
2043
2044 dvp = nfs3_fhtovp(&args->where.dir, exi);
2045
2046 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2047 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2048
2049 if (dvp == NULL) {
2050 error = ESTALE;
2051 goto err;
2052 }
2053
2054 dbva.va_mask = AT_ALL;
2055 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2056 davap = dbvap;
2057
2058 if (args->where.name == nfs3nametoolong) {
2059 resp->status = NFS3ERR_NAMETOOLONG;
2060 goto err1;
2061 }
2062
2063 if (args->where.name == NULL || *(args->where.name) == '\0') {
2064 resp->status = NFS3ERR_ACCES;
2065 goto err1;
2066 }
2067
2068 if (rdonly(exi, req)) {
2069 resp->status = NFS3ERR_ROFS;
2070 goto err1;
2071 }
2072
2073 if (is_system_labeled()) {
2074 bslabel_t *clabel = req->rq_label;
2075
2107 if (name == NULL) {
2108 /* This is really a Solaris EILSEQ */
2109 resp->status = NFS3ERR_INVAL;
2110 goto err1;
2111 }
2112
2113 symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2114 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2115 if (symdata == NULL) {
2116 /* This is really a Solaris EILSEQ */
2117 resp->status = NFS3ERR_INVAL;
2118 goto err1;
2119 }
2120
2121
2122 va.va_mask |= AT_TYPE;
2123 va.va_type = VLNK;
2124
2125 error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2126
2127 dava.va_mask = AT_ALL;
2128 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2129
2130 if (error)
2131 goto err;
2132
2133 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2134 NULL, NULL, NULL);
2135
2136 /*
2137 * Force modified data and metadata out to stable storage.
2138 */
2139 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2140
2141
2142 resp->status = NFS3_OK;
2143 if (error) {
2144 resp->resok.obj.handle_follows = FALSE;
2145 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2146 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2147 goto out;
2148 }
2149
2150 error = makefh3(&resp->resok.obj.handle, vp, exi);
2151 if (error)
2152 resp->resok.obj.handle_follows = FALSE;
2153 else
2154 resp->resok.obj.handle_follows = TRUE;
2155
2156 va.va_mask = AT_ALL;
2157 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2158
2159 /*
2160 * Force modified data and metadata out to stable storage.
2161 */
2162 (void) VOP_FSYNC(vp, 0, cr, NULL);
2163
2164 VN_RELE(vp);
2165
2166 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2167 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2168 goto out;
2169
2170 err:
2171 if (curthread->t_flag & T_WOULDBLOCK) {
2172 curthread->t_flag &= ~T_WOULDBLOCK;
2173 resp->status = NFS3ERR_JUKEBOX;
2174 } else
2175 resp->status = puterrno3(error);
2176 err1:
2177 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2210 struct vattr *davap;
2211 struct vattr dava;
2212 int mode;
2213 enum vcexcl excl;
2214 struct sockaddr *ca;
2215 char *name = NULL;
2216
2217 dbvap = NULL;
2218 davap = NULL;
2219
2220 dvp = nfs3_fhtovp(&args->where.dir, exi);
2221
2222 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2223 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2224
2225 if (dvp == NULL) {
2226 error = ESTALE;
2227 goto out;
2228 }
2229
2230 dbva.va_mask = AT_ALL;
2231 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2232 davap = dbvap;
2233
2234 if (args->where.name == nfs3nametoolong) {
2235 resp->status = NFS3ERR_NAMETOOLONG;
2236 goto out1;
2237 }
2238
2239 if (args->where.name == NULL || *(args->where.name) == '\0') {
2240 resp->status = NFS3ERR_ACCES;
2241 goto out1;
2242 }
2243
2244 if (rdonly(exi, req)) {
2245 resp->status = NFS3ERR_ROFS;
2246 goto out1;
2247 }
2248
2249 if (is_system_labeled()) {
2250 bslabel_t *clabel = req->rq_label;
2251
2313
2314 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2315 name = nfscmd_convname(ca, exi, args->where.name,
2316 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2317
2318 if (name == NULL) {
2319 resp->status = NFS3ERR_INVAL;
2320 goto out1;
2321 }
2322
2323 excl = EXCL;
2324
2325 mode = 0;
2326
2327 error = VOP_CREATE(dvp, name, &va, excl, mode,
2328 &vp, cr, 0, NULL, NULL);
2329
2330 if (name != args->where.name)
2331 kmem_free(name, MAXPATHLEN + 1);
2332
2333 dava.va_mask = AT_ALL;
2334 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2335
2336 /*
2337 * Force modified data and metadata out to stable storage.
2338 */
2339 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2340
2341 if (error)
2342 goto out;
2343
2344 resp->status = NFS3_OK;
2345
2346 error = makefh3(&resp->resok.obj.handle, vp, exi);
2347 if (error)
2348 resp->resok.obj.handle_follows = FALSE;
2349 else
2350 resp->resok.obj.handle_follows = TRUE;
2351
2352 va.va_mask = AT_ALL;
2353 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2354
2355 /*
2356 * Force modified metadata out to stable storage.
2357 *
2358 * if a underlying vp exists, pass it to VOP_FSYNC
2359 */
2360 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2361 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2362 else
2363 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2364
2365 VN_RELE(vp);
2366
2367 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2368 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2369 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2370 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2371 VN_RELE(dvp);
2372 return;
2373
2402 struct vattr bva;
2403 struct vattr *avap;
2404 struct vattr ava;
2405 vnode_t *targvp = NULL;
2406 struct sockaddr *ca;
2407 char *name = NULL;
2408
2409 bvap = NULL;
2410 avap = NULL;
2411
2412 vp = nfs3_fhtovp(&args->object.dir, exi);
2413
2414 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2415 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2416
2417 if (vp == NULL) {
2418 error = ESTALE;
2419 goto err;
2420 }
2421
2422 bva.va_mask = AT_ALL;
2423 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2424 avap = bvap;
2425
2426 if (vp->v_type != VDIR) {
2427 resp->status = NFS3ERR_NOTDIR;
2428 goto err1;
2429 }
2430
2431 if (args->object.name == nfs3nametoolong) {
2432 resp->status = NFS3ERR_NAMETOOLONG;
2433 goto err1;
2434 }
2435
2436 if (args->object.name == NULL || *(args->object.name) == '\0') {
2437 resp->status = NFS3ERR_ACCES;
2438 goto err1;
2439 }
2440
2441 if (rdonly(exi, req)) {
2442 resp->status = NFS3ERR_ROFS;
2443 goto err1;
2479
2480 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2481 resp->status = NFS3ERR_JUKEBOX;
2482 goto err1;
2483 }
2484
2485 if (!nbl_need_check(targvp)) {
2486 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2487 } else {
2488 nbl_start_crit(targvp, RW_READER);
2489 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2490 error = EACCES;
2491 } else {
2492 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2493 }
2494 nbl_end_crit(targvp);
2495 }
2496 VN_RELE(targvp);
2497 targvp = NULL;
2498
2499 ava.va_mask = AT_ALL;
2500 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2501
2502 /*
2503 * Force modified data and metadata out to stable storage.
2504 */
2505 (void) VOP_FSYNC(vp, 0, cr, NULL);
2506
2507 if (error)
2508 goto err;
2509
2510 resp->status = NFS3_OK;
2511 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2512 goto out;
2513
2514 err:
2515 if (curthread->t_flag & T_WOULDBLOCK) {
2516 curthread->t_flag &= ~T_WOULDBLOCK;
2517 resp->status = NFS3ERR_JUKEBOX;
2518 } else
2519 resp->status = puterrno3(error);
2520 err1:
2546 struct vattr *bvap;
2547 struct vattr bva;
2548 struct vattr *avap;
2549 struct vattr ava;
2550 struct sockaddr *ca;
2551 char *name = NULL;
2552
2553 bvap = NULL;
2554 avap = NULL;
2555
2556 vp = nfs3_fhtovp(&args->object.dir, exi);
2557
2558 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2559 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2560
2561 if (vp == NULL) {
2562 error = ESTALE;
2563 goto err;
2564 }
2565
2566 bva.va_mask = AT_ALL;
2567 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2568 avap = bvap;
2569
2570 if (vp->v_type != VDIR) {
2571 resp->status = NFS3ERR_NOTDIR;
2572 goto err1;
2573 }
2574
2575 if (args->object.name == nfs3nametoolong) {
2576 resp->status = NFS3ERR_NAMETOOLONG;
2577 goto err1;
2578 }
2579
2580 if (args->object.name == NULL || *(args->object.name) == '\0') {
2581 resp->status = NFS3ERR_ACCES;
2582 goto err1;
2583 }
2584
2585 if (rdonly(exi, req)) {
2586 resp->status = NFS3ERR_ROFS;
2587 goto err1;
2600 resp->status = NFS3ERR_ACCES;
2601 goto err1;
2602 }
2603 }
2604 }
2605
2606 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2607 name = nfscmd_convname(ca, exi, args->object.name,
2608 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2609
2610 if (name == NULL) {
2611 resp->status = NFS3ERR_INVAL;
2612 goto err1;
2613 }
2614
2615 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2616
2617 if (name != args->object.name)
2618 kmem_free(name, MAXPATHLEN + 1);
2619
2620 ava.va_mask = AT_ALL;
2621 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2622
2623 /*
2624 * Force modified data and metadata out to stable storage.
2625 */
2626 (void) VOP_FSYNC(vp, 0, cr, NULL);
2627
2628 if (error) {
2629 /*
2630 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2631 * if the directory is not empty. A System V NFS server
2632 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2633 * over the wire.
2634 */
2635 if (error == EEXIST)
2636 error = ENOTEMPTY;
2637 goto err;
2638 }
2639
2640 resp->status = NFS3_OK;
2641 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2702 if (fvp == NULL) {
2703 error = ESTALE;
2704 goto err;
2705 }
2706
2707 if (is_system_labeled()) {
2708 clabel = req->rq_label;
2709 ASSERT(clabel != NULL);
2710 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2711 "got client label from request(1)", struct svc_req *, req);
2712
2713 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2714 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2715 exi)) {
2716 resp->status = NFS3ERR_ACCES;
2717 goto err1;
2718 }
2719 }
2720 }
2721
2722 fbva.va_mask = AT_ALL;
2723 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2724 favap = fbvap;
2725
2726 fh3 = &args->to.dir;
2727 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2728 if (to_exi == NULL) {
2729 resp->status = NFS3ERR_ACCES;
2730 goto err1;
2731 }
2732 exi_rele(to_exi);
2733
2734 if (to_exi != exi) {
2735 resp->status = NFS3ERR_XDEV;
2736 goto err1;
2737 }
2738
2739 tvp = nfs3_fhtovp(&args->to.dir, exi);
2740 if (tvp == NULL) {
2741 error = ESTALE;
2742 goto err;
2743 }
2744
2745 tbva.va_mask = AT_ALL;
2746 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2747 tavap = tbvap;
2748
2749 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2750 resp->status = NFS3ERR_NOTDIR;
2751 goto err1;
2752 }
2753
2754 if (args->from.name == nfs3nametoolong ||
2755 args->to.name == nfs3nametoolong) {
2756 resp->status = NFS3ERR_NAMETOOLONG;
2757 goto err1;
2758 }
2759 if (args->from.name == NULL || *(args->from.name) == '\0' ||
2760 args->to.name == NULL || *(args->to.name) == '\0') {
2761 resp->status = NFS3ERR_ACCES;
2762 goto err1;
2763 }
2764
2765 if (rdonly(exi, req)) {
2766 resp->status = NFS3ERR_ROFS;
2828 }
2829 VN_RELE(targvp);
2830 }
2831
2832 if (!nbl_need_check(srcvp)) {
2833 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2834 } else {
2835 nbl_start_crit(srcvp, RW_READER);
2836 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2837 error = EACCES;
2838 else
2839 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2840 nbl_end_crit(srcvp);
2841 }
2842 if (error == 0)
2843 vn_renamepath(tvp, srcvp, args->to.name,
2844 strlen(args->to.name));
2845 VN_RELE(srcvp);
2846 srcvp = NULL;
2847
2848 fava.va_mask = AT_ALL;
2849 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2850 tava.va_mask = AT_ALL;
2851 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2852
2853 /*
2854 * Force modified data and metadata out to stable storage.
2855 */
2856 (void) VOP_FSYNC(fvp, 0, cr, NULL);
2857 (void) VOP_FSYNC(tvp, 0, cr, NULL);
2858
2859 if (error)
2860 goto err;
2861
2862 resp->status = NFS3_OK;
2863 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
2864 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2865 goto out;
2866
2867 err:
2868 if (curthread->t_flag & T_WOULDBLOCK) {
2869 curthread->t_flag &= ~T_WOULDBLOCK;
2870 resp->status = NFS3ERR_JUKEBOX;
2871 } else {
2913 struct exportinfo *to_exi;
2914 bslabel_t *clabel;
2915 struct sockaddr *ca;
2916 char *name = NULL;
2917
2918 vap = NULL;
2919 bvap = NULL;
2920 avap = NULL;
2921 dvp = NULL;
2922
2923 vp = nfs3_fhtovp(&args->file, exi);
2924
2925 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2926 cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2927
2928 if (vp == NULL) {
2929 error = ESTALE;
2930 goto out;
2931 }
2932
2933 va.va_mask = AT_ALL;
2934 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2935
2936 fh3 = &args->link.dir;
2937 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2938 if (to_exi == NULL) {
2939 resp->status = NFS3ERR_ACCES;
2940 goto out1;
2941 }
2942 exi_rele(to_exi);
2943
2944 if (to_exi != exi) {
2945 resp->status = NFS3ERR_XDEV;
2946 goto out1;
2947 }
2948
2949 if (is_system_labeled()) {
2950 clabel = req->rq_label;
2951
2952 ASSERT(clabel != NULL);
2953 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
2954 "got client label from request(1)", struct svc_req *, req);
2955
2956 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2957 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2958 exi)) {
2959 resp->status = NFS3ERR_ACCES;
2960 goto out1;
2961 }
2962 }
2963 }
2964
2965 dvp = nfs3_fhtovp(&args->link.dir, exi);
2966 if (dvp == NULL) {
2967 error = ESTALE;
2968 goto out;
2969 }
2970
2971 bva.va_mask = AT_ALL;
2972 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
2973
2974 if (dvp->v_type != VDIR) {
2975 resp->status = NFS3ERR_NOTDIR;
2976 goto out1;
2977 }
2978
2979 if (args->link.name == nfs3nametoolong) {
2980 resp->status = NFS3ERR_NAMETOOLONG;
2981 goto out1;
2982 }
2983
2984 if (args->link.name == NULL || *(args->link.name) == '\0') {
2985 resp->status = NFS3ERR_ACCES;
2986 goto out1;
2987 }
2988
2989 if (rdonly(exi, req)) {
2990 resp->status = NFS3ERR_ROFS;
2991 goto out1;
2992 }
2998 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2999 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3000 exi)) {
3001 resp->status = NFS3ERR_ACCES;
3002 goto out1;
3003 }
3004 }
3005 }
3006
3007 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3008 name = nfscmd_convname(ca, exi, args->link.name,
3009 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3010
3011 if (name == NULL) {
3012 resp->status = NFS3ERR_SERVERFAULT;
3013 goto out1;
3014 }
3015
3016 error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3017
3018 va.va_mask = AT_ALL;
3019 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3020 ava.va_mask = AT_ALL;
3021 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3022
3023 /*
3024 * Force modified data and metadata out to stable storage.
3025 */
3026 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3027 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3028
3029 if (error)
3030 goto out;
3031
3032 VN_RELE(dvp);
3033
3034 resp->status = NFS3_OK;
3035 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3036 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3037
3038 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3039 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3040
3041 VN_RELE(vp);
3130 }
3131
3132 if (is_system_labeled()) {
3133 bslabel_t *clabel = req->rq_label;
3134
3135 ASSERT(clabel != NULL);
3136 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3137 "got client label from request(1)", struct svc_req *, req);
3138
3139 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3140 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3141 exi)) {
3142 resp->status = NFS3ERR_ACCES;
3143 goto out1;
3144 }
3145 }
3146 }
3147
3148 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3149
3150 va.va_mask = AT_ALL;
3151 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3152
3153 if (vp->v_type != VDIR) {
3154 resp->status = NFS3ERR_NOTDIR;
3155 goto out1;
3156 }
3157
3158 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3159 if (error)
3160 goto out;
3161
3162 /*
3163 * Now don't allow arbitrary count to alloc;
3164 * allow the maximum not to exceed rfs3_tsize()
3165 */
3166 if (args->count > rfs3_tsize(req))
3167 args->count = rfs3_tsize(req);
3168
3169 /*
3170 * Make sure that there is room to read at least one entry
3171 * if any are available.
3172 */
3173 if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3174 count = DIRENT64_RECLEN(MAXNAMELEN);
3175 else
3176 count = args->count;
3177
3178 data = kmem_alloc(count, KM_SLEEP);
3179
3180 iov.iov_base = data;
3181 iov.iov_len = count;
3182 uio.uio_iov = &iov;
3183 uio.uio_iovcnt = 1;
3184 uio.uio_segflg = UIO_SYSSPACE;
3185 uio.uio_extflg = UIO_COPY_CACHED;
3186 uio.uio_loffset = (offset_t)args->cookie;
3187 uio.uio_resid = count;
3188
3189 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3190
3191 va.va_mask = AT_ALL;
3192 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3193
3194 if (error) {
3195 kmem_free(data, count);
3196 goto out;
3197 }
3198
3199 /*
3200 * If the count was not large enough to be able to guarantee
3201 * to be able to return at least one entry, then need to
3202 * check to see if NFS3ERR_TOOSMALL should be returned.
3203 */
3204 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3205 /*
3206 * bufsize is used to keep track of the size of the response.
3207 * It is primed with:
3208 * 1 for the status +
3209 * 1 for the dir_attributes.attributes boolean +
3210 * 2 for the cookie verifier
3211 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3212 * to bytes. If there are directory attributes to be
3402
3403 if (is_system_labeled()) {
3404 bslabel_t *clabel = req->rq_label;
3405
3406 ASSERT(clabel != NULL);
3407 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3408 char *, "got client label from request(1)",
3409 struct svc_req *, req);
3410
3411 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3412 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3413 exi)) {
3414 resp->status = NFS3ERR_ACCES;
3415 goto out1;
3416 }
3417 }
3418 }
3419
3420 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3421
3422 va.va_mask = AT_ALL;
3423 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3424
3425 if (vp->v_type != VDIR) {
3426 error = ENOTDIR;
3427 goto out;
3428 }
3429
3430 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3431 if (error)
3432 goto out;
3433
3434 /*
3435 * Don't allow arbitrary counts for allocation
3436 */
3437 if (args->maxcount > rfs3_tsize(req))
3438 args->maxcount = rfs3_tsize(req);
3439
3440 /*
3441 * Make sure that there is room to read at least one entry
3442 * if any are available
3443 */
3562 iseof = FALSE;
3563 goto good;
3564 }
3565 bufsize += entrysize;
3566 nents++;
3567 }
3568
3569 /*
3570 * If there is enough room to fit at least 1 more entry including
3571 * post op attributes and filehandle in the buffer AND that we haven't
3572 * exceeded dircount then go back and get some more.
3573 */
3574 if (!iseof &&
3575 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3576 space_left -= (prev_len - uio.uio_resid);
3577 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3578 goto getmoredents;
3579
3580 /* else, fall through */
3581 }
3582 good:
3583 va.va_mask = AT_ALL;
3584 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3585
3586 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3587
3588 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3589 resp->resok.infop = infop;
3590
3591 dp = (struct dirent64 *)data;
3592 for (i = 0; i < nents; i++) {
3593
3594 if (dp->d_ino == 0) {
3595 infop[i].attr.attributes = FALSE;
3596 infop[i].fh.handle_follows = FALSE;
3597 dp = nextdp(dp);
3598 continue;
3599 }
3600
3601 infop[i].namelen = namlen[i];
3602
3603 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3604 NULL, NULL, NULL);
3605 if (error) {
3606 infop[i].attr.attributes = FALSE;
3607 infop[i].fh.handle_follows = FALSE;
3608 dp = nextdp(dp);
3609 continue;
3610 }
3611
3612 nva.va_mask = AT_ALL;
3613 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3614
3615 /* Lie about the object type for a referral */
3616 if (vn_is_nfs_reparse(nvp, cr))
3617 nvap->va_type = VLNK;
3618
3619 if (vn_ismntpt(nvp)) {
3620 infop[i].attr.attributes = FALSE;
3621 infop[i].fh.handle_follows = FALSE;
3622 } else {
3623 vattr_to_post_op_attr(nvap, &infop[i].attr);
3624
3625 error = makefh3(&infop[i].fh.handle, nvp, exi);
3626 if (!error)
3627 infop[i].fh.handle_follows = TRUE;
3628 else
3629 infop[i].fh.handle_follows = FALSE;
3630 }
3631
3632 VN_RELE(nvp);
3633 dp = nextdp(dp);
3634 }
3635
3636 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3637 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3638 if (ndata == NULL)
3639 ndata = data;
3640
3641 if (ret > 0) {
3642 /*
3643 * We had to drop one or more entries in order to fit
3644 * during the character conversion. We need to patch
3645 * up the size and eof info.
3646 */
3647 if (iseof)
3648 iseof = FALSE;
3649
3650 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3749 }
3750
3751 if (is_system_labeled()) {
3752 bslabel_t *clabel = req->rq_label;
3753
3754 ASSERT(clabel != NULL);
3755 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3756 "got client label from request(1)", struct svc_req *, req);
3757
3758 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3759 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3760 exi)) {
3761 resp->status = NFS3ERR_ACCES;
3762 goto out1;
3763 }
3764 }
3765 }
3766
3767 error = VFS_STATVFS(vp->v_vfsp, &sb);
3768
3769 va.va_mask = AT_ALL;
3770 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3771
3772 if (error)
3773 goto out;
3774
3775 resp->status = NFS3_OK;
3776 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3777 if (sb.f_blocks != (fsblkcnt64_t)-1)
3778 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3779 else
3780 resp->resok.tbytes = (size3)sb.f_blocks;
3781 if (sb.f_bfree != (fsblkcnt64_t)-1)
3782 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3783 else
3784 resp->resok.fbytes = (size3)sb.f_bfree;
3785 if (sb.f_bavail != (fsblkcnt64_t)-1)
3786 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3787 else
3788 resp->resok.abytes = (size3)sb.f_bavail;
3789 resp->resok.tfiles = (size3)sb.f_files;
3790 resp->resok.ffiles = (size3)sb.f_ffree;
3846 }
3847
3848 if (is_system_labeled()) {
3849 bslabel_t *clabel = req->rq_label;
3850
3851 ASSERT(clabel != NULL);
3852 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3853 "got client label from request(1)", struct svc_req *, req);
3854
3855 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3856 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3857 exi)) {
3858 resp->status = NFS3ERR_STALE;
3859 vattr_to_post_op_attr(NULL,
3860 &resp->resfail.obj_attributes);
3861 goto out;
3862 }
3863 }
3864 }
3865
3866 va.va_mask = AT_ALL;
3867 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3868
3869 resp->status = NFS3_OK;
3870 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3871 xfer_size = rfs3_tsize(req);
3872 resp->resok.rtmax = xfer_size;
3873 resp->resok.rtpref = xfer_size;
3874 resp->resok.rtmult = DEV_BSIZE;
3875 resp->resok.wtmax = xfer_size;
3876 resp->resok.wtpref = xfer_size;
3877 resp->resok.wtmult = DEV_BSIZE;
3878 resp->resok.dtpref = MAXBSIZE;
3879
3880 /*
3881 * Large file spec: want maxfilesize based on limit of
3882 * underlying filesystem. We can guess 2^31-1 if need be.
3883 */
3884 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3885 if (error) {
3886 resp->status = puterrno3(error);
3887 goto out;
3950 error = ESTALE;
3951 goto out;
3952 }
3953
3954 if (is_system_labeled()) {
3955 bslabel_t *clabel = req->rq_label;
3956
3957 ASSERT(clabel != NULL);
3958 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3959 "got client label from request(1)", struct svc_req *, req);
3960
3961 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3962 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3963 exi)) {
3964 resp->status = NFS3ERR_ACCES;
3965 goto out1;
3966 }
3967 }
3968 }
3969
3970 va.va_mask = AT_ALL;
3971 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3972
3973 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
3974 if (error)
3975 goto out;
3976 resp->resok.info.link_max = (uint32)val;
3977
3978 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
3979 if (error)
3980 goto out;
3981 resp->resok.info.name_max = (uint32)val;
3982
3983 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3984 if (error)
3985 goto out;
3986 if (val == 1)
3987 resp->resok.info.no_trunc = TRUE;
3988 else
3989 resp->resok.info.no_trunc = FALSE;
3990
3991 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4043 vp = nfs3_fhtovp(&args->file, exi);
4044
4045 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4046 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4047
4048 if (vp == NULL) {
4049 error = ESTALE;
4050 goto out;
4051 }
4052
4053 bva.va_mask = AT_ALL;
4054 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4055
4056 /*
4057 * If we can't get the attributes, then we can't do the
4058 * right access checking. So, we'll fail the request.
4059 */
4060 if (error)
4061 goto out;
4062
4063 bvap = &bva;
4064
4065 if (rdonly(exi, req)) {
4066 resp->status = NFS3ERR_ROFS;
4067 goto out1;
4068 }
4069
4070 if (vp->v_type != VREG) {
4071 resp->status = NFS3ERR_INVAL;
4072 goto out1;
4073 }
4074
4075 if (is_system_labeled()) {
4076 bslabel_t *clabel = req->rq_label;
4077
4078 ASSERT(clabel != NULL);
4079 DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4080 "got client label from request(1)", struct svc_req *, req);
4081
4082 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4083 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4084 exi)) {
4085 resp->status = NFS3ERR_ACCES;
4086 goto out1;
4087 }
4088 }
4089 }
4090
4091 if (crgetuid(cr) != bva.va_uid &&
4092 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4093 goto out;
4094
4095 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4096
4097 ava.va_mask = AT_ALL;
4098 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4099
4100 if (error)
4101 goto out;
4102
4103 resp->status = NFS3_OK;
4104 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4105 resp->resok.verf = write3verf;
4106
4107 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4108 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4109
4110 VN_RELE(vp);
4111
4112 return;
4113
4114 out:
4115 if (curthread->t_flag & T_WOULDBLOCK) {
4116 curthread->t_flag &= ~T_WOULDBLOCK;
4117 resp->status = NFS3ERR_JUKEBOX;
4118 } else
|