1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/cred.h>
35 #include <sys/buf.h>
36 #include <sys/vfs.h>
37 #include <sys/vnode.h>
38 #include <sys/uio.h>
39 #include <sys/errno.h>
40 #include <sys/sysmacros.h>
41 #include <sys/statvfs.h>
42 #include <sys/kmem.h>
43 #include <sys/dirent.h>
44 #include <sys/cmn_err.h>
45 #include <sys/debug.h>
46 #include <sys/systeminfo.h>
47 #include <sys/flock.h>
48 #include <sys/nbmlock.h>
49 #include <sys/policy.h>
50 #include <sys/sdt.h>
51
52 #include <rpc/types.h>
53 #include <rpc/auth.h>
54 #include <rpc/svc.h>
55 #include <rpc/rpc_rdma.h>
56
57 #include <nfs/nfs.h>
58 #include <nfs/export.h>
59 #include <nfs/nfs_cmd.h>
60
61 #include <sys/strsubr.h>
62 #include <sys/tsol/label.h>
63 #include <sys/tsol/tndb.h>
64
65 #include <sys/zone.h>
66
67 #include <inet/ip.h>
68 #include <inet/ip6.h>
69
70 /*
71 * These are the interface routines for the server side of the
72 * Network File System. See the NFS version 3 protocol specification
73 * for a description of this interface.
74 */
75
76 static writeverf3 write3verf;
77
78 static int sattr3_to_vattr(sattr3 *, struct vattr *);
79 static int vattr_to_fattr3(struct vattr *, fattr3 *);
80 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
81 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
82 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
83 static int rdma_setup_read_data3(READ3args *, READ3resok *);
84
85 extern int nfs_loaned_buffers;
86
87 u_longlong_t nfs3_srv_caller_id;
88
89 /* ARGSUSED */
90 void
91 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
92 struct svc_req *req, cred_t *cr, bool_t ro)
93 {
94 int error;
95 vnode_t *vp;
96 struct vattr va;
97
98 vp = nfs3_fhtovp(&args->object, exi);
99
100 DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
101 cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
102
103 if (vp == NULL) {
104 error = ESTALE;
105 goto out;
106 }
107
108 va.va_mask = AT_ALL;
109 error = rfs4_delegated_getattr(vp, &va, 0, cr);
110
111 if (!error) {
112 /* Lie about the object type for a referral */
113 if (vn_is_nfs_reparse(vp, cr))
114 va.va_type = VLNK;
115
116 /* overflow error if time or size is out of range */
117 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
118 if (error)
119 goto out;
120 resp->status = NFS3_OK;
121
122 DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
123 cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
124
125 VN_RELE(vp);
126
127 return;
128 }
129
130 out:
131 if (curthread->t_flag & T_WOULDBLOCK) {
132 curthread->t_flag &= ~T_WOULDBLOCK;
133 resp->status = NFS3ERR_JUKEBOX;
134 } else
135 resp->status = puterrno3(error);
136
137 DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
138 cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
139
140 if (vp != NULL)
141 VN_RELE(vp);
142 }
143
144 void *
145 rfs3_getattr_getfh(GETATTR3args *args)
146 {
147
148 return (&args->object);
149 }
150
151 void
152 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
153 struct svc_req *req, cred_t *cr, bool_t ro)
154 {
155 int error;
156 vnode_t *vp;
157 struct vattr *bvap;
158 struct vattr bva;
159 struct vattr *avap;
160 struct vattr ava;
161 int flag;
162 int in_crit = 0;
163 struct flock64 bf;
164 caller_context_t ct;
165
166 bvap = NULL;
167 avap = NULL;
168
169 vp = nfs3_fhtovp(&args->object, exi);
170
171 DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
172 cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
173
174 if (vp == NULL) {
175 error = ESTALE;
176 goto out;
177 }
178
179 error = sattr3_to_vattr(&args->new_attributes, &ava);
180 if (error)
181 goto out;
182
183 if (is_system_labeled()) {
184 bslabel_t *clabel = req->rq_label;
185
186 ASSERT(clabel != NULL);
187 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
188 "got client label from request(1)", struct svc_req *, req);
189
190 if (!blequal(&l_admin_low->tsl_label, clabel)) {
191 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
192 exi)) {
193 resp->status = NFS3ERR_ACCES;
194 goto out1;
195 }
196 }
197 }
198
199 /*
200 * We need to specially handle size changes because of
201 * possible conflicting NBMAND locks. Get into critical
202 * region before VOP_GETATTR, so the size attribute is
203 * valid when checking conflicts.
204 *
205 * Also, check to see if the v4 side of the server has
206 * delegated this file. If so, then we return JUKEBOX to
207 * allow the client to retrasmit its request.
208 */
209 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
210 if (nbl_need_check(vp)) {
211 nbl_start_crit(vp, RW_READER);
212 in_crit = 1;
213 }
214 }
215
216 bva.va_mask = AT_ALL;
217 error = rfs4_delegated_getattr(vp, &bva, 0, cr);
218
219 /*
220 * If we can't get the attributes, then we can't do the
221 * right access checking. So, we'll fail the request.
222 */
223 if (error)
224 goto out;
225
226 bvap = &bva;
227
228 if (rdonly(ro, vp)) {
229 resp->status = NFS3ERR_ROFS;
230 goto out1;
231 }
232
233 if (args->guard.check &&
234 (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
235 args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
236 resp->status = NFS3ERR_NOT_SYNC;
237 goto out1;
238 }
239
240 if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
241 flag = ATTR_UTIME;
242 else
243 flag = 0;
244
245 /*
246 * If the filesystem is exported with nosuid, then mask off
247 * the setuid and setgid bits.
248 */
249 if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
250 (exi->exi_export.ex_flags & EX_NOSUID))
251 ava.va_mode &= ~(VSUID | VSGID);
252
253 ct.cc_sysid = 0;
254 ct.cc_pid = 0;
255 ct.cc_caller_id = nfs3_srv_caller_id;
256 ct.cc_flags = CC_DONTBLOCK;
257
258 /*
259 * We need to specially handle size changes because it is
260 * possible for the client to create a file with modes
261 * which indicate read-only, but with the file opened for
262 * writing. If the client then tries to set the size of
263 * the file, then the normal access checking done in
264 * VOP_SETATTR would prevent the client from doing so,
265 * although it should be legal for it to do so. To get
266 * around this, we do the access checking for ourselves
267 * and then use VOP_SPACE which doesn't do the access
268 * checking which VOP_SETATTR does. VOP_SPACE can only
269 * operate on VREG files, let VOP_SETATTR handle the other
270 * extremely rare cases.
271 * Also the client should not be allowed to change the
272 * size of the file if there is a conflicting non-blocking
273 * mandatory lock in the region the change.
274 */
275 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
276 if (in_crit) {
277 u_offset_t offset;
278 ssize_t length;
279
280 if (ava.va_size < bva.va_size) {
281 offset = ava.va_size;
282 length = bva.va_size - ava.va_size;
283 } else {
284 offset = bva.va_size;
285 length = ava.va_size - bva.va_size;
286 }
287 if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
288 NULL)) {
289 error = EACCES;
290 goto out;
291 }
292 }
293
294 if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
295 ava.va_mask &= ~AT_SIZE;
296 bf.l_type = F_WRLCK;
297 bf.l_whence = 0;
298 bf.l_start = (off64_t)ava.va_size;
299 bf.l_len = 0;
300 bf.l_sysid = 0;
301 bf.l_pid = 0;
302 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
303 (offset_t)ava.va_size, cr, &ct);
304 }
305 }
306
307 if (!error && ava.va_mask)
308 error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
309
310 /* check if a monitor detected a delegation conflict */
311 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
312 resp->status = NFS3ERR_JUKEBOX;
313 goto out1;
314 }
315
316 ava.va_mask = AT_ALL;
317 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
318
319 /*
320 * Force modified metadata out to stable storage.
321 */
322 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
323
324 if (error)
325 goto out;
326
327 if (in_crit)
328 nbl_end_crit(vp);
329
330 resp->status = NFS3_OK;
331 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
332
333 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
334 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
335
336 VN_RELE(vp);
337
338 return;
339
340 out:
341 if (curthread->t_flag & T_WOULDBLOCK) {
342 curthread->t_flag &= ~T_WOULDBLOCK;
343 resp->status = NFS3ERR_JUKEBOX;
344 } else
345 resp->status = puterrno3(error);
346 out1:
347 DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
348 cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
349
350 if (vp != NULL) {
351 if (in_crit)
352 nbl_end_crit(vp);
353 VN_RELE(vp);
354 }
355 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
356 }
357
358 void *
359 rfs3_setattr_getfh(SETATTR3args *args)
360 {
361
362 return (&args->object);
363 }
364
365 /* ARGSUSED */
366 void
367 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
368 struct svc_req *req, cred_t *cr, bool_t ro)
369 {
370 int error;
371 vnode_t *vp;
372 vnode_t *dvp;
373 struct vattr *vap;
374 struct vattr va;
375 struct vattr *dvap;
376 struct vattr dva;
377 nfs_fh3 *fhp;
378 struct sec_ol sec = {0, 0};
379 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
380 struct sockaddr *ca;
381 char *name = NULL;
382
383 dvap = NULL;
384
385 if (exi != NULL)
386 exi_hold(exi);
387
388 /*
389 * Allow lookups from the root - the default
390 * location of the public filehandle.
391 */
392 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
393 dvp = rootdir;
394 VN_HOLD(dvp);
395
396 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
397 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
398 } else {
399 dvp = nfs3_fhtovp(&args->what.dir, exi);
400
401 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
402 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
403
404 if (dvp == NULL) {
405 error = ESTALE;
406 goto out;
407 }
408 }
409
410 dva.va_mask = AT_ALL;
411 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
412
413 if (args->what.name == nfs3nametoolong) {
414 resp->status = NFS3ERR_NAMETOOLONG;
415 goto out1;
416 }
417
418 if (args->what.name == NULL || *(args->what.name) == '\0') {
419 resp->status = NFS3ERR_ACCES;
420 goto out1;
421 }
422
423 fhp = &args->what.dir;
424 if (strcmp(args->what.name, "..") == 0 &&
425 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
426 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
427 (dvp->v_flag & VROOT)) {
428 /*
429 * special case for ".." and 'nohide'exported root
430 */
431 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435 } else {
436 resp->status = NFS3ERR_NOENT;
437 goto out1;
438 }
439 }
440
441 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
442 name = nfscmd_convname(ca, exi, args->what.name,
443 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
444
445 if (name == NULL) {
446 resp->status = NFS3ERR_ACCES;
447 goto out1;
448 }
449
450 /*
451 * If the public filehandle is used then allow
452 * a multi-component lookup
453 */
454 if (PUBLIC_FH3(&args->what.dir)) {
455 publicfh_flag = TRUE;
456
457 exi_rele(exi);
458
459 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
460 &exi, &sec);
461
462 /*
463 * Since WebNFS may bypass MOUNT, we need to ensure this
464 * request didn't come from an unlabeled admin_low client.
465 */
466 if (is_system_labeled() && error == 0) {
467 int addr_type;
468 void *ipaddr;
469 tsol_tpc_t *tp;
470
471 if (ca->sa_family == AF_INET) {
472 addr_type = IPV4_VERSION;
473 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
474 } else if (ca->sa_family == AF_INET6) {
475 addr_type = IPV6_VERSION;
476 ipaddr = &((struct sockaddr_in6 *)
477 ca)->sin6_addr;
478 }
479 tp = find_tpc(ipaddr, addr_type, B_FALSE);
480 if (tp == NULL || tp->tpc_tp.tp_doi !=
481 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
482 SUN_CIPSO) {
483 VN_RELE(vp);
484 error = EACCES;
485 }
486 if (tp != NULL)
487 TPC_RELE(tp);
488 }
489 } else {
490 error = VOP_LOOKUP(dvp, name, &vp,
491 NULL, 0, NULL, cr, NULL, NULL, NULL);
492 }
493
494 if (name != args->what.name)
495 kmem_free(name, MAXPATHLEN + 1);
496
497 if (error == 0 && vn_ismntpt(vp)) {
498 error = rfs_cross_mnt(&vp, &exi);
499 if (error)
500 VN_RELE(vp);
501 }
502
503 if (is_system_labeled() && error == 0) {
504 bslabel_t *clabel = req->rq_label;
505
506 ASSERT(clabel != NULL);
507 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
508 "got client label from request(1)", struct svc_req *, req);
509
510 if (!blequal(&l_admin_low->tsl_label, clabel)) {
511 if (!do_rfs_label_check(clabel, dvp,
512 DOMINANCE_CHECK, exi)) {
513 VN_RELE(vp);
514 error = EACCES;
515 }
516 }
517 }
518
519 dva.va_mask = AT_ALL;
520 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
521
522 if (error)
523 goto out;
524
525 if (sec.sec_flags & SEC_QUERY) {
526 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
527 } else {
528 error = makefh3(&resp->resok.object, vp, exi);
529 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
530 auth_weak = TRUE;
531 }
532
533 if (error) {
534 VN_RELE(vp);
535 goto out;
536 }
537
538 va.va_mask = AT_ALL;
539 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
540
541 exi_rele(exi);
542 VN_RELE(vp);
543
544 resp->status = NFS3_OK;
545 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
546 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
547
548 /*
549 * If it's public fh, no 0x81, and client's flavor is
550 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
551 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
552 */
553 if (auth_weak)
554 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
555
556 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
557 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
558 VN_RELE(dvp);
559
560 return;
561
562 out:
563 if (curthread->t_flag & T_WOULDBLOCK) {
564 curthread->t_flag &= ~T_WOULDBLOCK;
565 resp->status = NFS3ERR_JUKEBOX;
566 } else
567 resp->status = puterrno3(error);
568 out1:
569 if (exi != NULL)
570 exi_rele(exi);
571
572 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
573 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
574
575 if (dvp != NULL)
576 VN_RELE(dvp);
577 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
578
579 }
580
581 void *
582 rfs3_lookup_getfh(LOOKUP3args *args)
583 {
584
585 return (&args->what.dir);
586 }
587
588 /* ARGSUSED */
589 void
590 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
591 struct svc_req *req, cred_t *cr, bool_t ro)
592 {
593 int error;
594 vnode_t *vp;
595 struct vattr *vap;
596 struct vattr va;
597 int checkwriteperm;
598 boolean_t dominant_label = B_FALSE;
599 boolean_t equal_label = B_FALSE;
600 boolean_t admin_low_client;
601
602 vap = NULL;
603
604 vp = nfs3_fhtovp(&args->object, exi);
605
606 DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
607 cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
608
609 if (vp == NULL) {
610 error = ESTALE;
611 goto out;
612 }
613
614 /*
615 * If the file system is exported read only, it is not appropriate
616 * to check write permissions for regular files and directories.
617 * Special files are interpreted by the client, so the underlying
618 * permissions are sent back to the client for interpretation.
619 */
620 if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
621 checkwriteperm = 0;
622 else
623 checkwriteperm = 1;
624
625 /*
626 * We need the mode so that we can correctly determine access
627 * permissions relative to a mandatory lock file. Access to
628 * mandatory lock files is denied on the server, so it might
629 * as well be reflected to the server during the open.
630 */
631 va.va_mask = AT_MODE;
632 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
633 if (error)
634 goto out;
635
636 vap = &va;
637
638 resp->resok.access = 0;
639
640 if (is_system_labeled()) {
641 bslabel_t *clabel = req->rq_label;
642
643 ASSERT(clabel != NULL);
644 DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
645 "got client label from request(1)", struct svc_req *, req);
646
647 if (!blequal(&l_admin_low->tsl_label, clabel)) {
648 if ((equal_label = do_rfs_label_check(clabel, vp,
649 EQUALITY_CHECK, exi)) == B_FALSE) {
650 dominant_label = do_rfs_label_check(clabel,
651 vp, DOMINANCE_CHECK, exi);
652 } else
653 dominant_label = B_TRUE;
654 admin_low_client = B_FALSE;
655 } else
656 admin_low_client = B_TRUE;
657 }
658
659 if (args->access & ACCESS3_READ) {
660 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
661 if (error) {
662 if (curthread->t_flag & T_WOULDBLOCK)
663 goto out;
664 } else if (!MANDLOCK(vp, va.va_mode) &&
665 (!is_system_labeled() || admin_low_client ||
666 dominant_label))
667 resp->resok.access |= ACCESS3_READ;
668 }
669 if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
670 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
671 if (error) {
672 if (curthread->t_flag & T_WOULDBLOCK)
673 goto out;
674 } else if (!is_system_labeled() || admin_low_client ||
675 dominant_label)
676 resp->resok.access |= ACCESS3_LOOKUP;
677 }
678 if (checkwriteperm &&
679 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
680 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
681 if (error) {
682 if (curthread->t_flag & T_WOULDBLOCK)
683 goto out;
684 } else if (!MANDLOCK(vp, va.va_mode) &&
685 (!is_system_labeled() || admin_low_client || equal_label)) {
686 resp->resok.access |=
687 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
688 }
689 }
690 if (checkwriteperm &&
691 (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
692 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
693 if (error) {
694 if (curthread->t_flag & T_WOULDBLOCK)
695 goto out;
696 } else if (!is_system_labeled() || admin_low_client ||
697 equal_label)
698 resp->resok.access |= ACCESS3_DELETE;
699 }
700 if (args->access & ACCESS3_EXECUTE) {
701 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
702 if (error) {
703 if (curthread->t_flag & T_WOULDBLOCK)
704 goto out;
705 } else if (!MANDLOCK(vp, va.va_mode) &&
706 (!is_system_labeled() || admin_low_client ||
707 dominant_label))
708 resp->resok.access |= ACCESS3_EXECUTE;
709 }
710
711 va.va_mask = AT_ALL;
712 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
713
714 resp->status = NFS3_OK;
715 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
716
717 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
718 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
719
720 VN_RELE(vp);
721
722 return;
723
724 out:
725 if (curthread->t_flag & T_WOULDBLOCK) {
726 curthread->t_flag &= ~T_WOULDBLOCK;
727 resp->status = NFS3ERR_JUKEBOX;
728 } else
729 resp->status = puterrno3(error);
730 DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
731 cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
732 if (vp != NULL)
733 VN_RELE(vp);
734 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
735 }
736
737 void *
738 rfs3_access_getfh(ACCESS3args *args)
739 {
740
741 return (&args->object);
742 }
743
744 /* ARGSUSED */
745 void
746 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
747 struct svc_req *req, cred_t *cr, bool_t ro)
748 {
749 int error;
750 vnode_t *vp;
751 struct vattr *vap;
752 struct vattr va;
753 struct iovec iov;
754 struct uio uio;
755 char *data;
756 struct sockaddr *ca;
757 char *name = NULL;
758 int is_referral = 0;
759
760 vap = NULL;
761
762 vp = nfs3_fhtovp(&args->symlink, exi);
763
764 DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
765 cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
766
767 if (vp == NULL) {
768 error = ESTALE;
769 goto out;
770 }
771
772 va.va_mask = AT_ALL;
773 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
774 if (error)
775 goto out;
776
777 vap = &va;
778
779 /* We lied about the object type for a referral */
780 if (vn_is_nfs_reparse(vp, cr))
781 is_referral = 1;
782
783 if (vp->v_type != VLNK && !is_referral) {
784 resp->status = NFS3ERR_INVAL;
785 goto out1;
786 }
787
788 if (MANDLOCK(vp, va.va_mode)) {
789 resp->status = NFS3ERR_ACCES;
790 goto out1;
791 }
792
793 if (is_system_labeled()) {
794 bslabel_t *clabel = req->rq_label;
795
796 ASSERT(clabel != NULL);
797 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
798 "got client label from request(1)", struct svc_req *, req);
799
800 if (!blequal(&l_admin_low->tsl_label, clabel)) {
801 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
802 exi)) {
803 resp->status = NFS3ERR_ACCES;
804 goto out1;
805 }
806 }
807 }
808
809 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
810
811 if (is_referral) {
812 char *s;
813 size_t strsz;
814
815 /* Get an artificial symlink based on a referral */
816 s = build_symlink(vp, cr, &strsz);
817 global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
818 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
819 vnode_t *, vp, char *, s);
820 if (s == NULL)
821 error = EINVAL;
822 else {
823 error = 0;
824 (void) strlcpy(data, s, MAXPATHLEN + 1);
825 kmem_free(s, strsz);
826 }
827
828 } else {
829
830 iov.iov_base = data;
831 iov.iov_len = MAXPATHLEN;
832 uio.uio_iov = &iov;
833 uio.uio_iovcnt = 1;
834 uio.uio_segflg = UIO_SYSSPACE;
835 uio.uio_extflg = UIO_COPY_CACHED;
836 uio.uio_loffset = 0;
837 uio.uio_resid = MAXPATHLEN;
838
839 error = VOP_READLINK(vp, &uio, cr, NULL);
840
841 if (!error)
842 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
843 }
844
845 va.va_mask = AT_ALL;
846 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
847
848 /* Lie about object type again just to be consistent */
849 if (is_referral && vap != NULL)
850 vap->va_type = VLNK;
851
852 #if 0 /* notyet */
853 /*
854 * Don't do this. It causes local disk writes when just
855 * reading the file and the overhead is deemed larger
856 * than the benefit.
857 */
858 /*
859 * Force modified metadata out to stable storage.
860 */
861 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
862 #endif
863
864 if (error) {
865 kmem_free(data, MAXPATHLEN + 1);
866 goto out;
867 }
868
869 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
870 name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
871 MAXPATHLEN + 1);
872
873 if (name == NULL) {
874 /*
875 * Even though the conversion failed, we return
876 * something. We just don't translate it.
877 */
878 name = data;
879 }
880
881 resp->status = NFS3_OK;
882 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
883 resp->resok.data = name;
884
885 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
886 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
887 VN_RELE(vp);
888
889 if (name != data)
890 kmem_free(data, MAXPATHLEN + 1);
891
892 return;
893
894 out:
895 if (curthread->t_flag & T_WOULDBLOCK) {
896 curthread->t_flag &= ~T_WOULDBLOCK;
897 resp->status = NFS3ERR_JUKEBOX;
898 } else
899 resp->status = puterrno3(error);
900 out1:
901 DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
902 cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
903 if (vp != NULL)
904 VN_RELE(vp);
905 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
906 }
907
908 void *
909 rfs3_readlink_getfh(READLINK3args *args)
910 {
911
912 return (&args->symlink);
913 }
914
915 void
916 rfs3_readlink_free(READLINK3res *resp)
917 {
918
919 if (resp->status == NFS3_OK)
920 kmem_free(resp->resok.data, MAXPATHLEN + 1);
921 }
922
923 /*
924 * Server routine to handle read
925 * May handle RDMA data as well as mblks
926 */
927 /* ARGSUSED */
928 void
929 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
930 struct svc_req *req, cred_t *cr, bool_t ro)
931 {
932 int error;
933 vnode_t *vp;
934 struct vattr *vap;
935 struct vattr va;
936 struct iovec iov, *iovp = NULL;
937 int iovcnt;
938 struct uio uio;
939 u_offset_t offset;
940 mblk_t *mp = NULL;
941 int in_crit = 0;
942 int need_rwunlock = 0;
943 caller_context_t ct;
944 int rdma_used = 0;
945 int loaned_buffers;
946 struct uio *uiop;
947
948 vap = NULL;
949
950 vp = nfs3_fhtovp(&args->file, exi);
951
952 DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
953 cred_t *, cr, vnode_t *, vp, READ3args *, args);
954
955 if (vp == NULL) {
956 error = ESTALE;
957 goto out;
958 }
959
960 if (args->wlist) {
961 if (args->count > clist_len(args->wlist)) {
962 error = EINVAL;
963 goto out;
964 }
965 rdma_used = 1;
966 }
967
968 /* use loaned buffers for TCP */
969 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
970
971 if (is_system_labeled()) {
972 bslabel_t *clabel = req->rq_label;
973
974 ASSERT(clabel != NULL);
975 DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
976 "got client label from request(1)", struct svc_req *, req);
977
978 if (!blequal(&l_admin_low->tsl_label, clabel)) {
979 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
980 exi)) {
981 resp->status = NFS3ERR_ACCES;
982 goto out1;
983 }
984 }
985 }
986
987 ct.cc_sysid = 0;
988 ct.cc_pid = 0;
989 ct.cc_caller_id = nfs3_srv_caller_id;
990 ct.cc_flags = CC_DONTBLOCK;
991
992 /*
993 * Enter the critical region before calling VOP_RWLOCK
994 * to avoid a deadlock with write requests.
995 */
996 if (nbl_need_check(vp)) {
997 nbl_start_crit(vp, RW_READER);
998 in_crit = 1;
999 if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
1000 NULL)) {
1001 error = EACCES;
1002 goto out;
1003 }
1004 }
1005
1006 error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1007
1008 /* check if a monitor detected a delegation conflict */
1009 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1010 resp->status = NFS3ERR_JUKEBOX;
1011 goto out1;
1012 }
1013
1014 need_rwunlock = 1;
1015
1016 va.va_mask = AT_ALL;
1017 error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1018
1019 /*
1020 * If we can't get the attributes, then we can't do the
1021 * right access checking. So, we'll fail the request.
1022 */
1023 if (error)
1024 goto out;
1025
1026 vap = &va;
1027
1028 if (vp->v_type != VREG) {
1029 resp->status = NFS3ERR_INVAL;
1030 goto out1;
1031 }
1032
1033 if (crgetuid(cr) != va.va_uid) {
1034 error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
1035 if (error) {
1036 if (curthread->t_flag & T_WOULDBLOCK)
1037 goto out;
1038 error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
1039 if (error)
1040 goto out;
1041 }
1042 }
1043
1044 if (MANDLOCK(vp, va.va_mode)) {
1045 resp->status = NFS3ERR_ACCES;
1046 goto out1;
1047 }
1048
1049 offset = args->offset;
1050 if (offset >= va.va_size) {
1051 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1052 if (in_crit)
1053 nbl_end_crit(vp);
1054 resp->status = NFS3_OK;
1055 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1056 resp->resok.count = 0;
1057 resp->resok.eof = TRUE;
1058 resp->resok.data.data_len = 0;
1059 resp->resok.data.data_val = NULL;
1060 resp->resok.data.mp = NULL;
1061 /* RDMA */
1062 resp->resok.wlist = args->wlist;
1063 resp->resok.wlist_len = resp->resok.count;
1064 if (resp->resok.wlist)
1065 clist_zero_len(resp->resok.wlist);
1066 goto done;
1067 }
1068
1069 if (args->count == 0) {
1070 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1071 if (in_crit)
1072 nbl_end_crit(vp);
1073 resp->status = NFS3_OK;
1074 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1075 resp->resok.count = 0;
1076 resp->resok.eof = FALSE;
1077 resp->resok.data.data_len = 0;
1078 resp->resok.data.data_val = NULL;
1079 resp->resok.data.mp = NULL;
1080 /* RDMA */
1081 resp->resok.wlist = args->wlist;
1082 resp->resok.wlist_len = resp->resok.count;
1083 if (resp->resok.wlist)
1084 clist_zero_len(resp->resok.wlist);
1085 goto done;
1086 }
1087
1088 /*
1089 * do not allocate memory more the max. allowed
1090 * transfer size
1091 */
1092 if (args->count > rfs3_tsize(req))
1093 args->count = rfs3_tsize(req);
1094
1095 if (loaned_buffers) {
1096 uiop = (uio_t *)rfs_setup_xuio(vp);
1097 ASSERT(uiop != NULL);
1098 uiop->uio_segflg = UIO_SYSSPACE;
1099 uiop->uio_loffset = args->offset;
1100 uiop->uio_resid = args->count;
1101
1102 /* Jump to do the read if successful */
1103 if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
1104 /*
1105 * Need to hold the vnode until after VOP_RETZCBUF()
1106 * is called.
1107 */
1108 VN_HOLD(vp);
1109 goto doio_read;
1110 }
1111
1112 DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
1113 uiop->uio_loffset, int, uiop->uio_resid);
1114
1115 uiop->uio_extflg = 0;
1116 /* failure to setup for zero copy */
1117 rfs_free_xuio((void *)uiop);
1118 loaned_buffers = 0;
1119 }
1120
1121 /*
1122 * If returning data via RDMA Write, then grab the chunk list.
1123 * If we aren't returning READ data w/RDMA_WRITE, then grab
1124 * a mblk.
1125 */
1126 if (rdma_used) {
1127 (void) rdma_get_wchunk(req, &iov, args->wlist);
1128 uio.uio_iov = &iov;
1129 uio.uio_iovcnt = 1;
1130 } else {
1131 /*
1132 * mp will contain the data to be sent out in the read reply.
1133 * For UDP, this will be freed after the reply has been sent
1134 * out by the driver. For TCP, it will be freed after the last
1135 * segment associated with the reply has been ACKed by the
1136 * client.
1137 */
1138 mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
1139 uio.uio_iov = iovp;
1140 uio.uio_iovcnt = iovcnt;
1141 }
1142
1143 uio.uio_segflg = UIO_SYSSPACE;
1144 uio.uio_extflg = UIO_COPY_CACHED;
1145 uio.uio_loffset = args->offset;
1146 uio.uio_resid = args->count;
1147 uiop = &uio;
1148
1149 doio_read:
1150 error = VOP_READ(vp, uiop, 0, cr, &ct);
1151
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;
1196
1197 if (rdma_used) {
1198 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1199 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1200 resp->status = NFS3ERR_INVAL;
1201 }
1202 } else {
1203 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1204 (resp->resok).wlist = NULL;
1205 }
1206
1207 done:
1208 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1209 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1210
1211 VN_RELE(vp);
1212
1213 if (iovp != NULL)
1214 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1215
1216 return;
1217
1218 out:
1219 if (curthread->t_flag & T_WOULDBLOCK) {
1220 curthread->t_flag &= ~T_WOULDBLOCK;
1221 resp->status = NFS3ERR_JUKEBOX;
1222 } else
1223 resp->status = puterrno3(error);
1224 out1:
1225 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1226 cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1227
1228 if (vp != NULL) {
1229 if (need_rwunlock)
1230 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1231 if (in_crit)
1232 nbl_end_crit(vp);
1233 VN_RELE(vp);
1234 }
1235 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1236
1237 if (iovp != NULL)
1238 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1239 }
1240
1241 void
1242 rfs3_read_free(READ3res *resp)
1243 {
1244 mblk_t *mp;
1245
1246 if (resp->status == NFS3_OK) {
1247 mp = resp->resok.data.mp;
1248 if (mp != NULL)
1249 freemsg(mp);
1250 }
1251 }
1252
1253 void *
1254 rfs3_read_getfh(READ3args *args)
1255 {
1256
1257 return (&args->file);
1258 }
1259
1260 #define MAX_IOVECS 12
1261
1262 #ifdef DEBUG
1263 static int rfs3_write_hits = 0;
1264 static int rfs3_write_misses = 0;
1265 #endif
1266
1267 void
1268 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1269 struct svc_req *req, cred_t *cr, bool_t ro)
1270 {
1271 int error;
1272 vnode_t *vp;
1273 struct vattr *bvap = NULL;
1274 struct vattr bva;
1275 struct vattr *avap = NULL;
1276 struct vattr ava;
1277 u_offset_t rlimit;
1278 struct uio uio;
1279 struct iovec iov[MAX_IOVECS];
1280 mblk_t *m;
1281 struct iovec *iovp;
1282 int iovcnt;
1283 int ioflag;
1284 cred_t *savecred;
1285 int in_crit = 0;
1286 int rwlock_ret = -1;
1287 caller_context_t ct;
1288
1289 vp = nfs3_fhtovp(&args->file, exi);
1290
1291 DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1292 cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1293
1294 if (vp == NULL) {
1295 error = ESTALE;
1296 goto err;
1297 }
1298
1299 if (is_system_labeled()) {
1300 bslabel_t *clabel = req->rq_label;
1301
1302 ASSERT(clabel != NULL);
1303 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1304 "got client label from request(1)", struct svc_req *, req);
1305
1306 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1307 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1308 exi)) {
1309 resp->status = NFS3ERR_ACCES;
1310 goto err1;
1311 }
1312 }
1313 }
1314
1315 ct.cc_sysid = 0;
1316 ct.cc_pid = 0;
1317 ct.cc_caller_id = nfs3_srv_caller_id;
1318 ct.cc_flags = CC_DONTBLOCK;
1319
1320 /*
1321 * We have to enter the critical region before calling VOP_RWLOCK
1322 * to avoid a deadlock with ufs.
1323 */
1324 if (nbl_need_check(vp)) {
1325 nbl_start_crit(vp, RW_READER);
1326 in_crit = 1;
1327 if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1328 NULL)) {
1329 error = EACCES;
1330 goto err;
1331 }
1332 }
1333
1334 rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1335
1336 /* check if a monitor detected a delegation conflict */
1337 if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1338 resp->status = NFS3ERR_JUKEBOX;
1339 rwlock_ret = -1;
1340 goto err1;
1341 }
1342
1343
1344 bva.va_mask = AT_ALL;
1345 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1346
1347 /*
1348 * If we can't get the attributes, then we can't do the
1349 * right access checking. So, we'll fail the request.
1350 */
1351 if (error)
1352 goto err;
1353
1354 bvap = &bva;
1355 avap = bvap;
1356
1357 if (args->count != args->data.data_len) {
1358 resp->status = NFS3ERR_INVAL;
1359 goto err1;
1360 }
1361
1362 if (rdonly(ro, vp)) {
1363 resp->status = NFS3ERR_ROFS;
1364 goto err1;
1365 }
1366
1367 if (vp->v_type != VREG) {
1368 resp->status = NFS3ERR_INVAL;
1369 goto err1;
1370 }
1371
1372 if (crgetuid(cr) != bva.va_uid &&
1373 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1374 goto err;
1375
1376 if (MANDLOCK(vp, bva.va_mode)) {
1377 resp->status = NFS3ERR_ACCES;
1378 goto err1;
1379 }
1380
1381 if (args->count == 0) {
1382 resp->status = NFS3_OK;
1383 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1384 resp->resok.count = 0;
1385 resp->resok.committed = args->stable;
1386 resp->resok.verf = write3verf;
1387 goto out;
1388 }
1389
1390 if (args->mblk != NULL) {
1391 iovcnt = 0;
1392 for (m = args->mblk; m != NULL; m = m->b_cont)
1393 iovcnt++;
1394 if (iovcnt <= MAX_IOVECS) {
1395 #ifdef DEBUG
1396 rfs3_write_hits++;
1397 #endif
1398 iovp = iov;
1399 } else {
1400 #ifdef DEBUG
1401 rfs3_write_misses++;
1402 #endif
1403 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1404 }
1405 mblk_to_iov(args->mblk, iovcnt, iovp);
1406
1407 } else if (args->rlist != NULL) {
1408 iovcnt = 1;
1409 iovp = iov;
1410 iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
1411 iovp->iov_len = args->count;
1412 } else {
1413 iovcnt = 1;
1414 iovp = iov;
1415 iovp->iov_base = args->data.data_val;
1416 iovp->iov_len = args->count;
1417 }
1418
1419 uio.uio_iov = iovp;
1420 uio.uio_iovcnt = iovcnt;
1421
1422 uio.uio_segflg = UIO_SYSSPACE;
1423 uio.uio_extflg = UIO_COPY_DEFAULT;
1424 uio.uio_loffset = args->offset;
1425 uio.uio_resid = args->count;
1426 uio.uio_llimit = curproc->p_fsz_ctl;
1427 rlimit = uio.uio_llimit - args->offset;
1428 if (rlimit < (u_offset_t)uio.uio_resid)
1429 uio.uio_resid = (int)rlimit;
1430
1431 if (args->stable == UNSTABLE)
1432 ioflag = 0;
1433 else if (args->stable == FILE_SYNC)
1434 ioflag = FSYNC;
1435 else if (args->stable == DATA_SYNC)
1436 ioflag = FDSYNC;
1437 else {
1438 if (iovp != iov)
1439 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1440 resp->status = NFS3ERR_INVAL;
1441 goto err1;
1442 }
1443
1444 /*
1445 * We're changing creds because VM may fault and we need
1446 * the cred of the current thread to be used if quota
1447 * checking is enabled.
1448 */
1449 savecred = curthread->t_cred;
1450 curthread->t_cred = cr;
1451 error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1452 curthread->t_cred = savecred;
1453
1454 if (iovp != iov)
1455 kmem_free(iovp, sizeof (*iovp) * iovcnt);
1456
1457 /* check if a monitor detected a delegation conflict */
1458 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1459 resp->status = NFS3ERR_JUKEBOX;
1460 goto err1;
1461 }
1462
1463 ava.va_mask = AT_ALL;
1464 avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1465
1466 if (error)
1467 goto err;
1468
1469 /*
1470 * If we were unable to get the V_WRITELOCK_TRUE, then we
1471 * may not have accurate after attrs, so check if
1472 * we have both attributes, they have a non-zero va_seq, and
1473 * va_seq has changed by exactly one,
1474 * if not, turn off the before attr.
1475 */
1476 if (rwlock_ret != V_WRITELOCK_TRUE) {
1477 if (bvap == NULL || avap == NULL ||
1478 bvap->va_seq == 0 || avap->va_seq == 0 ||
1479 avap->va_seq != (bvap->va_seq + 1)) {
1480 bvap = NULL;
1481 }
1482 }
1483
1484 resp->status = NFS3_OK;
1485 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1486 resp->resok.count = args->count - uio.uio_resid;
1487 resp->resok.committed = args->stable;
1488 resp->resok.verf = write3verf;
1489 goto out;
1490
1491 err:
1492 if (curthread->t_flag & T_WOULDBLOCK) {
1493 curthread->t_flag &= ~T_WOULDBLOCK;
1494 resp->status = NFS3ERR_JUKEBOX;
1495 } else
1496 resp->status = puterrno3(error);
1497 err1:
1498 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1499 out:
1500 DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1501 cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1502
1503 if (vp != NULL) {
1504 if (rwlock_ret != -1)
1505 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1506 if (in_crit)
1507 nbl_end_crit(vp);
1508 VN_RELE(vp);
1509 }
1510 }
1511
1512 void *
1513 rfs3_write_getfh(WRITE3args *args)
1514 {
1515
1516 return (&args->file);
1517 }
1518
1519 void
1520 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1521 struct svc_req *req, cred_t *cr, bool_t ro)
1522 {
1523 int error;
1524 int in_crit = 0;
1525 vnode_t *vp;
1526 vnode_t *tvp = NULL;
1527 vnode_t *dvp;
1528 struct vattr *vap;
1529 struct vattr va;
1530 struct vattr *dbvap;
1531 struct vattr dbva;
1532 struct vattr *davap;
1533 struct vattr dava;
1534 enum vcexcl excl;
1535 nfstime3 *mtime;
1536 len_t reqsize;
1537 bool_t trunc;
1538 struct sockaddr *ca;
1539 char *name = NULL;
1540
1541 dbvap = NULL;
1542 davap = NULL;
1543
1544 dvp = nfs3_fhtovp(&args->where.dir, exi);
1545
1546 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1547 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1548
1549 if (dvp == NULL) {
1550 error = ESTALE;
1551 goto out;
1552 }
1553
1554 dbva.va_mask = AT_ALL;
1555 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1556 davap = dbvap;
1557
1558 if (args->where.name == nfs3nametoolong) {
1559 resp->status = NFS3ERR_NAMETOOLONG;
1560 goto out1;
1561 }
1562
1563 if (args->where.name == NULL || *(args->where.name) == '\0') {
1564 resp->status = NFS3ERR_ACCES;
1565 goto out1;
1566 }
1567
1568 if (rdonly(ro, dvp)) {
1569 resp->status = NFS3ERR_ROFS;
1570 goto out1;
1571 }
1572
1573 if (is_system_labeled()) {
1574 bslabel_t *clabel = req->rq_label;
1575
1576 ASSERT(clabel != NULL);
1577 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1578 "got client label from request(1)", struct svc_req *, req);
1579
1580 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1581 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1582 exi)) {
1583 resp->status = NFS3ERR_ACCES;
1584 goto out1;
1585 }
1586 }
1587 }
1588
1589 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1590 name = nfscmd_convname(ca, exi, args->where.name,
1591 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1592
1593 if (name == NULL) {
1594 /* This is really a Solaris EILSEQ */
1595 resp->status = NFS3ERR_INVAL;
1596 goto out1;
1597 }
1598
1599 if (args->how.mode == EXCLUSIVE) {
1600 va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
1601 va.va_type = VREG;
1602 va.va_mode = (mode_t)0;
1603 /*
1604 * Ensure no time overflows and that types match
1605 */
1606 mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1607 va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
1608 va.va_mtime.tv_nsec = mtime->nseconds;
1609 excl = EXCL;
1610 } else {
1611 error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
1612 &va);
1613 if (error)
1614 goto out;
1615 va.va_mask |= AT_TYPE;
1616 va.va_type = VREG;
1617 if (args->how.mode == GUARDED)
1618 excl = EXCL;
1619 else {
1620 excl = NONEXCL;
1621
1622 /*
1623 * During creation of file in non-exclusive mode
1624 * if size of file is being set then make sure
1625 * that if the file already exists that no conflicting
1626 * non-blocking mandatory locks exists in the region
1627 * being modified. If there are conflicting locks fail
1628 * the operation with EACCES.
1629 */
1630 if (va.va_mask & AT_SIZE) {
1631 struct vattr tva;
1632
1633 /*
1634 * Does file already exist?
1635 */
1636 error = VOP_LOOKUP(dvp, name, &tvp,
1637 NULL, 0, NULL, cr, NULL, NULL, NULL);
1638
1639 /*
1640 * Check to see if the file has been delegated
1641 * to a v4 client. If so, then begin recall of
1642 * the delegation and return JUKEBOX to allow
1643 * the client to retrasmit its request.
1644 */
1645
1646 trunc = va.va_size == 0;
1647 if (!error &&
1648 rfs4_check_delegated(FWRITE, tvp, trunc)) {
1649 resp->status = NFS3ERR_JUKEBOX;
1650 goto out1;
1651 }
1652
1653 /*
1654 * Check for NBMAND lock conflicts
1655 */
1656 if (!error && nbl_need_check(tvp)) {
1657 u_offset_t offset;
1658 ssize_t len;
1659
1660 nbl_start_crit(tvp, RW_READER);
1661 in_crit = 1;
1662
1663 tva.va_mask = AT_SIZE;
1664 error = VOP_GETATTR(tvp, &tva, 0, cr,
1665 NULL);
1666 /*
1667 * Can't check for conflicts, so return
1668 * error.
1669 */
1670 if (error)
1671 goto out;
1672
1673 offset = tva.va_size < va.va_size ?
1674 tva.va_size : va.va_size;
1675 len = tva.va_size < va.va_size ?
1676 va.va_size - tva.va_size :
1677 tva.va_size - va.va_size;
1678 if (nbl_conflict(tvp, NBL_WRITE,
1679 offset, len, 0, NULL)) {
1680 error = EACCES;
1681 goto out;
1682 }
1683 } else if (tvp) {
1684 VN_RELE(tvp);
1685 tvp = NULL;
1686 }
1687 }
1688 }
1689 if (va.va_mask & AT_SIZE)
1690 reqsize = va.va_size;
1691 }
1692
1693 /*
1694 * Must specify the mode.
1695 */
1696 if (!(va.va_mask & AT_MODE)) {
1697 resp->status = NFS3ERR_INVAL;
1698 goto out1;
1699 }
1700
1701 /*
1702 * If the filesystem is exported with nosuid, then mask off
1703 * the setuid and setgid bits.
1704 */
1705 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1706 va.va_mode &= ~(VSUID | VSGID);
1707
1708 tryagain:
1709 /*
1710 * The file open mode used is VWRITE. If the client needs
1711 * some other semantic, then it should do the access checking
1712 * itself. It would have been nice to have the file open mode
1713 * passed as part of the arguments.
1714 */
1715 error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1716 &vp, cr, 0, NULL, NULL);
1717
1718 dava.va_mask = AT_ALL;
1719 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1720
1721 if (error) {
1722 /*
1723 * If we got something other than file already exists
1724 * then just return this error. Otherwise, we got
1725 * EEXIST. If we were doing a GUARDED create, then
1726 * just return this error. Otherwise, we need to
1727 * make sure that this wasn't a duplicate of an
1728 * exclusive create request.
1729 *
1730 * The assumption is made that a non-exclusive create
1731 * request will never return EEXIST.
1732 */
1733 if (error != EEXIST || args->how.mode == GUARDED)
1734 goto out;
1735 /*
1736 * Lookup the file so that we can get a vnode for it.
1737 */
1738 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1739 NULL, cr, NULL, NULL, NULL);
1740 if (error) {
1741 /*
1742 * We couldn't find the file that we thought that
1743 * we just created. So, we'll just try creating
1744 * it again.
1745 */
1746 if (error == ENOENT)
1747 goto tryagain;
1748 goto out;
1749 }
1750
1751 /*
1752 * If the file is delegated to a v4 client, go ahead
1753 * and initiate recall, this create is a hint that a
1754 * conflicting v3 open has occurred.
1755 */
1756
1757 if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
1758 VN_RELE(vp);
1759 resp->status = NFS3ERR_JUKEBOX;
1760 goto out1;
1761 }
1762
1763 va.va_mask = AT_ALL;
1764 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1765
1766 mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1767 /* % with INT32_MAX to prevent overflows */
1768 if (args->how.mode == EXCLUSIVE && (vap == NULL ||
1769 vap->va_mtime.tv_sec !=
1770 (mtime->seconds % INT32_MAX) ||
1771 vap->va_mtime.tv_nsec != mtime->nseconds)) {
1772 VN_RELE(vp);
1773 error = EEXIST;
1774 goto out;
1775 }
1776 } else {
1777
1778 if ((args->how.mode == UNCHECKED ||
1779 args->how.mode == GUARDED) &&
1780 args->how.createhow3_u.obj_attributes.size.set_it &&
1781 va.va_size == 0)
1782 trunc = TRUE;
1783 else
1784 trunc = FALSE;
1785
1786 if (rfs4_check_delegated(FWRITE, vp, trunc)) {
1787 VN_RELE(vp);
1788 resp->status = NFS3ERR_JUKEBOX;
1789 goto out1;
1790 }
1791
1792 va.va_mask = AT_ALL;
1793 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1794
1795 /*
1796 * We need to check to make sure that the file got
1797 * created to the indicated size. If not, we do a
1798 * setattr to try to change the size, but we don't
1799 * try too hard. This shouldn't a problem as most
1800 * clients will only specifiy a size of zero which
1801 * local file systems handle. However, even if
1802 * the client does specify a non-zero size, it can
1803 * still recover by checking the size of the file
1804 * after it has created it and then issue a setattr
1805 * request of its own to set the size of the file.
1806 */
1807 if (vap != NULL &&
1808 (args->how.mode == UNCHECKED ||
1809 args->how.mode == GUARDED) &&
1810 args->how.createhow3_u.obj_attributes.size.set_it &&
1811 vap->va_size != reqsize) {
1812 va.va_mask = AT_SIZE;
1813 va.va_size = reqsize;
1814 (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1815 va.va_mask = AT_ALL;
1816 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1817 }
1818 }
1819
1820 if (name != args->where.name)
1821 kmem_free(name, MAXPATHLEN + 1);
1822
1823 error = makefh3(&resp->resok.obj.handle, vp, exi);
1824 if (error)
1825 resp->resok.obj.handle_follows = FALSE;
1826 else
1827 resp->resok.obj.handle_follows = TRUE;
1828
1829 /*
1830 * Force modified data and metadata out to stable storage.
1831 */
1832 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1833 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1834
1835 VN_RELE(vp);
1836 if (tvp != NULL) {
1837 if (in_crit)
1838 nbl_end_crit(tvp);
1839 VN_RELE(tvp);
1840 }
1841
1842 resp->status = NFS3_OK;
1843 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1844 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1845
1846 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848
1849 VN_RELE(dvp);
1850 return;
1851
1852 out:
1853 if (curthread->t_flag & T_WOULDBLOCK) {
1854 curthread->t_flag &= ~T_WOULDBLOCK;
1855 resp->status = NFS3ERR_JUKEBOX;
1856 } else
1857 resp->status = puterrno3(error);
1858 out1:
1859 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1860 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1861
1862 if (name != NULL && name != args->where.name)
1863 kmem_free(name, MAXPATHLEN + 1);
1864
1865 if (tvp != NULL) {
1866 if (in_crit)
1867 nbl_end_crit(tvp);
1868 VN_RELE(tvp);
1869 }
1870 if (dvp != NULL)
1871 VN_RELE(dvp);
1872 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1873 }
1874
1875 void *
1876 rfs3_create_getfh(CREATE3args *args)
1877 {
1878
1879 return (&args->where.dir);
1880 }
1881
1882 void
1883 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1884 struct svc_req *req, cred_t *cr, bool_t ro)
1885 {
1886 int error;
1887 vnode_t *vp = NULL;
1888 vnode_t *dvp;
1889 struct vattr *vap;
1890 struct vattr va;
1891 struct vattr *dbvap;
1892 struct vattr dbva;
1893 struct vattr *davap;
1894 struct vattr dava;
1895 struct sockaddr *ca;
1896 char *name = NULL;
1897
1898 dbvap = NULL;
1899 davap = NULL;
1900
1901 dvp = nfs3_fhtovp(&args->where.dir, exi);
1902
1903 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1904 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1905
1906 if (dvp == NULL) {
1907 error = ESTALE;
1908 goto out;
1909 }
1910
1911 dbva.va_mask = AT_ALL;
1912 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1913 davap = dbvap;
1914
1915 if (args->where.name == nfs3nametoolong) {
1916 resp->status = NFS3ERR_NAMETOOLONG;
1917 goto out1;
1918 }
1919
1920 if (args->where.name == NULL || *(args->where.name) == '\0') {
1921 resp->status = NFS3ERR_ACCES;
1922 goto out1;
1923 }
1924
1925 if (rdonly(ro, dvp)) {
1926 resp->status = NFS3ERR_ROFS;
1927 goto out1;
1928 }
1929
1930 if (is_system_labeled()) {
1931 bslabel_t *clabel = req->rq_label;
1932
1933 ASSERT(clabel != NULL);
1934 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1935 "got client label from request(1)", struct svc_req *, req);
1936
1937 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1938 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1939 exi)) {
1940 resp->status = NFS3ERR_ACCES;
1941 goto out1;
1942 }
1943 }
1944 }
1945
1946 error = sattr3_to_vattr(&args->attributes, &va);
1947 if (error)
1948 goto out;
1949
1950 if (!(va.va_mask & AT_MODE)) {
1951 resp->status = NFS3ERR_INVAL;
1952 goto out1;
1953 }
1954
1955 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1956 name = nfscmd_convname(ca, exi, args->where.name,
1957 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1958
1959 if (name == NULL) {
1960 resp->status = NFS3ERR_INVAL;
1961 goto out1;
1962 }
1963
1964 va.va_mask |= AT_TYPE;
1965 va.va_type = VDIR;
1966
1967 error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
1968
1969 if (name != args->where.name)
1970 kmem_free(name, MAXPATHLEN + 1);
1971
1972 dava.va_mask = AT_ALL;
1973 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1974
1975 /*
1976 * Force modified data and metadata out to stable storage.
1977 */
1978 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1979
1980 if (error)
1981 goto out;
1982
1983 error = makefh3(&resp->resok.obj.handle, vp, exi);
1984 if (error)
1985 resp->resok.obj.handle_follows = FALSE;
1986 else
1987 resp->resok.obj.handle_follows = TRUE;
1988
1989 va.va_mask = AT_ALL;
1990 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1991
1992 /*
1993 * Force modified data and metadata out to stable storage.
1994 */
1995 (void) VOP_FSYNC(vp, 0, cr, NULL);
1996
1997 VN_RELE(vp);
1998
1999 resp->status = NFS3_OK;
2000 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2001 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2002
2003 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2005 VN_RELE(dvp);
2006
2007 return;
2008
2009 out:
2010 if (curthread->t_flag & T_WOULDBLOCK) {
2011 curthread->t_flag &= ~T_WOULDBLOCK;
2012 resp->status = NFS3ERR_JUKEBOX;
2013 } else
2014 resp->status = puterrno3(error);
2015 out1:
2016 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2017 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2018 if (dvp != NULL)
2019 VN_RELE(dvp);
2020 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2021 }
2022
2023 void *
2024 rfs3_mkdir_getfh(MKDIR3args *args)
2025 {
2026
2027 return (&args->where.dir);
2028 }
2029
2030 void
2031 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2032 struct svc_req *req, cred_t *cr, bool_t ro)
2033 {
2034 int error;
2035 vnode_t *vp;
2036 vnode_t *dvp;
2037 struct vattr *vap;
2038 struct vattr va;
2039 struct vattr *dbvap;
2040 struct vattr dbva;
2041 struct vattr *davap;
2042 struct vattr dava;
2043 struct sockaddr *ca;
2044 char *name = NULL;
2045 char *symdata = NULL;
2046
2047 dbvap = NULL;
2048 davap = NULL;
2049
2050 dvp = nfs3_fhtovp(&args->where.dir, exi);
2051
2052 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2053 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2054
2055 if (dvp == NULL) {
2056 error = ESTALE;
2057 goto err;
2058 }
2059
2060 dbva.va_mask = AT_ALL;
2061 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2062 davap = dbvap;
2063
2064 if (args->where.name == nfs3nametoolong) {
2065 resp->status = NFS3ERR_NAMETOOLONG;
2066 goto err1;
2067 }
2068
2069 if (args->where.name == NULL || *(args->where.name) == '\0') {
2070 resp->status = NFS3ERR_ACCES;
2071 goto err1;
2072 }
2073
2074 if (rdonly(ro, dvp)) {
2075 resp->status = NFS3ERR_ROFS;
2076 goto err1;
2077 }
2078
2079 if (is_system_labeled()) {
2080 bslabel_t *clabel = req->rq_label;
2081
2082 ASSERT(clabel != NULL);
2083 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2084 "got client label from request(1)", struct svc_req *, req);
2085
2086 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2087 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2088 exi)) {
2089 resp->status = NFS3ERR_ACCES;
2090 goto err1;
2091 }
2092 }
2093 }
2094
2095 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2096 if (error)
2097 goto err;
2098
2099 if (!(va.va_mask & AT_MODE)) {
2100 resp->status = NFS3ERR_INVAL;
2101 goto err1;
2102 }
2103
2104 if (args->symlink.symlink_data == nfs3nametoolong) {
2105 resp->status = NFS3ERR_NAMETOOLONG;
2106 goto err1;
2107 }
2108
2109 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2110 name = nfscmd_convname(ca, exi, args->where.name,
2111 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2112
2113 if (name == NULL) {
2114 /* This is really a Solaris EILSEQ */
2115 resp->status = NFS3ERR_INVAL;
2116 goto err1;
2117 }
2118
2119 symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2120 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2121 if (symdata == NULL) {
2122 /* This is really a Solaris EILSEQ */
2123 resp->status = NFS3ERR_INVAL;
2124 goto err1;
2125 }
2126
2127
2128 va.va_mask |= AT_TYPE;
2129 va.va_type = VLNK;
2130
2131 error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2132
2133 dava.va_mask = AT_ALL;
2134 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2135
2136 if (error)
2137 goto err;
2138
2139 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2140 NULL, NULL, NULL);
2141
2142 /*
2143 * Force modified data and metadata out to stable storage.
2144 */
2145 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2146
2147
2148 resp->status = NFS3_OK;
2149 if (error) {
2150 resp->resok.obj.handle_follows = FALSE;
2151 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2152 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2153 goto out;
2154 }
2155
2156 error = makefh3(&resp->resok.obj.handle, vp, exi);
2157 if (error)
2158 resp->resok.obj.handle_follows = FALSE;
2159 else
2160 resp->resok.obj.handle_follows = TRUE;
2161
2162 va.va_mask = AT_ALL;
2163 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2164
2165 /*
2166 * Force modified data and metadata out to stable storage.
2167 */
2168 (void) VOP_FSYNC(vp, 0, cr, NULL);
2169
2170 VN_RELE(vp);
2171
2172 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2173 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2174 goto out;
2175
2176 err:
2177 if (curthread->t_flag & T_WOULDBLOCK) {
2178 curthread->t_flag &= ~T_WOULDBLOCK;
2179 resp->status = NFS3ERR_JUKEBOX;
2180 } else
2181 resp->status = puterrno3(error);
2182 err1:
2183 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2184 out:
2185 if (name != NULL && name != args->where.name)
2186 kmem_free(name, MAXPATHLEN + 1);
2187 if (symdata != NULL && symdata != args->symlink.symlink_data)
2188 kmem_free(symdata, MAXPATHLEN + 1);
2189
2190 DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2191 cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2192
2193 if (dvp != NULL)
2194 VN_RELE(dvp);
2195 }
2196
2197 void *
2198 rfs3_symlink_getfh(SYMLINK3args *args)
2199 {
2200
2201 return (&args->where.dir);
2202 }
2203
2204 void
2205 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2206 struct svc_req *req, cred_t *cr, bool_t ro)
2207 {
2208 int error;
2209 vnode_t *vp;
2210 vnode_t *realvp;
2211 vnode_t *dvp;
2212 struct vattr *vap;
2213 struct vattr va;
2214 struct vattr *dbvap;
2215 struct vattr dbva;
2216 struct vattr *davap;
2217 struct vattr dava;
2218 int mode;
2219 enum vcexcl excl;
2220 struct sockaddr *ca;
2221 char *name = NULL;
2222
2223 dbvap = NULL;
2224 davap = NULL;
2225
2226 dvp = nfs3_fhtovp(&args->where.dir, exi);
2227
2228 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2229 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2230
2231 if (dvp == NULL) {
2232 error = ESTALE;
2233 goto out;
2234 }
2235
2236 dbva.va_mask = AT_ALL;
2237 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2238 davap = dbvap;
2239
2240 if (args->where.name == nfs3nametoolong) {
2241 resp->status = NFS3ERR_NAMETOOLONG;
2242 goto out1;
2243 }
2244
2245 if (args->where.name == NULL || *(args->where.name) == '\0') {
2246 resp->status = NFS3ERR_ACCES;
2247 goto out1;
2248 }
2249
2250 if (rdonly(ro, dvp)) {
2251 resp->status = NFS3ERR_ROFS;
2252 goto out1;
2253 }
2254
2255 if (is_system_labeled()) {
2256 bslabel_t *clabel = req->rq_label;
2257
2258 ASSERT(clabel != NULL);
2259 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2260 "got client label from request(1)", struct svc_req *, req);
2261
2262 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2263 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2264 exi)) {
2265 resp->status = NFS3ERR_ACCES;
2266 goto out1;
2267 }
2268 }
2269 }
2270
2271 switch (args->what.type) {
2272 case NF3CHR:
2273 case NF3BLK:
2274 error = sattr3_to_vattr(
2275 &args->what.mknoddata3_u.device.dev_attributes, &va);
2276 if (error)
2277 goto out;
2278 if (secpolicy_sys_devices(cr) != 0) {
2279 resp->status = NFS3ERR_PERM;
2280 goto out1;
2281 }
2282 if (args->what.type == NF3CHR)
2283 va.va_type = VCHR;
2284 else
2285 va.va_type = VBLK;
2286 va.va_rdev = makedevice(
2287 args->what.mknoddata3_u.device.spec.specdata1,
2288 args->what.mknoddata3_u.device.spec.specdata2);
2289 va.va_mask |= AT_TYPE | AT_RDEV;
2290 break;
2291 case NF3SOCK:
2292 error = sattr3_to_vattr(
2293 &args->what.mknoddata3_u.pipe_attributes, &va);
2294 if (error)
2295 goto out;
2296 va.va_type = VSOCK;
2297 va.va_mask |= AT_TYPE;
2298 break;
2299 case NF3FIFO:
2300 error = sattr3_to_vattr(
2301 &args->what.mknoddata3_u.pipe_attributes, &va);
2302 if (error)
2303 goto out;
2304 va.va_type = VFIFO;
2305 va.va_mask |= AT_TYPE;
2306 break;
2307 default:
2308 resp->status = NFS3ERR_BADTYPE;
2309 goto out1;
2310 }
2311
2312 /*
2313 * Must specify the mode.
2314 */
2315 if (!(va.va_mask & AT_MODE)) {
2316 resp->status = NFS3ERR_INVAL;
2317 goto out1;
2318 }
2319
2320 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2321 name = nfscmd_convname(ca, exi, args->where.name,
2322 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2323
2324 if (name == NULL) {
2325 resp->status = NFS3ERR_INVAL;
2326 goto out1;
2327 }
2328
2329 excl = EXCL;
2330
2331 mode = 0;
2332
2333 error = VOP_CREATE(dvp, name, &va, excl, mode,
2334 &vp, cr, 0, NULL, NULL);
2335
2336 if (name != args->where.name)
2337 kmem_free(name, MAXPATHLEN + 1);
2338
2339 dava.va_mask = AT_ALL;
2340 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2341
2342 /*
2343 * Force modified data and metadata out to stable storage.
2344 */
2345 (void) VOP_FSYNC(dvp, 0, cr, NULL);
2346
2347 if (error)
2348 goto out;
2349
2350 resp->status = NFS3_OK;
2351
2352 error = makefh3(&resp->resok.obj.handle, vp, exi);
2353 if (error)
2354 resp->resok.obj.handle_follows = FALSE;
2355 else
2356 resp->resok.obj.handle_follows = TRUE;
2357
2358 va.va_mask = AT_ALL;
2359 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2360
2361 /*
2362 * Force modified metadata out to stable storage.
2363 *
2364 * if a underlying vp exists, pass it to VOP_FSYNC
2365 */
2366 if (VOP_REALVP(vp, &realvp, NULL) == 0)
2367 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2368 else
2369 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2370
2371 VN_RELE(vp);
2372
2373 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2374 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2375 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2376 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2377 VN_RELE(dvp);
2378 return;
2379
2380 out:
2381 if (curthread->t_flag & T_WOULDBLOCK) {
2382 curthread->t_flag &= ~T_WOULDBLOCK;
2383 resp->status = NFS3ERR_JUKEBOX;
2384 } else
2385 resp->status = puterrno3(error);
2386 out1:
2387 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2388 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2389 if (dvp != NULL)
2390 VN_RELE(dvp);
2391 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2392 }
2393
2394 void *
2395 rfs3_mknod_getfh(MKNOD3args *args)
2396 {
2397
2398 return (&args->where.dir);
2399 }
2400
2401 void
2402 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2403 struct svc_req *req, cred_t *cr, bool_t ro)
2404 {
2405 int error = 0;
2406 vnode_t *vp;
2407 struct vattr *bvap;
2408 struct vattr bva;
2409 struct vattr *avap;
2410 struct vattr ava;
2411 vnode_t *targvp = NULL;
2412 struct sockaddr *ca;
2413 char *name = NULL;
2414
2415 bvap = NULL;
2416 avap = NULL;
2417
2418 vp = nfs3_fhtovp(&args->object.dir, exi);
2419
2420 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2421 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2422
2423 if (vp == NULL) {
2424 error = ESTALE;
2425 goto err;
2426 }
2427
2428 bva.va_mask = AT_ALL;
2429 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2430 avap = bvap;
2431
2432 if (vp->v_type != VDIR) {
2433 resp->status = NFS3ERR_NOTDIR;
2434 goto err1;
2435 }
2436
2437 if (args->object.name == nfs3nametoolong) {
2438 resp->status = NFS3ERR_NAMETOOLONG;
2439 goto err1;
2440 }
2441
2442 if (args->object.name == NULL || *(args->object.name) == '\0') {
2443 resp->status = NFS3ERR_ACCES;
2444 goto err1;
2445 }
2446
2447 if (rdonly(ro, vp)) {
2448 resp->status = NFS3ERR_ROFS;
2449 goto err1;
2450 }
2451
2452 if (is_system_labeled()) {
2453 bslabel_t *clabel = req->rq_label;
2454
2455 ASSERT(clabel != NULL);
2456 DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
2457 "got client label from request(1)", struct svc_req *, req);
2458
2459 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2460 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2461 exi)) {
2462 resp->status = NFS3ERR_ACCES;
2463 goto err1;
2464 }
2465 }
2466 }
2467
2468 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2469 name = nfscmd_convname(ca, exi, args->object.name,
2470 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2471
2472 if (name == NULL) {
2473 resp->status = NFS3ERR_INVAL;
2474 goto err1;
2475 }
2476
2477 /*
2478 * Check for a conflict with a non-blocking mandatory share
2479 * reservation and V4 delegations
2480 */
2481 error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2482 NULL, cr, NULL, NULL, NULL);
2483 if (error != 0)
2484 goto err;
2485
2486 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2487 resp->status = NFS3ERR_JUKEBOX;
2488 goto err1;
2489 }
2490
2491 if (!nbl_need_check(targvp)) {
2492 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2493 } else {
2494 nbl_start_crit(targvp, RW_READER);
2495 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2496 error = EACCES;
2497 } else {
2498 error = VOP_REMOVE(vp, name, cr, NULL, 0);
2499 }
2500 nbl_end_crit(targvp);
2501 }
2502 VN_RELE(targvp);
2503 targvp = NULL;
2504
2505 ava.va_mask = AT_ALL;
2506 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2507
2508 /*
2509 * Force modified data and metadata out to stable storage.
2510 */
2511 (void) VOP_FSYNC(vp, 0, cr, NULL);
2512
2513 if (error)
2514 goto err;
2515
2516 resp->status = NFS3_OK;
2517 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2518 goto out;
2519
2520 err:
2521 if (curthread->t_flag & T_WOULDBLOCK) {
2522 curthread->t_flag &= ~T_WOULDBLOCK;
2523 resp->status = NFS3ERR_JUKEBOX;
2524 } else
2525 resp->status = puterrno3(error);
2526 err1:
2527 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2528 out:
2529 DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2530 cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2531
2532 if (name != NULL && name != args->object.name)
2533 kmem_free(name, MAXPATHLEN + 1);
2534
2535 if (vp != NULL)
2536 VN_RELE(vp);
2537 }
2538
2539 void *
2540 rfs3_remove_getfh(REMOVE3args *args)
2541 {
2542
2543 return (&args->object.dir);
2544 }
2545
2546 void
2547 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2548 struct svc_req *req, cred_t *cr, bool_t ro)
2549 {
2550 int error;
2551 vnode_t *vp;
2552 struct vattr *bvap;
2553 struct vattr bva;
2554 struct vattr *avap;
2555 struct vattr ava;
2556 struct sockaddr *ca;
2557 char *name = NULL;
2558
2559 bvap = NULL;
2560 avap = NULL;
2561
2562 vp = nfs3_fhtovp(&args->object.dir, exi);
2563
2564 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2565 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2566
2567 if (vp == NULL) {
2568 error = ESTALE;
2569 goto err;
2570 }
2571
2572 bva.va_mask = AT_ALL;
2573 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2574 avap = bvap;
2575
2576 if (vp->v_type != VDIR) {
2577 resp->status = NFS3ERR_NOTDIR;
2578 goto err1;
2579 }
2580
2581 if (args->object.name == nfs3nametoolong) {
2582 resp->status = NFS3ERR_NAMETOOLONG;
2583 goto err1;
2584 }
2585
2586 if (args->object.name == NULL || *(args->object.name) == '\0') {
2587 resp->status = NFS3ERR_ACCES;
2588 goto err1;
2589 }
2590
2591 if (rdonly(ro, vp)) {
2592 resp->status = NFS3ERR_ROFS;
2593 goto err1;
2594 }
2595
2596 if (is_system_labeled()) {
2597 bslabel_t *clabel = req->rq_label;
2598
2599 ASSERT(clabel != NULL);
2600 DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
2601 "got client label from request(1)", struct svc_req *, req);
2602
2603 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2604 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2605 exi)) {
2606 resp->status = NFS3ERR_ACCES;
2607 goto err1;
2608 }
2609 }
2610 }
2611
2612 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2613 name = nfscmd_convname(ca, exi, args->object.name,
2614 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2615
2616 if (name == NULL) {
2617 resp->status = NFS3ERR_INVAL;
2618 goto err1;
2619 }
2620
2621 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2622
2623 if (name != args->object.name)
2624 kmem_free(name, MAXPATHLEN + 1);
2625
2626 ava.va_mask = AT_ALL;
2627 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2628
2629 /*
2630 * Force modified data and metadata out to stable storage.
2631 */
2632 (void) VOP_FSYNC(vp, 0, cr, NULL);
2633
2634 if (error) {
2635 /*
2636 * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2637 * if the directory is not empty. A System V NFS server
2638 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2639 * over the wire.
2640 */
2641 if (error == EEXIST)
2642 error = ENOTEMPTY;
2643 goto err;
2644 }
2645
2646 resp->status = NFS3_OK;
2647 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2648 goto out;
2649
2650 err:
2651 if (curthread->t_flag & T_WOULDBLOCK) {
2652 curthread->t_flag &= ~T_WOULDBLOCK;
2653 resp->status = NFS3ERR_JUKEBOX;
2654 } else
2655 resp->status = puterrno3(error);
2656 err1:
2657 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2658 out:
2659 DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2660 cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2661 if (vp != NULL)
2662 VN_RELE(vp);
2663
2664 }
2665
2666 void *
2667 rfs3_rmdir_getfh(RMDIR3args *args)
2668 {
2669
2670 return (&args->object.dir);
2671 }
2672
2673 void
2674 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2675 struct svc_req *req, cred_t *cr, bool_t ro)
2676 {
2677 int error = 0;
2678 vnode_t *fvp;
2679 vnode_t *tvp;
2680 vnode_t *targvp;
2681 struct vattr *fbvap;
2682 struct vattr fbva;
2683 struct vattr *favap;
2684 struct vattr fava;
2685 struct vattr *tbvap;
2686 struct vattr tbva;
2687 struct vattr *tavap;
2688 struct vattr tava;
2689 nfs_fh3 *fh3;
2690 struct exportinfo *to_exi;
2691 vnode_t *srcvp = NULL;
2692 bslabel_t *clabel;
2693 struct sockaddr *ca;
2694 char *name = NULL;
2695 char *toname = NULL;
2696
2697 fbvap = NULL;
2698 favap = NULL;
2699 tbvap = NULL;
2700 tavap = NULL;
2701 tvp = NULL;
2702
2703 fvp = nfs3_fhtovp(&args->from.dir, exi);
2704
2705 DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2706 cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2707
2708 if (fvp == NULL) {
2709 error = ESTALE;
2710 goto err;
2711 }
2712
2713 if (is_system_labeled()) {
2714 clabel = req->rq_label;
2715 ASSERT(clabel != NULL);
2716 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2717 "got client label from request(1)", struct svc_req *, req);
2718
2719 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2720 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2721 exi)) {
2722 resp->status = NFS3ERR_ACCES;
2723 goto err1;
2724 }
2725 }
2726 }
2727
2728 fbva.va_mask = AT_ALL;
2729 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2730 favap = fbvap;
2731
2732 fh3 = &args->to.dir;
2733 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2734 if (to_exi == NULL) {
2735 resp->status = NFS3ERR_ACCES;
2736 goto err1;
2737 }
2738 exi_rele(to_exi);
2739
2740 if (to_exi != exi) {
2741 resp->status = NFS3ERR_XDEV;
2742 goto err1;
2743 }
2744
2745 tvp = nfs3_fhtovp(&args->to.dir, exi);
2746 if (tvp == NULL) {
2747 error = ESTALE;
2748 goto err;
2749 }
2750
2751 tbva.va_mask = AT_ALL;
2752 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2753 tavap = tbvap;
2754
2755 if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2756 resp->status = NFS3ERR_NOTDIR;
2757 goto err1;
2758 }
2759
2760 if (args->from.name == nfs3nametoolong ||
2761 args->to.name == nfs3nametoolong) {
2762 resp->status = NFS3ERR_NAMETOOLONG;
2763 goto err1;
2764 }
2765 if (args->from.name == NULL || *(args->from.name) == '\0' ||
2766 args->to.name == NULL || *(args->to.name) == '\0') {
2767 resp->status = NFS3ERR_ACCES;
2768 goto err1;
2769 }
2770
2771 if (rdonly(ro, tvp)) {
2772 resp->status = NFS3ERR_ROFS;
2773 goto err1;
2774 }
2775
2776 if (is_system_labeled()) {
2777 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2778 if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2779 exi)) {
2780 resp->status = NFS3ERR_ACCES;
2781 goto err1;
2782 }
2783 }
2784 }
2785
2786 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2787 name = nfscmd_convname(ca, exi, args->from.name,
2788 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2789
2790 if (name == NULL) {
2791 resp->status = NFS3ERR_INVAL;
2792 goto err1;
2793 }
2794
2795 toname = nfscmd_convname(ca, exi, args->to.name,
2796 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2797
2798 if (toname == NULL) {
2799 resp->status = NFS3ERR_INVAL;
2800 goto err1;
2801 }
2802
2803 /*
2804 * Check for a conflict with a non-blocking mandatory share
2805 * reservation or V4 delegations.
2806 */
2807 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2808 NULL, cr, NULL, NULL, NULL);
2809 if (error != 0)
2810 goto err;
2811
2812 /*
2813 * If we rename a delegated file we should recall the
2814 * delegation, since future opens should fail or would
2815 * refer to a new file.
2816 */
2817 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2818 resp->status = NFS3ERR_JUKEBOX;
2819 goto err1;
2820 }
2821
2822 /*
2823 * Check for renaming over a delegated file. Check rfs4_deleg_policy
2824 * first to avoid VOP_LOOKUP if possible.
2825 */
2826 if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2827 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2828 NULL, NULL, NULL) == 0) {
2829
2830 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2831 VN_RELE(targvp);
2832 resp->status = NFS3ERR_JUKEBOX;
2833 goto err1;
2834 }
2835 VN_RELE(targvp);
2836 }
2837
2838 if (!nbl_need_check(srcvp)) {
2839 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2840 } else {
2841 nbl_start_crit(srcvp, RW_READER);
2842 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2843 error = EACCES;
2844 else
2845 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2846 nbl_end_crit(srcvp);
2847 }
2848 if (error == 0)
2849 vn_renamepath(tvp, srcvp, args->to.name,
2850 strlen(args->to.name));
2851 VN_RELE(srcvp);
2852 srcvp = NULL;
2853
2854 fava.va_mask = AT_ALL;
2855 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2856 tava.va_mask = AT_ALL;
2857 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2858
2859 /*
2860 * Force modified data and metadata out to stable storage.
2861 */
2862 (void) VOP_FSYNC(fvp, 0, cr, NULL);
2863 (void) VOP_FSYNC(tvp, 0, cr, NULL);
2864
2865 if (error)
2866 goto err;
2867
2868 resp->status = NFS3_OK;
2869 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
2870 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2871 goto out;
2872
2873 err:
2874 if (curthread->t_flag & T_WOULDBLOCK) {
2875 curthread->t_flag &= ~T_WOULDBLOCK;
2876 resp->status = NFS3ERR_JUKEBOX;
2877 } else {
2878 resp->status = puterrno3(error);
2879 }
2880 err1:
2881 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2882 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2883
2884 out:
2885 if (name != NULL && name != args->from.name)
2886 kmem_free(name, MAXPATHLEN + 1);
2887 if (toname != NULL && toname != args->to.name)
2888 kmem_free(toname, MAXPATHLEN + 1);
2889
2890 DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2891 cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
2892 if (fvp != NULL)
2893 VN_RELE(fvp);
2894 if (tvp != NULL)
2895 VN_RELE(tvp);
2896 }
2897
2898 void *
2899 rfs3_rename_getfh(RENAME3args *args)
2900 {
2901
2902 return (&args->from.dir);
2903 }
2904
2905 void
2906 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2907 struct svc_req *req, cred_t *cr, bool_t ro)
2908 {
2909 int error;
2910 vnode_t *vp;
2911 vnode_t *dvp;
2912 struct vattr *vap;
2913 struct vattr va;
2914 struct vattr *bvap;
2915 struct vattr bva;
2916 struct vattr *avap;
2917 struct vattr ava;
2918 nfs_fh3 *fh3;
2919 struct exportinfo *to_exi;
2920 bslabel_t *clabel;
2921 struct sockaddr *ca;
2922 char *name = NULL;
2923
2924 vap = NULL;
2925 bvap = NULL;
2926 avap = NULL;
2927 dvp = NULL;
2928
2929 vp = nfs3_fhtovp(&args->file, exi);
2930
2931 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2932 cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2933
2934 if (vp == NULL) {
2935 error = ESTALE;
2936 goto out;
2937 }
2938
2939 va.va_mask = AT_ALL;
2940 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2941
2942 fh3 = &args->link.dir;
2943 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2944 if (to_exi == NULL) {
2945 resp->status = NFS3ERR_ACCES;
2946 goto out1;
2947 }
2948 exi_rele(to_exi);
2949
2950 if (to_exi != exi) {
2951 resp->status = NFS3ERR_XDEV;
2952 goto out1;
2953 }
2954
2955 if (is_system_labeled()) {
2956 clabel = req->rq_label;
2957
2958 ASSERT(clabel != NULL);
2959 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
2960 "got client label from request(1)", struct svc_req *, req);
2961
2962 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2963 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2964 exi)) {
2965 resp->status = NFS3ERR_ACCES;
2966 goto out1;
2967 }
2968 }
2969 }
2970
2971 dvp = nfs3_fhtovp(&args->link.dir, exi);
2972 if (dvp == NULL) {
2973 error = ESTALE;
2974 goto out;
2975 }
2976
2977 bva.va_mask = AT_ALL;
2978 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
2979
2980 if (dvp->v_type != VDIR) {
2981 resp->status = NFS3ERR_NOTDIR;
2982 goto out1;
2983 }
2984
2985 if (args->link.name == nfs3nametoolong) {
2986 resp->status = NFS3ERR_NAMETOOLONG;
2987 goto out1;
2988 }
2989
2990 if (args->link.name == NULL || *(args->link.name) == '\0') {
2991 resp->status = NFS3ERR_ACCES;
2992 goto out1;
2993 }
2994
2995 if (rdonly(ro, dvp)) {
2996 resp->status = NFS3ERR_ROFS;
2997 goto out1;
2998 }
2999
3000 if (is_system_labeled()) {
3001 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3002 "got client label from request(1)", struct svc_req *, req);
3003
3004 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3005 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3006 exi)) {
3007 resp->status = NFS3ERR_ACCES;
3008 goto out1;
3009 }
3010 }
3011 }
3012
3013 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3014 name = nfscmd_convname(ca, exi, args->link.name,
3015 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3016
3017 if (name == NULL) {
3018 resp->status = NFS3ERR_SERVERFAULT;
3019 goto out1;
3020 }
3021
3022 error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3023
3024 va.va_mask = AT_ALL;
3025 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3026 ava.va_mask = AT_ALL;
3027 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3028
3029 /*
3030 * Force modified data and metadata out to stable storage.
3031 */
3032 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3033 (void) VOP_FSYNC(dvp, 0, cr, NULL);
3034
3035 if (error)
3036 goto out;
3037
3038 VN_RELE(dvp);
3039
3040 resp->status = NFS3_OK;
3041 vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3042 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3043
3044 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3045 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3046
3047 VN_RELE(vp);
3048
3049 return;
3050
3051 out:
3052 if (curthread->t_flag & T_WOULDBLOCK) {
3053 curthread->t_flag &= ~T_WOULDBLOCK;
3054 resp->status = NFS3ERR_JUKEBOX;
3055 } else
3056 resp->status = puterrno3(error);
3057 out1:
3058 if (name != NULL && name != args->link.name)
3059 kmem_free(name, MAXPATHLEN + 1);
3060
3061 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3062 cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3063
3064 if (vp != NULL)
3065 VN_RELE(vp);
3066 if (dvp != NULL)
3067 VN_RELE(dvp);
3068 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3069 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3070 }
3071
3072 void *
3073 rfs3_link_getfh(LINK3args *args)
3074 {
3075
3076 return (&args->file);
3077 }
3078
3079 /*
3080 * This macro defines the size of a response which contains attribute
3081 * information and one directory entry (whose length is specified by
3082 * the macro parameter). If the incoming request is larger than this,
3083 * then we are guaranteed to be able to return at one directory entry
3084 * if one exists. Therefore, we do not need to check for
3085 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it
3086 * is not, then we need to check to make sure that this error does not
3087 * need to be returned.
3088 *
3089 * NFS3_READDIR_MIN_COUNT is comprised of following :
3090 *
3091 * status - 1 * BYTES_PER_XDR_UNIT
3092 * attr. flag - 1 * BYTES_PER_XDR_UNIT
3093 * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3094 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3095 * boolean - 1 * BYTES_PER_XDR_UNIT
3096 * file id - 2 * BYTES_PER_XDR_UNIT
3097 * directory name length - 1 * BYTES_PER_XDR_UNIT
3098 * cookie - 2 * BYTES_PER_XDR_UNIT
3099 * end of list - 1 * BYTES_PER_XDR_UNIT
3100 * end of file - 1 * BYTES_PER_XDR_UNIT
3101 * Name length of directory to the nearest byte
3102 */
3103
3104 #define NFS3_READDIR_MIN_COUNT(length) \
3105 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3106 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3107
3108 /* ARGSUSED */
3109 void
3110 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3111 struct svc_req *req, cred_t *cr, bool_t ro)
3112 {
3113 int error;
3114 vnode_t *vp;
3115 struct vattr *vap;
3116 struct vattr va;
3117 struct iovec iov;
3118 struct uio uio;
3119 char *data;
3120 int iseof;
3121 int bufsize;
3122 int namlen;
3123 uint_t count;
3124 struct sockaddr *ca;
3125
3126 vap = NULL;
3127
3128 vp = nfs3_fhtovp(&args->dir, exi);
3129
3130 DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3131 cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3132
3133 if (vp == NULL) {
3134 error = ESTALE;
3135 goto out;
3136 }
3137
3138 if (is_system_labeled()) {
3139 bslabel_t *clabel = req->rq_label;
3140
3141 ASSERT(clabel != NULL);
3142 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3143 "got client label from request(1)", struct svc_req *, req);
3144
3145 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3146 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3147 exi)) {
3148 resp->status = NFS3ERR_ACCES;
3149 goto out1;
3150 }
3151 }
3152 }
3153
3154 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3155
3156 va.va_mask = AT_ALL;
3157 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3158
3159 if (vp->v_type != VDIR) {
3160 resp->status = NFS3ERR_NOTDIR;
3161 goto out1;
3162 }
3163
3164 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3165 if (error)
3166 goto out;
3167
3168 /*
3169 * Now don't allow arbitrary count to alloc;
3170 * allow the maximum not to exceed rfs3_tsize()
3171 */
3172 if (args->count > rfs3_tsize(req))
3173 args->count = rfs3_tsize(req);
3174
3175 /*
3176 * Make sure that there is room to read at least one entry
3177 * if any are available.
3178 */
3179 if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3180 count = DIRENT64_RECLEN(MAXNAMELEN);
3181 else
3182 count = args->count;
3183
3184 data = kmem_alloc(count, KM_SLEEP);
3185
3186 iov.iov_base = data;
3187 iov.iov_len = count;
3188 uio.uio_iov = &iov;
3189 uio.uio_iovcnt = 1;
3190 uio.uio_segflg = UIO_SYSSPACE;
3191 uio.uio_extflg = UIO_COPY_CACHED;
3192 uio.uio_loffset = (offset_t)args->cookie;
3193 uio.uio_resid = count;
3194
3195 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3196
3197 va.va_mask = AT_ALL;
3198 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3199
3200 if (error) {
3201 kmem_free(data, count);
3202 goto out;
3203 }
3204
3205 /*
3206 * If the count was not large enough to be able to guarantee
3207 * to be able to return at least one entry, then need to
3208 * check to see if NFS3ERR_TOOSMALL should be returned.
3209 */
3210 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3211 /*
3212 * bufsize is used to keep track of the size of the response.
3213 * It is primed with:
3214 * 1 for the status +
3215 * 1 for the dir_attributes.attributes boolean +
3216 * 2 for the cookie verifier
3217 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3218 * to bytes. If there are directory attributes to be
3219 * returned, then:
3220 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3221 * time BYTES_PER_XDR_UNIT is added to account for them.
3222 */
3223 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3224 if (vap != NULL)
3225 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3226 /*
3227 * An entry is composed of:
3228 * 1 for the true/false list indicator +
3229 * 2 for the fileid +
3230 * 1 for the length of the name +
3231 * 2 for the cookie +
3232 * all times BYTES_PER_XDR_UNIT to convert from
3233 * XDR units to bytes, plus the length of the name
3234 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3235 */
3236 if (count != uio.uio_resid) {
3237 namlen = strlen(((struct dirent64 *)data)->d_name);
3238 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3239 roundup(namlen, BYTES_PER_XDR_UNIT);
3240 }
3241 /*
3242 * We need to check to see if the number of bytes left
3243 * to go into the buffer will actually fit into the
3244 * buffer. This is calculated as the size of this
3245 * entry plus:
3246 * 1 for the true/false list indicator +
3247 * 1 for the eof indicator
3248 * times BYTES_PER_XDR_UNIT to convert from from
3249 * XDR units to bytes.
3250 */
3251 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3252 if (bufsize > args->count) {
3253 kmem_free(data, count);
3254 resp->status = NFS3ERR_TOOSMALL;
3255 goto out1;
3256 }
3257 }
3258
3259 /*
3260 * Have a valid readir buffer for the native character
3261 * set. Need to check if a conversion is necessary and
3262 * potentially rewrite the whole buffer. Note that if the
3263 * conversion expands names enough, the structure may not
3264 * fit. In this case, we need to drop entries until if fits
3265 * and patch the counts in order that the next readdir will
3266 * get the correct entries.
3267 */
3268 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3269 data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3270
3271
3272 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3273
3274 #if 0 /* notyet */
3275 /*
3276 * Don't do this. It causes local disk writes when just
3277 * reading the file and the overhead is deemed larger
3278 * than the benefit.
3279 */
3280 /*
3281 * Force modified metadata out to stable storage.
3282 */
3283 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3284 #endif
3285
3286 resp->status = NFS3_OK;
3287 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3288 resp->resok.cookieverf = 0;
3289 resp->resok.reply.entries = (entry3 *)data;
3290 resp->resok.reply.eof = iseof;
3291 resp->resok.size = count - uio.uio_resid;
3292 resp->resok.count = args->count;
3293 resp->resok.freecount = count;
3294
3295 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3296 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3297
3298 VN_RELE(vp);
3299
3300 return;
3301
3302 out:
3303 if (curthread->t_flag & T_WOULDBLOCK) {
3304 curthread->t_flag &= ~T_WOULDBLOCK;
3305 resp->status = NFS3ERR_JUKEBOX;
3306 } else
3307 resp->status = puterrno3(error);
3308 out1:
3309 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3310 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3311
3312 if (vp != NULL) {
3313 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3314 VN_RELE(vp);
3315 }
3316 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3317 }
3318
3319 void *
3320 rfs3_readdir_getfh(READDIR3args *args)
3321 {
3322
3323 return (&args->dir);
3324 }
3325
3326 void
3327 rfs3_readdir_free(READDIR3res *resp)
3328 {
3329
3330 if (resp->status == NFS3_OK)
3331 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3332 }
3333
3334 #ifdef nextdp
3335 #undef nextdp
3336 #endif
3337 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3338
3339 /*
3340 * This macro computes the size of a response which contains
3341 * one directory entry including the attributes as well as file handle.
3342 * If the incoming request is larger than this, then we are guaranteed to be
3343 * able to return at least one more directory entry if one exists.
3344 *
3345 * NFS3_READDIRPLUS_ENTRY is made up of the following:
3346 *
3347 * boolean - 1 * BYTES_PER_XDR_UNIT
3348 * file id - 2 * BYTES_PER_XDR_UNIT
3349 * directory name length - 1 * BYTES_PER_XDR_UNIT
3350 * cookie - 2 * BYTES_PER_XDR_UNIT
3351 * attribute flag - 1 * BYTES_PER_XDR_UNIT
3352 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3353 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT
3354 * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3355 * Maximum length of a file handle (NFS3_MAXFHSIZE)
3356 * name length of the entry to the nearest bytes
3357 */
3358 #define NFS3_READDIRPLUS_ENTRY(namelen) \
3359 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3360 BYTES_PER_XDR_UNIT + \
3361 NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3362
3363 static int rfs3_readdir_unit = MAXBSIZE;
3364
3365 /* ARGSUSED */
3366 void
3367 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3368 struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3369 {
3370 int error;
3371 vnode_t *vp;
3372 struct vattr *vap;
3373 struct vattr va;
3374 struct iovec iov;
3375 struct uio uio;
3376 char *data;
3377 int iseof;
3378 struct dirent64 *dp;
3379 vnode_t *nvp;
3380 struct vattr *nvap;
3381 struct vattr nva;
3382 entryplus3_info *infop = NULL;
3383 int size = 0;
3384 int nents = 0;
3385 int bufsize = 0;
3386 int entrysize = 0;
3387 int tofit = 0;
3388 int rd_unit = rfs3_readdir_unit;
3389 int prev_len;
3390 int space_left;
3391 int i;
3392 uint_t *namlen = NULL;
3393 char *ndata = NULL;
3394 struct sockaddr *ca;
3395 size_t ret;
3396
3397 vap = NULL;
3398
3399 vp = nfs3_fhtovp(&args->dir, exi);
3400
3401 DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3402 cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3403
3404 if (vp == NULL) {
3405 error = ESTALE;
3406 goto out;
3407 }
3408
3409 if (is_system_labeled()) {
3410 bslabel_t *clabel = req->rq_label;
3411
3412 ASSERT(clabel != NULL);
3413 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3414 char *, "got client label from request(1)",
3415 struct svc_req *, req);
3416
3417 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3418 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3419 exi)) {
3420 resp->status = NFS3ERR_ACCES;
3421 goto out1;
3422 }
3423 }
3424 }
3425
3426 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3427
3428 va.va_mask = AT_ALL;
3429 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3430
3431 if (vp->v_type != VDIR) {
3432 error = ENOTDIR;
3433 goto out;
3434 }
3435
3436 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3437 if (error)
3438 goto out;
3439
3440 /*
3441 * Don't allow arbitrary counts for allocation
3442 */
3443 if (args->maxcount > rfs3_tsize(req))
3444 args->maxcount = rfs3_tsize(req);
3445
3446 /*
3447 * Make sure that there is room to read at least one entry
3448 * if any are available
3449 */
3450 args->dircount = MIN(args->dircount, args->maxcount);
3451
3452 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3453 args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3454
3455 /*
3456 * This allocation relies on a minimum directory entry
3457 * being roughly 24 bytes. Therefore, the namlen array
3458 * will have enough space based on the maximum number of
3459 * entries to read.
3460 */
3461 namlen = kmem_alloc(args->dircount, KM_SLEEP);
3462
3463 space_left = args->dircount;
3464 data = kmem_alloc(args->dircount, KM_SLEEP);
3465 dp = (struct dirent64 *)data;
3466 uio.uio_iov = &iov;
3467 uio.uio_iovcnt = 1;
3468 uio.uio_segflg = UIO_SYSSPACE;
3469 uio.uio_extflg = UIO_COPY_CACHED;
3470 uio.uio_loffset = (offset_t)args->cookie;
3471
3472 /*
3473 * bufsize is used to keep track of the size of the response as we
3474 * get post op attributes and filehandles for each entry. This is
3475 * an optimization as the server may have read more entries than will
3476 * fit in the buffer specified by maxcount. We stop calculating
3477 * post op attributes and filehandles once we have exceeded maxcount.
3478 * This will minimize the effect of truncation.
3479 *
3480 * It is primed with:
3481 * 1 for the status +
3482 * 1 for the dir_attributes.attributes boolean +
3483 * 2 for the cookie verifier
3484 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3485 * to bytes. If there are directory attributes to be
3486 * returned, then:
3487 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3488 * time BYTES_PER_XDR_UNIT is added to account for them.
3489 */
3490 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3491 if (vap != NULL)
3492 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3493
3494 getmoredents:
3495 /*
3496 * Here we make a check so that our read unit is not larger than
3497 * the space left in the buffer.
3498 */
3499 rd_unit = MIN(rd_unit, space_left);
3500 iov.iov_base = (char *)dp;
3501 iov.iov_len = rd_unit;
3502 uio.uio_resid = rd_unit;
3503 prev_len = rd_unit;
3504
3505 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3506
3507 if (error) {
3508 kmem_free(data, args->dircount);
3509 goto out;
3510 }
3511
3512 if (uio.uio_resid == prev_len && !iseof) {
3513 if (nents == 0) {
3514 kmem_free(data, args->dircount);
3515 resp->status = NFS3ERR_TOOSMALL;
3516 goto out1;
3517 }
3518
3519 /*
3520 * We could not get any more entries, so get the attributes
3521 * and filehandle for the entries already obtained.
3522 */
3523 goto good;
3524 }
3525
3526 /*
3527 * We estimate the size of the response by assuming the
3528 * entry exists and attributes and filehandle are also valid
3529 */
3530 for (size = prev_len - uio.uio_resid;
3531 size > 0;
3532 size -= dp->d_reclen, dp = nextdp(dp)) {
3533
3534 if (dp->d_ino == 0) {
3535 nents++;
3536 continue;
3537 }
3538
3539 namlen[nents] = strlen(dp->d_name);
3540 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3541
3542 /*
3543 * We need to check to see if the number of bytes left
3544 * to go into the buffer will actually fit into the
3545 * buffer. This is calculated as the size of this
3546 * entry plus:
3547 * 1 for the true/false list indicator +
3548 * 1 for the eof indicator
3549 * times BYTES_PER_XDR_UNIT to convert from XDR units
3550 * to bytes.
3551 *
3552 * Also check the dircount limit against the first entry read
3553 *
3554 */
3555 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3556 if (bufsize + tofit > args->maxcount) {
3557 /*
3558 * We make a check here to see if this was the
3559 * first entry being measured. If so, then maxcount
3560 * was too small to begin with and so we need to
3561 * return with NFS3ERR_TOOSMALL.
3562 */
3563 if (nents == 0) {
3564 kmem_free(data, args->dircount);
3565 resp->status = NFS3ERR_TOOSMALL;
3566 goto out1;
3567 }
3568 iseof = FALSE;
3569 goto good;
3570 }
3571 bufsize += entrysize;
3572 nents++;
3573 }
3574
3575 /*
3576 * If there is enough room to fit at least 1 more entry including
3577 * post op attributes and filehandle in the buffer AND that we haven't
3578 * exceeded dircount then go back and get some more.
3579 */
3580 if (!iseof &&
3581 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3582 space_left -= (prev_len - uio.uio_resid);
3583 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3584 goto getmoredents;
3585
3586 /* else, fall through */
3587 }
3588 good:
3589 va.va_mask = AT_ALL;
3590 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3591
3592 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3593
3594 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3595 resp->resok.infop = infop;
3596
3597 dp = (struct dirent64 *)data;
3598 for (i = 0; i < nents; i++) {
3599
3600 if (dp->d_ino == 0) {
3601 infop[i].attr.attributes = FALSE;
3602 infop[i].fh.handle_follows = FALSE;
3603 dp = nextdp(dp);
3604 continue;
3605 }
3606
3607 infop[i].namelen = namlen[i];
3608
3609 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3610 NULL, NULL, NULL);
3611 if (error) {
3612 infop[i].attr.attributes = FALSE;
3613 infop[i].fh.handle_follows = FALSE;
3614 dp = nextdp(dp);
3615 continue;
3616 }
3617
3618 nva.va_mask = AT_ALL;
3619 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3620
3621 /* Lie about the object type for a referral */
3622 if (vn_is_nfs_reparse(nvp, cr))
3623 nvap->va_type = VLNK;
3624
3625 if (vn_ismntpt(nvp)) {
3626 infop[i].attr.attributes = FALSE;
3627 infop[i].fh.handle_follows = FALSE;
3628 } else {
3629 vattr_to_post_op_attr(nvap, &infop[i].attr);
3630
3631 error = makefh3(&infop[i].fh.handle, nvp, exi);
3632 if (!error)
3633 infop[i].fh.handle_follows = TRUE;
3634 else
3635 infop[i].fh.handle_follows = FALSE;
3636 }
3637
3638 VN_RELE(nvp);
3639 dp = nextdp(dp);
3640 }
3641
3642 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3643 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3644 if (ndata == NULL)
3645 ndata = data;
3646
3647 if (ret > 0) {
3648 /*
3649 * We had to drop one or more entries in order to fit
3650 * during the character conversion. We need to patch
3651 * up the size and eof info.
3652 */
3653 if (iseof)
3654 iseof = FALSE;
3655
3656 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3657 nents, ret);
3658 }
3659
3660
3661 #if 0 /* notyet */
3662 /*
3663 * Don't do this. It causes local disk writes when just
3664 * reading the file and the overhead is deemed larger
3665 * than the benefit.
3666 */
3667 /*
3668 * Force modified metadata out to stable storage.
3669 */
3670 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3671 #endif
3672
3673 kmem_free(namlen, args->dircount);
3674
3675 resp->status = NFS3_OK;
3676 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3677 resp->resok.cookieverf = 0;
3678 resp->resok.reply.entries = (entryplus3 *)ndata;
3679 resp->resok.reply.eof = iseof;
3680 resp->resok.size = nents;
3681 resp->resok.count = args->dircount - ret;
3682 resp->resok.maxcount = args->maxcount;
3683
3684 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686 if (ndata != data)
3687 kmem_free(data, args->dircount);
3688
3689
3690 VN_RELE(vp);
3691
3692 return;
3693
3694 out:
3695 if (curthread->t_flag & T_WOULDBLOCK) {
3696 curthread->t_flag &= ~T_WOULDBLOCK;
3697 resp->status = NFS3ERR_JUKEBOX;
3698 } else {
3699 resp->status = puterrno3(error);
3700 }
3701 out1:
3702 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3703 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3704
3705 if (vp != NULL) {
3706 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3707 VN_RELE(vp);
3708 }
3709
3710 if (namlen != NULL)
3711 kmem_free(namlen, args->dircount);
3712
3713 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3714 }
3715
3716 void *
3717 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3718 {
3719
3720 return (&args->dir);
3721 }
3722
3723 void
3724 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3725 {
3726
3727 if (resp->status == NFS3_OK) {
3728 kmem_free(resp->resok.reply.entries, resp->resok.count);
3729 kmem_free(resp->resok.infop,
3730 resp->resok.size * sizeof (struct entryplus3_info));
3731 }
3732 }
3733
3734 /* ARGSUSED */
3735 void
3736 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3737 struct svc_req *req, cred_t *cr, bool_t ro)
3738 {
3739 int error;
3740 vnode_t *vp;
3741 struct vattr *vap;
3742 struct vattr va;
3743 struct statvfs64 sb;
3744
3745 vap = NULL;
3746
3747 vp = nfs3_fhtovp(&args->fsroot, exi);
3748
3749 DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3750 cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3751
3752 if (vp == NULL) {
3753 error = ESTALE;
3754 goto out;
3755 }
3756
3757 if (is_system_labeled()) {
3758 bslabel_t *clabel = req->rq_label;
3759
3760 ASSERT(clabel != NULL);
3761 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3762 "got client label from request(1)", struct svc_req *, req);
3763
3764 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3765 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3766 exi)) {
3767 resp->status = NFS3ERR_ACCES;
3768 goto out1;
3769 }
3770 }
3771 }
3772
3773 error = VFS_STATVFS(vp->v_vfsp, &sb);
3774
3775 va.va_mask = AT_ALL;
3776 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3777
3778 if (error)
3779 goto out;
3780
3781 resp->status = NFS3_OK;
3782 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3783 if (sb.f_blocks != (fsblkcnt64_t)-1)
3784 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3785 else
3786 resp->resok.tbytes = (size3)sb.f_blocks;
3787 if (sb.f_bfree != (fsblkcnt64_t)-1)
3788 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3789 else
3790 resp->resok.fbytes = (size3)sb.f_bfree;
3791 if (sb.f_bavail != (fsblkcnt64_t)-1)
3792 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3793 else
3794 resp->resok.abytes = (size3)sb.f_bavail;
3795 resp->resok.tfiles = (size3)sb.f_files;
3796 resp->resok.ffiles = (size3)sb.f_ffree;
3797 resp->resok.afiles = (size3)sb.f_favail;
3798 resp->resok.invarsec = 0;
3799
3800 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3801 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3802 VN_RELE(vp);
3803
3804 return;
3805
3806 out:
3807 if (curthread->t_flag & T_WOULDBLOCK) {
3808 curthread->t_flag &= ~T_WOULDBLOCK;
3809 resp->status = NFS3ERR_JUKEBOX;
3810 } else
3811 resp->status = puterrno3(error);
3812 out1:
3813 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3814 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3815
3816 if (vp != NULL)
3817 VN_RELE(vp);
3818 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3819 }
3820
3821 void *
3822 rfs3_fsstat_getfh(FSSTAT3args *args)
3823 {
3824
3825 return (&args->fsroot);
3826 }
3827
3828 /* ARGSUSED */
3829 void
3830 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3831 struct svc_req *req, cred_t *cr, bool_t ro)
3832 {
3833 vnode_t *vp;
3834 struct vattr *vap;
3835 struct vattr va;
3836 uint32_t xfer_size;
3837 ulong_t l = 0;
3838 int error;
3839
3840 vp = nfs3_fhtovp(&args->fsroot, exi);
3841
3842 DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3843 cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3844
3845 if (vp == NULL) {
3846 if (curthread->t_flag & T_WOULDBLOCK) {
3847 curthread->t_flag &= ~T_WOULDBLOCK;
3848 resp->status = NFS3ERR_JUKEBOX;
3849 } else
3850 resp->status = NFS3ERR_STALE;
3851 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3852 goto out;
3853 }
3854
3855 if (is_system_labeled()) {
3856 bslabel_t *clabel = req->rq_label;
3857
3858 ASSERT(clabel != NULL);
3859 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3860 "got client label from request(1)", struct svc_req *, req);
3861
3862 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3863 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3864 exi)) {
3865 resp->status = NFS3ERR_STALE;
3866 vattr_to_post_op_attr(NULL,
3867 &resp->resfail.obj_attributes);
3868 goto out;
3869 }
3870 }
3871 }
3872
3873 va.va_mask = AT_ALL;
3874 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3875
3876 resp->status = NFS3_OK;
3877 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3878 xfer_size = rfs3_tsize(req);
3879 resp->resok.rtmax = xfer_size;
3880 resp->resok.rtpref = xfer_size;
3881 resp->resok.rtmult = DEV_BSIZE;
3882 resp->resok.wtmax = xfer_size;
3883 resp->resok.wtpref = xfer_size;
3884 resp->resok.wtmult = DEV_BSIZE;
3885 resp->resok.dtpref = MAXBSIZE;
3886
3887 /*
3888 * Large file spec: want maxfilesize based on limit of
3889 * underlying filesystem. We can guess 2^31-1 if need be.
3890 */
3891 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3892 if (error) {
3893 resp->status = puterrno3(error);
3894 goto out;
3895 }
3896
3897 /*
3898 * If the underlying file system does not support _PC_FILESIZEBITS,
3899 * return a reasonable default. Note that error code on VOP_PATHCONF
3900 * will be 0, even if the underlying file system does not support
3901 * _PC_FILESIZEBITS.
3902 */
3903 if (l == (ulong_t)-1) {
3904 resp->resok.maxfilesize = MAXOFF32_T;
3905 } else {
3906 if (l >= (sizeof (uint64_t) * 8))
3907 resp->resok.maxfilesize = INT64_MAX;
3908 else
3909 resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3910 }
3911
3912 resp->resok.time_delta.seconds = 0;
3913 resp->resok.time_delta.nseconds = 1000;
3914 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3915 FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3916
3917 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3918 cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3919
3920 VN_RELE(vp);
3921
3922 return;
3923
3924 out:
3925 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3926 cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3927 if (vp != NULL)
3928 VN_RELE(vp);
3929 }
3930
3931 void *
3932 rfs3_fsinfo_getfh(FSINFO3args *args)
3933 {
3934 return (&args->fsroot);
3935 }
3936
3937 /* ARGSUSED */
3938 void
3939 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3940 struct svc_req *req, cred_t *cr, bool_t ro)
3941 {
3942 int error;
3943 vnode_t *vp;
3944 struct vattr *vap;
3945 struct vattr va;
3946 ulong_t val;
3947
3948 vap = NULL;
3949
3950 vp = nfs3_fhtovp(&args->object, exi);
3951
3952 DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3953 cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3954
3955 if (vp == NULL) {
3956 error = ESTALE;
3957 goto out;
3958 }
3959
3960 if (is_system_labeled()) {
3961 bslabel_t *clabel = req->rq_label;
3962
3963 ASSERT(clabel != NULL);
3964 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3965 "got client label from request(1)", struct svc_req *, req);
3966
3967 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3968 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3969 exi)) {
3970 resp->status = NFS3ERR_ACCES;
3971 goto out1;
3972 }
3973 }
3974 }
3975
3976 va.va_mask = AT_ALL;
3977 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3978
3979 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
3980 if (error)
3981 goto out;
3982 resp->resok.info.link_max = (uint32)val;
3983
3984 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
3985 if (error)
3986 goto out;
3987 resp->resok.info.name_max = (uint32)val;
3988
3989 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3990 if (error)
3991 goto out;
3992 if (val == 1)
3993 resp->resok.info.no_trunc = TRUE;
3994 else
3995 resp->resok.info.no_trunc = FALSE;
3996
3997 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3998 if (error)
3999 goto out;
4000 if (val == 1)
4001 resp->resok.info.chown_restricted = TRUE;
4002 else
4003 resp->resok.info.chown_restricted = FALSE;
4004
4005 resp->status = NFS3_OK;
4006 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4007 resp->resok.info.case_insensitive = FALSE;
4008 resp->resok.info.case_preserving = TRUE;
4009 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4010 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4011 VN_RELE(vp);
4012 return;
4013
4014 out:
4015 if (curthread->t_flag & T_WOULDBLOCK) {
4016 curthread->t_flag &= ~T_WOULDBLOCK;
4017 resp->status = NFS3ERR_JUKEBOX;
4018 } else
4019 resp->status = puterrno3(error);
4020 out1:
4021 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4022 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4023 if (vp != NULL)
4024 VN_RELE(vp);
4025 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4026 }
4027
4028 void *
4029 rfs3_pathconf_getfh(PATHCONF3args *args)
4030 {
4031
4032 return (&args->object);
4033 }
4034
4035 void
4036 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4037 struct svc_req *req, cred_t *cr, bool_t ro)
4038 {
4039 int error;
4040 vnode_t *vp;
4041 struct vattr *bvap;
4042 struct vattr bva;
4043 struct vattr *avap;
4044 struct vattr ava;
4045
4046 bvap = NULL;
4047 avap = NULL;
4048
4049 vp = nfs3_fhtovp(&args->file, exi);
4050
4051 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4052 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4053
4054 if (vp == NULL) {
4055 error = ESTALE;
4056 goto out;
4057 }
4058
4059 bva.va_mask = AT_ALL;
4060 error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4061
4062 /*
4063 * If we can't get the attributes, then we can't do the
4064 * right access checking. So, we'll fail the request.
4065 */
4066 if (error)
4067 goto out;
4068
4069 bvap = &bva;
4070
4071 if (rdonly(ro, vp)) {
4072 resp->status = NFS3ERR_ROFS;
4073 goto out1;
4074 }
4075
4076 if (vp->v_type != VREG) {
4077 resp->status = NFS3ERR_INVAL;
4078 goto out1;
4079 }
4080
4081 if (is_system_labeled()) {
4082 bslabel_t *clabel = req->rq_label;
4083
4084 ASSERT(clabel != NULL);
4085 DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4086 "got client label from request(1)", struct svc_req *, req);
4087
4088 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4089 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4090 exi)) {
4091 resp->status = NFS3ERR_ACCES;
4092 goto out1;
4093 }
4094 }
4095 }
4096
4097 if (crgetuid(cr) != bva.va_uid &&
4098 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4099 goto out;
4100
4101 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4102
4103 ava.va_mask = AT_ALL;
4104 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4105
4106 if (error)
4107 goto out;
4108
4109 resp->status = NFS3_OK;
4110 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4111 resp->resok.verf = write3verf;
4112
4113 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4114 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4115
4116 VN_RELE(vp);
4117
4118 return;
4119
4120 out:
4121 if (curthread->t_flag & T_WOULDBLOCK) {
4122 curthread->t_flag &= ~T_WOULDBLOCK;
4123 resp->status = NFS3ERR_JUKEBOX;
4124 } else
4125 resp->status = puterrno3(error);
4126 out1:
4127 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4128 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4129
4130 if (vp != NULL)
4131 VN_RELE(vp);
4132 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4133 }
4134
4135 void *
4136 rfs3_commit_getfh(COMMIT3args *args)
4137 {
4138
4139 return (&args->file);
4140 }
4141
4142 static int
4143 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4144 {
4145
4146 vap->va_mask = 0;
4147
4148 if (sap->mode.set_it) {
4149 vap->va_mode = (mode_t)sap->mode.mode;
4150 vap->va_mask |= AT_MODE;
4151 }
4152 if (sap->uid.set_it) {
4153 vap->va_uid = (uid_t)sap->uid.uid;
4154 vap->va_mask |= AT_UID;
4155 }
4156 if (sap->gid.set_it) {
4157 vap->va_gid = (gid_t)sap->gid.gid;
4158 vap->va_mask |= AT_GID;
4159 }
4160 if (sap->size.set_it) {
4161 if (sap->size.size > (size3)((u_longlong_t)-1))
4162 return (EINVAL);
4163 vap->va_size = sap->size.size;
4164 vap->va_mask |= AT_SIZE;
4165 }
4166 if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
4167 #ifndef _LP64
4168 /* check time validity */
4169 if (!NFS3_TIME_OK(sap->atime.atime.seconds))
4170 return (EOVERFLOW);
4171 #endif
4172 /*
4173 * nfs protocol defines times as unsigned so don't extend sign,
4174 * unless sysadmin set nfs_allow_preepoch_time.
4175 */
4176 NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4177 sap->atime.atime.seconds);
4178 vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
4179 vap->va_mask |= AT_ATIME;
4180 } else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
4181 gethrestime(&vap->va_atime);
4182 vap->va_mask |= AT_ATIME;
4183 }
4184 if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
4185 #ifndef _LP64
4186 /* check time validity */
4187 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4188 return (EOVERFLOW);
4189 #endif
4190 /*
4191 * nfs protocol defines times as unsigned so don't extend sign,
4192 * unless sysadmin set nfs_allow_preepoch_time.
4193 */
4194 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4195 sap->mtime.mtime.seconds);
4196 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4197 vap->va_mask |= AT_MTIME;
4198 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4199 gethrestime(&vap->va_mtime);
4200 vap->va_mask |= AT_MTIME;
4201 }
4202
4203 return (0);
4204 }
4205
4206 static ftype3 vt_to_nf3[] = {
4207 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4208 };
4209
4210 static int
4211 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4212 {
4213
4214 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4215 /* Return error if time or size overflow */
4216 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4217 return (EOVERFLOW);
4218 }
4219 fap->type = vt_to_nf3[vap->va_type];
4220 fap->mode = (mode3)(vap->va_mode & MODEMASK);
4221 fap->nlink = (uint32)vap->va_nlink;
4222 if (vap->va_uid == UID_NOBODY)
4223 fap->uid = (uid3)NFS_UID_NOBODY;
4224 else
4225 fap->uid = (uid3)vap->va_uid;
4226 if (vap->va_gid == GID_NOBODY)
4227 fap->gid = (gid3)NFS_GID_NOBODY;
4228 else
4229 fap->gid = (gid3)vap->va_gid;
4230 fap->size = (size3)vap->va_size;
4231 fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
4232 fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
4233 fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
4234 fap->fsid = (uint64)vap->va_fsid;
4235 fap->fileid = (fileid3)vap->va_nodeid;
4236 fap->atime.seconds = vap->va_atime.tv_sec;
4237 fap->atime.nseconds = vap->va_atime.tv_nsec;
4238 fap->mtime.seconds = vap->va_mtime.tv_sec;
4239 fap->mtime.nseconds = vap->va_mtime.tv_nsec;
4240 fap->ctime.seconds = vap->va_ctime.tv_sec;
4241 fap->ctime.nseconds = vap->va_ctime.tv_nsec;
4242 return (0);
4243 }
4244
4245 static int
4246 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
4247 {
4248
4249 /* Return error if time or size overflow */
4250 if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4251 NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4252 NFS3_SIZE_OK(vap->va_size))) {
4253 return (EOVERFLOW);
4254 }
4255 wccap->size = (size3)vap->va_size;
4256 wccap->mtime.seconds = vap->va_mtime.tv_sec;
4257 wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
4258 wccap->ctime.seconds = vap->va_ctime.tv_sec;
4259 wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
4260 return (0);
4261 }
4262
4263 static void
4264 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
4265 {
4266
4267 /* don't return attrs if time overflow */
4268 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4269 poap->attributes = TRUE;
4270 } else
4271 poap->attributes = FALSE;
4272 }
4273
4274 void
4275 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4276 {
4277
4278 /* don't return attrs if time overflow */
4279 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4280 poap->attributes = TRUE;
4281 } else
4282 poap->attributes = FALSE;
4283 }
4284
4285 static void
4286 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4287 {
4288
4289 vattr_to_pre_op_attr(bvap, &wccp->before);
4290 vattr_to_post_op_attr(avap, &wccp->after);
4291 }
4292
4293 void
4294 rfs3_srvrinit(void)
4295 {
4296 struct rfs3_verf_overlay {
4297 uint_t id; /* a "unique" identifier */
4298 int ts; /* a unique timestamp */
4299 } *verfp;
4300 timestruc_t now;
4301
4302 /*
4303 * The following algorithm attempts to find a unique verifier
4304 * to be used as the write verifier returned from the server
4305 * to the client. It is important that this verifier change
4306 * whenever the server reboots. Of secondary importance, it
4307 * is important for the verifier to be unique between two
4308 * different servers.
4309 *
4310 * Thus, an attempt is made to use the system hostid and the
4311 * current time in seconds when the nfssrv kernel module is
4312 * loaded. It is assumed that an NFS server will not be able
4313 * to boot and then to reboot in less than a second. If the
4314 * hostid has not been set, then the current high resolution
4315 * time is used. This will ensure different verifiers each
4316 * time the server reboots and minimize the chances that two
4317 * different servers will have the same verifier.
4318 */
4319
4320 #ifndef lint
4321 /*
4322 * We ASSERT that this constant logic expression is
4323 * always true because in the past, it wasn't.
4324 */
4325 ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4326 #endif
4327
4328 gethrestime(&now);
4329 verfp = (struct rfs3_verf_overlay *)&write3verf;
4330 verfp->ts = (int)now.tv_sec;
4331 verfp->id = zone_get_hostid(NULL);
4332
4333 if (verfp->id == 0)
4334 verfp->id = (uint_t)now.tv_nsec;
4335
4336 nfs3_srv_caller_id = fs_new_caller_id();
4337
4338 }
4339
4340 static int
4341 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4342 {
4343 struct clist *wcl;
4344 int wlist_len;
4345 count3 count = rok->count;
4346
4347 wcl = args->wlist;
4348 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4349 return (FALSE);
4350 }
4351
4352 wcl = args->wlist;
4353 rok->wlist_len = wlist_len;
4354 rok->wlist = wcl;
4355 return (TRUE);
4356 }
4357
4358 void
4359 rfs3_srvrfini(void)
4360 {
4361 /* Nothing to do */
4362 }