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