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