2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * nfs version 2, 3 and 4 server calls to vnode ops
41 * - these routines generally have 3 phases
42 * 1 - break down and validate rpc request in mbuf list
43 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44 * function in nfsd_port.c
45 * 3 - build the rpc reply in an mbuf list
46 * For nfsv4, these functions are called for each Op within the Compound RPC.
50 #include <fs/nfs/nfsport.h>
53 extern u_int32_t newnfs_false, newnfs_true;
54 extern enum vtype nv34tov_type[8];
55 extern struct timeval nfsboottime;
56 extern int nfs_rootfhset;
57 extern int nfsrv_enable_crossmntpt;
58 extern int nfsrv_statehashsize;
59 extern int nfsrv_layouthashsize;
60 extern time_t nfsdev_time;
61 extern volatile int nfsrv_devidcnt;
62 extern int nfsd_debuglevel;
63 extern u_long sb_max_adj;
64 extern int nfsrv_pnfsatime;
65 extern int nfsrv_maxpnfsmirror;
66 #endif /* !APPLEKEXT */
68 static int nfs_async = 0;
69 SYSCTL_DECL(_vfs_nfsd);
70 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
71 "Tell client that writes were synced even though they were not");
72 extern int nfsrv_doflexfile;
73 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
74 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
77 * This list defines the GSS mechanisms supported.
78 * (Don't ask me how you get these strings from the RFC stuff like
79 * iso(1), org(3)... but someone did it, so I don't need to know.)
81 static struct nfsgss_mechlist nfsgss_mechlist[] = {
82 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
87 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
88 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
89 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
90 int *diraft_retp, nfsattrbit_t *attrbitp,
91 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
93 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
94 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
95 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
96 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
97 NFSPROC_T *p, struct nfsexstuff *exp);
100 * nfs access service (not a part of NFS V2)
103 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
104 vnode_t vp, struct nfsexstuff *exp)
107 int getret, error = 0;
109 u_int32_t testmode, nfsmode, supported = 0;
111 struct thread *p = curthread;
113 if (nd->nd_repstat) {
114 nfsrv_postopattr(nd, 1, &nva);
117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
118 nfsmode = fxdr_unsigned(u_int32_t, *tl);
119 if ((nd->nd_flag & ND_NFSV4) &&
120 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
121 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
122 NFSACCESS_EXECUTE))) {
123 nd->nd_repstat = NFSERR_INVAL;
127 if (nfsmode & NFSACCESS_READ) {
128 supported |= NFSACCESS_READ;
129 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
130 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
131 nfsmode &= ~NFSACCESS_READ;
133 if (nfsmode & NFSACCESS_MODIFY) {
134 supported |= NFSACCESS_MODIFY;
135 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
136 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
137 nfsmode &= ~NFSACCESS_MODIFY;
139 if (nfsmode & NFSACCESS_EXTEND) {
140 supported |= NFSACCESS_EXTEND;
141 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
142 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
143 nfsmode &= ~NFSACCESS_EXTEND;
145 if (nfsmode & NFSACCESS_DELETE) {
146 supported |= NFSACCESS_DELETE;
147 if (vp->v_type == VDIR)
148 deletebit = VDELETE_CHILD;
151 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
152 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
153 nfsmode &= ~NFSACCESS_DELETE;
155 if (vnode_vtype(vp) == VDIR)
156 testmode = NFSACCESS_LOOKUP;
158 testmode = NFSACCESS_EXECUTE;
159 if (nfsmode & testmode) {
160 supported |= (nfsmode & testmode);
161 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
162 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
163 nfsmode &= ~testmode;
165 nfsmode &= supported;
166 if (nd->nd_flag & ND_NFSV3) {
167 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
168 nfsrv_postopattr(nd, getret, &nva);
171 if (nd->nd_flag & ND_NFSV4) {
172 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
173 *tl++ = txdr_unsigned(supported);
175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
176 *tl = txdr_unsigned(nfsmode);
183 NFSEXITCODE2(error, nd);
188 * nfs getattr service
191 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
192 vnode_t vp, __unused struct nfsexstuff *exp)
196 int at_root = 0, error = 0, supports_nfsv4acls;
197 struct nfsreferral *refp;
198 nfsattrbit_t attrbits, tmpbits;
200 struct vnode *tvp = NULL;
202 uint64_t mounted_on_fileno = 0;
204 struct thread *p = curthread;
208 if (nd->nd_flag & ND_NFSV4) {
209 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
216 * Check for a referral.
218 refp = nfsv4root_getreferral(vp, NULL, 0);
220 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
225 if (nd->nd_repstat == 0) {
227 NFSSET_ATTRBIT(&tmpbits, &attrbits);
230 * GETATTR with write-only attr time_access_set and time_modify_set
231 * should return NFS4ERR_INVAL.
233 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
234 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
235 error = NFSERR_INVAL;
239 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
240 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
241 accmode |= VREAD_ACL;
243 if (NFSNONZERO_ATTRBIT(&tmpbits))
244 accmode |= VREAD_ATTRIBUTES;
246 nd->nd_repstat = nfsvno_accchk(vp, accmode,
247 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
248 NFSACCCHK_VPISLOCKED, NULL);
252 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
253 if (!nd->nd_repstat) {
254 if (nd->nd_flag & ND_NFSV4) {
255 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
256 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
258 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
260 if (nd->nd_repstat == 0) {
261 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
263 if (nfsrv_enable_crossmntpt != 0 &&
264 vp->v_type == VDIR &&
265 (vp->v_vflag & VV_ROOT) != 0 &&
267 tvp = mp->mnt_vnodecovered;
275 if ((nd->nd_repstat =
276 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
277 nd->nd_repstat = VOP_GETATTR(
278 tvp, &va, nd->nd_cred);
282 if (nd->nd_repstat == 0)
283 mounted_on_fileno = (uint64_t)
288 if (nd->nd_repstat == 0)
289 nd->nd_repstat = vfs_busy(mp, 0);
291 if (nd->nd_repstat == 0) {
292 (void)nfsvno_fillattr(nd, mp, vp, &nva,
293 &fh, 0, &attrbits, nd->nd_cred, p,
294 isdgram, 1, supports_nfsv4acls,
295 at_root, mounted_on_fileno);
302 nfsrv_fillattr(nd, &nva);
310 NFSEXITCODE2(error, nd);
315 * nfs setattr service
318 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
319 vnode_t vp, struct nfsexstuff *exp)
321 struct nfsvattr nva, nva2;
323 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
325 struct timespec guard = { 0, 0 };
326 nfsattrbit_t attrbits, retbits;
327 nfsv4stateid_t stateid;
328 NFSACL_T *aclp = NULL;
329 struct thread *p = curthread;
331 if (nd->nd_repstat) {
332 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
335 #ifdef NFS4_ACL_EXTATTR_NAME
336 aclp = acl_alloc(M_WAITOK);
340 NFSVNO_ATTRINIT(&nva);
341 if (nd->nd_flag & ND_NFSV4) {
342 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
343 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
344 stateid.other[0] = *tl++;
345 stateid.other[1] = *tl++;
346 stateid.other[2] = *tl;
347 if (stateid.other[0] == 0x55555555 &&
348 stateid.other[1] == 0x55555555 &&
349 stateid.other[2] == 0x55555555 &&
350 stateid.seqid == 0xffffffff)
353 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
357 /* For NFSv4, only va_uid is used from nva2. */
358 NFSZERO_ATTRBIT(&retbits);
359 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
360 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
362 nd->nd_repstat = preat_ret;
364 NFSZERO_ATTRBIT(&retbits);
365 if (nd->nd_flag & ND_NFSV3) {
366 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
367 gcheck = fxdr_unsigned(int, *tl);
369 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
370 fxdr_nfsv3time(tl, &guard);
372 if (!nd->nd_repstat && gcheck &&
373 (nva2.na_ctime.tv_sec != guard.tv_sec ||
374 nva2.na_ctime.tv_nsec != guard.tv_nsec))
375 nd->nd_repstat = NFSERR_NOT_SYNC;
376 if (nd->nd_repstat) {
378 #ifdef NFS4_ACL_EXTATTR_NAME
381 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
384 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
385 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
388 * Now that we have all the fields, lets do it.
389 * If the size is being changed write access is required, otherwise
390 * just check for a read only file system.
392 if (!nd->nd_repstat) {
393 if (NFSVNO_NOTSETSIZE(&nva)) {
394 if (NFSVNO_EXRDONLY(exp) ||
395 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
396 nd->nd_repstat = EROFS;
398 if (vnode_vtype(vp) != VREG)
399 nd->nd_repstat = EINVAL;
400 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
401 NFSVNO_EXSTRICTACCESS(exp))
402 nd->nd_repstat = nfsvno_accchk(vp,
403 VWRITE, nd->nd_cred, exp, p,
404 NFSACCCHK_NOOVERRIDE,
405 NFSACCCHK_VPISLOCKED, NULL);
409 * Proxy operations from the MDS are allowed via the all 0s special
412 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
413 gotproxystateid == 0)
414 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
415 &nva, &attrbits, exp, p);
417 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
419 * For V4, try setting the attrbutes in sets, so that the
420 * reply bitmap will be correct for an error case.
422 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
423 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
424 NFSVNO_ATTRINIT(&nva2);
425 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
426 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
427 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
429 if (!nd->nd_repstat) {
430 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
431 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
432 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
433 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
436 if (!nd->nd_repstat &&
437 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
438 NFSVNO_ATTRINIT(&nva2);
439 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
440 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
443 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
445 if (!nd->nd_repstat &&
446 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
447 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
448 NFSVNO_ATTRINIT(&nva2);
449 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
450 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
451 if (nva.na_vaflags & VA_UTIMES_NULL) {
452 nva2.na_vaflags |= VA_UTIMES_NULL;
453 NFSVNO_SETACTIVE(&nva2, vaflags);
455 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
457 if (!nd->nd_repstat) {
458 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
459 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
460 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
461 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
464 if (!nd->nd_repstat &&
465 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
466 NFSVNO_ATTRINIT(&nva2);
467 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
468 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
471 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
474 #ifdef NFS4_ACL_EXTATTR_NAME
475 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
476 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
477 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
479 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
482 } else if (!nd->nd_repstat) {
483 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
486 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
487 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
489 nd->nd_repstat = postat_ret;
492 #ifdef NFS4_ACL_EXTATTR_NAME
495 if (nd->nd_flag & ND_NFSV3)
496 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
497 else if (nd->nd_flag & ND_NFSV4)
498 (void) nfsrv_putattrbit(nd, &retbits);
499 else if (!nd->nd_repstat)
500 nfsrv_fillattr(nd, &nva);
507 #ifdef NFS4_ACL_EXTATTR_NAME
510 if (nd->nd_flag & ND_NFSV4) {
512 * For all nd_repstat, the V4 reply includes a bitmap,
513 * even NFSERR_BADXDR, which is what this will end up
516 (void) nfsrv_putattrbit(nd, &retbits);
518 NFSEXITCODE2(error, nd);
524 * (Also performs lookup parent for v4)
527 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
528 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
530 struct nameidata named;
531 vnode_t vp, dirp = NULL;
532 int error = 0, dattr_ret = 1;
533 struct nfsvattr nva, dattr;
536 struct thread *p = curthread;
538 if (nd->nd_repstat) {
539 nfsrv_postopattr(nd, dattr_ret, &dattr);
544 * For some reason, if dp is a symlink, the error
545 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
547 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
548 nd->nd_repstat = NFSERR_SYMLINK;
553 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
554 LOCKLEAF | SAVESTART);
555 nfsvno_setpathbuf(&named, &bufp, &hashp);
556 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
559 nfsvno_relpathbuf(&named);
562 if (!nd->nd_repstat) {
563 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
566 nfsvno_relpathbuf(&named);
568 if (nd->nd_repstat) {
570 if (nd->nd_flag & ND_NFSV3)
571 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
575 if (nd->nd_flag & ND_NFSV3)
576 nfsrv_postopattr(nd, dattr_ret, &dattr);
579 if (named.ni_startdir)
580 vrele(named.ni_startdir);
581 nfsvno_relpathbuf(&named);
583 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
584 vp->v_type != VDIR && vp->v_type != VLNK)
586 * Only allow lookup of VDIR and VLNK for traversal of
587 * non-exported volumes during NFSv4 mounting.
589 nd->nd_repstat = ENOENT;
590 if (nd->nd_repstat == 0)
591 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
592 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
593 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
594 if (vpp != NULL && nd->nd_repstat == 0)
599 if (nd->nd_flag & ND_NFSV3)
600 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
604 if (nd->nd_repstat) {
605 if (nd->nd_flag & ND_NFSV3)
606 nfsrv_postopattr(nd, dattr_ret, &dattr);
609 if (nd->nd_flag & ND_NFSV2) {
610 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
611 nfsrv_fillattr(nd, &nva);
612 } else if (nd->nd_flag & ND_NFSV3) {
613 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
614 nfsrv_postopattr(nd, 0, &nva);
615 nfsrv_postopattr(nd, dattr_ret, &dattr);
619 NFSEXITCODE2(error, nd);
624 * nfs readlink service
627 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
628 vnode_t vp, __unused struct nfsexstuff *exp)
631 mbuf_t mp = NULL, mpend = NULL;
634 struct thread *p = curthread;
636 if (nd->nd_repstat) {
637 nfsrv_postopattr(nd, getret, &nva);
640 if (vnode_vtype(vp) != VLNK) {
641 if (nd->nd_flag & ND_NFSV2)
642 nd->nd_repstat = ENXIO;
644 nd->nd_repstat = EINVAL;
647 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
649 if (nd->nd_flag & ND_NFSV3)
650 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
652 if (nd->nd_flag & ND_NFSV3)
653 nfsrv_postopattr(nd, getret, &nva);
656 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
657 *tl = txdr_unsigned(len);
658 mbuf_setnext(nd->nd_mb, mp);
660 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
671 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
672 vnode_t vp, struct nfsexstuff *exp)
675 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
679 struct nfsstate st, *stp = &st;
680 struct nfslock lo, *lop = &lo;
681 nfsv4stateid_t stateid;
683 struct thread *p = curthread;
685 if (nd->nd_repstat) {
686 nfsrv_postopattr(nd, getret, &nva);
689 if (nd->nd_flag & ND_NFSV2) {
690 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
691 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
692 reqlen = fxdr_unsigned(int, *tl);
693 } else if (nd->nd_flag & ND_NFSV3) {
694 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
695 off = fxdr_hyper(tl);
697 reqlen = fxdr_unsigned(int, *tl);
699 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
700 reqlen = fxdr_unsigned(int, *(tl + 6));
702 if (reqlen > NFS_SRVMAXDATA(nd)) {
703 reqlen = NFS_SRVMAXDATA(nd);
704 } else if (reqlen < 0) {
709 if (nd->nd_flag & ND_NFSV4) {
710 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
711 lop->lo_flags = NFSLCK_READ;
712 stp->ls_ownerlen = 0;
714 stp->ls_uid = nd->nd_cred->cr_uid;
715 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
716 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
717 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
718 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
719 if ((nd->nd_flag & ND_NFSV41) != 0)
720 clientid.qval = nd->nd_clientid.qval;
721 else if (nd->nd_clientid.qval != clientid.qval)
722 printf("EEK1 multiple clids\n");
724 if ((nd->nd_flag & ND_NFSV41) != 0)
725 printf("EEK! no clientid from session\n");
726 nd->nd_flag |= ND_IMPLIEDCLID;
727 nd->nd_clientid.qval = clientid.qval;
729 stp->ls_stateid.other[2] = *tl++;
731 * Don't allow the client to use a special stateid for a DS op.
733 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
734 ((stp->ls_stateid.other[0] == 0x0 &&
735 stp->ls_stateid.other[1] == 0x0 &&
736 stp->ls_stateid.other[2] == 0x0) ||
737 (stp->ls_stateid.other[0] == 0xffffffff &&
738 stp->ls_stateid.other[1] == 0xffffffff &&
739 stp->ls_stateid.other[2] == 0xffffffff) ||
740 stp->ls_stateid.seqid != 0))
741 nd->nd_repstat = NFSERR_BADSTATEID;
742 /* However, allow the proxy stateid. */
743 if (stp->ls_stateid.seqid == 0xffffffff &&
744 stp->ls_stateid.other[0] == 0x55555555 &&
745 stp->ls_stateid.other[1] == 0x55555555 &&
746 stp->ls_stateid.other[2] == 0x55555555)
748 off = fxdr_hyper(tl);
751 lop->lo_end = off + reqlen;
753 * Paranoia, just in case it wraps around.
755 if (lop->lo_end < off)
756 lop->lo_end = NFS64BITSSET;
758 if (vnode_vtype(vp) != VREG) {
759 if (nd->nd_flag & ND_NFSV3)
760 nd->nd_repstat = EINVAL;
762 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
765 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
767 nd->nd_repstat = getret;
768 if (!nd->nd_repstat &&
769 (nva.na_uid != nd->nd_cred->cr_uid ||
770 NFSVNO_EXSTRICTACCESS(exp))) {
771 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
773 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
775 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
776 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
777 NFSACCCHK_VPISLOCKED, NULL);
780 * DS reads are marked by ND_DSSERVER or use the proxy special
783 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
784 ND_NFSV4 && gotproxystateid == 0)
785 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
786 &stateid, exp, nd, p);
787 if (nd->nd_repstat) {
789 if (nd->nd_flag & ND_NFSV3)
790 nfsrv_postopattr(nd, getret, &nva);
793 if (off >= nva.na_size) {
796 } else if (reqlen == 0)
798 else if ((off + reqlen) >= nva.na_size) {
799 cnt = nva.na_size - off;
805 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
807 if (!(nd->nd_flag & ND_NFSV4)) {
808 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
810 nd->nd_repstat = getret;
812 if (nd->nd_repstat) {
816 if (nd->nd_flag & ND_NFSV3)
817 nfsrv_postopattr(nd, getret, &nva);
822 if (nd->nd_flag & ND_NFSV2) {
823 nfsrv_fillattr(nd, &nva);
824 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
826 if (nd->nd_flag & ND_NFSV3) {
827 nfsrv_postopattr(nd, getret, &nva);
828 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
829 *tl++ = txdr_unsigned(cnt);
831 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
835 *tl++ = newnfs_false;
837 *tl = txdr_unsigned(cnt);
839 mbuf_setnext(nd->nd_mb, m3);
841 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
849 NFSEXITCODE2(error, nd);
857 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
858 vnode_t vp, struct nfsexstuff *exp)
863 struct nfsvattr nva, forat;
864 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
865 int gotproxystateid, stable = NFSWRITE_FILESYNC;
867 struct nfsstate st, *stp = &st;
868 struct nfslock lo, *lop = &lo;
869 nfsv4stateid_t stateid;
871 nfsattrbit_t attrbits;
872 struct thread *p = curthread;
874 if (nd->nd_repstat) {
875 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
879 if (nd->nd_flag & ND_NFSV2) {
880 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
881 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
883 retlen = len = fxdr_unsigned(int32_t, *tl);
884 } else if (nd->nd_flag & ND_NFSV3) {
885 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
886 off = fxdr_hyper(tl);
888 stable = fxdr_unsigned(int, *tl++);
889 retlen = len = fxdr_unsigned(int32_t, *tl);
891 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
892 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
893 lop->lo_flags = NFSLCK_WRITE;
894 stp->ls_ownerlen = 0;
896 stp->ls_uid = nd->nd_cred->cr_uid;
897 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
898 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
899 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
900 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
901 if ((nd->nd_flag & ND_NFSV41) != 0)
902 clientid.qval = nd->nd_clientid.qval;
903 else if (nd->nd_clientid.qval != clientid.qval)
904 printf("EEK2 multiple clids\n");
906 if ((nd->nd_flag & ND_NFSV41) != 0)
907 printf("EEK! no clientid from session\n");
908 nd->nd_flag |= ND_IMPLIEDCLID;
909 nd->nd_clientid.qval = clientid.qval;
911 stp->ls_stateid.other[2] = *tl++;
913 * Don't allow the client to use a special stateid for a DS op.
915 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
916 ((stp->ls_stateid.other[0] == 0x0 &&
917 stp->ls_stateid.other[1] == 0x0 &&
918 stp->ls_stateid.other[2] == 0x0) ||
919 (stp->ls_stateid.other[0] == 0xffffffff &&
920 stp->ls_stateid.other[1] == 0xffffffff &&
921 stp->ls_stateid.other[2] == 0xffffffff) ||
922 stp->ls_stateid.seqid != 0))
923 nd->nd_repstat = NFSERR_BADSTATEID;
924 /* However, allow the proxy stateid. */
925 if (stp->ls_stateid.seqid == 0xffffffff &&
926 stp->ls_stateid.other[0] == 0x55555555 &&
927 stp->ls_stateid.other[1] == 0x55555555 &&
928 stp->ls_stateid.other[2] == 0x55555555)
930 off = fxdr_hyper(tl);
933 stable = fxdr_unsigned(int, *tl++);
934 retlen = len = fxdr_unsigned(int32_t, *tl);
935 lop->lo_end = off + len;
937 * Paranoia, just in case it wraps around, which shouldn't
938 * ever happen anyhow.
940 if (lop->lo_end < lop->lo_first)
941 lop->lo_end = NFS64BITSSET;
945 * Loop through the mbuf chain, counting how many mbufs are a
946 * part of this write operation, so the iovec size is known.
950 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
966 if (retlen > NFS_SRVMAXIO || retlen < 0)
967 nd->nd_repstat = EIO;
968 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
969 if (nd->nd_flag & ND_NFSV3)
970 nd->nd_repstat = EINVAL;
972 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
975 NFSZERO_ATTRBIT(&attrbits);
976 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
977 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
979 nd->nd_repstat = forat_ret;
980 if (!nd->nd_repstat &&
981 (forat.na_uid != nd->nd_cred->cr_uid ||
982 NFSVNO_EXSTRICTACCESS(exp)))
983 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
985 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
987 * DS reads are marked by ND_DSSERVER or use the proxy special
990 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
991 ND_NFSV4 && gotproxystateid == 0)
992 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
993 &stateid, exp, nd, p);
994 if (nd->nd_repstat) {
996 if (nd->nd_flag & ND_NFSV3)
997 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1002 * For NFS Version 2, it is not obvious what a write of zero length
1003 * should do, but I might as well be consistent with Version 3,
1004 * which is to return ok so long as there are no permission problems.
1007 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable,
1008 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1009 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1013 if (nd->nd_flag & ND_NFSV4)
1016 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1018 if (!nd->nd_repstat)
1019 nd->nd_repstat = aftat_ret;
1020 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1021 if (nd->nd_flag & ND_NFSV3)
1022 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1025 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1026 *tl++ = txdr_unsigned(retlen);
1028 * If nfs_async is set, then pretend the write was FILESYNC.
1029 * Warning: Doing this violates RFC1813 and runs a risk
1030 * of data written by a client being lost when the server
1033 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1034 *tl++ = txdr_unsigned(stable);
1036 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1038 * Actually, there is no need to txdr these fields,
1039 * but it may make the values more human readable,
1040 * for debugging purposes.
1042 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1043 *tl = txdr_unsigned(nfsboottime.tv_usec);
1044 } else if (!nd->nd_repstat)
1045 nfsrv_fillattr(nd, &nva);
1048 NFSEXITCODE2(0, nd);
1052 NFSEXITCODE2(error, nd);
1057 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1058 * now does a truncate to 0 length via. setattr if it already exists
1059 * The core creation routine has been extracted out into nfsrv_creatsub(),
1060 * so it can also be used by nfsrv_open() for V4.
1063 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1064 vnode_t dp, struct nfsexstuff *exp)
1066 struct nfsvattr nva, dirfor, diraft;
1067 struct nfsv2_sattr *sp;
1068 struct nameidata named;
1070 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1071 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1073 vnode_t vp = NULL, dirp = NULL;
1078 int32_t cverf[2], tverf[2] = { 0, 0 };
1079 struct thread *p = curthread;
1081 if (nd->nd_repstat) {
1082 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1085 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1086 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1087 nfsvno_setpathbuf(&named, &bufp, &hashp);
1088 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1091 if (!nd->nd_repstat) {
1092 NFSVNO_ATTRINIT(&nva);
1093 if (nd->nd_flag & ND_NFSV2) {
1094 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1095 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1098 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1099 NFSVNO_SETATTRVAL(&nva, mode,
1100 nfstov_mode(sp->sa_mode));
1101 switch (nva.na_type) {
1103 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1105 NFSVNO_SETATTRVAL(&nva, size,
1111 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118 how = fxdr_unsigned(int, *tl);
1120 case NFSCREATE_GUARDED:
1121 case NFSCREATE_UNCHECKED:
1122 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1126 case NFSCREATE_EXCLUSIVE:
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1133 NFSVNO_SETATTRVAL(&nva, type, VREG);
1136 if (nd->nd_repstat) {
1137 nfsvno_relpathbuf(&named);
1138 if (nd->nd_flag & ND_NFSV3) {
1139 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1141 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1148 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1150 if (nd->nd_flag & ND_NFSV2) {
1154 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1158 if (nd->nd_repstat) {
1159 if (nd->nd_flag & ND_NFSV3)
1160 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1167 if (!(nd->nd_flag & ND_NFSV2)) {
1169 case NFSCREATE_GUARDED:
1171 nd->nd_repstat = EEXIST;
1173 case NFSCREATE_UNCHECKED:
1175 case NFSCREATE_EXCLUSIVE:
1176 if (named.ni_vp == NULL)
1177 NFSVNO_SETATTRVAL(&nva, mode, 0);
1183 * Iff doesn't exist, create it
1184 * otherwise just truncate to 0 length
1185 * should I set the mode too ?
1187 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1188 &exclusive_flag, cverf, rdev, exp);
1190 if (!nd->nd_repstat) {
1191 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1192 if (!nd->nd_repstat)
1193 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1196 if (!nd->nd_repstat) {
1197 tverf[0] = nva.na_atime.tv_sec;
1198 tverf[1] = nva.na_atime.tv_nsec;
1201 if (nd->nd_flag & ND_NFSV2) {
1202 if (!nd->nd_repstat) {
1203 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1204 nfsrv_fillattr(nd, &nva);
1207 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1208 || cverf[1] != tverf[1]))
1209 nd->nd_repstat = EEXIST;
1210 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1212 if (!nd->nd_repstat) {
1213 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1214 nfsrv_postopattr(nd, 0, &nva);
1216 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1220 NFSEXITCODE2(0, nd);
1224 nfsvno_relpathbuf(&named);
1225 NFSEXITCODE2(error, nd);
1230 * nfs v3 mknod service (and v4 create)
1233 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1234 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1236 struct nfsvattr nva, dirfor, diraft;
1238 struct nameidata named;
1239 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1240 u_int32_t major, minor;
1241 enum vtype vtyp = VNON;
1242 nfstype nfs4type = NFNON;
1243 vnode_t vp, dirp = NULL;
1244 nfsattrbit_t attrbits;
1245 char *bufp = NULL, *pathcp = NULL;
1246 u_long *hashp, cnflags;
1247 NFSACL_T *aclp = NULL;
1248 struct thread *p = curthread;
1250 NFSVNO_ATTRINIT(&nva);
1251 cnflags = (LOCKPARENT | SAVESTART);
1252 if (nd->nd_repstat) {
1253 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1256 #ifdef NFS4_ACL_EXTATTR_NAME
1257 aclp = acl_alloc(M_WAITOK);
1262 * For V4, the creation stuff is here, Yuck!
1264 if (nd->nd_flag & ND_NFSV4) {
1265 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1266 vtyp = nfsv34tov_type(*tl);
1267 nfs4type = fxdr_unsigned(nfstype, *tl);
1270 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1277 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1278 major = fxdr_unsigned(u_int32_t, *tl++);
1279 minor = fxdr_unsigned(u_int32_t, *tl);
1280 nva.na_rdev = NFSMAKEDEV(major, minor);
1286 cnflags = (LOCKPARENT | SAVENAME);
1289 nd->nd_repstat = NFSERR_BADTYPE;
1291 #ifdef NFS4_ACL_EXTATTR_NAME
1297 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1298 nfsvno_setpathbuf(&named, &bufp, &hashp);
1299 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1302 if (!nd->nd_repstat) {
1303 if (nd->nd_flag & ND_NFSV3) {
1304 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1305 vtyp = nfsv34tov_type(*tl);
1307 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1311 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1312 (vtyp == VCHR || vtyp == VBLK)) {
1313 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1314 major = fxdr_unsigned(u_int32_t, *tl++);
1315 minor = fxdr_unsigned(u_int32_t, *tl);
1316 nva.na_rdev = NFSMAKEDEV(major, minor);
1320 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1321 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1322 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1323 dirfor.na_gid == nva.na_gid)
1324 NFSVNO_UNSET(&nva, gid);
1325 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1327 if (nd->nd_repstat) {
1329 #ifdef NFS4_ACL_EXTATTR_NAME
1332 nfsvno_relpathbuf(&named);
1334 free(pathcp, M_TEMP);
1335 if (nd->nd_flag & ND_NFSV3)
1336 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1342 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1343 * in va_mode, so we'll have to set a default here.
1345 if (NFSVNO_NOTSETMODE(&nva)) {
1353 named.ni_cnd.cn_flags |= WILLBEDIR;
1354 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1355 if (nd->nd_repstat) {
1357 if (nd->nd_flag & ND_NFSV3)
1358 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1362 #ifdef NFS4_ACL_EXTATTR_NAME
1365 if (nd->nd_flag & ND_NFSV3)
1366 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1371 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1373 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1375 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1376 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1378 #ifdef NFS4_ACL_EXTATTR_NAME
1382 } else if (vtyp == VLNK) {
1383 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1384 &dirfor, &diraft, &diraft_ret, &attrbits,
1385 aclp, p, exp, pathcp, pathlen);
1386 #ifdef NFS4_ACL_EXTATTR_NAME
1389 free(pathcp, M_TEMP);
1394 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1395 if (!nd->nd_repstat) {
1397 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1398 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1399 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1400 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1402 if (vpp != NULL && nd->nd_repstat == 0) {
1403 NFSVOPUNLOCK(vp, 0);
1409 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1411 if (!nd->nd_repstat) {
1412 if (nd->nd_flag & ND_NFSV3) {
1413 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1414 nfsrv_postopattr(nd, 0, &nva);
1416 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1417 *tl++ = newnfs_false;
1418 txdr_hyper(dirfor.na_filerev, tl);
1420 txdr_hyper(diraft.na_filerev, tl);
1421 (void) nfsrv_putattrbit(nd, &attrbits);
1424 if (nd->nd_flag & ND_NFSV3)
1425 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1426 #ifdef NFS4_ACL_EXTATTR_NAME
1431 NFSEXITCODE2(0, nd);
1435 #ifdef NFS4_ACL_EXTATTR_NAME
1439 nfsvno_relpathbuf(&named);
1441 free(pathcp, M_TEMP);
1443 NFSEXITCODE2(error, nd);
1448 * nfs remove service
1451 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1452 vnode_t dp, struct nfsexstuff *exp)
1454 struct nameidata named;
1456 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1457 vnode_t dirp = NULL;
1458 struct nfsvattr dirfor, diraft;
1461 struct thread *p = curthread;
1463 if (nd->nd_repstat) {
1464 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1467 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1468 LOCKPARENT | LOCKLEAF);
1469 nfsvno_setpathbuf(&named, &bufp, &hashp);
1470 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1473 nfsvno_relpathbuf(&named);
1476 if (!nd->nd_repstat) {
1477 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1480 nfsvno_relpathbuf(&named);
1483 if (!(nd->nd_flag & ND_NFSV2)) {
1484 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1491 if (!nd->nd_repstat) {
1492 if (nd->nd_flag & ND_NFSV4) {
1493 if (vnode_vtype(named.ni_vp) == VDIR)
1494 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1495 nd->nd_cred, p, exp);
1497 nd->nd_repstat = nfsvno_removesub(&named, 1,
1498 nd->nd_cred, p, exp);
1499 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1500 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1501 nd->nd_cred, p, exp);
1503 nd->nd_repstat = nfsvno_removesub(&named, 0,
1504 nd->nd_cred, p, exp);
1507 if (!(nd->nd_flag & ND_NFSV2)) {
1509 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1513 if (nd->nd_flag & ND_NFSV3) {
1514 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1516 } else if (!nd->nd_repstat) {
1517 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1518 *tl++ = newnfs_false;
1519 txdr_hyper(dirfor.na_filerev, tl);
1521 txdr_hyper(diraft.na_filerev, tl);
1526 NFSEXITCODE2(error, nd);
1531 * nfs rename service
1534 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1535 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1538 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1539 int tdirfor_ret = 1, tdiraft_ret = 1;
1540 struct nameidata fromnd, tond;
1541 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1542 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1543 struct nfsexstuff tnes;
1545 char *bufp, *tbufp = NULL;
1548 struct thread *p = curthread;
1550 if (nd->nd_repstat) {
1551 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1552 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1555 if (!(nd->nd_flag & ND_NFSV2))
1556 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1557 tond.ni_cnd.cn_nameiop = 0;
1558 tond.ni_startdir = NULL;
1559 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1560 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1561 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1566 nfsvno_relpathbuf(&fromnd);
1570 * Unlock dp in this code section, so it is unlocked before
1571 * tdp gets locked. This avoids a potential LOR if tdp is the
1572 * parent directory of dp.
1574 if (nd->nd_flag & ND_NFSV4) {
1578 NFSVOPUNLOCK(dp, 0);
1579 /* Might lock tdp. */
1580 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1583 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1585 NFSVOPUNLOCK(dp, 0);
1588 tfh.nfsrvfh_len = 0;
1589 error = nfsrv_mtofh(nd, &tfh);
1591 error = nfsvno_getfh(dp, &fh, p);
1594 /* todp is always NULL except NFSv4 */
1595 nfsvno_relpathbuf(&fromnd);
1599 /* If this is the same file handle, just VREF() the vnode. */
1600 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1601 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1605 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1607 NFSVOPUNLOCK(dp, 0);
1609 NFSVOPUNLOCK(dp, 0);
1610 nd->nd_cred->cr_uid = nd->nd_saveduid;
1611 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1612 0); /* Locks tdp. */
1614 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1616 NFSVOPUNLOCK(tdp, 0);
1620 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1621 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1622 if (!nd->nd_repstat) {
1623 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1628 nfsvno_relpathbuf(&fromnd);
1629 nfsvno_relpathbuf(&tond);
1633 if (nd->nd_repstat) {
1634 if (nd->nd_flag & ND_NFSV3) {
1635 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1637 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1643 nfsvno_relpathbuf(&fromnd);
1644 nfsvno_relpathbuf(&tond);
1649 * Done parsing, now down to business.
1651 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1652 if (nd->nd_repstat) {
1653 if (nd->nd_flag & ND_NFSV3) {
1654 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1656 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1663 nfsvno_relpathbuf(&tond);
1666 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1667 tond.ni_cnd.cn_flags |= WILLBEDIR;
1668 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1669 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1670 nd->nd_flag, nd->nd_cred, p);
1672 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1674 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1679 if (nd->nd_flag & ND_NFSV3) {
1680 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1681 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1682 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1683 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1684 *tl++ = newnfs_false;
1685 txdr_hyper(fdirfor.na_filerev, tl);
1687 txdr_hyper(fdiraft.na_filerev, tl);
1689 *tl++ = newnfs_false;
1690 txdr_hyper(tdirfor.na_filerev, tl);
1692 txdr_hyper(tdiraft.na_filerev, tl);
1696 NFSEXITCODE2(error, nd);
1704 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1705 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1707 struct nameidata named;
1709 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1710 vnode_t dirp = NULL, dp = NULL;
1711 struct nfsvattr dirfor, diraft, at;
1712 struct nfsexstuff tnes;
1716 struct thread *p = curthread;
1718 if (nd->nd_repstat) {
1719 nfsrv_postopattr(nd, getret, &at);
1720 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1723 NFSVOPUNLOCK(vp, 0);
1724 if (vnode_vtype(vp) == VDIR) {
1725 if (nd->nd_flag & ND_NFSV4)
1726 nd->nd_repstat = NFSERR_ISDIR;
1728 nd->nd_repstat = NFSERR_INVAL;
1732 if (!nd->nd_repstat) {
1733 if (nd->nd_flag & ND_NFSV4) {
1737 error = nfsrv_mtofh(nd, &dfh);
1740 /* tovp is always NULL unless NFSv4 */
1743 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1745 NFSVOPUNLOCK(dp, 0);
1748 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1749 LOCKPARENT | SAVENAME | NOCACHE);
1750 if (!nd->nd_repstat) {
1751 nfsvno_setpathbuf(&named, &bufp, &hashp);
1752 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1757 nfsvno_relpathbuf(&named);
1760 if (!nd->nd_repstat) {
1761 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1766 nfsvno_relpathbuf(&named);
1770 if (nd->nd_flag & ND_NFSV2) {
1774 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1778 if (!nd->nd_repstat)
1779 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1780 if (nd->nd_flag & ND_NFSV3)
1781 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1783 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1787 if (nd->nd_flag & ND_NFSV3) {
1788 nfsrv_postopattr(nd, getret, &at);
1789 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1790 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1791 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1792 *tl++ = newnfs_false;
1793 txdr_hyper(dirfor.na_filerev, tl);
1795 txdr_hyper(diraft.na_filerev, tl);
1799 NFSEXITCODE2(error, nd);
1804 * nfs symbolic link service
1807 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1808 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1810 struct nfsvattr nva, dirfor, diraft;
1811 struct nameidata named;
1812 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1813 vnode_t dirp = NULL;
1814 char *bufp, *pathcp = NULL;
1816 struct thread *p = curthread;
1818 if (nd->nd_repstat) {
1819 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1824 NFSVNO_ATTRINIT(&nva);
1825 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1826 LOCKPARENT | SAVESTART | NOCACHE);
1827 nfsvno_setpathbuf(&named, &bufp, &hashp);
1828 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1829 if (!error && !nd->nd_repstat)
1830 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1833 nfsvno_relpathbuf(&named);
1836 if (!nd->nd_repstat) {
1837 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1840 nfsvno_relpathbuf(&named);
1842 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1848 * And call nfsrvd_symlinksub() to do the common code. It will
1849 * return EBADRPC upon a parsing error, 0 otherwise.
1851 if (!nd->nd_repstat) {
1853 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1855 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1856 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1858 } else if (dirp != NULL) {
1859 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1863 free(pathcp, M_TEMP);
1865 if (nd->nd_flag & ND_NFSV3) {
1866 if (!nd->nd_repstat) {
1867 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1868 nfsrv_postopattr(nd, 0, &nva);
1870 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1874 NFSEXITCODE2(error, nd);
1879 * Common code for creating a symbolic link.
1882 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1883 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1884 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1885 int *diraft_retp, nfsattrbit_t *attrbitp,
1886 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1891 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1892 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1893 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1894 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1895 if (nd->nd_flag & ND_NFSV3) {
1896 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1897 if (!nd->nd_repstat)
1898 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1899 nvap, nd, p, 1, NULL);
1901 if (vpp != NULL && nd->nd_repstat == 0) {
1902 NFSVOPUNLOCK(ndp->ni_vp, 0);
1908 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1911 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1912 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1913 *tl++ = newnfs_false;
1914 txdr_hyper(dirforp->na_filerev, tl);
1916 txdr_hyper(diraftp->na_filerev, tl);
1917 (void) nfsrv_putattrbit(nd, attrbitp);
1920 NFSEXITCODE2(0, nd);
1927 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1928 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1930 struct nfsvattr nva, dirfor, diraft;
1931 struct nameidata named;
1933 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1934 vnode_t dirp = NULL;
1937 struct thread *p = curthread;
1939 if (nd->nd_repstat) {
1940 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1943 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1944 LOCKPARENT | SAVENAME | NOCACHE);
1945 nfsvno_setpathbuf(&named, &bufp, &hashp);
1946 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1949 if (!nd->nd_repstat) {
1950 NFSVNO_ATTRINIT(&nva);
1951 if (nd->nd_flag & ND_NFSV3) {
1952 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1956 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1957 nva.na_mode = nfstov_mode(*tl++);
1960 if (!nd->nd_repstat) {
1961 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1964 nfsvno_relpathbuf(&named);
1966 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1970 if (nd->nd_repstat) {
1972 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1976 if (nd->nd_flag & ND_NFSV3)
1977 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1982 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1985 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1987 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1988 &diraft_ret, NULL, NULL, p, exp);
1990 if (nd->nd_flag & ND_NFSV3) {
1991 if (!nd->nd_repstat) {
1992 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1993 nfsrv_postopattr(nd, 0, &nva);
1995 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1996 } else if (!nd->nd_repstat) {
1997 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1998 nfsrv_fillattr(nd, &nva);
2002 NFSEXITCODE2(0, nd);
2006 nfsvno_relpathbuf(&named);
2007 NFSEXITCODE2(error, nd);
2012 * Code common to mkdir for V2,3 and 4.
2015 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2016 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2017 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2018 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2019 NFSPROC_T *p, struct nfsexstuff *exp)
2024 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2025 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2026 nd->nd_cred, p, exp);
2027 if (!nd->nd_repstat) {
2029 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2030 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2031 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2032 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2034 if (vpp && !nd->nd_repstat) {
2035 NFSVOPUNLOCK(vp, 0);
2042 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2045 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2046 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2047 *tl++ = newnfs_false;
2048 txdr_hyper(dirforp->na_filerev, tl);
2050 txdr_hyper(diraftp->na_filerev, tl);
2051 (void) nfsrv_putattrbit(nd, attrbitp);
2054 NFSEXITCODE2(0, nd);
2058 * nfs commit service
2061 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2062 vnode_t vp, __unused struct nfsexstuff *exp)
2064 struct nfsvattr bfor, aft;
2066 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2068 struct thread *p = curthread;
2070 if (nd->nd_repstat) {
2071 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2075 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2076 if (vp->v_type != VREG) {
2077 if (nd->nd_flag & ND_NFSV3)
2078 error = NFSERR_NOTSUPP;
2080 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2083 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2086 * XXX At this time VOP_FSYNC() does not accept offset and byte
2087 * count parameters, so these arguments are useless (someday maybe).
2089 off = fxdr_hyper(tl);
2091 cnt = fxdr_unsigned(int, *tl);
2092 if (nd->nd_flag & ND_NFSV3)
2093 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2094 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2095 if (nd->nd_flag & ND_NFSV3) {
2096 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2097 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2100 if (!nd->nd_repstat) {
2101 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2102 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2103 *tl = txdr_unsigned(nfsboottime.tv_usec);
2107 NFSEXITCODE2(0, nd);
2111 NFSEXITCODE2(error, nd);
2116 * nfs statfs service
2119 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2120 vnode_t vp, __unused struct nfsexstuff *exp)
2127 struct thread *p = curthread;
2130 if (nd->nd_repstat) {
2131 nfsrv_postopattr(nd, getret, &at);
2134 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2135 nd->nd_repstat = nfsvno_statfs(vp, sf);
2136 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2138 if (nd->nd_flag & ND_NFSV3)
2139 nfsrv_postopattr(nd, getret, &at);
2142 if (nd->nd_flag & ND_NFSV2) {
2143 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2144 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2145 *tl++ = txdr_unsigned(sf->f_bsize);
2146 *tl++ = txdr_unsigned(sf->f_blocks);
2147 *tl++ = txdr_unsigned(sf->f_bfree);
2148 *tl = txdr_unsigned(sf->f_bavail);
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2151 tval = (u_quad_t)sf->f_blocks;
2152 tval *= (u_quad_t)sf->f_bsize;
2153 txdr_hyper(tval, tl); tl += 2;
2154 tval = (u_quad_t)sf->f_bfree;
2155 tval *= (u_quad_t)sf->f_bsize;
2156 txdr_hyper(tval, tl); tl += 2;
2157 tval = (u_quad_t)sf->f_bavail;
2158 tval *= (u_quad_t)sf->f_bsize;
2159 txdr_hyper(tval, tl); tl += 2;
2160 tval = (u_quad_t)sf->f_files;
2161 txdr_hyper(tval, tl); tl += 2;
2162 tval = (u_quad_t)sf->f_ffree;
2163 txdr_hyper(tval, tl); tl += 2;
2164 tval = (u_quad_t)sf->f_ffree;
2165 txdr_hyper(tval, tl); tl += 2;
2171 NFSEXITCODE2(0, nd);
2176 * nfs fsinfo service
2179 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2180 vnode_t vp, __unused struct nfsexstuff *exp)
2183 struct nfsfsinfo fs;
2186 struct thread *p = curthread;
2188 if (nd->nd_repstat) {
2189 nfsrv_postopattr(nd, getret, &at);
2192 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2193 nfsvno_getfs(&fs, isdgram);
2195 nfsrv_postopattr(nd, getret, &at);
2196 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2197 *tl++ = txdr_unsigned(fs.fs_rtmax);
2198 *tl++ = txdr_unsigned(fs.fs_rtpref);
2199 *tl++ = txdr_unsigned(fs.fs_rtmult);
2200 *tl++ = txdr_unsigned(fs.fs_wtmax);
2201 *tl++ = txdr_unsigned(fs.fs_wtpref);
2202 *tl++ = txdr_unsigned(fs.fs_wtmult);
2203 *tl++ = txdr_unsigned(fs.fs_dtpref);
2204 txdr_hyper(fs.fs_maxfilesize, tl);
2206 txdr_nfsv3time(&fs.fs_timedelta, tl);
2208 *tl = txdr_unsigned(fs.fs_properties);
2211 NFSEXITCODE2(0, nd);
2216 * nfs pathconf service
2219 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2220 vnode_t vp, __unused struct nfsexstuff *exp)
2222 struct nfsv3_pathconf *pc;
2224 long linkmax, namemax, chownres, notrunc;
2226 struct thread *p = curthread;
2228 if (nd->nd_repstat) {
2229 nfsrv_postopattr(nd, getret, &at);
2232 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2234 if (!nd->nd_repstat)
2235 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2237 if (!nd->nd_repstat)
2238 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2239 &chownres, nd->nd_cred, p);
2240 if (!nd->nd_repstat)
2241 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2243 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2245 nfsrv_postopattr(nd, getret, &at);
2246 if (!nd->nd_repstat) {
2247 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2248 pc->pc_linkmax = txdr_unsigned(linkmax);
2249 pc->pc_namemax = txdr_unsigned(namemax);
2250 pc->pc_notrunc = txdr_unsigned(notrunc);
2251 pc->pc_chownrestricted = txdr_unsigned(chownres);
2254 * These should probably be supported by VOP_PATHCONF(), but
2255 * until msdosfs is exportable (why would you want to?), the
2256 * Unix defaults should be ok.
2258 pc->pc_caseinsensitive = newnfs_false;
2259 pc->pc_casepreserving = newnfs_true;
2263 NFSEXITCODE2(0, nd);
2268 * nfsv4 lock service
2271 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2272 vnode_t vp, struct nfsexstuff *exp)
2276 struct nfsstate *stp = NULL;
2277 struct nfslock *lop;
2278 struct nfslockconflict cf;
2280 u_short flags = NFSLCK_LOCK, lflags;
2281 u_int64_t offset, len;
2282 nfsv4stateid_t stateid;
2284 struct thread *p = curthread;
2286 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2287 i = fxdr_unsigned(int, *tl++);
2289 case NFSV4LOCKT_READW:
2290 flags |= NFSLCK_BLOCKING;
2291 case NFSV4LOCKT_READ:
2292 lflags = NFSLCK_READ;
2294 case NFSV4LOCKT_WRITEW:
2295 flags |= NFSLCK_BLOCKING;
2296 case NFSV4LOCKT_WRITE:
2297 lflags = NFSLCK_WRITE;
2300 nd->nd_repstat = NFSERR_BADXDR;
2303 if (*tl++ == newnfs_true)
2304 flags |= NFSLCK_RECLAIM;
2305 offset = fxdr_hyper(tl);
2307 len = fxdr_hyper(tl);
2309 if (*tl == newnfs_true)
2310 flags |= NFSLCK_OPENTOLOCK;
2311 if (flags & NFSLCK_OPENTOLOCK) {
2312 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2313 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2314 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2315 nd->nd_repstat = NFSERR_BADXDR;
2318 stp = malloc(sizeof (struct nfsstate) + i,
2319 M_NFSDSTATE, M_WAITOK);
2320 stp->ls_ownerlen = i;
2321 stp->ls_op = nd->nd_rp;
2322 stp->ls_seq = fxdr_unsigned(int, *tl++);
2323 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2324 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2326 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2329 * For the special stateid of other all 0s and seqid == 1, set
2330 * the stateid to the current stateid, if it is set.
2332 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2333 stp->ls_stateid.seqid == 1 &&
2334 stp->ls_stateid.other[0] == 0 &&
2335 stp->ls_stateid.other[1] == 0 &&
2336 stp->ls_stateid.other[2] == 0) {
2337 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2338 stp->ls_stateid = nd->nd_curstateid;
2339 stp->ls_stateid.seqid = 0;
2341 nd->nd_repstat = NFSERR_BADSTATEID;
2346 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2347 clientid.lval[0] = *tl++;
2348 clientid.lval[1] = *tl++;
2349 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2350 if ((nd->nd_flag & ND_NFSV41) != 0)
2351 clientid.qval = nd->nd_clientid.qval;
2352 else if (nd->nd_clientid.qval != clientid.qval)
2353 printf("EEK3 multiple clids\n");
2355 if ((nd->nd_flag & ND_NFSV41) != 0)
2356 printf("EEK! no clientid from session\n");
2357 nd->nd_flag |= ND_IMPLIEDCLID;
2358 nd->nd_clientid.qval = clientid.qval;
2360 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2364 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2365 stp = malloc(sizeof (struct nfsstate),
2366 M_NFSDSTATE, M_WAITOK);
2367 stp->ls_ownerlen = 0;
2368 stp->ls_op = nd->nd_rp;
2369 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2370 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2372 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2375 * For the special stateid of other all 0s and seqid == 1, set
2376 * the stateid to the current stateid, if it is set.
2378 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2379 stp->ls_stateid.seqid == 1 &&
2380 stp->ls_stateid.other[0] == 0 &&
2381 stp->ls_stateid.other[1] == 0 &&
2382 stp->ls_stateid.other[2] == 0) {
2383 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2384 stp->ls_stateid = nd->nd_curstateid;
2385 stp->ls_stateid.seqid = 0;
2387 nd->nd_repstat = NFSERR_BADSTATEID;
2392 stp->ls_seq = fxdr_unsigned(int, *tl);
2393 clientid.lval[0] = stp->ls_stateid.other[0];
2394 clientid.lval[1] = stp->ls_stateid.other[1];
2395 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2396 if ((nd->nd_flag & ND_NFSV41) != 0)
2397 clientid.qval = nd->nd_clientid.qval;
2398 else if (nd->nd_clientid.qval != clientid.qval)
2399 printf("EEK4 multiple clids\n");
2401 if ((nd->nd_flag & ND_NFSV41) != 0)
2402 printf("EEK! no clientid from session\n");
2403 nd->nd_flag |= ND_IMPLIEDCLID;
2404 nd->nd_clientid.qval = clientid.qval;
2407 lop = malloc(sizeof (struct nfslock),
2408 M_NFSDLOCK, M_WAITOK);
2409 lop->lo_first = offset;
2410 if (len == NFS64BITSSET) {
2411 lop->lo_end = NFS64BITSSET;
2413 lop->lo_end = offset + len;
2414 if (lop->lo_end <= lop->lo_first)
2415 nd->nd_repstat = NFSERR_INVAL;
2417 lop->lo_flags = lflags;
2418 stp->ls_flags = flags;
2419 stp->ls_uid = nd->nd_cred->cr_uid;
2422 * Do basic access checking.
2424 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2425 if (vnode_vtype(vp) == VDIR)
2426 nd->nd_repstat = NFSERR_ISDIR;
2428 nd->nd_repstat = NFSERR_INVAL;
2430 if (!nd->nd_repstat) {
2431 if (lflags & NFSLCK_WRITE) {
2432 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2433 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2434 NFSACCCHK_VPISLOCKED, NULL);
2436 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2437 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2438 NFSACCCHK_VPISLOCKED, NULL);
2440 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2441 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2442 NFSACCCHK_VPISLOCKED, NULL);
2447 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2448 * seqid# gets updated. nfsrv_lockctrl() will return the value
2449 * of nd_repstat, if it gets that far.
2451 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2452 &stateid, exp, nd, p);
2454 free(lop, M_NFSDLOCK);
2456 free(stp, M_NFSDSTATE);
2457 if (!nd->nd_repstat) {
2458 /* For NFSv4.1, set the Current StateID. */
2459 if ((nd->nd_flag & ND_NFSV41) != 0) {
2460 nd->nd_curstateid = stateid;
2461 nd->nd_flag |= ND_CURSTATEID;
2463 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2464 *tl++ = txdr_unsigned(stateid.seqid);
2465 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2466 } else if (nd->nd_repstat == NFSERR_DENIED) {
2467 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2468 txdr_hyper(cf.cl_first, tl);
2470 if (cf.cl_end == NFS64BITSSET)
2473 len = cf.cl_end - cf.cl_first;
2474 txdr_hyper(len, tl);
2476 if (cf.cl_flags == NFSLCK_WRITE)
2477 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2479 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2480 *tl++ = stateid.other[0];
2481 *tl = stateid.other[1];
2482 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2485 NFSEXITCODE2(0, nd);
2490 free(stp, M_NFSDSTATE);
2491 NFSEXITCODE2(error, nd);
2496 * nfsv4 lock test service
2499 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2500 vnode_t vp, struct nfsexstuff *exp)
2504 struct nfsstate *stp = NULL;
2505 struct nfslock lo, *lop = &lo;
2506 struct nfslockconflict cf;
2508 nfsv4stateid_t stateid;
2511 struct thread *p = curthread;
2513 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2514 i = fxdr_unsigned(int, *(tl + 7));
2515 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2516 nd->nd_repstat = NFSERR_BADXDR;
2519 stp = malloc(sizeof (struct nfsstate) + i,
2520 M_NFSDSTATE, M_WAITOK);
2521 stp->ls_ownerlen = i;
2523 stp->ls_flags = NFSLCK_TEST;
2524 stp->ls_uid = nd->nd_cred->cr_uid;
2525 i = fxdr_unsigned(int, *tl++);
2527 case NFSV4LOCKT_READW:
2528 stp->ls_flags |= NFSLCK_BLOCKING;
2529 case NFSV4LOCKT_READ:
2530 lo.lo_flags = NFSLCK_READ;
2532 case NFSV4LOCKT_WRITEW:
2533 stp->ls_flags |= NFSLCK_BLOCKING;
2534 case NFSV4LOCKT_WRITE:
2535 lo.lo_flags = NFSLCK_WRITE;
2538 nd->nd_repstat = NFSERR_BADXDR;
2541 lo.lo_first = fxdr_hyper(tl);
2543 len = fxdr_hyper(tl);
2544 if (len == NFS64BITSSET) {
2545 lo.lo_end = NFS64BITSSET;
2547 lo.lo_end = lo.lo_first + len;
2548 if (lo.lo_end <= lo.lo_first)
2549 nd->nd_repstat = NFSERR_INVAL;
2552 clientid.lval[0] = *tl++;
2553 clientid.lval[1] = *tl;
2554 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2555 if ((nd->nd_flag & ND_NFSV41) != 0)
2556 clientid.qval = nd->nd_clientid.qval;
2557 else if (nd->nd_clientid.qval != clientid.qval)
2558 printf("EEK5 multiple clids\n");
2560 if ((nd->nd_flag & ND_NFSV41) != 0)
2561 printf("EEK! no clientid from session\n");
2562 nd->nd_flag |= ND_IMPLIEDCLID;
2563 nd->nd_clientid.qval = clientid.qval;
2565 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2568 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2569 if (vnode_vtype(vp) == VDIR)
2570 nd->nd_repstat = NFSERR_ISDIR;
2572 nd->nd_repstat = NFSERR_INVAL;
2574 if (!nd->nd_repstat)
2575 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2576 &stateid, exp, nd, p);
2577 if (nd->nd_repstat) {
2578 if (nd->nd_repstat == NFSERR_DENIED) {
2579 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2580 txdr_hyper(cf.cl_first, tl);
2582 if (cf.cl_end == NFS64BITSSET)
2585 len = cf.cl_end - cf.cl_first;
2586 txdr_hyper(len, tl);
2588 if (cf.cl_flags == NFSLCK_WRITE)
2589 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2591 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2592 *tl++ = stp->ls_stateid.other[0];
2593 *tl = stp->ls_stateid.other[1];
2594 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2599 free(stp, M_NFSDSTATE);
2600 NFSEXITCODE2(0, nd);
2605 free(stp, M_NFSDSTATE);
2606 NFSEXITCODE2(error, nd);
2611 * nfsv4 unlock service
2614 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2615 vnode_t vp, struct nfsexstuff *exp)
2619 struct nfsstate *stp;
2620 struct nfslock *lop;
2622 nfsv4stateid_t stateid;
2625 struct thread *p = curthread;
2627 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2628 stp = malloc(sizeof (struct nfsstate),
2629 M_NFSDSTATE, M_WAITOK);
2630 lop = malloc(sizeof (struct nfslock),
2631 M_NFSDLOCK, M_WAITOK);
2632 stp->ls_flags = NFSLCK_UNLOCK;
2633 lop->lo_flags = NFSLCK_UNLOCK;
2634 stp->ls_op = nd->nd_rp;
2635 i = fxdr_unsigned(int, *tl++);
2637 case NFSV4LOCKT_READW:
2638 stp->ls_flags |= NFSLCK_BLOCKING;
2639 case NFSV4LOCKT_READ:
2641 case NFSV4LOCKT_WRITEW:
2642 stp->ls_flags |= NFSLCK_BLOCKING;
2643 case NFSV4LOCKT_WRITE:
2646 nd->nd_repstat = NFSERR_BADXDR;
2647 free(stp, M_NFSDSTATE);
2648 free(lop, M_NFSDLOCK);
2651 stp->ls_ownerlen = 0;
2652 stp->ls_uid = nd->nd_cred->cr_uid;
2653 stp->ls_seq = fxdr_unsigned(int, *tl++);
2654 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2655 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2657 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2660 * For the special stateid of other all 0s and seqid == 1, set the
2661 * stateid to the current stateid, if it is set.
2663 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2664 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2665 stp->ls_stateid.other[2] == 0) {
2666 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2667 stp->ls_stateid = nd->nd_curstateid;
2668 stp->ls_stateid.seqid = 0;
2670 nd->nd_repstat = NFSERR_BADSTATEID;
2675 lop->lo_first = fxdr_hyper(tl);
2677 len = fxdr_hyper(tl);
2678 if (len == NFS64BITSSET) {
2679 lop->lo_end = NFS64BITSSET;
2681 lop->lo_end = lop->lo_first + len;
2682 if (lop->lo_end <= lop->lo_first)
2683 nd->nd_repstat = NFSERR_INVAL;
2685 clientid.lval[0] = stp->ls_stateid.other[0];
2686 clientid.lval[1] = stp->ls_stateid.other[1];
2687 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2688 if ((nd->nd_flag & ND_NFSV41) != 0)
2689 clientid.qval = nd->nd_clientid.qval;
2690 else if (nd->nd_clientid.qval != clientid.qval)
2691 printf("EEK6 multiple clids\n");
2693 if ((nd->nd_flag & ND_NFSV41) != 0)
2694 printf("EEK! no clientid from session\n");
2695 nd->nd_flag |= ND_IMPLIEDCLID;
2696 nd->nd_clientid.qval = clientid.qval;
2698 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2699 if (vnode_vtype(vp) == VDIR)
2700 nd->nd_repstat = NFSERR_ISDIR;
2702 nd->nd_repstat = NFSERR_INVAL;
2705 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2706 * seqid# gets incremented. nfsrv_lockctrl() will return the
2707 * value of nd_repstat, if it gets that far.
2709 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2710 &stateid, exp, nd, p);
2712 free(stp, M_NFSDSTATE);
2714 free(lop, M_NFSDLOCK);
2715 if (!nd->nd_repstat) {
2716 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2717 *tl++ = txdr_unsigned(stateid.seqid);
2718 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2722 NFSEXITCODE2(error, nd);
2727 * nfsv4 open service
2730 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2731 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2735 struct nfsstate *stp = NULL;
2736 int error = 0, create, claim, exclusive_flag = 0;
2737 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2738 int how = NFSCREATE_UNCHECKED;
2739 int32_t cverf[2], tverf[2] = { 0, 0 };
2740 vnode_t vp = NULL, dirp = NULL;
2741 struct nfsvattr nva, dirfor, diraft;
2742 struct nameidata named;
2743 nfsv4stateid_t stateid, delegstateid;
2744 nfsattrbit_t attrbits;
2748 NFSACL_T *aclp = NULL;
2749 struct thread *p = curthread;
2751 #ifdef NFS4_ACL_EXTATTR_NAME
2752 aclp = acl_alloc(M_WAITOK);
2755 NFSZERO_ATTRBIT(&attrbits);
2756 named.ni_startdir = NULL;
2757 named.ni_cnd.cn_nameiop = 0;
2758 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2759 i = fxdr_unsigned(int, *(tl + 5));
2760 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2761 nd->nd_repstat = NFSERR_BADXDR;
2764 stp = malloc(sizeof (struct nfsstate) + i,
2765 M_NFSDSTATE, M_WAITOK);
2766 stp->ls_ownerlen = i;
2767 stp->ls_op = nd->nd_rp;
2768 stp->ls_flags = NFSLCK_OPEN;
2769 stp->ls_uid = nd->nd_cred->cr_uid;
2770 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2771 i = fxdr_unsigned(int, *tl++);
2773 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2774 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2776 /* For now, ignore these. */
2777 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2778 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2779 case NFSV4OPEN_WANTANYDELEG:
2780 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2782 i &= ~NFSV4OPEN_WANTDELEGMASK;
2784 case NFSV4OPEN_WANTREADDELEG:
2785 stp->ls_flags |= NFSLCK_WANTRDELEG;
2786 i &= ~NFSV4OPEN_WANTDELEGMASK;
2788 case NFSV4OPEN_WANTWRITEDELEG:
2789 stp->ls_flags |= NFSLCK_WANTWDELEG;
2790 i &= ~NFSV4OPEN_WANTDELEGMASK;
2792 case NFSV4OPEN_WANTNODELEG:
2793 stp->ls_flags |= NFSLCK_WANTNODELEG;
2794 i &= ~NFSV4OPEN_WANTDELEGMASK;
2796 case NFSV4OPEN_WANTCANCEL:
2797 printf("NFSv4: ignore Open WantCancel\n");
2798 i &= ~NFSV4OPEN_WANTDELEGMASK;
2801 /* nd_repstat will be set to NFSERR_INVAL below. */
2806 case NFSV4OPEN_ACCESSREAD:
2807 stp->ls_flags |= NFSLCK_READACCESS;
2809 case NFSV4OPEN_ACCESSWRITE:
2810 stp->ls_flags |= NFSLCK_WRITEACCESS;
2812 case NFSV4OPEN_ACCESSBOTH:
2813 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2816 nd->nd_repstat = NFSERR_INVAL;
2818 i = fxdr_unsigned(int, *tl++);
2820 case NFSV4OPEN_DENYNONE:
2822 case NFSV4OPEN_DENYREAD:
2823 stp->ls_flags |= NFSLCK_READDENY;
2825 case NFSV4OPEN_DENYWRITE:
2826 stp->ls_flags |= NFSLCK_WRITEDENY;
2828 case NFSV4OPEN_DENYBOTH:
2829 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2832 nd->nd_repstat = NFSERR_INVAL;
2834 clientid.lval[0] = *tl++;
2835 clientid.lval[1] = *tl;
2836 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2837 if ((nd->nd_flag & ND_NFSV41) != 0)
2838 clientid.qval = nd->nd_clientid.qval;
2839 else if (nd->nd_clientid.qval != clientid.qval)
2840 printf("EEK7 multiple clids\n");
2842 if ((nd->nd_flag & ND_NFSV41) != 0)
2843 printf("EEK! no clientid from session\n");
2844 nd->nd_flag |= ND_IMPLIEDCLID;
2845 nd->nd_clientid.qval = clientid.qval;
2847 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2850 NFSVNO_ATTRINIT(&nva);
2851 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2852 create = fxdr_unsigned(int, *tl);
2853 if (!nd->nd_repstat)
2854 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2855 if (create == NFSV4OPEN_CREATE) {
2858 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2859 how = fxdr_unsigned(int, *tl);
2861 case NFSCREATE_UNCHECKED:
2862 case NFSCREATE_GUARDED:
2863 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2867 * If the na_gid being set is the same as that of
2868 * the directory it is going in, clear it, since
2869 * that is what will be set by default. This allows
2870 * a user that isn't in that group to do the create.
2872 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2873 nva.na_gid == dirfor.na_gid)
2874 NFSVNO_UNSET(&nva, gid);
2875 if (!nd->nd_repstat)
2876 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2878 case NFSCREATE_EXCLUSIVE:
2879 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2883 case NFSCREATE_EXCLUSIVE41:
2884 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2887 error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
2890 if (NFSISSET_ATTRBIT(&attrbits,
2891 NFSATTRBIT_TIMEACCESSSET))
2892 nd->nd_repstat = NFSERR_INVAL;
2894 * If the na_gid being set is the same as that of
2895 * the directory it is going in, clear it, since
2896 * that is what will be set by default. This allows
2897 * a user that isn't in that group to do the create.
2899 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2900 nva.na_gid == dirfor.na_gid)
2901 NFSVNO_UNSET(&nva, gid);
2902 if (nd->nd_repstat == 0)
2903 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2906 nd->nd_repstat = NFSERR_BADXDR;
2909 } else if (create != NFSV4OPEN_NOCREATE) {
2910 nd->nd_repstat = NFSERR_BADXDR;
2915 * Now, handle the claim, which usually includes looking up a
2916 * name in the directory referenced by dp. The exception is
2917 * NFSV4OPEN_CLAIMPREVIOUS.
2919 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2920 claim = fxdr_unsigned(int, *tl);
2921 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2922 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2923 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2924 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2925 stp->ls_flags |= NFSLCK_DELEGCUR;
2926 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2927 stp->ls_flags |= NFSLCK_DELEGPREV;
2929 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2930 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2931 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2932 claim != NFSV4OPEN_CLAIMNULL)
2933 nd->nd_repstat = NFSERR_INVAL;
2934 if (nd->nd_repstat) {
2935 nd->nd_repstat = nfsrv_opencheck(clientid,
2936 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2939 if (create == NFSV4OPEN_CREATE)
2940 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2941 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2943 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2944 LOCKLEAF | SAVESTART);
2945 nfsvno_setpathbuf(&named, &bufp, &hashp);
2946 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2949 #ifdef NFS4_ACL_EXTATTR_NAME
2952 free(stp, M_NFSDSTATE);
2953 nfsvno_relpathbuf(&named);
2954 NFSEXITCODE2(error, nd);
2957 if (!nd->nd_repstat) {
2958 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2962 nfsvno_relpathbuf(&named);
2964 if (create == NFSV4OPEN_CREATE) {
2966 case NFSCREATE_UNCHECKED:
2969 * Clear the setable attribute bits, except
2970 * for Size, if it is being truncated.
2972 NFSZERO_ATTRBIT(&attrbits);
2973 if (NFSVNO_ISSETSIZE(&nva))
2974 NFSSETBIT_ATTRBIT(&attrbits,
2978 case NFSCREATE_GUARDED:
2979 if (named.ni_vp && !nd->nd_repstat)
2980 nd->nd_repstat = EEXIST;
2982 case NFSCREATE_EXCLUSIVE:
2987 case NFSCREATE_EXCLUSIVE41:
2992 nfsvno_open(nd, &named, clientid, &stateid, stp,
2993 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2994 nd->nd_cred, exp, &vp);
2995 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2996 NFSV4OPEN_CLAIMFH) {
2997 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2998 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2999 i = fxdr_unsigned(int, *tl);
3001 case NFSV4OPEN_DELEGATEREAD:
3002 stp->ls_flags |= NFSLCK_DELEGREAD;
3004 case NFSV4OPEN_DELEGATEWRITE:
3005 stp->ls_flags |= NFSLCK_DELEGWRITE;
3006 case NFSV4OPEN_DELEGATENONE:
3009 nd->nd_repstat = NFSERR_BADXDR;
3012 stp->ls_flags |= NFSLCK_RECLAIM;
3015 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3016 nd->nd_repstat = NFSERR_INVAL;
3019 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3020 if ((vp->v_iflag & VI_DOOMED) == 0)
3021 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3022 stp, vp, nd, p, nd->nd_repstat);
3024 nd->nd_repstat = NFSERR_PERM;
3026 nd->nd_repstat = NFSERR_BADXDR;
3031 * Do basic access checking.
3033 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3035 * The IETF working group decided that this is the correct
3036 * error return for all non-regular files.
3038 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3040 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3041 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3042 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3043 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3044 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3045 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3047 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3048 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
3049 NFSACCCHK_VPISLOCKED, NULL);
3052 if (!nd->nd_repstat) {
3053 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3054 if (!nd->nd_repstat) {
3055 tverf[0] = nva.na_atime.tv_sec;
3056 tverf[1] = nva.na_atime.tv_nsec;
3059 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3060 cverf[1] != tverf[1]))
3061 nd->nd_repstat = EEXIST;
3063 * Do the open locking/delegation stuff.
3065 if (!nd->nd_repstat)
3066 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3067 &delegstateid, &rflags, exp, p, nva.na_filerev);
3070 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3071 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3072 * (ie: Leave the NFSVOPUNLOCK() about here.)
3075 NFSVOPUNLOCK(vp, 0);
3077 free(stp, M_NFSDSTATE);
3078 if (!nd->nd_repstat && dirp)
3079 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3080 if (!nd->nd_repstat) {
3081 /* For NFSv4.1, set the Current StateID. */
3082 if ((nd->nd_flag & ND_NFSV41) != 0) {
3083 nd->nd_curstateid = stateid;
3084 nd->nd_flag |= ND_CURSTATEID;
3086 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3087 *tl++ = txdr_unsigned(stateid.seqid);
3088 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3089 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3090 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3091 *tl++ = newnfs_true;
3097 *tl++ = newnfs_false; /* Since dirp is not locked */
3098 txdr_hyper(dirfor.na_filerev, tl);
3100 txdr_hyper(diraft.na_filerev, tl);
3103 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3104 (void) nfsrv_putattrbit(nd, &attrbits);
3105 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3106 if (rflags & NFSV4OPEN_READDELEGATE)
3107 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3108 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3109 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3110 else if (retext != 0) {
3111 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3112 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3113 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3114 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3115 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3116 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3117 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3118 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3119 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3120 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3122 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3123 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3124 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3127 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3128 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3131 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3132 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3133 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3134 *tl++ = txdr_unsigned(delegstateid.seqid);
3135 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3137 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3138 if (rflags & NFSV4OPEN_RECALL)
3142 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3143 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3144 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3145 txdr_hyper(nva.na_size, tl);
3147 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3148 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3149 *tl++ = txdr_unsigned(0x0);
3150 acemask = NFSV4ACE_ALLFILESMASK;
3151 if (nva.na_mode & S_IRUSR)
3152 acemask |= NFSV4ACE_READMASK;
3153 if (nva.na_mode & S_IWUSR)
3154 acemask |= NFSV4ACE_WRITEMASK;
3155 if (nva.na_mode & S_IXUSR)
3156 acemask |= NFSV4ACE_EXECUTEMASK;
3157 *tl = txdr_unsigned(acemask);
3158 (void) nfsm_strtom(nd, "OWNER@", 6);
3166 #ifdef NFS4_ACL_EXTATTR_NAME
3169 NFSEXITCODE2(0, nd);
3173 #ifdef NFS4_ACL_EXTATTR_NAME
3177 free(stp, M_NFSDSTATE);
3178 NFSEXITCODE2(error, nd);
3183 * nfsv4 close service
3186 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3187 vnode_t vp, __unused struct nfsexstuff *exp)
3190 struct nfsstate st, *stp = &st;
3191 int error = 0, writeacc;
3192 nfsv4stateid_t stateid;
3195 struct thread *p = curthread;
3197 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3198 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3199 stp->ls_ownerlen = 0;
3200 stp->ls_op = nd->nd_rp;
3201 stp->ls_uid = nd->nd_cred->cr_uid;
3202 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3203 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3207 * For the special stateid of other all 0s and seqid == 1, set the
3208 * stateid to the current stateid, if it is set.
3210 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3211 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3212 stp->ls_stateid.other[2] == 0) {
3213 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3214 stp->ls_stateid = nd->nd_curstateid;
3216 nd->nd_repstat = NFSERR_BADSTATEID;
3221 stp->ls_flags = NFSLCK_CLOSE;
3222 clientid.lval[0] = stp->ls_stateid.other[0];
3223 clientid.lval[1] = stp->ls_stateid.other[1];
3224 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3225 if ((nd->nd_flag & ND_NFSV41) != 0)
3226 clientid.qval = nd->nd_clientid.qval;
3227 else if (nd->nd_clientid.qval != clientid.qval)
3228 printf("EEK8 multiple clids\n");
3230 if ((nd->nd_flag & ND_NFSV41) != 0)
3231 printf("EEK! no clientid from session\n");
3232 nd->nd_flag |= ND_IMPLIEDCLID;
3233 nd->nd_clientid.qval = clientid.qval;
3235 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3237 /* For pNFS, update the attributes. */
3238 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3239 nfsrv_updatemdsattr(vp, &na, p);
3241 if (!nd->nd_repstat) {
3243 * If the stateid that has been closed is the current stateid,
3246 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3247 stateid.other[0] == nd->nd_curstateid.other[0] &&
3248 stateid.other[1] == nd->nd_curstateid.other[1] &&
3249 stateid.other[2] == nd->nd_curstateid.other[2])
3250 nd->nd_flag &= ~ND_CURSTATEID;
3251 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3252 *tl++ = txdr_unsigned(stateid.seqid);
3253 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3255 NFSEXITCODE2(0, nd);
3259 NFSEXITCODE2(error, nd);
3264 * nfsv4 delegpurge service
3267 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3268 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3273 struct thread *p = curthread;
3275 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3276 nd->nd_repstat = NFSERR_WRONGSEC;
3279 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3280 clientid.lval[0] = *tl++;
3281 clientid.lval[1] = *tl;
3282 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3283 if ((nd->nd_flag & ND_NFSV41) != 0)
3284 clientid.qval = nd->nd_clientid.qval;
3285 else if (nd->nd_clientid.qval != clientid.qval)
3286 printf("EEK9 multiple clids\n");
3288 if ((nd->nd_flag & ND_NFSV41) != 0)
3289 printf("EEK! no clientid from session\n");
3290 nd->nd_flag |= ND_IMPLIEDCLID;
3291 nd->nd_clientid.qval = clientid.qval;
3293 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3294 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3296 NFSEXITCODE2(error, nd);
3301 * nfsv4 delegreturn service
3304 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3305 vnode_t vp, __unused struct nfsexstuff *exp)
3308 int error = 0, writeacc;
3309 nfsv4stateid_t stateid;
3312 struct thread *p = curthread;
3314 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3315 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3316 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3317 clientid.lval[0] = stateid.other[0];
3318 clientid.lval[1] = stateid.other[1];
3319 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3320 if ((nd->nd_flag & ND_NFSV41) != 0)
3321 clientid.qval = nd->nd_clientid.qval;
3322 else if (nd->nd_clientid.qval != clientid.qval)
3323 printf("EEK10 multiple clids\n");
3325 if ((nd->nd_flag & ND_NFSV41) != 0)
3326 printf("EEK! no clientid from session\n");
3327 nd->nd_flag |= ND_IMPLIEDCLID;
3328 nd->nd_clientid.qval = clientid.qval;
3330 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3331 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3332 /* For pNFS, update the attributes. */
3333 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3334 nfsrv_updatemdsattr(vp, &na, p);
3337 NFSEXITCODE2(error, nd);
3342 * nfsv4 get file handle service
3345 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3346 vnode_t vp, __unused struct nfsexstuff *exp)
3349 struct thread *p = curthread;
3351 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3353 if (!nd->nd_repstat)
3354 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3355 NFSEXITCODE2(0, nd);
3360 * nfsv4 open confirm service
3363 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3364 vnode_t vp, __unused struct nfsexstuff *exp)
3367 struct nfsstate st, *stp = &st;
3369 nfsv4stateid_t stateid;
3371 struct thread *p = curthread;
3373 if ((nd->nd_flag & ND_NFSV41) != 0) {
3374 nd->nd_repstat = NFSERR_NOTSUPP;
3377 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3378 stp->ls_ownerlen = 0;
3379 stp->ls_op = nd->nd_rp;
3380 stp->ls_uid = nd->nd_cred->cr_uid;
3381 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3382 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3384 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3385 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3386 stp->ls_flags = NFSLCK_CONFIRM;
3387 clientid.lval[0] = stp->ls_stateid.other[0];
3388 clientid.lval[1] = stp->ls_stateid.other[1];
3389 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3390 if ((nd->nd_flag & ND_NFSV41) != 0)
3391 clientid.qval = nd->nd_clientid.qval;
3392 else if (nd->nd_clientid.qval != clientid.qval)
3393 printf("EEK11 multiple clids\n");
3395 if ((nd->nd_flag & ND_NFSV41) != 0)
3396 printf("EEK! no clientid from session\n");
3397 nd->nd_flag |= ND_IMPLIEDCLID;
3398 nd->nd_clientid.qval = clientid.qval;
3400 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3402 if (!nd->nd_repstat) {
3403 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3404 *tl++ = txdr_unsigned(stateid.seqid);
3405 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3409 NFSEXITCODE2(error, nd);
3414 * nfsv4 open downgrade service
3417 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3418 vnode_t vp, __unused struct nfsexstuff *exp)
3422 struct nfsstate st, *stp = &st;
3424 nfsv4stateid_t stateid;
3426 struct thread *p = curthread;
3428 /* opendowngrade can only work on a file object.*/
3429 if (vp->v_type != VREG) {
3430 error = NFSERR_INVAL;
3433 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3434 stp->ls_ownerlen = 0;
3435 stp->ls_op = nd->nd_rp;
3436 stp->ls_uid = nd->nd_cred->cr_uid;
3437 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3438 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3440 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3443 * For the special stateid of other all 0s and seqid == 1, set the
3444 * stateid to the current stateid, if it is set.
3446 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3447 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3448 stp->ls_stateid.other[2] == 0) {
3449 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3450 stp->ls_stateid = nd->nd_curstateid;
3452 nd->nd_repstat = NFSERR_BADSTATEID;
3457 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3458 i = fxdr_unsigned(int, *tl++);
3459 if ((nd->nd_flag & ND_NFSV41) != 0)
3460 i &= ~NFSV4OPEN_WANTDELEGMASK;
3462 case NFSV4OPEN_ACCESSREAD:
3463 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3465 case NFSV4OPEN_ACCESSWRITE:
3466 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3468 case NFSV4OPEN_ACCESSBOTH:
3469 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3473 nd->nd_repstat = NFSERR_INVAL;
3475 i = fxdr_unsigned(int, *tl);
3477 case NFSV4OPEN_DENYNONE:
3479 case NFSV4OPEN_DENYREAD:
3480 stp->ls_flags |= NFSLCK_READDENY;
3482 case NFSV4OPEN_DENYWRITE:
3483 stp->ls_flags |= NFSLCK_WRITEDENY;
3485 case NFSV4OPEN_DENYBOTH:
3486 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3489 nd->nd_repstat = NFSERR_INVAL;
3492 clientid.lval[0] = stp->ls_stateid.other[0];
3493 clientid.lval[1] = stp->ls_stateid.other[1];
3494 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3495 if ((nd->nd_flag & ND_NFSV41) != 0)
3496 clientid.qval = nd->nd_clientid.qval;
3497 else if (nd->nd_clientid.qval != clientid.qval)
3498 printf("EEK12 multiple clids\n");
3500 if ((nd->nd_flag & ND_NFSV41) != 0)
3501 printf("EEK! no clientid from session\n");
3502 nd->nd_flag |= ND_IMPLIEDCLID;
3503 nd->nd_clientid.qval = clientid.qval;
3505 if (!nd->nd_repstat)
3506 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3508 if (!nd->nd_repstat) {
3509 /* For NFSv4.1, set the Current StateID. */
3510 if ((nd->nd_flag & ND_NFSV41) != 0) {
3511 nd->nd_curstateid = stateid;
3512 nd->nd_flag |= ND_CURSTATEID;
3514 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3515 *tl++ = txdr_unsigned(stateid.seqid);
3516 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3520 NFSEXITCODE2(error, nd);
3525 * nfsv4 renew lease service
3528 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3529 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3534 struct thread *p = curthread;
3536 if ((nd->nd_flag & ND_NFSV41) != 0) {
3537 nd->nd_repstat = NFSERR_NOTSUPP;
3540 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3541 nd->nd_repstat = NFSERR_WRONGSEC;
3544 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3545 clientid.lval[0] = *tl++;
3546 clientid.lval[1] = *tl;
3547 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3548 if ((nd->nd_flag & ND_NFSV41) != 0)
3549 clientid.qval = nd->nd_clientid.qval;
3550 else if (nd->nd_clientid.qval != clientid.qval)
3551 printf("EEK13 multiple clids\n");
3553 if ((nd->nd_flag & ND_NFSV41) != 0)
3554 printf("EEK! no clientid from session\n");
3555 nd->nd_flag |= ND_IMPLIEDCLID;
3556 nd->nd_clientid.qval = clientid.qval;
3558 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3559 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3561 NFSEXITCODE2(error, nd);
3566 * nfsv4 security info service
3569 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3570 vnode_t dp, struct nfsexstuff *exp)
3574 struct nameidata named;
3575 vnode_t dirp = NULL, vp;
3577 struct nfsexstuff retnes;
3579 int error = 0, savflag, i;
3582 struct thread *p = curthread;
3585 * All this just to get the export flags for the name.
3587 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3588 LOCKLEAF | SAVESTART);
3589 nfsvno_setpathbuf(&named, &bufp, &hashp);
3590 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3593 nfsvno_relpathbuf(&named);
3596 if (!nd->nd_repstat) {
3597 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3600 nfsvno_relpathbuf(&named);
3606 vrele(named.ni_startdir);
3607 nfsvno_relpathbuf(&named);
3608 fh.nfsrvfh_len = NFSX_MYFH;
3610 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3612 savflag = nd->nd_flag;
3613 if (!nd->nd_repstat) {
3614 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3618 nd->nd_flag = savflag;
3623 * Finally have the export flags for name, so we can create
3624 * the security info.
3627 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3628 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3629 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3630 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3631 *tl = txdr_unsigned(RPCAUTH_UNIX);
3633 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3634 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3635 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3636 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3637 nfsgss_mechlist[KERBV_MECH].len);
3638 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3639 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3640 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3642 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3643 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3644 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3645 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3646 nfsgss_mechlist[KERBV_MECH].len);
3647 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3648 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3649 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3651 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3652 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3653 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3654 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3655 nfsgss_mechlist[KERBV_MECH].len);
3656 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3657 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3658 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3662 *sizp = txdr_unsigned(len);
3665 NFSEXITCODE2(error, nd);
3670 * nfsv4 set client id service
3673 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3674 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3678 int error = 0, idlen;
3679 struct nfsclient *clp = NULL;
3680 struct sockaddr_in *rad;
3681 u_char *verf, *ucp, *ucp2, addrbuf[24];
3682 nfsquad_t clientid, confirm;
3683 struct thread *p = curthread;
3685 if ((nd->nd_flag & ND_NFSV41) != 0) {
3686 nd->nd_repstat = NFSERR_NOTSUPP;
3689 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3690 nd->nd_repstat = NFSERR_WRONGSEC;
3693 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3694 verf = (u_char *)tl;
3695 tl += (NFSX_VERF / NFSX_UNSIGNED);
3696 i = fxdr_unsigned(int, *tl);
3697 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3698 nd->nd_repstat = NFSERR_BADXDR;
3702 if (nd->nd_flag & ND_GSS)
3703 i += nd->nd_princlen;
3704 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3706 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3707 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3708 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3709 clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
3711 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3712 clp->lc_req.nr_cred = NULL;
3713 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3714 clp->lc_idlen = idlen;
3715 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3718 if (nd->nd_flag & ND_GSS) {
3719 clp->lc_flags = LCL_GSS;
3720 if (nd->nd_flag & ND_GSSINTEGRITY)
3721 clp->lc_flags |= LCL_GSSINTEGRITY;
3722 else if (nd->nd_flag & ND_GSSPRIVACY)
3723 clp->lc_flags |= LCL_GSSPRIVACY;
3727 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3728 clp->lc_flags |= LCL_NAME;
3729 clp->lc_namelen = nd->nd_princlen;
3730 clp->lc_name = &clp->lc_id[idlen];
3731 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3733 clp->lc_uid = nd->nd_cred->cr_uid;
3734 clp->lc_gid = nd->nd_cred->cr_gid;
3736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3737 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3738 error = nfsrv_getclientipaddr(nd, clp);
3741 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3742 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3745 * nfsrv_setclient() does the actual work of adding it to the
3746 * client list. If there is no error, the structure has been
3747 * linked into the client list and clp should no longer be used
3748 * here. When an error is returned, it has not been linked in,
3749 * so it should be free'd.
3751 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3752 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3753 if (clp->lc_flags & LCL_TCPCALLBACK)
3754 (void) nfsm_strtom(nd, "tcp", 3);
3756 (void) nfsm_strtom(nd, "udp", 3);
3757 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3758 ucp = (u_char *)&rad->sin_addr.s_addr;
3759 ucp2 = (u_char *)&rad->sin_port;
3760 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3761 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3762 ucp2[0] & 0xff, ucp2[1] & 0xff);
3763 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3766 free(clp->lc_req.nr_nam, M_SONAME);
3767 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3768 free(clp->lc_stateid, M_NFSDCLIENT);
3769 free(clp, M_NFSDCLIENT);
3771 if (!nd->nd_repstat) {
3772 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3773 *tl++ = clientid.lval[0];
3774 *tl++ = clientid.lval[1];
3775 *tl++ = confirm.lval[0];
3776 *tl = confirm.lval[1];
3780 NFSEXITCODE2(0, nd);
3784 free(clp->lc_req.nr_nam, M_SONAME);
3785 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3786 free(clp->lc_stateid, M_NFSDCLIENT);
3787 free(clp, M_NFSDCLIENT);
3789 NFSEXITCODE2(error, nd);
3794 * nfsv4 set client id confirm service
3797 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3798 __unused int isdgram, __unused vnode_t vp,
3799 __unused struct nfsexstuff *exp)
3803 nfsquad_t clientid, confirm;
3804 struct thread *p = curthread;
3806 if ((nd->nd_flag & ND_NFSV41) != 0) {
3807 nd->nd_repstat = NFSERR_NOTSUPP;
3810 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3811 nd->nd_repstat = NFSERR_WRONGSEC;
3814 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3815 clientid.lval[0] = *tl++;
3816 clientid.lval[1] = *tl++;
3817 confirm.lval[0] = *tl++;
3818 confirm.lval[1] = *tl;
3821 * nfsrv_getclient() searches the client list for a match and
3822 * returns the appropriate NFSERR status.
3824 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3825 NULL, NULL, confirm, 0, nd, p);
3827 NFSEXITCODE2(error, nd);
3832 * nfsv4 verify service
3835 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3836 vnode_t vp, __unused struct nfsexstuff *exp)
3838 int error = 0, ret, fhsize = NFSX_MYFH;
3839 struct nfsvattr nva;
3841 struct nfsfsinfo fs;
3843 struct thread *p = curthread;
3845 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3846 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3847 if (!nd->nd_repstat)
3848 nd->nd_repstat = nfsvno_statfs(vp, sf);
3849 if (!nd->nd_repstat)
3850 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3851 if (!nd->nd_repstat) {
3852 nfsvno_getfs(&fs, isdgram);
3853 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3854 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3856 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3858 nd->nd_repstat = NFSERR_SAME;
3859 else if (ret != NFSERR_NOTSAME)
3860 nd->nd_repstat = ret;
3862 nd->nd_repstat = ret;
3867 NFSEXITCODE2(error, nd);
3875 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3876 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3877 __unused struct nfsexstuff *exp)
3880 int error = 0, createdir __unused;
3882 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3883 createdir = fxdr_unsigned(int, *tl);
3884 nd->nd_repstat = NFSERR_NOTSUPP;
3887 NFSEXITCODE2(error, nd);
3892 * nfsv4 release lock owner service
3895 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3896 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3899 struct nfsstate *stp = NULL;
3902 struct thread *p = curthread;
3904 if ((nd->nd_flag & ND_NFSV41) != 0) {
3905 nd->nd_repstat = NFSERR_NOTSUPP;
3908 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3909 nd->nd_repstat = NFSERR_WRONGSEC;
3912 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3913 len = fxdr_unsigned(int, *(tl + 2));
3914 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3915 nd->nd_repstat = NFSERR_BADXDR;
3918 stp = malloc(sizeof (struct nfsstate) + len,
3919 M_NFSDSTATE, M_WAITOK);
3920 stp->ls_ownerlen = len;
3922 stp->ls_flags = NFSLCK_RELEASE;
3923 stp->ls_uid = nd->nd_cred->cr_uid;
3924 clientid.lval[0] = *tl++;
3925 clientid.lval[1] = *tl;
3926 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3927 if ((nd->nd_flag & ND_NFSV41) != 0)
3928 clientid.qval = nd->nd_clientid.qval;
3929 else if (nd->nd_clientid.qval != clientid.qval)
3930 printf("EEK14 multiple clids\n");
3932 if ((nd->nd_flag & ND_NFSV41) != 0)
3933 printf("EEK! no clientid from session\n");
3934 nd->nd_flag |= ND_IMPLIEDCLID;
3935 nd->nd_clientid.qval = clientid.qval;
3937 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3940 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3941 free(stp, M_NFSDSTATE);
3943 NFSEXITCODE2(0, nd);
3947 free(stp, M_NFSDSTATE);
3948 NFSEXITCODE2(error, nd);
3953 * nfsv4 exchange_id service
3956 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3957 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3960 int error = 0, i, idlen;
3961 struct nfsclient *clp = NULL;
3962 nfsquad_t clientid, confirm;
3964 uint32_t sp4type, v41flags;
3965 uint64_t owner_minor;
3966 struct timespec verstime;
3967 struct sockaddr_in *sad, *rad;
3968 struct thread *p = curthread;
3970 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3971 nd->nd_repstat = NFSERR_WRONGSEC;
3974 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3975 verf = (uint8_t *)tl;
3976 tl += (NFSX_VERF / NFSX_UNSIGNED);
3977 i = fxdr_unsigned(int, *tl);
3978 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3979 nd->nd_repstat = NFSERR_BADXDR;
3983 if (nd->nd_flag & ND_GSS)
3984 i += nd->nd_princlen;
3985 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3987 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3988 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3989 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3990 clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
3992 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3993 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
3994 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3995 rad->sin_family = AF_INET;
3996 rad->sin_addr.s_addr = 0;
3998 if (sad->sin_family == AF_INET)
3999 rad->sin_addr.s_addr = sad->sin_addr.s_addr;
4000 clp->lc_req.nr_cred = NULL;
4001 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4002 clp->lc_idlen = idlen;
4003 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4006 if ((nd->nd_flag & ND_GSS) != 0) {
4007 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4008 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4009 clp->lc_flags |= LCL_GSSINTEGRITY;
4010 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4011 clp->lc_flags |= LCL_GSSPRIVACY;
4013 clp->lc_flags = LCL_NFSV41;
4014 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4015 clp->lc_flags |= LCL_NAME;
4016 clp->lc_namelen = nd->nd_princlen;
4017 clp->lc_name = &clp->lc_id[idlen];
4018 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4020 clp->lc_uid = nd->nd_cred->cr_uid;
4021 clp->lc_gid = nd->nd_cred->cr_gid;
4023 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4024 v41flags = fxdr_unsigned(uint32_t, *tl++);
4025 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4026 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4027 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4028 nd->nd_repstat = NFSERR_INVAL;
4031 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4032 confirm.lval[1] = 1;
4034 confirm.lval[1] = 0;
4035 if (nfsrv_devidcnt == 0)
4036 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4038 v41flags = NFSV4EXCH_USEPNFSMDS;
4039 sp4type = fxdr_unsigned(uint32_t, *tl);
4040 if (sp4type != NFSV4EXCH_SP4NONE) {
4041 nd->nd_repstat = NFSERR_NOTSUPP;
4046 * nfsrv_setclient() does the actual work of adding it to the
4047 * client list. If there is no error, the structure has been
4048 * linked into the client list and clp should no longer be used
4049 * here. When an error is returned, it has not been linked in,
4050 * so it should be free'd.
4052 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4054 free(clp->lc_req.nr_nam, M_SONAME);
4055 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4056 free(clp->lc_stateid, M_NFSDCLIENT);
4057 free(clp, M_NFSDCLIENT);
4059 if (nd->nd_repstat == 0) {
4060 if (confirm.lval[1] != 0)
4061 v41flags |= NFSV4EXCH_CONFIRMEDR;
4062 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4063 *tl++ = clientid.lval[0]; /* ClientID */
4064 *tl++ = clientid.lval[1];
4065 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4066 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4067 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4068 owner_minor = 0; /* Owner */
4069 txdr_hyper(owner_minor, tl); /* Minor */
4070 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4071 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4072 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4073 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4074 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4075 *tl = txdr_unsigned(1);
4076 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4077 (void)nfsm_strtom(nd, version, strlen(version));
4078 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4079 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4080 verstime.tv_nsec = 0;
4081 txdr_nfsv4time(&verstime, tl);
4083 NFSEXITCODE2(0, nd);
4087 free(clp->lc_req.nr_nam, M_SONAME);
4088 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4089 free(clp->lc_stateid, M_NFSDCLIENT);
4090 free(clp, M_NFSDCLIENT);
4092 NFSEXITCODE2(error, nd);
4097 * nfsv4 create session service
4100 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4101 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4105 nfsquad_t clientid, confirm;
4106 struct nfsdsession *sep = NULL;
4108 struct thread *p = curthread;
4110 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4111 nd->nd_repstat = NFSERR_WRONGSEC;
4114 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4115 M_NFSDSESSION, M_WAITOK | M_ZERO);
4116 sep->sess_refcnt = 1;
4117 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4118 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4119 clientid.lval[0] = *tl++;
4120 clientid.lval[1] = *tl++;
4121 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4122 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4123 /* Persistent sessions and RDMA are not supported. */
4124 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4126 /* Fore channel attributes. */
4127 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4128 tl++; /* Header pad always 0. */
4129 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4130 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4131 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4132 printf("Consider increasing kern.ipc.maxsockbuf\n");
4134 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4135 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4136 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4137 printf("Consider increasing kern.ipc.maxsockbuf\n");
4139 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4140 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4141 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4142 if (sep->sess_maxslots > NFSV4_SLOTS)
4143 sep->sess_maxslots = NFSV4_SLOTS;
4144 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4146 nd->nd_repstat = NFSERR_BADXDR;
4148 } else if (rdmacnt == 1)
4149 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4151 /* Back channel attributes. */
4152 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4153 tl++; /* Header pad always 0. */
4154 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4155 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4156 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4157 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4158 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4159 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4161 nd->nd_repstat = NFSERR_BADXDR;
4163 } else if (rdmacnt == 1)
4164 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4166 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4167 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4170 * nfsrv_getclient() searches the client list for a match and
4171 * returns the appropriate NFSERR status.
4173 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4174 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4175 if (nd->nd_repstat == 0) {
4176 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4177 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4178 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4179 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4180 *tl++ = txdr_unsigned(sep->sess_crflags);
4182 /* Fore channel attributes. */
4184 *tl++ = txdr_unsigned(sep->sess_maxreq);
4185 *tl++ = txdr_unsigned(sep->sess_maxresp);
4186 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4187 *tl++ = txdr_unsigned(sep->sess_maxops);
4188 *tl++ = txdr_unsigned(sep->sess_maxslots);
4189 *tl++ = txdr_unsigned(1);
4190 *tl++ = txdr_unsigned(0); /* No RDMA. */
4192 /* Back channel attributes. */
4194 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4195 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4196 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4197 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4198 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4199 *tl++ = txdr_unsigned(1);
4200 *tl = txdr_unsigned(0); /* No RDMA. */
4203 if (nd->nd_repstat != 0 && sep != NULL)
4204 free(sep, M_NFSDSESSION);
4205 NFSEXITCODE2(error, nd);
4210 * nfsv4 sequence service
4213 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4214 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4217 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4218 int cache_this, error = 0;
4219 struct thread *p = curthread;
4221 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4222 nd->nd_repstat = NFSERR_WRONGSEC;
4225 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4226 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4227 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4228 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4229 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4230 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4231 if (*tl == newnfs_true)
4235 nd->nd_flag |= ND_HASSEQUENCE;
4236 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4237 &target_highest_slotid, cache_this, &sflags, p);
4238 if (nd->nd_repstat == 0) {
4239 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4240 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4241 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4242 *tl++ = txdr_unsigned(sequenceid);
4243 *tl++ = txdr_unsigned(nd->nd_slotid);
4244 *tl++ = txdr_unsigned(highest_slotid);
4245 *tl++ = txdr_unsigned(target_highest_slotid);
4246 *tl = txdr_unsigned(sflags);
4249 NFSEXITCODE2(error, nd);
4254 * nfsv4 reclaim complete service
4257 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4258 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4261 int error = 0, onefs;
4263 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4264 nd->nd_repstat = NFSERR_WRONGSEC;
4267 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4269 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4270 * to be used after a file system has been transferred to a different
4271 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4272 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4273 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4274 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4275 * NFS_OK without doing anything.
4278 if (*tl == newnfs_true)
4280 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4282 NFSEXITCODE2(error, nd);
4287 * nfsv4 destroy clientid service
4290 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4291 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4296 struct thread *p = curthread;
4298 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4299 nd->nd_repstat = NFSERR_WRONGSEC;
4302 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4303 clientid.lval[0] = *tl++;
4304 clientid.lval[1] = *tl;
4305 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4307 NFSEXITCODE2(error, nd);
4312 * nfsv4 bind connection to session service
4315 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4316 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4319 uint8_t sessid[NFSX_V4SESSIONID];
4320 int error = 0, foreaft;
4322 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4323 nd->nd_repstat = NFSERR_WRONGSEC;
4326 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4327 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4328 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4329 foreaft = fxdr_unsigned(int, *tl++);
4330 if (*tl == newnfs_true) {
4331 /* RDMA is not supported. */
4332 nd->nd_repstat = NFSERR_NOTSUPP;
4336 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4337 if (nd->nd_repstat == 0) {
4338 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4340 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4341 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4342 *tl++ = txdr_unsigned(foreaft);
4346 NFSEXITCODE2(error, nd);
4351 * nfsv4 destroy session service
4354 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4355 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4357 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4360 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4361 nd->nd_repstat = NFSERR_WRONGSEC;
4364 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4365 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4366 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4368 NFSEXITCODE2(error, nd);
4373 * nfsv4 free stateid service
4376 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4377 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4380 nfsv4stateid_t stateid;
4382 struct thread *p = curthread;
4384 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4385 nd->nd_repstat = NFSERR_WRONGSEC;
4388 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4389 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4390 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4393 * For the special stateid of other all 0s and seqid == 1, set the
4394 * stateid to the current stateid, if it is set.
4396 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4397 stateid.other[1] == 0 && stateid.other[2] == 0) {
4398 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4399 stateid = nd->nd_curstateid;
4402 nd->nd_repstat = NFSERR_BADSTATEID;
4407 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4409 /* If the current stateid has been free'd, unset it. */
4410 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4411 stateid.other[0] == nd->nd_curstateid.other[0] &&
4412 stateid.other[1] == nd->nd_curstateid.other[1] &&
4413 stateid.other[2] == nd->nd_curstateid.other[2])
4414 nd->nd_flag &= ~ND_CURSTATEID;
4416 NFSEXITCODE2(error, nd);
4421 * nfsv4 layoutget service
4424 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4425 vnode_t vp, struct nfsexstuff *exp)
4428 nfsv4stateid_t stateid;
4429 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4430 uint64_t offset, len, minlen;
4432 struct thread *p = curthread;
4434 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4435 nd->nd_repstat = NFSERR_WRONGSEC;
4438 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4440 tl++; /* Signal layout available. Ignore for now. */
4441 layouttype = fxdr_unsigned(int, *tl++);
4442 iomode = fxdr_unsigned(int, *tl++);
4443 offset = fxdr_hyper(tl); tl += 2;
4444 len = fxdr_hyper(tl); tl += 2;
4445 minlen = fxdr_hyper(tl); tl += 2;
4446 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4447 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4448 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4449 maxcnt = fxdr_unsigned(int, *tl);
4450 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4451 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4454 (minlen != UINT64_MAX && offset + minlen < offset) ||
4455 (len != UINT64_MAX && offset + len < offset)) {
4456 nd->nd_repstat = NFSERR_INVAL;
4461 * For the special stateid of other all 0s and seqid == 1, set the
4462 * stateid to the current stateid, if it is set.
4464 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4465 stateid.other[1] == 0 && stateid.other[2] == 0) {
4466 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4467 stateid = nd->nd_curstateid;
4470 nd->nd_repstat = NFSERR_BADSTATEID;
4476 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4477 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4478 else if (layouttype == NFSLAYOUT_FLEXFILE)
4479 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4482 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4484 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4485 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4486 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4487 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4489 if (nd->nd_repstat == 0) {
4490 /* For NFSv4.1, set the Current StateID. */
4491 if ((nd->nd_flag & ND_NFSV41) != 0) {
4492 nd->nd_curstateid = stateid;
4493 nd->nd_flag |= ND_CURSTATEID;
4495 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4497 *tl++ = txdr_unsigned(retonclose);
4498 *tl++ = txdr_unsigned(stateid.seqid);
4499 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4500 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4501 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4502 txdr_hyper(offset, tl); tl += 2;
4503 txdr_hyper(len, tl); tl += 2;
4504 *tl++ = txdr_unsigned(iomode);
4505 *tl = txdr_unsigned(layouttype);
4506 nfsm_strtom(nd, layp, layoutlen);
4507 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4508 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4514 NFSEXITCODE2(error, nd);
4519 * nfsv4 layoutcommit service
4522 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4523 vnode_t vp, struct nfsexstuff *exp)
4526 nfsv4stateid_t stateid;
4527 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4529 uint64_t offset, len, newoff, newsize;
4530 struct timespec newmtime;
4532 struct thread *p = curthread;
4535 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4536 nd->nd_repstat = NFSERR_WRONGSEC;
4539 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4541 offset = fxdr_hyper(tl); tl += 2;
4542 len = fxdr_hyper(tl); tl += 2;
4543 reclaim = fxdr_unsigned(int, *tl++);
4544 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4545 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4546 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4548 * For the special stateid of other all 0s and seqid == 1, set the
4549 * stateid to the current stateid, if it is set.
4551 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4552 stateid.other[1] == 0 && stateid.other[2] == 0) {
4553 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4554 stateid = nd->nd_curstateid;
4557 nd->nd_repstat = NFSERR_BADSTATEID;
4562 hasnewoff = fxdr_unsigned(int, *tl);
4563 if (hasnewoff != 0) {
4564 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4565 newoff = fxdr_hyper(tl); tl += 2;
4567 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4568 hasnewmtime = fxdr_unsigned(int, *tl);
4569 if (hasnewmtime != 0) {
4570 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4571 fxdr_nfsv4time(tl, &newmtime);
4572 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4574 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4575 layouttype = fxdr_unsigned(int, *tl++);
4576 maxcnt = fxdr_unsigned(int, *tl);
4578 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4579 error = nfsrv_mtostr(nd, layp, maxcnt);
4583 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4584 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4585 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4586 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4587 if (nd->nd_repstat == 0) {
4588 if (hasnewsize != 0) {
4589 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4590 *tl++ = newnfs_true;
4591 txdr_hyper(newsize, tl);
4593 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4600 NFSEXITCODE2(error, nd);
4605 * nfsv4 layoutreturn service
4608 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4609 vnode_t vp, struct nfsexstuff *exp)
4611 uint32_t *tl, *layp;
4612 nfsv4stateid_t stateid;
4613 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4614 uint64_t offset, len;
4615 struct thread *p = curthread;
4618 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4619 nd->nd_repstat = NFSERR_WRONGSEC;
4622 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4624 layouttype = fxdr_unsigned(int, *tl++);
4625 iomode = fxdr_unsigned(int, *tl++);
4626 kind = fxdr_unsigned(int, *tl);
4627 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4628 layouttype, iomode, kind);
4629 if (kind == NFSV4LAYOUTRET_FILE) {
4630 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4632 offset = fxdr_hyper(tl); tl += 2;
4633 len = fxdr_hyper(tl); tl += 2;
4634 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4635 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4636 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4639 * For the special stateid of other all 0s and seqid == 1, set
4640 * the stateid to the current stateid, if it is set.
4642 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4643 stateid.other[1] == 0 && stateid.other[2] == 0) {
4644 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4645 stateid = nd->nd_curstateid;
4648 nd->nd_repstat = NFSERR_BADSTATEID;
4653 maxcnt = fxdr_unsigned(int, *tl);
4655 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4656 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4661 if (reclaim == newnfs_true) {
4662 nd->nd_repstat = NFSERR_INVAL;
4668 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4669 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4671 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4673 if (nd->nd_repstat == 0) {
4674 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4677 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4678 *tl++ = txdr_unsigned(stateid.seqid);
4679 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4686 NFSEXITCODE2(error, nd);
4691 * nfsv4 getdeviceinfo service
4694 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4695 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4697 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
4698 int cnt, devaddrlen, error = 0, i, layouttype;
4699 char devid[NFSX_V4DEVICEID], *devaddr;
4702 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4703 nd->nd_repstat = NFSERR_WRONGSEC;
4706 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4707 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4708 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4709 layouttype = fxdr_unsigned(int, *tl++);
4710 maxcnt = fxdr_unsigned(uint32_t, *tl++);
4711 cnt = fxdr_unsigned(int, *tl);
4712 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
4714 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
4715 nd->nd_repstat = NFSERR_INVAL;
4719 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
4720 for (i = 0; i < cnt; i++)
4721 notify[i] = fxdr_unsigned(uint32_t, *tl++);
4723 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
4727 * Check that the device id is not stale. Device ids are recreated
4728 * each time the nfsd threads are restarted.
4730 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
4731 if (dev_time != nfsdev_time) {
4732 nd->nd_repstat = NFSERR_NOENT;
4736 /* Look for the device id. */
4737 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
4738 notify, &devaddrlen, &devaddr);
4739 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
4740 if (nd->nd_repstat == 0) {
4741 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4742 *tl = txdr_unsigned(layouttype);
4743 nfsm_strtom(nd, devaddr, devaddrlen);
4745 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
4749 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
4750 *tl++ = txdr_unsigned(cnt);
4751 for (i = 0; i < cnt; i++)
4752 *tl++ = txdr_unsigned(notify[i]);
4753 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
4754 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4755 *tl = txdr_unsigned(maxcnt);
4758 NFSEXITCODE2(error, nd);
4763 * nfsv4 test stateid service
4766 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
4767 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4770 nfsv4stateid_t *stateidp = NULL, *tstateidp;
4771 int cnt, error = 0, i, ret;
4772 struct thread *p = curthread;
4774 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4775 nd->nd_repstat = NFSERR_WRONGSEC;
4778 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4779 cnt = fxdr_unsigned(int, *tl);
4780 if (cnt <= 0 || cnt > 1024) {
4781 nd->nd_repstat = NFSERR_BADXDR;
4784 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
4785 tstateidp = stateidp;
4786 for (i = 0; i < cnt; i++) {
4787 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4788 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4789 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
4792 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4793 *tl = txdr_unsigned(cnt);
4794 tstateidp = stateidp;
4795 for (i = 0; i < cnt; i++) {
4796 ret = nfsrv_teststateid(nd, tstateidp, p);
4797 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4798 *tl = txdr_unsigned(ret);
4802 free(stateidp, M_TEMP);
4803 NFSEXITCODE2(error, nd);
4808 * nfsv4 service not supported
4811 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4812 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4815 nd->nd_repstat = NFSERR_NOTSUPP;
4816 NFSEXITCODE2(0, nd);