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 #include "opt_inet6.h"
42 * nfs version 2, 3 and 4 server calls to vnode ops
43 * - these routines generally have 3 phases
44 * 1 - break down and validate rpc request in mbuf list
45 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
46 * function in nfsd_port.c
47 * 3 - build the rpc reply in an mbuf list
48 * For nfsv4, these functions are called for each Op within the Compound RPC.
52 #include <fs/nfs/nfsport.h>
53 #include <sys/extattr.h>
54 #include <sys/filio.h>
57 extern u_int32_t newnfs_false, newnfs_true;
58 extern enum vtype nv34tov_type[8];
59 extern struct timeval nfsboottime;
60 extern int nfs_rootfhset;
61 extern int nfsrv_enable_crossmntpt;
62 extern int nfsrv_statehashsize;
63 extern int nfsrv_layouthashsize;
64 extern time_t nfsdev_time;
65 extern volatile int nfsrv_devidcnt;
66 extern int nfsd_debuglevel;
67 extern u_long sb_max_adj;
68 extern int nfsrv_pnfsatime;
69 extern int nfsrv_maxpnfsmirror;
70 extern int nfs_maxcopyrange;
71 #endif /* !APPLEKEXT */
73 static int nfs_async = 0;
74 SYSCTL_DECL(_vfs_nfsd);
75 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
76 "Tell client that writes were synced even though they were not");
77 extern int nfsrv_doflexfile;
78 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
79 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
80 static int nfsrv_linux42server = 1;
81 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
82 &nfsrv_linux42server, 0,
83 "Enable Linux style NFSv4.2 server (non-RFC compliant)");
86 * This list defines the GSS mechanisms supported.
87 * (Don't ask me how you get these strings from the RFC stuff like
88 * iso(1), org(3)... but someone did it, so I don't need to know.)
90 static struct nfsgss_mechlist nfsgss_mechlist[] = {
91 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
96 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
97 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
98 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
99 int *diraft_retp, nfsattrbit_t *attrbitp,
100 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
102 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
103 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
104 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
105 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
106 NFSPROC_T *p, struct nfsexstuff *exp);
109 * nfs access service (not a part of NFS V2)
112 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
113 vnode_t vp, struct nfsexstuff *exp)
116 int getret, error = 0;
118 u_int32_t testmode, nfsmode, supported = 0;
120 struct thread *p = curthread;
122 if (nd->nd_repstat) {
123 nfsrv_postopattr(nd, 1, &nva);
126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
127 nfsmode = fxdr_unsigned(u_int32_t, *tl);
128 if ((nd->nd_flag & ND_NFSV4) &&
129 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
130 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
131 NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
132 NFSACCESS_XALIST))) {
133 nd->nd_repstat = NFSERR_INVAL;
137 if (nfsmode & NFSACCESS_READ) {
138 supported |= NFSACCESS_READ;
139 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
140 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
141 nfsmode &= ~NFSACCESS_READ;
143 if (nfsmode & NFSACCESS_MODIFY) {
144 supported |= NFSACCESS_MODIFY;
145 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
146 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
147 nfsmode &= ~NFSACCESS_MODIFY;
149 if (nfsmode & NFSACCESS_EXTEND) {
150 supported |= NFSACCESS_EXTEND;
151 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
152 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
153 nfsmode &= ~NFSACCESS_EXTEND;
155 if (nfsmode & NFSACCESS_XAREAD) {
156 supported |= NFSACCESS_XAREAD;
157 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
158 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
159 nfsmode &= ~NFSACCESS_XAREAD;
161 if (nfsmode & NFSACCESS_XAWRITE) {
162 supported |= NFSACCESS_XAWRITE;
163 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
164 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
165 nfsmode &= ~NFSACCESS_XAWRITE;
167 if (nfsmode & NFSACCESS_XALIST) {
168 supported |= NFSACCESS_XALIST;
169 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
170 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
171 nfsmode &= ~NFSACCESS_XALIST;
173 if (nfsmode & NFSACCESS_DELETE) {
174 supported |= NFSACCESS_DELETE;
175 if (vp->v_type == VDIR)
176 deletebit = VDELETE_CHILD;
179 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
180 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
181 nfsmode &= ~NFSACCESS_DELETE;
183 if (vnode_vtype(vp) == VDIR)
184 testmode = NFSACCESS_LOOKUP;
186 testmode = NFSACCESS_EXECUTE;
187 if (nfsmode & testmode) {
188 supported |= (nfsmode & testmode);
189 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
190 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
191 nfsmode &= ~testmode;
193 nfsmode &= supported;
194 if (nd->nd_flag & ND_NFSV3) {
195 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
196 nfsrv_postopattr(nd, getret, &nva);
199 if (nd->nd_flag & ND_NFSV4) {
200 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
201 *tl++ = txdr_unsigned(supported);
203 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
204 *tl = txdr_unsigned(nfsmode);
211 NFSEXITCODE2(error, nd);
216 * nfs getattr service
219 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
220 vnode_t vp, __unused struct nfsexstuff *exp)
224 int at_root = 0, error = 0, supports_nfsv4acls;
225 struct nfsreferral *refp;
226 nfsattrbit_t attrbits, tmpbits;
228 struct vnode *tvp = NULL;
230 uint64_t mounted_on_fileno = 0;
232 struct thread *p = curthread;
236 if (nd->nd_flag & ND_NFSV4) {
237 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
244 * Check for a referral.
246 refp = nfsv4root_getreferral(vp, NULL, 0);
248 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
253 if (nd->nd_repstat == 0) {
255 NFSSET_ATTRBIT(&tmpbits, &attrbits);
258 * GETATTR with write-only attr time_access_set and time_modify_set
259 * should return NFS4ERR_INVAL.
261 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
262 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
263 error = NFSERR_INVAL;
267 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
268 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
269 accmode |= VREAD_ACL;
271 if (NFSNONZERO_ATTRBIT(&tmpbits))
272 accmode |= VREAD_ATTRIBUTES;
274 nd->nd_repstat = nfsvno_accchk(vp, accmode,
275 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
276 NFSACCCHK_VPISLOCKED, NULL);
280 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
281 if (!nd->nd_repstat) {
282 if (nd->nd_flag & ND_NFSV4) {
283 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
284 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
286 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
288 if (nd->nd_repstat == 0) {
289 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
291 if (nfsrv_enable_crossmntpt != 0 &&
292 vp->v_type == VDIR &&
293 (vp->v_vflag & VV_ROOT) != 0 &&
295 tvp = mp->mnt_vnodecovered;
303 if ((nd->nd_repstat =
304 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
305 nd->nd_repstat = VOP_GETATTR(
306 tvp, &va, nd->nd_cred);
310 if (nd->nd_repstat == 0)
311 mounted_on_fileno = (uint64_t)
316 if (nd->nd_repstat == 0)
317 nd->nd_repstat = vfs_busy(mp, 0);
319 if (nd->nd_repstat == 0) {
320 (void)nfsvno_fillattr(nd, mp, vp, &nva,
321 &fh, 0, &attrbits, nd->nd_cred, p,
322 isdgram, 1, supports_nfsv4acls,
323 at_root, mounted_on_fileno);
330 nfsrv_fillattr(nd, &nva);
338 NFSEXITCODE2(error, nd);
343 * nfs setattr service
346 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
347 vnode_t vp, struct nfsexstuff *exp)
349 struct nfsvattr nva, nva2;
351 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
353 struct timespec guard = { 0, 0 };
354 nfsattrbit_t attrbits, retbits;
355 nfsv4stateid_t stateid;
356 NFSACL_T *aclp = NULL;
357 struct thread *p = curthread;
359 if (nd->nd_repstat) {
360 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
363 #ifdef NFS4_ACL_EXTATTR_NAME
364 aclp = acl_alloc(M_WAITOK);
368 NFSVNO_ATTRINIT(&nva);
369 if (nd->nd_flag & ND_NFSV4) {
370 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
371 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
372 stateid.other[0] = *tl++;
373 stateid.other[1] = *tl++;
374 stateid.other[2] = *tl;
375 if (stateid.other[0] == 0x55555555 &&
376 stateid.other[1] == 0x55555555 &&
377 stateid.other[2] == 0x55555555 &&
378 stateid.seqid == 0xffffffff)
381 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
385 /* For NFSv4, only va_uid is used from nva2. */
386 NFSZERO_ATTRBIT(&retbits);
387 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
388 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
390 nd->nd_repstat = preat_ret;
392 NFSZERO_ATTRBIT(&retbits);
393 if (nd->nd_flag & ND_NFSV3) {
394 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
395 gcheck = fxdr_unsigned(int, *tl);
397 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
398 fxdr_nfsv3time(tl, &guard);
400 if (!nd->nd_repstat && gcheck &&
401 (nva2.na_ctime.tv_sec != guard.tv_sec ||
402 nva2.na_ctime.tv_nsec != guard.tv_nsec))
403 nd->nd_repstat = NFSERR_NOT_SYNC;
404 if (nd->nd_repstat) {
406 #ifdef NFS4_ACL_EXTATTR_NAME
409 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
412 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
413 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
416 * Now that we have all the fields, lets do it.
417 * If the size is being changed write access is required, otherwise
418 * just check for a read only file system.
420 if (!nd->nd_repstat) {
421 if (NFSVNO_NOTSETSIZE(&nva)) {
422 if (NFSVNO_EXRDONLY(exp) ||
423 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
424 nd->nd_repstat = EROFS;
426 if (vnode_vtype(vp) != VREG)
427 nd->nd_repstat = EINVAL;
428 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
429 NFSVNO_EXSTRICTACCESS(exp))
430 nd->nd_repstat = nfsvno_accchk(vp,
431 VWRITE, nd->nd_cred, exp, p,
432 NFSACCCHK_NOOVERRIDE,
433 NFSACCCHK_VPISLOCKED, NULL);
437 * Proxy operations from the MDS are allowed via the all 0s special
440 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
441 gotproxystateid == 0)
442 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
443 &nva, &attrbits, exp, p);
445 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
447 * For V4, try setting the attrbutes in sets, so that the
448 * reply bitmap will be correct for an error case.
450 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
451 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
452 NFSVNO_ATTRINIT(&nva2);
453 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
454 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
455 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
457 if (!nd->nd_repstat) {
458 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
459 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
460 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
461 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
464 if (!nd->nd_repstat &&
465 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
466 NFSVNO_ATTRINIT(&nva2);
467 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
468 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
471 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
473 if (!nd->nd_repstat &&
474 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
475 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
476 NFSVNO_ATTRINIT(&nva2);
477 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
478 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
479 if (nva.na_vaflags & VA_UTIMES_NULL) {
480 nva2.na_vaflags |= VA_UTIMES_NULL;
481 NFSVNO_SETACTIVE(&nva2, vaflags);
483 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
485 if (!nd->nd_repstat) {
486 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
487 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
488 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
489 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
492 if (!nd->nd_repstat &&
493 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
494 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
495 NFSVNO_ATTRINIT(&nva2);
496 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
497 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
499 if (!nd->nd_repstat) {
500 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
501 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
502 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
503 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
507 #ifdef NFS4_ACL_EXTATTR_NAME
508 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
509 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
510 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
512 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
515 } else if (!nd->nd_repstat) {
516 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
519 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
520 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
522 nd->nd_repstat = postat_ret;
525 #ifdef NFS4_ACL_EXTATTR_NAME
528 if (nd->nd_flag & ND_NFSV3)
529 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
530 else if (nd->nd_flag & ND_NFSV4)
531 (void) nfsrv_putattrbit(nd, &retbits);
532 else if (!nd->nd_repstat)
533 nfsrv_fillattr(nd, &nva);
540 #ifdef NFS4_ACL_EXTATTR_NAME
543 if (nd->nd_flag & ND_NFSV4) {
545 * For all nd_repstat, the V4 reply includes a bitmap,
546 * even NFSERR_BADXDR, which is what this will end up
549 (void) nfsrv_putattrbit(nd, &retbits);
551 NFSEXITCODE2(error, nd);
557 * (Also performs lookup parent for v4)
560 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
561 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
563 struct nameidata named;
564 vnode_t vp, dirp = NULL;
565 int error = 0, dattr_ret = 1;
566 struct nfsvattr nva, dattr;
569 struct thread *p = curthread;
571 if (nd->nd_repstat) {
572 nfsrv_postopattr(nd, dattr_ret, &dattr);
577 * For some reason, if dp is a symlink, the error
578 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
580 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
581 nd->nd_repstat = NFSERR_SYMLINK;
586 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
587 LOCKLEAF | SAVESTART);
588 nfsvno_setpathbuf(&named, &bufp, &hashp);
589 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
592 nfsvno_relpathbuf(&named);
595 if (!nd->nd_repstat) {
596 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
599 nfsvno_relpathbuf(&named);
601 if (nd->nd_repstat) {
603 if (nd->nd_flag & ND_NFSV3)
604 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
608 if (nd->nd_flag & ND_NFSV3)
609 nfsrv_postopattr(nd, dattr_ret, &dattr);
612 if (named.ni_startdir)
613 vrele(named.ni_startdir);
614 nfsvno_relpathbuf(&named);
616 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
617 vp->v_type != VDIR && vp->v_type != VLNK)
619 * Only allow lookup of VDIR and VLNK for traversal of
620 * non-exported volumes during NFSv4 mounting.
622 nd->nd_repstat = ENOENT;
623 if (nd->nd_repstat == 0)
624 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
625 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
626 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
627 if (vpp != NULL && nd->nd_repstat == 0)
632 if (nd->nd_flag & ND_NFSV3)
633 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
637 if (nd->nd_repstat) {
638 if (nd->nd_flag & ND_NFSV3)
639 nfsrv_postopattr(nd, dattr_ret, &dattr);
642 if (nd->nd_flag & ND_NFSV2) {
643 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
644 nfsrv_fillattr(nd, &nva);
645 } else if (nd->nd_flag & ND_NFSV3) {
646 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
647 nfsrv_postopattr(nd, 0, &nva);
648 nfsrv_postopattr(nd, dattr_ret, &dattr);
652 NFSEXITCODE2(error, nd);
657 * nfs readlink service
660 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
661 vnode_t vp, __unused struct nfsexstuff *exp)
664 mbuf_t mp = NULL, mpend = NULL;
667 struct thread *p = curthread;
669 if (nd->nd_repstat) {
670 nfsrv_postopattr(nd, getret, &nva);
673 if (vnode_vtype(vp) != VLNK) {
674 if (nd->nd_flag & ND_NFSV2)
675 nd->nd_repstat = ENXIO;
677 nd->nd_repstat = EINVAL;
680 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
682 if (nd->nd_flag & ND_NFSV3)
683 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
685 if (nd->nd_flag & ND_NFSV3)
686 nfsrv_postopattr(nd, getret, &nva);
689 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
690 *tl = txdr_unsigned(len);
691 mbuf_setnext(nd->nd_mb, mp);
693 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
704 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
705 vnode_t vp, struct nfsexstuff *exp)
708 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
712 struct nfsstate st, *stp = &st;
713 struct nfslock lo, *lop = &lo;
714 nfsv4stateid_t stateid;
716 struct thread *p = curthread;
718 if (nd->nd_repstat) {
719 nfsrv_postopattr(nd, getret, &nva);
722 if (nd->nd_flag & ND_NFSV2) {
723 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
724 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
725 reqlen = fxdr_unsigned(int, *tl);
726 } else if (nd->nd_flag & ND_NFSV3) {
727 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
728 off = fxdr_hyper(tl);
730 reqlen = fxdr_unsigned(int, *tl);
732 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
733 reqlen = fxdr_unsigned(int, *(tl + 6));
735 if (reqlen > NFS_SRVMAXDATA(nd)) {
736 reqlen = NFS_SRVMAXDATA(nd);
737 } else if (reqlen < 0) {
742 if (nd->nd_flag & ND_NFSV4) {
743 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
744 lop->lo_flags = NFSLCK_READ;
745 stp->ls_ownerlen = 0;
747 stp->ls_uid = nd->nd_cred->cr_uid;
748 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
749 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
750 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
751 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
752 if ((nd->nd_flag & ND_NFSV41) != 0)
753 clientid.qval = nd->nd_clientid.qval;
754 else if (nd->nd_clientid.qval != clientid.qval)
755 printf("EEK1 multiple clids\n");
757 if ((nd->nd_flag & ND_NFSV41) != 0)
758 printf("EEK! no clientid from session\n");
759 nd->nd_flag |= ND_IMPLIEDCLID;
760 nd->nd_clientid.qval = clientid.qval;
762 stp->ls_stateid.other[2] = *tl++;
764 * Don't allow the client to use a special stateid for a DS op.
766 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
767 ((stp->ls_stateid.other[0] == 0x0 &&
768 stp->ls_stateid.other[1] == 0x0 &&
769 stp->ls_stateid.other[2] == 0x0) ||
770 (stp->ls_stateid.other[0] == 0xffffffff &&
771 stp->ls_stateid.other[1] == 0xffffffff &&
772 stp->ls_stateid.other[2] == 0xffffffff) ||
773 stp->ls_stateid.seqid != 0))
774 nd->nd_repstat = NFSERR_BADSTATEID;
775 /* However, allow the proxy stateid. */
776 if (stp->ls_stateid.seqid == 0xffffffff &&
777 stp->ls_stateid.other[0] == 0x55555555 &&
778 stp->ls_stateid.other[1] == 0x55555555 &&
779 stp->ls_stateid.other[2] == 0x55555555)
781 off = fxdr_hyper(tl);
784 lop->lo_end = off + reqlen;
786 * Paranoia, just in case it wraps around.
788 if (lop->lo_end < off)
789 lop->lo_end = NFS64BITSSET;
791 if (vnode_vtype(vp) != VREG) {
792 if (nd->nd_flag & ND_NFSV3)
793 nd->nd_repstat = EINVAL;
795 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
798 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
800 nd->nd_repstat = getret;
801 if (!nd->nd_repstat &&
802 (nva.na_uid != nd->nd_cred->cr_uid ||
803 NFSVNO_EXSTRICTACCESS(exp))) {
804 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
806 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
808 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
809 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
810 NFSACCCHK_VPISLOCKED, NULL);
813 * DS reads are marked by ND_DSSERVER or use the proxy special
816 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
817 ND_NFSV4 && gotproxystateid == 0)
818 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
819 &stateid, exp, nd, p);
820 if (nd->nd_repstat) {
822 if (nd->nd_flag & ND_NFSV3)
823 nfsrv_postopattr(nd, getret, &nva);
826 if (off >= nva.na_size) {
829 } else if (reqlen == 0)
831 else if ((off + reqlen) >= nva.na_size) {
832 cnt = nva.na_size - off;
838 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
840 if (!(nd->nd_flag & ND_NFSV4)) {
841 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
843 nd->nd_repstat = getret;
845 if (nd->nd_repstat) {
849 if (nd->nd_flag & ND_NFSV3)
850 nfsrv_postopattr(nd, getret, &nva);
855 if (nd->nd_flag & ND_NFSV2) {
856 nfsrv_fillattr(nd, &nva);
857 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
859 if (nd->nd_flag & ND_NFSV3) {
860 nfsrv_postopattr(nd, getret, &nva);
861 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
862 *tl++ = txdr_unsigned(cnt);
864 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
868 *tl++ = newnfs_false;
870 *tl = txdr_unsigned(cnt);
872 mbuf_setnext(nd->nd_mb, m3);
874 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
882 NFSEXITCODE2(error, nd);
890 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
891 vnode_t vp, struct nfsexstuff *exp)
894 struct nfsvattr nva, forat;
895 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
896 int gotproxystateid, stable = NFSWRITE_FILESYNC;
898 struct nfsstate st, *stp = &st;
899 struct nfslock lo, *lop = &lo;
900 nfsv4stateid_t stateid;
902 nfsattrbit_t attrbits;
903 struct thread *p = curthread;
905 if (nd->nd_repstat) {
906 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
910 if (nd->nd_flag & ND_NFSV2) {
911 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
912 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
914 retlen = len = fxdr_unsigned(int32_t, *tl);
915 } else if (nd->nd_flag & ND_NFSV3) {
916 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
917 off = fxdr_hyper(tl);
919 stable = fxdr_unsigned(int, *tl++);
920 retlen = len = fxdr_unsigned(int32_t, *tl);
922 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
923 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
924 lop->lo_flags = NFSLCK_WRITE;
925 stp->ls_ownerlen = 0;
927 stp->ls_uid = nd->nd_cred->cr_uid;
928 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
929 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
930 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
931 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
932 if ((nd->nd_flag & ND_NFSV41) != 0)
933 clientid.qval = nd->nd_clientid.qval;
934 else if (nd->nd_clientid.qval != clientid.qval)
935 printf("EEK2 multiple clids\n");
937 if ((nd->nd_flag & ND_NFSV41) != 0)
938 printf("EEK! no clientid from session\n");
939 nd->nd_flag |= ND_IMPLIEDCLID;
940 nd->nd_clientid.qval = clientid.qval;
942 stp->ls_stateid.other[2] = *tl++;
944 * Don't allow the client to use a special stateid for a DS op.
946 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
947 ((stp->ls_stateid.other[0] == 0x0 &&
948 stp->ls_stateid.other[1] == 0x0 &&
949 stp->ls_stateid.other[2] == 0x0) ||
950 (stp->ls_stateid.other[0] == 0xffffffff &&
951 stp->ls_stateid.other[1] == 0xffffffff &&
952 stp->ls_stateid.other[2] == 0xffffffff) ||
953 stp->ls_stateid.seqid != 0))
954 nd->nd_repstat = NFSERR_BADSTATEID;
955 /* However, allow the proxy stateid. */
956 if (stp->ls_stateid.seqid == 0xffffffff &&
957 stp->ls_stateid.other[0] == 0x55555555 &&
958 stp->ls_stateid.other[1] == 0x55555555 &&
959 stp->ls_stateid.other[2] == 0x55555555)
961 off = fxdr_hyper(tl);
964 stable = fxdr_unsigned(int, *tl++);
965 retlen = len = fxdr_unsigned(int32_t, *tl);
966 lop->lo_end = off + len;
968 * Paranoia, just in case it wraps around, which shouldn't
969 * ever happen anyhow.
971 if (lop->lo_end < lop->lo_first)
972 lop->lo_end = NFS64BITSSET;
975 if (retlen > NFS_SRVMAXIO || retlen < 0)
976 nd->nd_repstat = EIO;
977 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
978 if (nd->nd_flag & ND_NFSV3)
979 nd->nd_repstat = EINVAL;
981 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
984 NFSZERO_ATTRBIT(&attrbits);
985 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
986 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
988 nd->nd_repstat = forat_ret;
989 if (!nd->nd_repstat &&
990 (forat.na_uid != nd->nd_cred->cr_uid ||
991 NFSVNO_EXSTRICTACCESS(exp)))
992 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
994 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
996 * DS reads are marked by ND_DSSERVER or use the proxy special
999 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1000 ND_NFSV4 && gotproxystateid == 0)
1001 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1002 &stateid, exp, nd, p);
1003 if (nd->nd_repstat) {
1005 if (nd->nd_flag & ND_NFSV3)
1006 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1011 * For NFS Version 2, it is not obvious what a write of zero length
1012 * should do, but I might as well be consistent with Version 3,
1013 * which is to return ok so long as there are no permission problems.
1016 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1017 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1018 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1022 if (nd->nd_flag & ND_NFSV4)
1025 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1027 if (!nd->nd_repstat)
1028 nd->nd_repstat = aftat_ret;
1029 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1030 if (nd->nd_flag & ND_NFSV3)
1031 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1034 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1035 *tl++ = txdr_unsigned(retlen);
1037 * If nfs_async is set, then pretend the write was FILESYNC.
1038 * Warning: Doing this violates RFC1813 and runs a risk
1039 * of data written by a client being lost when the server
1042 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1043 *tl++ = txdr_unsigned(stable);
1045 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1047 * Actually, there is no need to txdr these fields,
1048 * but it may make the values more human readable,
1049 * for debugging purposes.
1051 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1052 *tl = txdr_unsigned(nfsboottime.tv_usec);
1053 } else if (!nd->nd_repstat)
1054 nfsrv_fillattr(nd, &nva);
1057 NFSEXITCODE2(0, nd);
1061 NFSEXITCODE2(error, nd);
1066 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1067 * now does a truncate to 0 length via. setattr if it already exists
1068 * The core creation routine has been extracted out into nfsrv_creatsub(),
1069 * so it can also be used by nfsrv_open() for V4.
1072 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1073 vnode_t dp, struct nfsexstuff *exp)
1075 struct nfsvattr nva, dirfor, diraft;
1076 struct nfsv2_sattr *sp;
1077 struct nameidata named;
1079 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1080 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1082 vnode_t vp = NULL, dirp = NULL;
1087 int32_t cverf[2], tverf[2] = { 0, 0 };
1088 struct thread *p = curthread;
1090 if (nd->nd_repstat) {
1091 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1094 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1095 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1096 nfsvno_setpathbuf(&named, &bufp, &hashp);
1097 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1100 if (!nd->nd_repstat) {
1101 NFSVNO_ATTRINIT(&nva);
1102 if (nd->nd_flag & ND_NFSV2) {
1103 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1104 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1107 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1108 NFSVNO_SETATTRVAL(&nva, mode,
1109 nfstov_mode(sp->sa_mode));
1110 switch (nva.na_type) {
1112 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1114 NFSVNO_SETATTRVAL(&nva, size,
1120 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1127 how = fxdr_unsigned(int, *tl);
1129 case NFSCREATE_GUARDED:
1130 case NFSCREATE_UNCHECKED:
1131 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1135 case NFSCREATE_EXCLUSIVE:
1136 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1142 NFSVNO_SETATTRVAL(&nva, type, VREG);
1145 if (nd->nd_repstat) {
1146 nfsvno_relpathbuf(&named);
1147 if (nd->nd_flag & ND_NFSV3) {
1148 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1150 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1157 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1159 if (nd->nd_flag & ND_NFSV2) {
1163 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1167 if (nd->nd_repstat) {
1168 if (nd->nd_flag & ND_NFSV3)
1169 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1176 if (!(nd->nd_flag & ND_NFSV2)) {
1178 case NFSCREATE_GUARDED:
1180 nd->nd_repstat = EEXIST;
1182 case NFSCREATE_UNCHECKED:
1184 case NFSCREATE_EXCLUSIVE:
1185 if (named.ni_vp == NULL)
1186 NFSVNO_SETATTRVAL(&nva, mode, 0);
1192 * Iff doesn't exist, create it
1193 * otherwise just truncate to 0 length
1194 * should I set the mode too ?
1196 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1197 &exclusive_flag, cverf, rdev, exp);
1199 if (!nd->nd_repstat) {
1200 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1201 if (!nd->nd_repstat)
1202 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1205 if (!nd->nd_repstat) {
1206 tverf[0] = nva.na_atime.tv_sec;
1207 tverf[1] = nva.na_atime.tv_nsec;
1210 if (nd->nd_flag & ND_NFSV2) {
1211 if (!nd->nd_repstat) {
1212 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1213 nfsrv_fillattr(nd, &nva);
1216 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1217 || cverf[1] != tverf[1]))
1218 nd->nd_repstat = EEXIST;
1219 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1221 if (!nd->nd_repstat) {
1222 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1223 nfsrv_postopattr(nd, 0, &nva);
1225 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1229 NFSEXITCODE2(0, nd);
1233 nfsvno_relpathbuf(&named);
1234 NFSEXITCODE2(error, nd);
1239 * nfs v3 mknod service (and v4 create)
1242 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1243 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1245 struct nfsvattr nva, dirfor, diraft;
1247 struct nameidata named;
1248 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1249 u_int32_t major, minor;
1250 enum vtype vtyp = VNON;
1251 nfstype nfs4type = NFNON;
1252 vnode_t vp, dirp = NULL;
1253 nfsattrbit_t attrbits;
1254 char *bufp = NULL, *pathcp = NULL;
1255 u_long *hashp, cnflags;
1256 NFSACL_T *aclp = NULL;
1257 struct thread *p = curthread;
1259 NFSVNO_ATTRINIT(&nva);
1260 cnflags = (LOCKPARENT | SAVESTART);
1261 if (nd->nd_repstat) {
1262 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1265 #ifdef NFS4_ACL_EXTATTR_NAME
1266 aclp = acl_alloc(M_WAITOK);
1271 * For V4, the creation stuff is here, Yuck!
1273 if (nd->nd_flag & ND_NFSV4) {
1274 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1275 vtyp = nfsv34tov_type(*tl);
1276 nfs4type = fxdr_unsigned(nfstype, *tl);
1279 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1286 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1287 major = fxdr_unsigned(u_int32_t, *tl++);
1288 minor = fxdr_unsigned(u_int32_t, *tl);
1289 nva.na_rdev = NFSMAKEDEV(major, minor);
1295 cnflags = (LOCKPARENT | SAVENAME);
1298 nd->nd_repstat = NFSERR_BADTYPE;
1300 #ifdef NFS4_ACL_EXTATTR_NAME
1306 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1307 nfsvno_setpathbuf(&named, &bufp, &hashp);
1308 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1311 if (!nd->nd_repstat) {
1312 if (nd->nd_flag & ND_NFSV3) {
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1314 vtyp = nfsv34tov_type(*tl);
1316 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1320 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1321 (vtyp == VCHR || vtyp == VBLK)) {
1322 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1323 major = fxdr_unsigned(u_int32_t, *tl++);
1324 minor = fxdr_unsigned(u_int32_t, *tl);
1325 nva.na_rdev = NFSMAKEDEV(major, minor);
1329 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1330 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1331 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1332 dirfor.na_gid == nva.na_gid)
1333 NFSVNO_UNSET(&nva, gid);
1334 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1336 if (nd->nd_repstat) {
1338 #ifdef NFS4_ACL_EXTATTR_NAME
1341 nfsvno_relpathbuf(&named);
1343 free(pathcp, M_TEMP);
1344 if (nd->nd_flag & ND_NFSV3)
1345 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1351 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1352 * in va_mode, so we'll have to set a default here.
1354 if (NFSVNO_NOTSETMODE(&nva)) {
1362 named.ni_cnd.cn_flags |= WILLBEDIR;
1363 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1364 if (nd->nd_repstat) {
1366 if (nd->nd_flag & ND_NFSV3)
1367 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1371 #ifdef NFS4_ACL_EXTATTR_NAME
1374 if (nd->nd_flag & ND_NFSV3)
1375 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1380 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1382 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1384 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1385 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1387 #ifdef NFS4_ACL_EXTATTR_NAME
1391 } else if (vtyp == VLNK) {
1392 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1393 &dirfor, &diraft, &diraft_ret, &attrbits,
1394 aclp, p, exp, pathcp, pathlen);
1395 #ifdef NFS4_ACL_EXTATTR_NAME
1398 free(pathcp, M_TEMP);
1403 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1404 if (!nd->nd_repstat) {
1406 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1407 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1408 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1409 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1411 if (vpp != NULL && nd->nd_repstat == 0) {
1418 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1420 if (!nd->nd_repstat) {
1421 if (nd->nd_flag & ND_NFSV3) {
1422 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1423 nfsrv_postopattr(nd, 0, &nva);
1425 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1426 *tl++ = newnfs_false;
1427 txdr_hyper(dirfor.na_filerev, tl);
1429 txdr_hyper(diraft.na_filerev, tl);
1430 (void) nfsrv_putattrbit(nd, &attrbits);
1433 if (nd->nd_flag & ND_NFSV3)
1434 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1435 #ifdef NFS4_ACL_EXTATTR_NAME
1440 NFSEXITCODE2(0, nd);
1444 #ifdef NFS4_ACL_EXTATTR_NAME
1448 nfsvno_relpathbuf(&named);
1450 free(pathcp, M_TEMP);
1452 NFSEXITCODE2(error, nd);
1457 * nfs remove service
1460 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1461 vnode_t dp, struct nfsexstuff *exp)
1463 struct nameidata named;
1465 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1466 vnode_t dirp = NULL;
1467 struct nfsvattr dirfor, diraft;
1470 struct thread *p = curthread;
1472 if (nd->nd_repstat) {
1473 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1476 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1477 LOCKPARENT | LOCKLEAF);
1478 nfsvno_setpathbuf(&named, &bufp, &hashp);
1479 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1482 nfsvno_relpathbuf(&named);
1485 if (!nd->nd_repstat) {
1486 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1489 nfsvno_relpathbuf(&named);
1492 if (!(nd->nd_flag & ND_NFSV2)) {
1493 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1500 if (!nd->nd_repstat) {
1501 if (nd->nd_flag & ND_NFSV4) {
1502 if (vnode_vtype(named.ni_vp) == VDIR)
1503 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1504 nd->nd_cred, p, exp);
1506 nd->nd_repstat = nfsvno_removesub(&named, 1,
1507 nd->nd_cred, p, exp);
1508 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1509 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1510 nd->nd_cred, p, exp);
1512 nd->nd_repstat = nfsvno_removesub(&named, 0,
1513 nd->nd_cred, p, exp);
1516 if (!(nd->nd_flag & ND_NFSV2)) {
1518 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1522 if (nd->nd_flag & ND_NFSV3) {
1523 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1525 } else if (!nd->nd_repstat) {
1526 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1527 *tl++ = newnfs_false;
1528 txdr_hyper(dirfor.na_filerev, tl);
1530 txdr_hyper(diraft.na_filerev, tl);
1535 NFSEXITCODE2(error, nd);
1540 * nfs rename service
1543 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1544 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1547 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1548 int tdirfor_ret = 1, tdiraft_ret = 1;
1549 struct nameidata fromnd, tond;
1550 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1551 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1552 struct nfsexstuff tnes;
1554 char *bufp, *tbufp = NULL;
1557 struct thread *p = curthread;
1559 if (nd->nd_repstat) {
1560 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1561 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1564 if (!(nd->nd_flag & ND_NFSV2))
1565 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1566 tond.ni_cnd.cn_nameiop = 0;
1567 tond.ni_startdir = NULL;
1568 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1569 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1570 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1575 nfsvno_relpathbuf(&fromnd);
1579 * Unlock dp in this code section, so it is unlocked before
1580 * tdp gets locked. This avoids a potential LOR if tdp is the
1581 * parent directory of dp.
1583 if (nd->nd_flag & ND_NFSV4) {
1588 /* Might lock tdp. */
1589 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1592 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1597 tfh.nfsrvfh_len = 0;
1598 error = nfsrv_mtofh(nd, &tfh);
1600 error = nfsvno_getfh(dp, &fh, p);
1603 /* todp is always NULL except NFSv4 */
1604 nfsvno_relpathbuf(&fromnd);
1608 /* If this is the same file handle, just VREF() the vnode. */
1609 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1610 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1614 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1619 nd->nd_cred->cr_uid = nd->nd_saveduid;
1620 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1621 0); /* Locks tdp. */
1623 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1629 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1630 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1631 if (!nd->nd_repstat) {
1632 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1637 nfsvno_relpathbuf(&fromnd);
1638 nfsvno_relpathbuf(&tond);
1642 if (nd->nd_repstat) {
1643 if (nd->nd_flag & ND_NFSV3) {
1644 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1646 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1652 nfsvno_relpathbuf(&fromnd);
1653 nfsvno_relpathbuf(&tond);
1658 * Done parsing, now down to business.
1660 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1661 if (nd->nd_repstat) {
1662 if (nd->nd_flag & ND_NFSV3) {
1663 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1665 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1672 nfsvno_relpathbuf(&tond);
1675 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1676 tond.ni_cnd.cn_flags |= WILLBEDIR;
1677 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1678 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1679 nd->nd_flag, nd->nd_cred, p);
1681 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1683 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1688 if (nd->nd_flag & ND_NFSV3) {
1689 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1690 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1691 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1692 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1693 *tl++ = newnfs_false;
1694 txdr_hyper(fdirfor.na_filerev, tl);
1696 txdr_hyper(fdiraft.na_filerev, tl);
1698 *tl++ = newnfs_false;
1699 txdr_hyper(tdirfor.na_filerev, tl);
1701 txdr_hyper(tdiraft.na_filerev, tl);
1705 NFSEXITCODE2(error, nd);
1713 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1714 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1716 struct nameidata named;
1718 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1719 vnode_t dirp = NULL, dp = NULL;
1720 struct nfsvattr dirfor, diraft, at;
1721 struct nfsexstuff tnes;
1725 struct thread *p = curthread;
1727 if (nd->nd_repstat) {
1728 nfsrv_postopattr(nd, getret, &at);
1729 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1733 if (vnode_vtype(vp) == VDIR) {
1734 if (nd->nd_flag & ND_NFSV4)
1735 nd->nd_repstat = NFSERR_ISDIR;
1737 nd->nd_repstat = NFSERR_INVAL;
1741 if (!nd->nd_repstat) {
1742 if (nd->nd_flag & ND_NFSV4) {
1746 error = nfsrv_mtofh(nd, &dfh);
1749 /* tovp is always NULL unless NFSv4 */
1752 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1757 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1758 LOCKPARENT | SAVENAME | NOCACHE);
1759 if (!nd->nd_repstat) {
1760 nfsvno_setpathbuf(&named, &bufp, &hashp);
1761 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1766 nfsvno_relpathbuf(&named);
1769 if (!nd->nd_repstat) {
1770 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1775 nfsvno_relpathbuf(&named);
1779 if (nd->nd_flag & ND_NFSV2) {
1783 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1787 if (!nd->nd_repstat)
1788 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1789 if (nd->nd_flag & ND_NFSV3)
1790 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1792 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1796 if (nd->nd_flag & ND_NFSV3) {
1797 nfsrv_postopattr(nd, getret, &at);
1798 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1799 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1800 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1801 *tl++ = newnfs_false;
1802 txdr_hyper(dirfor.na_filerev, tl);
1804 txdr_hyper(diraft.na_filerev, tl);
1808 NFSEXITCODE2(error, nd);
1813 * nfs symbolic link service
1816 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1817 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1819 struct nfsvattr nva, dirfor, diraft;
1820 struct nameidata named;
1821 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1822 vnode_t dirp = NULL;
1823 char *bufp, *pathcp = NULL;
1825 struct thread *p = curthread;
1827 if (nd->nd_repstat) {
1828 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1833 NFSVNO_ATTRINIT(&nva);
1834 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1835 LOCKPARENT | SAVESTART | NOCACHE);
1836 nfsvno_setpathbuf(&named, &bufp, &hashp);
1837 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1838 if (!error && !nd->nd_repstat)
1839 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1842 nfsvno_relpathbuf(&named);
1845 if (!nd->nd_repstat) {
1846 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1849 nfsvno_relpathbuf(&named);
1851 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1857 * And call nfsrvd_symlinksub() to do the common code. It will
1858 * return EBADRPC upon a parsing error, 0 otherwise.
1860 if (!nd->nd_repstat) {
1862 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1864 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1865 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1867 } else if (dirp != NULL) {
1868 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1872 free(pathcp, M_TEMP);
1874 if (nd->nd_flag & ND_NFSV3) {
1875 if (!nd->nd_repstat) {
1876 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1877 nfsrv_postopattr(nd, 0, &nva);
1879 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1883 NFSEXITCODE2(error, nd);
1888 * Common code for creating a symbolic link.
1891 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1892 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1893 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1894 int *diraft_retp, nfsattrbit_t *attrbitp,
1895 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1900 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1901 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1902 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1903 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1904 if (nd->nd_flag & ND_NFSV3) {
1905 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1906 if (!nd->nd_repstat)
1907 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1908 nvap, nd, p, 1, NULL);
1910 if (vpp != NULL && nd->nd_repstat == 0) {
1911 NFSVOPUNLOCK(ndp->ni_vp);
1917 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1920 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1921 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1922 *tl++ = newnfs_false;
1923 txdr_hyper(dirforp->na_filerev, tl);
1925 txdr_hyper(diraftp->na_filerev, tl);
1926 (void) nfsrv_putattrbit(nd, attrbitp);
1929 NFSEXITCODE2(0, nd);
1936 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1937 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1939 struct nfsvattr nva, dirfor, diraft;
1940 struct nameidata named;
1942 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1943 vnode_t dirp = NULL;
1946 struct thread *p = curthread;
1948 if (nd->nd_repstat) {
1949 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1952 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1953 LOCKPARENT | SAVENAME | NOCACHE);
1954 nfsvno_setpathbuf(&named, &bufp, &hashp);
1955 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1958 if (!nd->nd_repstat) {
1959 NFSVNO_ATTRINIT(&nva);
1960 if (nd->nd_flag & ND_NFSV3) {
1961 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1965 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1966 nva.na_mode = nfstov_mode(*tl++);
1969 if (!nd->nd_repstat) {
1970 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1973 nfsvno_relpathbuf(&named);
1975 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1979 if (nd->nd_repstat) {
1981 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1985 if (nd->nd_flag & ND_NFSV3)
1986 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1991 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1994 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1996 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1997 &diraft_ret, NULL, NULL, p, exp);
1999 if (nd->nd_flag & ND_NFSV3) {
2000 if (!nd->nd_repstat) {
2001 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2002 nfsrv_postopattr(nd, 0, &nva);
2004 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2005 } else if (!nd->nd_repstat) {
2006 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2007 nfsrv_fillattr(nd, &nva);
2011 NFSEXITCODE2(0, nd);
2015 nfsvno_relpathbuf(&named);
2016 NFSEXITCODE2(error, nd);
2021 * Code common to mkdir for V2,3 and 4.
2024 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2025 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2026 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2027 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2028 NFSPROC_T *p, struct nfsexstuff *exp)
2033 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2034 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2035 nd->nd_cred, p, exp);
2036 if (!nd->nd_repstat) {
2038 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2039 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2040 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2041 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2043 if (vpp && !nd->nd_repstat) {
2051 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2054 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2055 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2056 *tl++ = newnfs_false;
2057 txdr_hyper(dirforp->na_filerev, tl);
2059 txdr_hyper(diraftp->na_filerev, tl);
2060 (void) nfsrv_putattrbit(nd, attrbitp);
2063 NFSEXITCODE2(0, nd);
2067 * nfs commit service
2070 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2071 vnode_t vp, __unused struct nfsexstuff *exp)
2073 struct nfsvattr bfor, aft;
2075 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2077 struct thread *p = curthread;
2079 if (nd->nd_repstat) {
2080 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2084 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2085 if (vp->v_type != VREG) {
2086 if (nd->nd_flag & ND_NFSV3)
2087 error = NFSERR_NOTSUPP;
2089 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2092 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2095 * XXX At this time VOP_FSYNC() does not accept offset and byte
2096 * count parameters, so these arguments are useless (someday maybe).
2098 off = fxdr_hyper(tl);
2100 cnt = fxdr_unsigned(int, *tl);
2101 if (nd->nd_flag & ND_NFSV3)
2102 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2103 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2104 if (nd->nd_flag & ND_NFSV3) {
2105 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2106 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2109 if (!nd->nd_repstat) {
2110 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2111 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2112 *tl = txdr_unsigned(nfsboottime.tv_usec);
2116 NFSEXITCODE2(0, nd);
2120 NFSEXITCODE2(error, nd);
2125 * nfs statfs service
2128 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2129 vnode_t vp, __unused struct nfsexstuff *exp)
2136 struct thread *p = curthread;
2139 if (nd->nd_repstat) {
2140 nfsrv_postopattr(nd, getret, &at);
2143 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2144 nd->nd_repstat = nfsvno_statfs(vp, sf);
2145 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2147 if (nd->nd_flag & ND_NFSV3)
2148 nfsrv_postopattr(nd, getret, &at);
2151 if (nd->nd_flag & ND_NFSV2) {
2152 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2153 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2154 *tl++ = txdr_unsigned(sf->f_bsize);
2155 *tl++ = txdr_unsigned(sf->f_blocks);
2156 *tl++ = txdr_unsigned(sf->f_bfree);
2157 *tl = txdr_unsigned(sf->f_bavail);
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2160 tval = (u_quad_t)sf->f_blocks;
2161 tval *= (u_quad_t)sf->f_bsize;
2162 txdr_hyper(tval, tl); tl += 2;
2163 tval = (u_quad_t)sf->f_bfree;
2164 tval *= (u_quad_t)sf->f_bsize;
2165 txdr_hyper(tval, tl); tl += 2;
2166 tval = (u_quad_t)sf->f_bavail;
2167 tval *= (u_quad_t)sf->f_bsize;
2168 txdr_hyper(tval, tl); tl += 2;
2169 tval = (u_quad_t)sf->f_files;
2170 txdr_hyper(tval, tl); tl += 2;
2171 tval = (u_quad_t)sf->f_ffree;
2172 txdr_hyper(tval, tl); tl += 2;
2173 tval = (u_quad_t)sf->f_ffree;
2174 txdr_hyper(tval, tl); tl += 2;
2180 NFSEXITCODE2(0, nd);
2185 * nfs fsinfo service
2188 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2189 vnode_t vp, __unused struct nfsexstuff *exp)
2192 struct nfsfsinfo fs;
2195 struct thread *p = curthread;
2197 if (nd->nd_repstat) {
2198 nfsrv_postopattr(nd, getret, &at);
2201 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2202 nfsvno_getfs(&fs, isdgram);
2204 nfsrv_postopattr(nd, getret, &at);
2205 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2206 *tl++ = txdr_unsigned(fs.fs_rtmax);
2207 *tl++ = txdr_unsigned(fs.fs_rtpref);
2208 *tl++ = txdr_unsigned(fs.fs_rtmult);
2209 *tl++ = txdr_unsigned(fs.fs_wtmax);
2210 *tl++ = txdr_unsigned(fs.fs_wtpref);
2211 *tl++ = txdr_unsigned(fs.fs_wtmult);
2212 *tl++ = txdr_unsigned(fs.fs_dtpref);
2213 txdr_hyper(fs.fs_maxfilesize, tl);
2215 txdr_nfsv3time(&fs.fs_timedelta, tl);
2217 *tl = txdr_unsigned(fs.fs_properties);
2220 NFSEXITCODE2(0, nd);
2225 * nfs pathconf service
2228 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2229 vnode_t vp, __unused struct nfsexstuff *exp)
2231 struct nfsv3_pathconf *pc;
2233 long linkmax, namemax, chownres, notrunc;
2235 struct thread *p = curthread;
2237 if (nd->nd_repstat) {
2238 nfsrv_postopattr(nd, getret, &at);
2241 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2243 if (!nd->nd_repstat)
2244 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2246 if (!nd->nd_repstat)
2247 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2248 &chownres, nd->nd_cred, p);
2249 if (!nd->nd_repstat)
2250 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2252 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2254 nfsrv_postopattr(nd, getret, &at);
2255 if (!nd->nd_repstat) {
2256 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2257 pc->pc_linkmax = txdr_unsigned(linkmax);
2258 pc->pc_namemax = txdr_unsigned(namemax);
2259 pc->pc_notrunc = txdr_unsigned(notrunc);
2260 pc->pc_chownrestricted = txdr_unsigned(chownres);
2263 * These should probably be supported by VOP_PATHCONF(), but
2264 * until msdosfs is exportable (why would you want to?), the
2265 * Unix defaults should be ok.
2267 pc->pc_caseinsensitive = newnfs_false;
2268 pc->pc_casepreserving = newnfs_true;
2272 NFSEXITCODE2(0, nd);
2277 * nfsv4 lock service
2280 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2281 vnode_t vp, struct nfsexstuff *exp)
2285 struct nfsstate *stp = NULL;
2286 struct nfslock *lop;
2287 struct nfslockconflict cf;
2289 u_short flags = NFSLCK_LOCK, lflags;
2290 u_int64_t offset, len;
2291 nfsv4stateid_t stateid;
2293 struct thread *p = curthread;
2295 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2296 i = fxdr_unsigned(int, *tl++);
2298 case NFSV4LOCKT_READW:
2299 flags |= NFSLCK_BLOCKING;
2300 case NFSV4LOCKT_READ:
2301 lflags = NFSLCK_READ;
2303 case NFSV4LOCKT_WRITEW:
2304 flags |= NFSLCK_BLOCKING;
2305 case NFSV4LOCKT_WRITE:
2306 lflags = NFSLCK_WRITE;
2309 nd->nd_repstat = NFSERR_BADXDR;
2312 if (*tl++ == newnfs_true)
2313 flags |= NFSLCK_RECLAIM;
2314 offset = fxdr_hyper(tl);
2316 len = fxdr_hyper(tl);
2318 if (*tl == newnfs_true)
2319 flags |= NFSLCK_OPENTOLOCK;
2320 if (flags & NFSLCK_OPENTOLOCK) {
2321 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2322 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2323 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2324 nd->nd_repstat = NFSERR_BADXDR;
2327 stp = malloc(sizeof (struct nfsstate) + i,
2328 M_NFSDSTATE, M_WAITOK);
2329 stp->ls_ownerlen = i;
2330 stp->ls_op = nd->nd_rp;
2331 stp->ls_seq = fxdr_unsigned(int, *tl++);
2332 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2333 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2335 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2338 * For the special stateid of other all 0s and seqid == 1, set
2339 * the stateid to the current stateid, if it is set.
2341 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2342 stp->ls_stateid.seqid == 1 &&
2343 stp->ls_stateid.other[0] == 0 &&
2344 stp->ls_stateid.other[1] == 0 &&
2345 stp->ls_stateid.other[2] == 0) {
2346 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2347 stp->ls_stateid = nd->nd_curstateid;
2348 stp->ls_stateid.seqid = 0;
2350 nd->nd_repstat = NFSERR_BADSTATEID;
2355 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2356 clientid.lval[0] = *tl++;
2357 clientid.lval[1] = *tl++;
2358 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2359 if ((nd->nd_flag & ND_NFSV41) != 0)
2360 clientid.qval = nd->nd_clientid.qval;
2361 else if (nd->nd_clientid.qval != clientid.qval)
2362 printf("EEK3 multiple clids\n");
2364 if ((nd->nd_flag & ND_NFSV41) != 0)
2365 printf("EEK! no clientid from session\n");
2366 nd->nd_flag |= ND_IMPLIEDCLID;
2367 nd->nd_clientid.qval = clientid.qval;
2369 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2373 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2374 stp = malloc(sizeof (struct nfsstate),
2375 M_NFSDSTATE, M_WAITOK);
2376 stp->ls_ownerlen = 0;
2377 stp->ls_op = nd->nd_rp;
2378 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2379 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2381 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2384 * For the special stateid of other all 0s and seqid == 1, set
2385 * the stateid to the current stateid, if it is set.
2387 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2388 stp->ls_stateid.seqid == 1 &&
2389 stp->ls_stateid.other[0] == 0 &&
2390 stp->ls_stateid.other[1] == 0 &&
2391 stp->ls_stateid.other[2] == 0) {
2392 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2393 stp->ls_stateid = nd->nd_curstateid;
2394 stp->ls_stateid.seqid = 0;
2396 nd->nd_repstat = NFSERR_BADSTATEID;
2401 stp->ls_seq = fxdr_unsigned(int, *tl);
2402 clientid.lval[0] = stp->ls_stateid.other[0];
2403 clientid.lval[1] = stp->ls_stateid.other[1];
2404 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2405 if ((nd->nd_flag & ND_NFSV41) != 0)
2406 clientid.qval = nd->nd_clientid.qval;
2407 else if (nd->nd_clientid.qval != clientid.qval)
2408 printf("EEK4 multiple clids\n");
2410 if ((nd->nd_flag & ND_NFSV41) != 0)
2411 printf("EEK! no clientid from session\n");
2412 nd->nd_flag |= ND_IMPLIEDCLID;
2413 nd->nd_clientid.qval = clientid.qval;
2416 lop = malloc(sizeof (struct nfslock),
2417 M_NFSDLOCK, M_WAITOK);
2418 lop->lo_first = offset;
2419 if (len == NFS64BITSSET) {
2420 lop->lo_end = NFS64BITSSET;
2422 lop->lo_end = offset + len;
2423 if (lop->lo_end <= lop->lo_first)
2424 nd->nd_repstat = NFSERR_INVAL;
2426 lop->lo_flags = lflags;
2427 stp->ls_flags = flags;
2428 stp->ls_uid = nd->nd_cred->cr_uid;
2431 * Do basic access checking.
2433 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2434 if (vnode_vtype(vp) == VDIR)
2435 nd->nd_repstat = NFSERR_ISDIR;
2437 nd->nd_repstat = NFSERR_INVAL;
2439 if (!nd->nd_repstat) {
2440 if (lflags & NFSLCK_WRITE) {
2441 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2442 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2443 NFSACCCHK_VPISLOCKED, NULL);
2445 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2446 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2447 NFSACCCHK_VPISLOCKED, NULL);
2449 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2450 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2451 NFSACCCHK_VPISLOCKED, NULL);
2456 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2457 * seqid# gets updated. nfsrv_lockctrl() will return the value
2458 * of nd_repstat, if it gets that far.
2460 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2461 &stateid, exp, nd, p);
2463 free(lop, M_NFSDLOCK);
2465 free(stp, M_NFSDSTATE);
2466 if (!nd->nd_repstat) {
2467 /* For NFSv4.1, set the Current StateID. */
2468 if ((nd->nd_flag & ND_NFSV41) != 0) {
2469 nd->nd_curstateid = stateid;
2470 nd->nd_flag |= ND_CURSTATEID;
2472 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2473 *tl++ = txdr_unsigned(stateid.seqid);
2474 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2475 } else if (nd->nd_repstat == NFSERR_DENIED) {
2476 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2477 txdr_hyper(cf.cl_first, tl);
2479 if (cf.cl_end == NFS64BITSSET)
2482 len = cf.cl_end - cf.cl_first;
2483 txdr_hyper(len, tl);
2485 if (cf.cl_flags == NFSLCK_WRITE)
2486 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2488 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2489 *tl++ = stateid.other[0];
2490 *tl = stateid.other[1];
2491 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2494 NFSEXITCODE2(0, nd);
2499 free(stp, M_NFSDSTATE);
2500 NFSEXITCODE2(error, nd);
2505 * nfsv4 lock test service
2508 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2509 vnode_t vp, struct nfsexstuff *exp)
2513 struct nfsstate *stp = NULL;
2514 struct nfslock lo, *lop = &lo;
2515 struct nfslockconflict cf;
2517 nfsv4stateid_t stateid;
2520 struct thread *p = curthread;
2522 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2523 i = fxdr_unsigned(int, *(tl + 7));
2524 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2525 nd->nd_repstat = NFSERR_BADXDR;
2528 stp = malloc(sizeof (struct nfsstate) + i,
2529 M_NFSDSTATE, M_WAITOK);
2530 stp->ls_ownerlen = i;
2532 stp->ls_flags = NFSLCK_TEST;
2533 stp->ls_uid = nd->nd_cred->cr_uid;
2534 i = fxdr_unsigned(int, *tl++);
2536 case NFSV4LOCKT_READW:
2537 stp->ls_flags |= NFSLCK_BLOCKING;
2538 case NFSV4LOCKT_READ:
2539 lo.lo_flags = NFSLCK_READ;
2541 case NFSV4LOCKT_WRITEW:
2542 stp->ls_flags |= NFSLCK_BLOCKING;
2543 case NFSV4LOCKT_WRITE:
2544 lo.lo_flags = NFSLCK_WRITE;
2547 nd->nd_repstat = NFSERR_BADXDR;
2550 lo.lo_first = fxdr_hyper(tl);
2552 len = fxdr_hyper(tl);
2553 if (len == NFS64BITSSET) {
2554 lo.lo_end = NFS64BITSSET;
2556 lo.lo_end = lo.lo_first + len;
2557 if (lo.lo_end <= lo.lo_first)
2558 nd->nd_repstat = NFSERR_INVAL;
2561 clientid.lval[0] = *tl++;
2562 clientid.lval[1] = *tl;
2563 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2564 if ((nd->nd_flag & ND_NFSV41) != 0)
2565 clientid.qval = nd->nd_clientid.qval;
2566 else if (nd->nd_clientid.qval != clientid.qval)
2567 printf("EEK5 multiple clids\n");
2569 if ((nd->nd_flag & ND_NFSV41) != 0)
2570 printf("EEK! no clientid from session\n");
2571 nd->nd_flag |= ND_IMPLIEDCLID;
2572 nd->nd_clientid.qval = clientid.qval;
2574 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2577 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2578 if (vnode_vtype(vp) == VDIR)
2579 nd->nd_repstat = NFSERR_ISDIR;
2581 nd->nd_repstat = NFSERR_INVAL;
2583 if (!nd->nd_repstat)
2584 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2585 &stateid, exp, nd, p);
2586 if (nd->nd_repstat) {
2587 if (nd->nd_repstat == NFSERR_DENIED) {
2588 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2589 txdr_hyper(cf.cl_first, tl);
2591 if (cf.cl_end == NFS64BITSSET)
2594 len = cf.cl_end - cf.cl_first;
2595 txdr_hyper(len, tl);
2597 if (cf.cl_flags == NFSLCK_WRITE)
2598 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2600 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2601 *tl++ = stp->ls_stateid.other[0];
2602 *tl = stp->ls_stateid.other[1];
2603 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2608 free(stp, M_NFSDSTATE);
2609 NFSEXITCODE2(0, nd);
2614 free(stp, M_NFSDSTATE);
2615 NFSEXITCODE2(error, nd);
2620 * nfsv4 unlock service
2623 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2624 vnode_t vp, struct nfsexstuff *exp)
2628 struct nfsstate *stp;
2629 struct nfslock *lop;
2631 nfsv4stateid_t stateid;
2634 struct thread *p = curthread;
2636 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2637 stp = malloc(sizeof (struct nfsstate),
2638 M_NFSDSTATE, M_WAITOK);
2639 lop = malloc(sizeof (struct nfslock),
2640 M_NFSDLOCK, M_WAITOK);
2641 stp->ls_flags = NFSLCK_UNLOCK;
2642 lop->lo_flags = NFSLCK_UNLOCK;
2643 stp->ls_op = nd->nd_rp;
2644 i = fxdr_unsigned(int, *tl++);
2646 case NFSV4LOCKT_READW:
2647 stp->ls_flags |= NFSLCK_BLOCKING;
2648 case NFSV4LOCKT_READ:
2650 case NFSV4LOCKT_WRITEW:
2651 stp->ls_flags |= NFSLCK_BLOCKING;
2652 case NFSV4LOCKT_WRITE:
2655 nd->nd_repstat = NFSERR_BADXDR;
2656 free(stp, M_NFSDSTATE);
2657 free(lop, M_NFSDLOCK);
2660 stp->ls_ownerlen = 0;
2661 stp->ls_uid = nd->nd_cred->cr_uid;
2662 stp->ls_seq = fxdr_unsigned(int, *tl++);
2663 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2664 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2666 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2669 * For the special stateid of other all 0s and seqid == 1, set the
2670 * stateid to the current stateid, if it is set.
2672 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2673 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2674 stp->ls_stateid.other[2] == 0) {
2675 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2676 stp->ls_stateid = nd->nd_curstateid;
2677 stp->ls_stateid.seqid = 0;
2679 nd->nd_repstat = NFSERR_BADSTATEID;
2684 lop->lo_first = fxdr_hyper(tl);
2686 len = fxdr_hyper(tl);
2687 if (len == NFS64BITSSET) {
2688 lop->lo_end = NFS64BITSSET;
2690 lop->lo_end = lop->lo_first + len;
2691 if (lop->lo_end <= lop->lo_first)
2692 nd->nd_repstat = NFSERR_INVAL;
2694 clientid.lval[0] = stp->ls_stateid.other[0];
2695 clientid.lval[1] = stp->ls_stateid.other[1];
2696 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2697 if ((nd->nd_flag & ND_NFSV41) != 0)
2698 clientid.qval = nd->nd_clientid.qval;
2699 else if (nd->nd_clientid.qval != clientid.qval)
2700 printf("EEK6 multiple clids\n");
2702 if ((nd->nd_flag & ND_NFSV41) != 0)
2703 printf("EEK! no clientid from session\n");
2704 nd->nd_flag |= ND_IMPLIEDCLID;
2705 nd->nd_clientid.qval = clientid.qval;
2707 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2708 if (vnode_vtype(vp) == VDIR)
2709 nd->nd_repstat = NFSERR_ISDIR;
2711 nd->nd_repstat = NFSERR_INVAL;
2714 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2715 * seqid# gets incremented. nfsrv_lockctrl() will return the
2716 * value of nd_repstat, if it gets that far.
2718 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2719 &stateid, exp, nd, p);
2721 free(stp, M_NFSDSTATE);
2723 free(lop, M_NFSDLOCK);
2724 if (!nd->nd_repstat) {
2725 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2726 *tl++ = txdr_unsigned(stateid.seqid);
2727 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2731 NFSEXITCODE2(error, nd);
2736 * nfsv4 open service
2739 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2740 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2744 struct nfsstate *stp = NULL;
2745 int error = 0, create, claim, exclusive_flag = 0;
2746 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2747 int how = NFSCREATE_UNCHECKED;
2748 int32_t cverf[2], tverf[2] = { 0, 0 };
2749 vnode_t vp = NULL, dirp = NULL;
2750 struct nfsvattr nva, dirfor, diraft;
2751 struct nameidata named;
2752 nfsv4stateid_t stateid, delegstateid;
2753 nfsattrbit_t attrbits;
2757 NFSACL_T *aclp = NULL;
2758 struct thread *p = curthread;
2760 #ifdef NFS4_ACL_EXTATTR_NAME
2761 aclp = acl_alloc(M_WAITOK);
2764 NFSZERO_ATTRBIT(&attrbits);
2765 named.ni_startdir = NULL;
2766 named.ni_cnd.cn_nameiop = 0;
2767 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2768 i = fxdr_unsigned(int, *(tl + 5));
2769 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2770 nd->nd_repstat = NFSERR_BADXDR;
2773 stp = malloc(sizeof (struct nfsstate) + i,
2774 M_NFSDSTATE, M_WAITOK);
2775 stp->ls_ownerlen = i;
2776 stp->ls_op = nd->nd_rp;
2777 stp->ls_flags = NFSLCK_OPEN;
2778 stp->ls_uid = nd->nd_cred->cr_uid;
2779 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2780 i = fxdr_unsigned(int, *tl++);
2782 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2783 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2785 /* For now, ignore these. */
2786 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2787 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2788 case NFSV4OPEN_WANTANYDELEG:
2789 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2791 i &= ~NFSV4OPEN_WANTDELEGMASK;
2793 case NFSV4OPEN_WANTREADDELEG:
2794 stp->ls_flags |= NFSLCK_WANTRDELEG;
2795 i &= ~NFSV4OPEN_WANTDELEGMASK;
2797 case NFSV4OPEN_WANTWRITEDELEG:
2798 stp->ls_flags |= NFSLCK_WANTWDELEG;
2799 i &= ~NFSV4OPEN_WANTDELEGMASK;
2801 case NFSV4OPEN_WANTNODELEG:
2802 stp->ls_flags |= NFSLCK_WANTNODELEG;
2803 i &= ~NFSV4OPEN_WANTDELEGMASK;
2805 case NFSV4OPEN_WANTCANCEL:
2806 printf("NFSv4: ignore Open WantCancel\n");
2807 i &= ~NFSV4OPEN_WANTDELEGMASK;
2810 /* nd_repstat will be set to NFSERR_INVAL below. */
2815 case NFSV4OPEN_ACCESSREAD:
2816 stp->ls_flags |= NFSLCK_READACCESS;
2818 case NFSV4OPEN_ACCESSWRITE:
2819 stp->ls_flags |= NFSLCK_WRITEACCESS;
2821 case NFSV4OPEN_ACCESSBOTH:
2822 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2825 nd->nd_repstat = NFSERR_INVAL;
2827 i = fxdr_unsigned(int, *tl++);
2829 case NFSV4OPEN_DENYNONE:
2831 case NFSV4OPEN_DENYREAD:
2832 stp->ls_flags |= NFSLCK_READDENY;
2834 case NFSV4OPEN_DENYWRITE:
2835 stp->ls_flags |= NFSLCK_WRITEDENY;
2837 case NFSV4OPEN_DENYBOTH:
2838 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2841 nd->nd_repstat = NFSERR_INVAL;
2843 clientid.lval[0] = *tl++;
2844 clientid.lval[1] = *tl;
2845 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2846 if ((nd->nd_flag & ND_NFSV41) != 0)
2847 clientid.qval = nd->nd_clientid.qval;
2848 else if (nd->nd_clientid.qval != clientid.qval)
2849 printf("EEK7 multiple clids\n");
2851 if ((nd->nd_flag & ND_NFSV41) != 0)
2852 printf("EEK! no clientid from session\n");
2853 nd->nd_flag |= ND_IMPLIEDCLID;
2854 nd->nd_clientid.qval = clientid.qval;
2856 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2859 NFSVNO_ATTRINIT(&nva);
2860 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2861 create = fxdr_unsigned(int, *tl);
2862 if (!nd->nd_repstat)
2863 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2864 if (create == NFSV4OPEN_CREATE) {
2867 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2868 how = fxdr_unsigned(int, *tl);
2870 case NFSCREATE_UNCHECKED:
2871 case NFSCREATE_GUARDED:
2872 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2876 * If the na_gid being set is the same as that of
2877 * the directory it is going in, clear it, since
2878 * that is what will be set by default. This allows
2879 * a user that isn't in that group to do the create.
2881 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2882 nva.na_gid == dirfor.na_gid)
2883 NFSVNO_UNSET(&nva, gid);
2884 if (!nd->nd_repstat)
2885 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2887 case NFSCREATE_EXCLUSIVE:
2888 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2892 case NFSCREATE_EXCLUSIVE41:
2893 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2896 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2899 if (NFSISSET_ATTRBIT(&attrbits,
2900 NFSATTRBIT_TIMEACCESSSET))
2901 nd->nd_repstat = NFSERR_INVAL;
2903 * If the na_gid being set is the same as that of
2904 * the directory it is going in, clear it, since
2905 * that is what will be set by default. This allows
2906 * a user that isn't in that group to do the create.
2908 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2909 nva.na_gid == dirfor.na_gid)
2910 NFSVNO_UNSET(&nva, gid);
2911 if (nd->nd_repstat == 0)
2912 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2915 nd->nd_repstat = NFSERR_BADXDR;
2918 } else if (create != NFSV4OPEN_NOCREATE) {
2919 nd->nd_repstat = NFSERR_BADXDR;
2924 * Now, handle the claim, which usually includes looking up a
2925 * name in the directory referenced by dp. The exception is
2926 * NFSV4OPEN_CLAIMPREVIOUS.
2928 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2929 claim = fxdr_unsigned(int, *tl);
2930 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2931 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2932 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2933 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2934 stp->ls_flags |= NFSLCK_DELEGCUR;
2935 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2936 stp->ls_flags |= NFSLCK_DELEGPREV;
2938 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2939 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2940 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2941 claim != NFSV4OPEN_CLAIMNULL)
2942 nd->nd_repstat = NFSERR_INVAL;
2943 if (nd->nd_repstat) {
2944 nd->nd_repstat = nfsrv_opencheck(clientid,
2945 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2948 if (create == NFSV4OPEN_CREATE)
2949 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2950 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2952 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2953 LOCKLEAF | SAVESTART);
2954 nfsvno_setpathbuf(&named, &bufp, &hashp);
2955 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2958 #ifdef NFS4_ACL_EXTATTR_NAME
2961 free(stp, M_NFSDSTATE);
2962 nfsvno_relpathbuf(&named);
2963 NFSEXITCODE2(error, nd);
2966 if (!nd->nd_repstat) {
2967 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2971 nfsvno_relpathbuf(&named);
2973 if (create == NFSV4OPEN_CREATE) {
2975 case NFSCREATE_UNCHECKED:
2978 * Clear the setable attribute bits, except
2979 * for Size, if it is being truncated.
2981 NFSZERO_ATTRBIT(&attrbits);
2982 if (NFSVNO_ISSETSIZE(&nva))
2983 NFSSETBIT_ATTRBIT(&attrbits,
2987 case NFSCREATE_GUARDED:
2988 if (named.ni_vp && !nd->nd_repstat)
2989 nd->nd_repstat = EEXIST;
2991 case NFSCREATE_EXCLUSIVE:
2996 case NFSCREATE_EXCLUSIVE41:
3001 nfsvno_open(nd, &named, clientid, &stateid, stp,
3002 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3003 nd->nd_cred, exp, &vp);
3004 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3005 NFSV4OPEN_CLAIMFH) {
3006 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3007 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3008 i = fxdr_unsigned(int, *tl);
3010 case NFSV4OPEN_DELEGATEREAD:
3011 stp->ls_flags |= NFSLCK_DELEGREAD;
3013 case NFSV4OPEN_DELEGATEWRITE:
3014 stp->ls_flags |= NFSLCK_DELEGWRITE;
3015 case NFSV4OPEN_DELEGATENONE:
3018 nd->nd_repstat = NFSERR_BADXDR;
3021 stp->ls_flags |= NFSLCK_RECLAIM;
3024 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3025 nd->nd_repstat = NFSERR_INVAL;
3028 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3029 if (!VN_IS_DOOMED(vp))
3030 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3031 stp, vp, nd, p, nd->nd_repstat);
3033 nd->nd_repstat = NFSERR_PERM;
3035 nd->nd_repstat = NFSERR_BADXDR;
3040 * Do basic access checking.
3042 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3044 * The IETF working group decided that this is the correct
3045 * error return for all non-regular files.
3047 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3049 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3050 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3051 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3052 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3053 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3054 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
3056 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3057 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
3058 NFSACCCHK_VPISLOCKED, NULL);
3061 if (!nd->nd_repstat) {
3062 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3063 if (!nd->nd_repstat) {
3064 tverf[0] = nva.na_atime.tv_sec;
3065 tverf[1] = nva.na_atime.tv_nsec;
3068 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3069 cverf[1] != tverf[1]))
3070 nd->nd_repstat = EEXIST;
3072 * Do the open locking/delegation stuff.
3074 if (!nd->nd_repstat)
3075 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3076 &delegstateid, &rflags, exp, p, nva.na_filerev);
3079 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3080 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3081 * (ie: Leave the NFSVOPUNLOCK() about here.)
3086 free(stp, M_NFSDSTATE);
3087 if (!nd->nd_repstat && dirp)
3088 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3089 if (!nd->nd_repstat) {
3090 /* For NFSv4.1, set the Current StateID. */
3091 if ((nd->nd_flag & ND_NFSV41) != 0) {
3092 nd->nd_curstateid = stateid;
3093 nd->nd_flag |= ND_CURSTATEID;
3095 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3096 *tl++ = txdr_unsigned(stateid.seqid);
3097 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3098 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3099 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3100 *tl++ = newnfs_true;
3106 *tl++ = newnfs_false; /* Since dirp is not locked */
3107 txdr_hyper(dirfor.na_filerev, tl);
3109 txdr_hyper(diraft.na_filerev, tl);
3112 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3113 (void) nfsrv_putattrbit(nd, &attrbits);
3114 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3115 if (rflags & NFSV4OPEN_READDELEGATE)
3116 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3117 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3118 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3119 else if (retext != 0) {
3120 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3121 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3122 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3123 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3124 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3125 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3126 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3127 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3128 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3129 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3131 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3132 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3133 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3136 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3137 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3140 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3141 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3142 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3143 *tl++ = txdr_unsigned(delegstateid.seqid);
3144 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3146 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3147 if (rflags & NFSV4OPEN_RECALL)
3151 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3152 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3153 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3154 txdr_hyper(nva.na_size, tl);
3156 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3157 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3158 *tl++ = txdr_unsigned(0x0);
3159 acemask = NFSV4ACE_ALLFILESMASK;
3160 if (nva.na_mode & S_IRUSR)
3161 acemask |= NFSV4ACE_READMASK;
3162 if (nva.na_mode & S_IWUSR)
3163 acemask |= NFSV4ACE_WRITEMASK;
3164 if (nva.na_mode & S_IXUSR)
3165 acemask |= NFSV4ACE_EXECUTEMASK;
3166 *tl = txdr_unsigned(acemask);
3167 (void) nfsm_strtom(nd, "OWNER@", 6);
3175 #ifdef NFS4_ACL_EXTATTR_NAME
3178 NFSEXITCODE2(0, nd);
3182 #ifdef NFS4_ACL_EXTATTR_NAME
3186 free(stp, M_NFSDSTATE);
3187 NFSEXITCODE2(error, nd);
3192 * nfsv4 close service
3195 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3196 vnode_t vp, __unused struct nfsexstuff *exp)
3199 struct nfsstate st, *stp = &st;
3200 int error = 0, writeacc;
3201 nfsv4stateid_t stateid;
3204 struct thread *p = curthread;
3206 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3207 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3208 stp->ls_ownerlen = 0;
3209 stp->ls_op = nd->nd_rp;
3210 stp->ls_uid = nd->nd_cred->cr_uid;
3211 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3212 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3216 * For the special stateid of other all 0s and seqid == 1, set the
3217 * stateid to the current stateid, if it is set.
3219 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3220 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3221 stp->ls_stateid.other[2] == 0) {
3222 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3223 stp->ls_stateid = nd->nd_curstateid;
3225 nd->nd_repstat = NFSERR_BADSTATEID;
3230 stp->ls_flags = NFSLCK_CLOSE;
3231 clientid.lval[0] = stp->ls_stateid.other[0];
3232 clientid.lval[1] = stp->ls_stateid.other[1];
3233 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3234 if ((nd->nd_flag & ND_NFSV41) != 0)
3235 clientid.qval = nd->nd_clientid.qval;
3236 else if (nd->nd_clientid.qval != clientid.qval)
3237 printf("EEK8 multiple clids\n");
3239 if ((nd->nd_flag & ND_NFSV41) != 0)
3240 printf("EEK! no clientid from session\n");
3241 nd->nd_flag |= ND_IMPLIEDCLID;
3242 nd->nd_clientid.qval = clientid.qval;
3244 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3246 /* For pNFS, update the attributes. */
3247 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3248 nfsrv_updatemdsattr(vp, &na, p);
3250 if (!nd->nd_repstat) {
3252 * If the stateid that has been closed is the current stateid,
3255 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3256 stateid.other[0] == nd->nd_curstateid.other[0] &&
3257 stateid.other[1] == nd->nd_curstateid.other[1] &&
3258 stateid.other[2] == nd->nd_curstateid.other[2])
3259 nd->nd_flag &= ~ND_CURSTATEID;
3260 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3261 *tl++ = txdr_unsigned(stateid.seqid);
3262 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3264 NFSEXITCODE2(0, nd);
3268 NFSEXITCODE2(error, nd);
3273 * nfsv4 delegpurge service
3276 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3277 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3282 struct thread *p = curthread;
3284 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3285 nd->nd_repstat = NFSERR_WRONGSEC;
3288 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3289 clientid.lval[0] = *tl++;
3290 clientid.lval[1] = *tl;
3291 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3292 if ((nd->nd_flag & ND_NFSV41) != 0)
3293 clientid.qval = nd->nd_clientid.qval;
3294 else if (nd->nd_clientid.qval != clientid.qval)
3295 printf("EEK9 multiple clids\n");
3297 if ((nd->nd_flag & ND_NFSV41) != 0)
3298 printf("EEK! no clientid from session\n");
3299 nd->nd_flag |= ND_IMPLIEDCLID;
3300 nd->nd_clientid.qval = clientid.qval;
3302 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3303 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3305 NFSEXITCODE2(error, nd);
3310 * nfsv4 delegreturn service
3313 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3314 vnode_t vp, __unused struct nfsexstuff *exp)
3317 int error = 0, writeacc;
3318 nfsv4stateid_t stateid;
3321 struct thread *p = curthread;
3323 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3324 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3325 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3326 clientid.lval[0] = stateid.other[0];
3327 clientid.lval[1] = stateid.other[1];
3328 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3329 if ((nd->nd_flag & ND_NFSV41) != 0)
3330 clientid.qval = nd->nd_clientid.qval;
3331 else if (nd->nd_clientid.qval != clientid.qval)
3332 printf("EEK10 multiple clids\n");
3334 if ((nd->nd_flag & ND_NFSV41) != 0)
3335 printf("EEK! no clientid from session\n");
3336 nd->nd_flag |= ND_IMPLIEDCLID;
3337 nd->nd_clientid.qval = clientid.qval;
3339 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3340 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3341 /* For pNFS, update the attributes. */
3342 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3343 nfsrv_updatemdsattr(vp, &na, p);
3346 NFSEXITCODE2(error, nd);
3351 * nfsv4 get file handle service
3354 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3355 vnode_t vp, __unused struct nfsexstuff *exp)
3358 struct thread *p = curthread;
3360 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3362 if (!nd->nd_repstat)
3363 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3364 NFSEXITCODE2(0, nd);
3369 * nfsv4 open confirm service
3372 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3373 vnode_t vp, __unused struct nfsexstuff *exp)
3376 struct nfsstate st, *stp = &st;
3378 nfsv4stateid_t stateid;
3380 struct thread *p = curthread;
3382 if ((nd->nd_flag & ND_NFSV41) != 0) {
3383 nd->nd_repstat = NFSERR_NOTSUPP;
3386 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3387 stp->ls_ownerlen = 0;
3388 stp->ls_op = nd->nd_rp;
3389 stp->ls_uid = nd->nd_cred->cr_uid;
3390 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3391 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3393 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3394 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3395 stp->ls_flags = NFSLCK_CONFIRM;
3396 clientid.lval[0] = stp->ls_stateid.other[0];
3397 clientid.lval[1] = stp->ls_stateid.other[1];
3398 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3399 if ((nd->nd_flag & ND_NFSV41) != 0)
3400 clientid.qval = nd->nd_clientid.qval;
3401 else if (nd->nd_clientid.qval != clientid.qval)
3402 printf("EEK11 multiple clids\n");
3404 if ((nd->nd_flag & ND_NFSV41) != 0)
3405 printf("EEK! no clientid from session\n");
3406 nd->nd_flag |= ND_IMPLIEDCLID;
3407 nd->nd_clientid.qval = clientid.qval;
3409 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3411 if (!nd->nd_repstat) {
3412 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3413 *tl++ = txdr_unsigned(stateid.seqid);
3414 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3418 NFSEXITCODE2(error, nd);
3423 * nfsv4 open downgrade service
3426 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3427 vnode_t vp, __unused struct nfsexstuff *exp)
3431 struct nfsstate st, *stp = &st;
3433 nfsv4stateid_t stateid;
3435 struct thread *p = curthread;
3437 /* opendowngrade can only work on a file object.*/
3438 if (vp->v_type != VREG) {
3439 error = NFSERR_INVAL;
3442 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3443 stp->ls_ownerlen = 0;
3444 stp->ls_op = nd->nd_rp;
3445 stp->ls_uid = nd->nd_cred->cr_uid;
3446 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3447 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3449 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3452 * For the special stateid of other all 0s and seqid == 1, set the
3453 * stateid to the current stateid, if it is set.
3455 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3456 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3457 stp->ls_stateid.other[2] == 0) {
3458 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3459 stp->ls_stateid = nd->nd_curstateid;
3461 nd->nd_repstat = NFSERR_BADSTATEID;
3466 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3467 i = fxdr_unsigned(int, *tl++);
3468 if ((nd->nd_flag & ND_NFSV41) != 0)
3469 i &= ~NFSV4OPEN_WANTDELEGMASK;
3471 case NFSV4OPEN_ACCESSREAD:
3472 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3474 case NFSV4OPEN_ACCESSWRITE:
3475 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3477 case NFSV4OPEN_ACCESSBOTH:
3478 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3482 nd->nd_repstat = NFSERR_INVAL;
3484 i = fxdr_unsigned(int, *tl);
3486 case NFSV4OPEN_DENYNONE:
3488 case NFSV4OPEN_DENYREAD:
3489 stp->ls_flags |= NFSLCK_READDENY;
3491 case NFSV4OPEN_DENYWRITE:
3492 stp->ls_flags |= NFSLCK_WRITEDENY;
3494 case NFSV4OPEN_DENYBOTH:
3495 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3498 nd->nd_repstat = NFSERR_INVAL;
3501 clientid.lval[0] = stp->ls_stateid.other[0];
3502 clientid.lval[1] = stp->ls_stateid.other[1];
3503 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3504 if ((nd->nd_flag & ND_NFSV41) != 0)
3505 clientid.qval = nd->nd_clientid.qval;
3506 else if (nd->nd_clientid.qval != clientid.qval)
3507 printf("EEK12 multiple clids\n");
3509 if ((nd->nd_flag & ND_NFSV41) != 0)
3510 printf("EEK! no clientid from session\n");
3511 nd->nd_flag |= ND_IMPLIEDCLID;
3512 nd->nd_clientid.qval = clientid.qval;
3514 if (!nd->nd_repstat)
3515 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3517 if (!nd->nd_repstat) {
3518 /* For NFSv4.1, set the Current StateID. */
3519 if ((nd->nd_flag & ND_NFSV41) != 0) {
3520 nd->nd_curstateid = stateid;
3521 nd->nd_flag |= ND_CURSTATEID;
3523 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3524 *tl++ = txdr_unsigned(stateid.seqid);
3525 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3529 NFSEXITCODE2(error, nd);
3534 * nfsv4 renew lease service
3537 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3538 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3543 struct thread *p = curthread;
3545 if ((nd->nd_flag & ND_NFSV41) != 0) {
3546 nd->nd_repstat = NFSERR_NOTSUPP;
3549 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3550 nd->nd_repstat = NFSERR_WRONGSEC;
3553 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3554 clientid.lval[0] = *tl++;
3555 clientid.lval[1] = *tl;
3556 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3557 if ((nd->nd_flag & ND_NFSV41) != 0)
3558 clientid.qval = nd->nd_clientid.qval;
3559 else if (nd->nd_clientid.qval != clientid.qval)
3560 printf("EEK13 multiple clids\n");
3562 if ((nd->nd_flag & ND_NFSV41) != 0)
3563 printf("EEK! no clientid from session\n");
3564 nd->nd_flag |= ND_IMPLIEDCLID;
3565 nd->nd_clientid.qval = clientid.qval;
3567 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3568 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3570 NFSEXITCODE2(error, nd);
3575 * nfsv4 security info service
3578 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3579 vnode_t dp, struct nfsexstuff *exp)
3583 struct nameidata named;
3584 vnode_t dirp = NULL, vp;
3586 struct nfsexstuff retnes;
3588 int error = 0, savflag, i;
3591 struct thread *p = curthread;
3594 * All this just to get the export flags for the name.
3596 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3597 LOCKLEAF | SAVESTART);
3598 nfsvno_setpathbuf(&named, &bufp, &hashp);
3599 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3602 nfsvno_relpathbuf(&named);
3605 if (!nd->nd_repstat) {
3606 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3609 nfsvno_relpathbuf(&named);
3615 vrele(named.ni_startdir);
3616 nfsvno_relpathbuf(&named);
3617 fh.nfsrvfh_len = NFSX_MYFH;
3619 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3621 savflag = nd->nd_flag;
3622 if (!nd->nd_repstat) {
3623 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3627 nd->nd_flag = savflag;
3632 * Finally have the export flags for name, so we can create
3633 * the security info.
3636 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3637 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3638 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3639 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3640 *tl = txdr_unsigned(RPCAUTH_UNIX);
3642 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
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_SVCNONE);
3651 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
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_SVCINTEGRITY);
3660 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3661 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3662 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3663 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3664 nfsgss_mechlist[KERBV_MECH].len);
3665 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3666 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3667 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3671 *sizp = txdr_unsigned(len);
3674 NFSEXITCODE2(error, nd);
3679 * nfsv4 set client id service
3682 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3683 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3687 int error = 0, idlen;
3688 struct nfsclient *clp = NULL;
3690 struct sockaddr_in *rin;
3693 struct sockaddr_in6 *rin6;
3695 #if defined(INET) || defined(INET6)
3698 u_char *verf, *addrbuf;
3699 nfsquad_t clientid, confirm;
3700 struct thread *p = curthread;
3702 if ((nd->nd_flag & ND_NFSV41) != 0) {
3703 nd->nd_repstat = NFSERR_NOTSUPP;
3706 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3707 nd->nd_repstat = NFSERR_WRONGSEC;
3710 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3711 verf = (u_char *)tl;
3712 tl += (NFSX_VERF / NFSX_UNSIGNED);
3713 i = fxdr_unsigned(int, *tl);
3714 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3715 nd->nd_repstat = NFSERR_BADXDR;
3719 if (nd->nd_flag & ND_GSS)
3720 i += nd->nd_princlen;
3721 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3723 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3724 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3725 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3726 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3727 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3729 clp->lc_req.nr_cred = NULL;
3730 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3731 clp->lc_idlen = idlen;
3732 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3735 if (nd->nd_flag & ND_GSS) {
3736 clp->lc_flags = LCL_GSS;
3737 if (nd->nd_flag & ND_GSSINTEGRITY)
3738 clp->lc_flags |= LCL_GSSINTEGRITY;
3739 else if (nd->nd_flag & ND_GSSPRIVACY)
3740 clp->lc_flags |= LCL_GSSPRIVACY;
3744 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3745 clp->lc_flags |= LCL_NAME;
3746 clp->lc_namelen = nd->nd_princlen;
3747 clp->lc_name = &clp->lc_id[idlen];
3748 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3750 clp->lc_uid = nd->nd_cred->cr_uid;
3751 clp->lc_gid = nd->nd_cred->cr_gid;
3753 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3754 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3755 error = nfsrv_getclientipaddr(nd, clp);
3758 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3759 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3762 * nfsrv_setclient() does the actual work of adding it to the
3763 * client list. If there is no error, the structure has been
3764 * linked into the client list and clp should no longer be used
3765 * here. When an error is returned, it has not been linked in,
3766 * so it should be free'd.
3768 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3769 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3771 * 8 is the maximum length of the port# string.
3773 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3774 switch (clp->lc_req.nr_nam->sa_family) {
3777 if (clp->lc_flags & LCL_TCPCALLBACK)
3778 (void) nfsm_strtom(nd, "tcp", 3);
3780 (void) nfsm_strtom(nd, "udp", 3);
3781 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3782 ucp = (u_char *)&rin->sin_addr.s_addr;
3783 ucp2 = (u_char *)&rin->sin_port;
3784 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3785 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3786 ucp2[0] & 0xff, ucp2[1] & 0xff);
3791 if (clp->lc_flags & LCL_TCPCALLBACK)
3792 (void) nfsm_strtom(nd, "tcp6", 4);
3794 (void) nfsm_strtom(nd, "udp6", 4);
3795 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3796 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3802 ucp2 = (u_char *)&rin6->sin6_port;
3803 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3808 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3809 free(addrbuf, M_TEMP);
3812 free(clp->lc_req.nr_nam, M_SONAME);
3813 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3814 free(clp->lc_stateid, M_NFSDCLIENT);
3815 free(clp, M_NFSDCLIENT);
3817 if (!nd->nd_repstat) {
3818 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3819 *tl++ = clientid.lval[0];
3820 *tl++ = clientid.lval[1];
3821 *tl++ = confirm.lval[0];
3822 *tl = confirm.lval[1];
3826 NFSEXITCODE2(0, nd);
3830 free(clp->lc_req.nr_nam, M_SONAME);
3831 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3832 free(clp->lc_stateid, M_NFSDCLIENT);
3833 free(clp, M_NFSDCLIENT);
3835 NFSEXITCODE2(error, nd);
3840 * nfsv4 set client id confirm service
3843 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3844 __unused int isdgram, __unused vnode_t vp,
3845 __unused struct nfsexstuff *exp)
3849 nfsquad_t clientid, confirm;
3850 struct thread *p = curthread;
3852 if ((nd->nd_flag & ND_NFSV41) != 0) {
3853 nd->nd_repstat = NFSERR_NOTSUPP;
3856 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3857 nd->nd_repstat = NFSERR_WRONGSEC;
3860 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3861 clientid.lval[0] = *tl++;
3862 clientid.lval[1] = *tl++;
3863 confirm.lval[0] = *tl++;
3864 confirm.lval[1] = *tl;
3867 * nfsrv_getclient() searches the client list for a match and
3868 * returns the appropriate NFSERR status.
3870 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3871 NULL, NULL, confirm, 0, nd, p);
3873 NFSEXITCODE2(error, nd);
3878 * nfsv4 verify service
3881 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3882 vnode_t vp, __unused struct nfsexstuff *exp)
3884 int error = 0, ret, fhsize = NFSX_MYFH;
3885 struct nfsvattr nva;
3887 struct nfsfsinfo fs;
3889 struct thread *p = curthread;
3891 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3892 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3893 if (!nd->nd_repstat)
3894 nd->nd_repstat = nfsvno_statfs(vp, sf);
3895 if (!nd->nd_repstat)
3896 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3897 if (!nd->nd_repstat) {
3898 nfsvno_getfs(&fs, isdgram);
3899 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3900 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3902 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3904 nd->nd_repstat = NFSERR_SAME;
3905 else if (ret != NFSERR_NOTSAME)
3906 nd->nd_repstat = ret;
3908 nd->nd_repstat = ret;
3913 NFSEXITCODE2(error, nd);
3921 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3922 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3923 __unused struct nfsexstuff *exp)
3926 int error = 0, createdir __unused;
3928 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3929 createdir = fxdr_unsigned(int, *tl);
3930 nd->nd_repstat = NFSERR_NOTSUPP;
3933 NFSEXITCODE2(error, nd);
3938 * nfsv4 release lock owner service
3941 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3942 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3945 struct nfsstate *stp = NULL;
3948 struct thread *p = curthread;
3950 if ((nd->nd_flag & ND_NFSV41) != 0) {
3951 nd->nd_repstat = NFSERR_NOTSUPP;
3954 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3955 nd->nd_repstat = NFSERR_WRONGSEC;
3958 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3959 len = fxdr_unsigned(int, *(tl + 2));
3960 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3961 nd->nd_repstat = NFSERR_BADXDR;
3964 stp = malloc(sizeof (struct nfsstate) + len,
3965 M_NFSDSTATE, M_WAITOK);
3966 stp->ls_ownerlen = len;
3968 stp->ls_flags = NFSLCK_RELEASE;
3969 stp->ls_uid = nd->nd_cred->cr_uid;
3970 clientid.lval[0] = *tl++;
3971 clientid.lval[1] = *tl;
3972 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3973 if ((nd->nd_flag & ND_NFSV41) != 0)
3974 clientid.qval = nd->nd_clientid.qval;
3975 else if (nd->nd_clientid.qval != clientid.qval)
3976 printf("EEK14 multiple clids\n");
3978 if ((nd->nd_flag & ND_NFSV41) != 0)
3979 printf("EEK! no clientid from session\n");
3980 nd->nd_flag |= ND_IMPLIEDCLID;
3981 nd->nd_clientid.qval = clientid.qval;
3983 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3986 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3987 free(stp, M_NFSDSTATE);
3989 NFSEXITCODE2(0, nd);
3993 free(stp, M_NFSDSTATE);
3994 NFSEXITCODE2(error, nd);
3999 * nfsv4 exchange_id service
4002 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4003 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4006 int error = 0, i, idlen;
4007 struct nfsclient *clp = NULL;
4008 nfsquad_t clientid, confirm;
4010 uint32_t sp4type, v41flags;
4011 uint64_t owner_minor;
4012 struct timespec verstime;
4014 struct sockaddr_in *sin, *rin;
4017 struct sockaddr_in6 *sin6, *rin6;
4019 struct thread *p = curthread;
4021 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4022 nd->nd_repstat = NFSERR_WRONGSEC;
4025 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4026 verf = (uint8_t *)tl;
4027 tl += (NFSX_VERF / NFSX_UNSIGNED);
4028 i = fxdr_unsigned(int, *tl);
4029 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4030 nd->nd_repstat = NFSERR_BADXDR;
4034 if (nd->nd_flag & ND_GSS)
4035 i += nd->nd_princlen;
4036 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4038 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4039 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4040 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4041 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4042 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4044 switch (nd->nd_nam->sa_family) {
4047 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4048 sin = (struct sockaddr_in *)nd->nd_nam;
4049 rin->sin_family = AF_INET;
4050 rin->sin_len = sizeof(struct sockaddr_in);
4052 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4057 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4058 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4059 rin6->sin6_family = AF_INET6;
4060 rin6->sin6_len = sizeof(struct sockaddr_in6);
4061 rin6->sin6_port = 0;
4062 rin6->sin6_addr = sin6->sin6_addr;
4066 clp->lc_req.nr_cred = NULL;
4067 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4068 clp->lc_idlen = idlen;
4069 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4072 if ((nd->nd_flag & ND_GSS) != 0) {
4073 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4074 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4075 clp->lc_flags |= LCL_GSSINTEGRITY;
4076 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4077 clp->lc_flags |= LCL_GSSPRIVACY;
4079 clp->lc_flags = LCL_NFSV41;
4080 if ((nd->nd_flag & ND_NFSV42) != 0)
4081 clp->lc_flags |= LCL_NFSV42;
4082 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4083 clp->lc_flags |= LCL_NAME;
4084 clp->lc_namelen = nd->nd_princlen;
4085 clp->lc_name = &clp->lc_id[idlen];
4086 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4088 clp->lc_uid = nd->nd_cred->cr_uid;
4089 clp->lc_gid = nd->nd_cred->cr_gid;
4091 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4092 v41flags = fxdr_unsigned(uint32_t, *tl++);
4093 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4094 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4095 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4096 nd->nd_repstat = NFSERR_INVAL;
4099 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4100 confirm.lval[1] = 1;
4102 confirm.lval[1] = 0;
4103 if (nfsrv_devidcnt == 0)
4104 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4106 v41flags = NFSV4EXCH_USEPNFSMDS;
4107 sp4type = fxdr_unsigned(uint32_t, *tl);
4108 if (sp4type != NFSV4EXCH_SP4NONE) {
4109 nd->nd_repstat = NFSERR_NOTSUPP;
4114 * nfsrv_setclient() does the actual work of adding it to the
4115 * client list. If there is no error, the structure has been
4116 * linked into the client list and clp should no longer be used
4117 * here. When an error is returned, it has not been linked in,
4118 * so it should be free'd.
4120 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4122 free(clp->lc_req.nr_nam, M_SONAME);
4123 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4124 free(clp->lc_stateid, M_NFSDCLIENT);
4125 free(clp, M_NFSDCLIENT);
4127 if (nd->nd_repstat == 0) {
4128 if (confirm.lval[1] != 0)
4129 v41flags |= NFSV4EXCH_CONFIRMEDR;
4130 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4131 *tl++ = clientid.lval[0]; /* ClientID */
4132 *tl++ = clientid.lval[1];
4133 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4134 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4135 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4136 owner_minor = 0; /* Owner */
4137 txdr_hyper(owner_minor, tl); /* Minor */
4138 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4139 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4140 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4141 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4142 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4143 *tl = txdr_unsigned(1);
4144 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4145 (void)nfsm_strtom(nd, version, strlen(version));
4146 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4147 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4148 verstime.tv_nsec = 0;
4149 txdr_nfsv4time(&verstime, tl);
4151 NFSEXITCODE2(0, nd);
4155 free(clp->lc_req.nr_nam, M_SONAME);
4156 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4157 free(clp->lc_stateid, M_NFSDCLIENT);
4158 free(clp, M_NFSDCLIENT);
4160 NFSEXITCODE2(error, nd);
4165 * nfsv4 create session service
4168 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4169 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4173 nfsquad_t clientid, confirm;
4174 struct nfsdsession *sep = NULL;
4176 struct thread *p = curthread;
4178 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4179 nd->nd_repstat = NFSERR_WRONGSEC;
4182 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4183 M_NFSDSESSION, M_WAITOK | M_ZERO);
4184 sep->sess_refcnt = 1;
4185 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4186 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4187 clientid.lval[0] = *tl++;
4188 clientid.lval[1] = *tl++;
4189 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4190 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4191 /* Persistent sessions and RDMA are not supported. */
4192 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4194 /* Fore channel attributes. */
4195 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4196 tl++; /* Header pad always 0. */
4197 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4198 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4199 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4200 printf("Consider increasing kern.ipc.maxsockbuf\n");
4202 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4203 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4204 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4205 printf("Consider increasing kern.ipc.maxsockbuf\n");
4207 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4208 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4209 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4210 if (sep->sess_maxslots > NFSV4_SLOTS)
4211 sep->sess_maxslots = NFSV4_SLOTS;
4212 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4214 nd->nd_repstat = NFSERR_BADXDR;
4216 } else if (rdmacnt == 1)
4217 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4219 /* Back channel attributes. */
4220 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4221 tl++; /* Header pad always 0. */
4222 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4223 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4224 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4225 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4226 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4227 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4229 nd->nd_repstat = NFSERR_BADXDR;
4231 } else if (rdmacnt == 1)
4232 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4234 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4235 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4238 * nfsrv_getclient() searches the client list for a match and
4239 * returns the appropriate NFSERR status.
4241 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4242 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4243 if (nd->nd_repstat == 0) {
4244 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4245 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4246 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4247 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4248 *tl++ = txdr_unsigned(sep->sess_crflags);
4250 /* Fore channel attributes. */
4252 *tl++ = txdr_unsigned(sep->sess_maxreq);
4253 *tl++ = txdr_unsigned(sep->sess_maxresp);
4254 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4255 *tl++ = txdr_unsigned(sep->sess_maxops);
4256 *tl++ = txdr_unsigned(sep->sess_maxslots);
4257 *tl++ = txdr_unsigned(1);
4258 *tl++ = txdr_unsigned(0); /* No RDMA. */
4260 /* Back channel attributes. */
4262 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4263 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4264 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4265 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4266 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4267 *tl++ = txdr_unsigned(1);
4268 *tl = txdr_unsigned(0); /* No RDMA. */
4271 if (nd->nd_repstat != 0 && sep != NULL)
4272 free(sep, M_NFSDSESSION);
4273 NFSEXITCODE2(error, nd);
4278 * nfsv4 sequence service
4281 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4282 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4285 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4286 int cache_this, error = 0;
4287 struct thread *p = curthread;
4289 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4290 nd->nd_repstat = NFSERR_WRONGSEC;
4293 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4294 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4295 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4296 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4297 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4298 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4299 if (*tl == newnfs_true)
4303 nd->nd_flag |= ND_HASSEQUENCE;
4304 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4305 &target_highest_slotid, cache_this, &sflags, p);
4306 if (nd->nd_repstat == 0) {
4307 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4308 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4309 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4310 *tl++ = txdr_unsigned(sequenceid);
4311 *tl++ = txdr_unsigned(nd->nd_slotid);
4312 *tl++ = txdr_unsigned(highest_slotid);
4313 *tl++ = txdr_unsigned(target_highest_slotid);
4314 *tl = txdr_unsigned(sflags);
4317 NFSEXITCODE2(error, nd);
4322 * nfsv4 reclaim complete service
4325 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4326 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4329 int error = 0, onefs;
4331 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4332 nd->nd_repstat = NFSERR_WRONGSEC;
4335 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4337 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4338 * to be used after a file system has been transferred to a different
4339 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4340 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4341 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4342 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4343 * NFS_OK without doing anything.
4346 if (*tl == newnfs_true)
4348 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4350 NFSEXITCODE2(error, nd);
4355 * nfsv4 destroy clientid service
4358 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4359 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4364 struct thread *p = curthread;
4366 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4367 nd->nd_repstat = NFSERR_WRONGSEC;
4370 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4371 clientid.lval[0] = *tl++;
4372 clientid.lval[1] = *tl;
4373 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4375 NFSEXITCODE2(error, nd);
4380 * nfsv4 bind connection to session service
4383 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4384 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4387 uint8_t sessid[NFSX_V4SESSIONID];
4388 int error = 0, foreaft;
4390 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4391 nd->nd_repstat = NFSERR_WRONGSEC;
4394 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4395 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4396 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4397 foreaft = fxdr_unsigned(int, *tl++);
4398 if (*tl == newnfs_true) {
4399 /* RDMA is not supported. */
4400 nd->nd_repstat = NFSERR_NOTSUPP;
4404 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4405 if (nd->nd_repstat == 0) {
4406 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4408 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4409 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4410 *tl++ = txdr_unsigned(foreaft);
4414 NFSEXITCODE2(error, nd);
4419 * nfsv4 destroy session service
4422 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4423 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4425 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4428 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4429 nd->nd_repstat = NFSERR_WRONGSEC;
4432 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4433 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4434 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4436 NFSEXITCODE2(error, nd);
4441 * nfsv4 free stateid service
4444 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4445 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4448 nfsv4stateid_t stateid;
4450 struct thread *p = curthread;
4452 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4453 nd->nd_repstat = NFSERR_WRONGSEC;
4456 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4457 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4458 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
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;
4475 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4477 /* If the current stateid has been free'd, unset it. */
4478 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4479 stateid.other[0] == nd->nd_curstateid.other[0] &&
4480 stateid.other[1] == nd->nd_curstateid.other[1] &&
4481 stateid.other[2] == nd->nd_curstateid.other[2])
4482 nd->nd_flag &= ~ND_CURSTATEID;
4484 NFSEXITCODE2(error, nd);
4489 * nfsv4 layoutget service
4492 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4493 vnode_t vp, struct nfsexstuff *exp)
4496 nfsv4stateid_t stateid;
4497 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4498 uint64_t offset, len, minlen;
4500 struct thread *p = curthread;
4502 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4503 nd->nd_repstat = NFSERR_WRONGSEC;
4506 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4508 tl++; /* Signal layout available. Ignore for now. */
4509 layouttype = fxdr_unsigned(int, *tl++);
4510 iomode = fxdr_unsigned(int, *tl++);
4511 offset = fxdr_hyper(tl); tl += 2;
4512 len = fxdr_hyper(tl); tl += 2;
4513 minlen = fxdr_hyper(tl); tl += 2;
4514 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4515 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4516 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4517 maxcnt = fxdr_unsigned(int, *tl);
4518 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4519 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4522 (minlen != UINT64_MAX && offset + minlen < offset) ||
4523 (len != UINT64_MAX && offset + len < offset)) {
4524 nd->nd_repstat = NFSERR_INVAL;
4529 * For the special stateid of other all 0s and seqid == 1, set the
4530 * stateid to the current stateid, if it is set.
4532 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4533 stateid.other[1] == 0 && stateid.other[2] == 0) {
4534 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4535 stateid = nd->nd_curstateid;
4538 nd->nd_repstat = NFSERR_BADSTATEID;
4544 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4545 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4546 else if (layouttype == NFSLAYOUT_FLEXFILE)
4547 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4550 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4552 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4553 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4554 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4555 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4557 if (nd->nd_repstat == 0) {
4558 /* For NFSv4.1, set the Current StateID. */
4559 if ((nd->nd_flag & ND_NFSV41) != 0) {
4560 nd->nd_curstateid = stateid;
4561 nd->nd_flag |= ND_CURSTATEID;
4563 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4565 *tl++ = txdr_unsigned(retonclose);
4566 *tl++ = txdr_unsigned(stateid.seqid);
4567 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4568 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4569 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4570 txdr_hyper(offset, tl); tl += 2;
4571 txdr_hyper(len, tl); tl += 2;
4572 *tl++ = txdr_unsigned(iomode);
4573 *tl = txdr_unsigned(layouttype);
4574 nfsm_strtom(nd, layp, layoutlen);
4575 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4576 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4582 NFSEXITCODE2(error, nd);
4587 * nfsv4 layoutcommit service
4590 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4591 vnode_t vp, struct nfsexstuff *exp)
4594 nfsv4stateid_t stateid;
4595 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4597 uint64_t offset, len, newoff = 0, newsize;
4598 struct timespec newmtime;
4600 struct thread *p = curthread;
4603 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4604 nd->nd_repstat = NFSERR_WRONGSEC;
4607 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4609 offset = fxdr_hyper(tl); tl += 2;
4610 len = fxdr_hyper(tl); tl += 2;
4611 reclaim = fxdr_unsigned(int, *tl++);
4612 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4613 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4614 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4616 * For the special stateid of other all 0s and seqid == 1, set the
4617 * stateid to the current stateid, if it is set.
4619 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4620 stateid.other[1] == 0 && stateid.other[2] == 0) {
4621 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4622 stateid = nd->nd_curstateid;
4625 nd->nd_repstat = NFSERR_BADSTATEID;
4630 hasnewoff = fxdr_unsigned(int, *tl);
4631 if (hasnewoff != 0) {
4632 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4633 newoff = fxdr_hyper(tl); tl += 2;
4635 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4636 hasnewmtime = fxdr_unsigned(int, *tl);
4637 if (hasnewmtime != 0) {
4638 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4639 fxdr_nfsv4time(tl, &newmtime);
4640 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4642 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4643 layouttype = fxdr_unsigned(int, *tl++);
4644 maxcnt = fxdr_unsigned(int, *tl);
4646 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4647 error = nfsrv_mtostr(nd, layp, maxcnt);
4651 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4652 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4653 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4654 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4655 if (nd->nd_repstat == 0) {
4656 if (hasnewsize != 0) {
4657 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4658 *tl++ = newnfs_true;
4659 txdr_hyper(newsize, tl);
4661 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4668 NFSEXITCODE2(error, nd);
4673 * nfsv4 layoutreturn service
4676 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4677 vnode_t vp, struct nfsexstuff *exp)
4679 uint32_t *tl, *layp;
4680 nfsv4stateid_t stateid;
4681 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4682 uint64_t offset, len;
4683 struct thread *p = curthread;
4686 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4687 nd->nd_repstat = NFSERR_WRONGSEC;
4690 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4692 layouttype = fxdr_unsigned(int, *tl++);
4693 iomode = fxdr_unsigned(int, *tl++);
4694 kind = fxdr_unsigned(int, *tl);
4695 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4696 layouttype, iomode, kind);
4697 if (kind == NFSV4LAYOUTRET_FILE) {
4698 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4700 offset = fxdr_hyper(tl); tl += 2;
4701 len = fxdr_hyper(tl); tl += 2;
4702 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4703 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4704 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4707 * For the special stateid of other all 0s and seqid == 1, set
4708 * the stateid to the current stateid, if it is set.
4710 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4711 stateid.other[1] == 0 && stateid.other[2] == 0) {
4712 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4713 stateid = nd->nd_curstateid;
4716 nd->nd_repstat = NFSERR_BADSTATEID;
4721 maxcnt = fxdr_unsigned(int, *tl);
4723 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4724 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4729 if (reclaim == newnfs_true) {
4730 nd->nd_repstat = NFSERR_INVAL;
4736 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4737 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4739 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4741 if (nd->nd_repstat == 0) {
4742 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4745 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4746 *tl++ = txdr_unsigned(stateid.seqid);
4747 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4754 NFSEXITCODE2(error, nd);
4759 * nfsv4 layout error service
4762 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
4763 vnode_t vp, struct nfsexstuff *exp)
4766 nfsv4stateid_t stateid;
4767 int cnt, error = 0, i, stat;
4769 char devid[NFSX_V4DEVICEID];
4770 uint64_t offset, len;
4772 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4773 nd->nd_repstat = NFSERR_WRONGSEC;
4776 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4778 offset = fxdr_hyper(tl); tl += 2;
4779 len = fxdr_hyper(tl); tl += 2;
4780 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4781 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4782 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4783 cnt = fxdr_unsigned(int, *tl);
4784 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
4785 (uintmax_t)len, cnt);
4787 * For the special stateid of other all 0s and seqid == 1, set
4788 * the stateid to the current stateid, if it is set.
4790 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4791 stateid.other[1] == 0 && stateid.other[2] == 0) {
4792 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4793 stateid = nd->nd_curstateid;
4796 nd->nd_repstat = NFSERR_BADSTATEID;
4802 * Ignore offset, len and stateid for now.
4804 for (i = 0; i < cnt; i++) {
4805 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
4807 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4808 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4809 stat = fxdr_unsigned(int, *tl++);
4810 opnum = fxdr_unsigned(int, *tl);
4811 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
4813 * Except for NFSERR_ACCES and NFSERR_STALE errors,
4814 * disable the mirror.
4816 if (stat != NFSERR_ACCES && stat != NFSERR_STALE)
4817 nfsrv_delds(devid, curthread);
4821 NFSEXITCODE2(error, nd);
4826 * nfsv4 layout stats service
4829 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
4830 vnode_t vp, struct nfsexstuff *exp)
4833 nfsv4stateid_t stateid;
4835 int layouttype __unused;
4836 char devid[NFSX_V4DEVICEID] __unused;
4837 uint64_t offset, len, readcount, readbytes, writecount, writebytes
4840 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4841 nd->nd_repstat = NFSERR_WRONGSEC;
4844 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
4845 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
4846 offset = fxdr_hyper(tl); tl += 2;
4847 len = fxdr_hyper(tl); tl += 2;
4848 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4849 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4850 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4851 readcount = fxdr_hyper(tl); tl += 2;
4852 readbytes = fxdr_hyper(tl); tl += 2;
4853 writecount = fxdr_hyper(tl); tl += 2;
4854 writebytes = fxdr_hyper(tl); tl += 2;
4855 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4856 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4857 layouttype = fxdr_unsigned(int, *tl++);
4858 cnt = fxdr_unsigned(int, *tl);
4859 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
4862 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
4864 * For the special stateid of other all 0s and seqid == 1, set
4865 * the stateid to the current stateid, if it is set.
4867 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4868 stateid.other[1] == 0 && stateid.other[2] == 0) {
4869 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4870 stateid = nd->nd_curstateid;
4873 nd->nd_repstat = NFSERR_BADSTATEID;
4879 * No use for the stats for now.
4883 NFSEXITCODE2(error, nd);
4888 * nfsv4 io_advise service
4891 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
4892 vnode_t vp, struct nfsexstuff *exp)
4895 nfsv4stateid_t stateid;
4900 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4901 nd->nd_repstat = NFSERR_WRONGSEC;
4904 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
4905 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4906 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4907 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4908 offset = fxdr_hyper(tl); tl += 2;
4909 len = fxdr_hyper(tl);
4910 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
4914 * For the special stateid of other all 0s and seqid == 1, set
4915 * the stateid to the current stateid, if it is set.
4917 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4918 stateid.other[1] == 0 && stateid.other[2] == 0) {
4919 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4920 stateid = nd->nd_curstateid;
4923 nd->nd_repstat = NFSERR_BADSTATEID;
4929 nd->nd_repstat = NFSERR_INVAL;
4934 if (vp->v_type != VREG) {
4935 if (vp->v_type == VDIR)
4936 nd->nd_repstat = NFSERR_ISDIR;
4938 nd->nd_repstat = NFSERR_WRONGTYPE;
4943 * For now, we can only handle WILLNEED and DONTNEED and don't use
4946 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
4947 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
4948 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
4949 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
4951 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
4952 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
4953 NFSZERO_ATTRBIT(&hints);
4955 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
4957 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4959 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
4960 NFSZERO_ATTRBIT(&hints);
4962 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
4964 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4968 NFSZERO_ATTRBIT(&hints);
4969 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4972 nfsrv_putattrbit(nd, &hints);
4973 NFSEXITCODE2(error, nd);
4977 NFSEXITCODE2(error, nd);
4982 * nfsv4 getdeviceinfo service
4985 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
4986 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4988 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
4989 int cnt, devaddrlen, error = 0, i, layouttype;
4990 char devid[NFSX_V4DEVICEID], *devaddr;
4993 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4994 nd->nd_repstat = NFSERR_WRONGSEC;
4997 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4998 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4999 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5000 layouttype = fxdr_unsigned(int, *tl++);
5001 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5002 cnt = fxdr_unsigned(int, *tl);
5003 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5005 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5006 nd->nd_repstat = NFSERR_INVAL;
5010 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5011 for (i = 0; i < cnt; i++)
5012 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5014 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5018 * Check that the device id is not stale. Device ids are recreated
5019 * each time the nfsd threads are restarted.
5021 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5022 if (dev_time != nfsdev_time) {
5023 nd->nd_repstat = NFSERR_NOENT;
5027 /* Look for the device id. */
5028 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5029 notify, &devaddrlen, &devaddr);
5030 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5031 if (nd->nd_repstat == 0) {
5032 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5033 *tl = txdr_unsigned(layouttype);
5034 nfsm_strtom(nd, devaddr, devaddrlen);
5036 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5040 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5041 *tl++ = txdr_unsigned(cnt);
5042 for (i = 0; i < cnt; i++)
5043 *tl++ = txdr_unsigned(notify[i]);
5044 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5045 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5046 *tl = txdr_unsigned(maxcnt);
5049 NFSEXITCODE2(error, nd);
5054 * nfsv4 test stateid service
5057 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5058 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5061 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5062 int cnt, error = 0, i, ret;
5063 struct thread *p = curthread;
5065 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5066 nd->nd_repstat = NFSERR_WRONGSEC;
5069 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5070 cnt = fxdr_unsigned(int, *tl);
5071 if (cnt <= 0 || cnt > 1024) {
5072 nd->nd_repstat = NFSERR_BADXDR;
5075 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5076 tstateidp = stateidp;
5077 for (i = 0; i < cnt; i++) {
5078 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5079 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5080 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5083 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5084 *tl = txdr_unsigned(cnt);
5085 tstateidp = stateidp;
5086 for (i = 0; i < cnt; i++) {
5087 ret = nfsrv_teststateid(nd, tstateidp, p);
5088 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5089 *tl = txdr_unsigned(ret);
5093 free(stateidp, M_TEMP);
5094 NFSEXITCODE2(error, nd);
5099 * nfs allocate service
5102 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5103 vnode_t vp, struct nfsexstuff *exp)
5106 struct nfsvattr forat;
5107 int error = 0, forat_ret = 1, gotproxystateid;
5109 struct nfsstate st, *stp = &st;
5110 struct nfslock lo, *lop = &lo;
5111 nfsv4stateid_t stateid;
5113 nfsattrbit_t attrbits;
5115 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5116 nd->nd_repstat = NFSERR_WRONGSEC;
5119 gotproxystateid = 0;
5120 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5121 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5122 lop->lo_flags = NFSLCK_WRITE;
5123 stp->ls_ownerlen = 0;
5125 stp->ls_uid = nd->nd_cred->cr_uid;
5126 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5127 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5128 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5129 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5130 if ((nd->nd_flag & ND_NFSV41) != 0)
5131 clientid.qval = nd->nd_clientid.qval;
5132 else if (nd->nd_clientid.qval != clientid.qval)
5133 printf("EEK2 multiple clids\n");
5135 if ((nd->nd_flag & ND_NFSV41) != 0)
5136 printf("EEK! no clientid from session\n");
5137 nd->nd_flag |= ND_IMPLIEDCLID;
5138 nd->nd_clientid.qval = clientid.qval;
5140 stp->ls_stateid.other[2] = *tl++;
5142 * Don't allow this to be done for a DS.
5144 if ((nd->nd_flag & ND_DSSERVER) != 0)
5145 nd->nd_repstat = NFSERR_NOTSUPP;
5146 /* However, allow the proxy stateid. */
5147 if (stp->ls_stateid.seqid == 0xffffffff &&
5148 stp->ls_stateid.other[0] == 0x55555555 &&
5149 stp->ls_stateid.other[1] == 0x55555555 &&
5150 stp->ls_stateid.other[2] == 0x55555555)
5151 gotproxystateid = 1;
5152 off = fxdr_hyper(tl); tl += 2;
5153 lop->lo_first = off;
5154 len = fxdr_hyper(tl);
5155 lop->lo_end = off + len;
5157 * Paranoia, just in case it wraps around, which shouldn't
5158 * ever happen anyhow.
5160 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0))
5161 nd->nd_repstat = NFSERR_INVAL;
5163 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5164 nd->nd_repstat = NFSERR_WRONGTYPE;
5165 NFSZERO_ATTRBIT(&attrbits);
5166 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5167 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5168 if (nd->nd_repstat == 0)
5169 nd->nd_repstat = forat_ret;
5170 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5171 NFSVNO_EXSTRICTACCESS(exp)))
5172 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5173 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5175 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5176 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5177 &stateid, exp, nd, curthread);
5179 if (nd->nd_repstat == 0)
5180 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5183 NFSEXITCODE2(0, nd);
5187 NFSEXITCODE2(error, nd);
5195 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5196 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5200 int cnt, error = 0, ret;
5201 off_t inoff, outoff;
5204 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5205 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5207 nfsv4stateid_t stateid;
5208 nfsattrbit_t attrbits;
5209 void *rl_rcookie, *rl_wcookie;
5211 rl_rcookie = rl_wcookie = NULL;
5212 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5213 nd->nd_repstat = NFSERR_WRONGSEC;
5216 if (nfsrv_devidcnt > 0) {
5218 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5219 * will do the copy via I/O on the DS(s).
5221 nd->nd_repstat = NFSERR_NOTSUPP;
5225 /* Copying a byte range within the same file is not allowed. */
5226 nd->nd_repstat = NFSERR_INVAL;
5229 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5231 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5232 inlop->lo_flags = NFSLCK_READ;
5233 instp->ls_ownerlen = 0;
5234 instp->ls_op = NULL;
5235 instp->ls_uid = nd->nd_cred->cr_uid;
5236 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5237 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5238 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5239 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5240 clientid.qval = nd->nd_clientid.qval;
5241 instp->ls_stateid.other[2] = *tl++;
5242 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5243 outlop->lo_flags = NFSLCK_WRITE;
5244 outstp->ls_ownerlen = 0;
5245 outstp->ls_op = NULL;
5246 outstp->ls_uid = nd->nd_cred->cr_uid;
5247 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5248 outstp->ls_stateid.other[0] = *tl++;
5249 outstp->ls_stateid.other[1] = *tl++;
5250 outstp->ls_stateid.other[2] = *tl++;
5251 inoff = fxdr_hyper(tl); tl += 2;
5252 inlop->lo_first = inoff;
5253 outoff = fxdr_hyper(tl); tl += 2;
5254 outlop->lo_first = outoff;
5255 len = fxdr_hyper(tl); tl += 2;
5257 /* len == 0 means to EOF. */
5258 inlop->lo_end = OFF_MAX;
5259 outlop->lo_end = OFF_MAX;
5261 inlop->lo_end = inlop->lo_first + len;
5262 outlop->lo_end = outlop->lo_first + len;
5266 * At this time only consecutive, synchronous copy is supported,
5267 * so ca_consecutive and ca_synchronous can be ignored.
5271 cnt = fxdr_unsigned(int, *tl);
5272 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5273 nd->nd_repstat = NFSERR_NOTSUPP;
5274 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5275 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5276 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5278 nd->nd_repstat = NFSERR_INVAL;
5280 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5281 nd->nd_repstat = NFSERR_WRONGTYPE;
5283 /* Check permissions for the input file. */
5284 NFSZERO_ATTRBIT(&attrbits);
5285 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5286 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5287 if (nd->nd_repstat == 0)
5288 nd->nd_repstat = ret;
5289 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5290 NFSVNO_EXSTRICTACCESS(exp)))
5291 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5292 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5294 if (nd->nd_repstat == 0)
5295 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5296 clientid, &stateid, exp, nd, curthread);
5298 if (nd->nd_repstat != 0)
5301 error = NFSVOPLOCK(tovp, LK_SHARED);
5304 if (vnode_vtype(tovp) != VREG)
5305 nd->nd_repstat = NFSERR_WRONGTYPE;
5307 /* For the output file, we only need the Owner attribute. */
5308 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5309 if (nd->nd_repstat == 0)
5310 nd->nd_repstat = ret;
5311 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5312 NFSVNO_EXSTRICTACCESS(exp)))
5313 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5314 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5316 if (nd->nd_repstat == 0)
5317 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5318 clientid, &stateid, toexp, nd, curthread);
5321 /* Range lock the byte ranges for both invp and outvp. */
5322 if (nd->nd_repstat == 0) {
5325 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5327 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5330 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5332 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5335 if (rl_rcookie != NULL)
5337 vn_rangelock_unlock(tovp, rl_wcookie);
5339 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5342 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5344 vn_rangelock_unlock(vp, rl_rcookie);
5347 error = NFSVOPLOCK(vp, LK_SHARED);
5349 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5352 * Since invp is range locked, na_size should
5355 if (len == 0 && at.na_size > inoff) {
5357 * If len == 0, set it based on invp's
5358 * size. If offset is past EOF, just
5361 len = at.na_size - inoff;
5362 } else if (nfsrv_linux42server == 0 &&
5363 inoff + len > at.na_size) {
5365 * RFC-7862 says that NFSERR_INVAL must
5366 * be returned when inoff + len exceeds
5367 * the file size, however the NFSv4.2
5368 * Linux client likes to do this, so
5369 * only check if nfsrv_linux42server
5372 nd->nd_repstat = NFSERR_INVAL;
5376 if (ret != 0 && nd->nd_repstat == 0)
5377 nd->nd_repstat = ret;
5378 } else if (nd->nd_repstat == 0)
5379 nd->nd_repstat = error;
5383 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange.
5384 * This limit is applied to ensure that the RPC replies in a
5387 if (len > nfs_maxcopyrange)
5388 xfer = nfs_maxcopyrange;
5391 if (nd->nd_repstat == 0) {
5392 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5393 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL);
5394 if (nd->nd_repstat == 0)
5398 /* Unlock the ranges. */
5399 if (rl_rcookie != NULL)
5400 vn_rangelock_unlock(vp, rl_rcookie);
5401 if (rl_wcookie != NULL)
5402 vn_rangelock_unlock(tovp, rl_wcookie);
5404 if (nd->nd_repstat == 0) {
5405 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5407 *tl++ = txdr_unsigned(0); /* No callback ids. */
5408 txdr_hyper(len, tl); tl += 2;
5409 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5410 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5411 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5412 *tl++ = newnfs_true;
5418 NFSEXITCODE2(error, nd);
5423 NFSEXITCODE2(error, nd);
5431 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5432 vnode_t vp, struct nfsexstuff *exp)
5436 int content, error = 0;
5439 nfsattrbit_t attrbits;
5442 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5443 nd->nd_repstat = NFSERR_WRONGSEC;
5446 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5447 /* Ignore the stateid for now. */
5448 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5449 off = fxdr_hyper(tl); tl += 2;
5450 content = fxdr_unsigned(int, *tl);
5451 if (content == NFSV4CONTENT_DATA)
5453 else if (content == NFSV4CONTENT_HOLE)
5456 nd->nd_repstat = NFSERR_BADXDR;
5457 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR)
5458 nd->nd_repstat = NFSERR_ISDIR;
5459 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5460 nd->nd_repstat = NFSERR_WRONGTYPE;
5461 if (nd->nd_repstat == 0 && off < 0)
5462 nd->nd_repstat = NFSERR_NXIO;
5463 if (nd->nd_repstat == 0) {
5464 /* Check permissions for the input file. */
5465 NFSZERO_ATTRBIT(&attrbits);
5466 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5467 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5470 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5471 NFSVNO_EXSTRICTACCESS(exp)))
5472 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5473 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5475 if (nd->nd_repstat != 0)
5478 /* nfsvno_seek() unlocks and vrele()s the vp. */
5479 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5480 nd->nd_cred, curthread);
5481 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5482 nfsrv_linux42server != 0)
5483 nd->nd_repstat = NFSERR_NXIO;
5484 if (nd->nd_repstat == 0) {
5485 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5487 *tl++ = newnfs_true;
5489 *tl++ = newnfs_false;
5490 txdr_hyper(off, tl);
5492 NFSEXITCODE2(error, nd);
5496 NFSEXITCODE2(error, nd);
5501 * nfs get extended attribute service
5504 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5505 vnode_t vp, __unused struct nfsexstuff *exp)
5508 mbuf_t mp = NULL, mpend = NULL;
5511 struct thread *p = curthread;
5514 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5515 nd->nd_repstat = NFSERR_WRONGSEC;
5518 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5519 len = fxdr_unsigned(int, *tl);
5521 nd->nd_repstat = NFSERR_BADXDR;
5524 if (len > EXTATTR_MAXNAMELEN) {
5525 nd->nd_repstat = NFSERR_NOXATTR;
5528 name = malloc(len + 1, M_TEMP, M_WAITOK);
5529 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5530 if (nd->nd_repstat == 0)
5531 nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp,
5532 nd->nd_cred, p, &mp, &mpend, &len);
5533 if (nd->nd_repstat == ENOATTR)
5534 nd->nd_repstat = NFSERR_NOXATTR;
5535 else if (nd->nd_repstat == EOPNOTSUPP)
5536 nd->nd_repstat = NFSERR_NOTSUPP;
5537 if (nd->nd_repstat == 0) {
5538 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5539 *tl = txdr_unsigned(len);
5540 mbuf_setnext(nd->nd_mb, mp);
5542 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
5547 if (nd->nd_repstat == 0)
5548 nd->nd_repstat = error;
5550 NFSEXITCODE2(0, nd);
5555 * nfs set extended attribute service
5558 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5559 vnode_t vp, __unused struct nfsexstuff *exp)
5562 struct nfsvattr ova, nva;
5563 nfsattrbit_t attrbits;
5564 int error, len, opt;
5567 struct thread *p = curthread;
5571 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5572 nd->nd_repstat = NFSERR_WRONGSEC;
5575 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5576 opt = fxdr_unsigned(int, *tl++);
5577 len = fxdr_unsigned(int, *tl);
5579 nd->nd_repstat = NFSERR_BADXDR;
5582 if (len > EXTATTR_MAXNAMELEN) {
5583 nd->nd_repstat = NFSERR_NOXATTR;
5586 name = malloc(len + 1, M_TEMP, M_WAITOK);
5587 error = nfsrv_mtostr(nd, name, len);
5590 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5591 len = fxdr_unsigned(int, *tl);
5592 if (len <= 0 || len > IOSIZE_MAX) {
5593 nd->nd_repstat = NFSERR_XATTR2BIG;
5597 case NFSV4SXATTR_CREATE:
5598 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5599 &siz, nd->nd_cred, p);
5600 if (error != ENOATTR)
5601 nd->nd_repstat = NFSERR_EXIST;
5604 case NFSV4SXATTR_REPLACE:
5605 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5606 &siz, nd->nd_cred, p);
5608 nd->nd_repstat = NFSERR_NOXATTR;
5610 case NFSV4SXATTR_EITHER:
5613 nd->nd_repstat = NFSERR_BADXDR;
5615 if (nd->nd_repstat != 0)
5618 /* Now, do the Set Extended attribute, with Change before and after. */
5619 NFSZERO_ATTRBIT(&attrbits);
5620 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5621 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5622 if (nd->nd_repstat == 0) {
5623 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
5624 nd->nd_dpos, nd->nd_cred, p);
5625 if (nd->nd_repstat == ENXIO)
5626 nd->nd_repstat = NFSERR_XATTR2BIG;
5628 if (nd->nd_repstat == 0)
5629 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
5630 if (nd->nd_repstat == 0)
5631 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5632 if (nd->nd_repstat == 0) {
5633 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5634 *tl++ = newnfs_true;
5635 txdr_hyper(ova.na_filerev, tl); tl += 2;
5636 txdr_hyper(nva.na_filerev, tl);
5641 if (nd->nd_repstat == 0)
5642 nd->nd_repstat = error;
5644 NFSEXITCODE2(0, nd);
5649 * nfs remove extended attribute service
5652 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
5653 vnode_t vp, __unused struct nfsexstuff *exp)
5656 struct nfsvattr ova, nva;
5657 nfsattrbit_t attrbits;
5660 struct thread *p = curthread;
5664 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5665 nd->nd_repstat = NFSERR_WRONGSEC;
5668 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5669 len = fxdr_unsigned(int, *tl);
5671 nd->nd_repstat = NFSERR_BADXDR;
5674 if (len > EXTATTR_MAXNAMELEN) {
5675 nd->nd_repstat = NFSERR_NOXATTR;
5678 name = malloc(len + 1, M_TEMP, M_WAITOK);
5679 error = nfsrv_mtostr(nd, name, len);
5683 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
5684 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
5685 error = NFSERR_NOXATTR;
5689 * Now, do the Remove Extended attribute, with Change before and
5692 NFSZERO_ATTRBIT(&attrbits);
5693 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5694 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5695 if (nd->nd_repstat == 0) {
5696 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
5697 if (nd->nd_repstat == ENOATTR)
5698 nd->nd_repstat = NFSERR_NOXATTR;
5700 if (nd->nd_repstat == 0)
5701 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5702 if (nd->nd_repstat == 0) {
5703 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
5704 txdr_hyper(ova.na_filerev, tl); tl += 2;
5705 txdr_hyper(nva.na_filerev, tl);
5710 if (nd->nd_repstat == 0)
5711 nd->nd_repstat = error;
5713 NFSEXITCODE2(0, nd);
5718 * nfs list extended attribute service
5721 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
5722 vnode_t vp, __unused struct nfsexstuff *exp)
5724 uint32_t cnt, *tl, len, len2, i, pos, retlen;
5726 uint64_t cookie, cookie2;
5729 struct thread *p = curthread;
5733 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5734 nd->nd_repstat = NFSERR_WRONGSEC;
5737 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5739 * The cookie doesn't need to be in net byte order, but FreeBSD
5740 * does so to make it more readable in packet traces.
5742 cookie = fxdr_hyper(tl); tl += 2;
5743 len = fxdr_unsigned(uint32_t, *tl);
5744 if (len == 0 || cookie >= IOSIZE_MAX) {
5745 nd->nd_repstat = NFSERR_BADXDR;
5748 if (len > nd->nd_maxresp - NFS_MAXXDR)
5749 len = nd->nd_maxresp - NFS_MAXXDR;
5751 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
5753 if (nd->nd_repstat == EOPNOTSUPP)
5754 nd->nd_repstat = NFSERR_NOTSUPP;
5755 if (nd->nd_repstat == 0) {
5756 cookie2 = cookie + len;
5757 if (cookie2 < cookie)
5758 nd->nd_repstat = NFSERR_BADXDR;
5760 if (nd->nd_repstat == 0) {
5761 /* Now copy the entries out. */
5762 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
5763 if (len == 0 && retlen <= len2) {
5764 /* The cookie was at eof. */
5765 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
5767 txdr_hyper(cookie2, tl); tl += 2;
5768 *tl++ = txdr_unsigned(0);
5773 /* Sanity check the cookie. */
5774 for (pos = 0; pos < len; pos += (i + 1)) {
5779 if (pos != cookie) {
5780 nd->nd_repstat = NFSERR_INVAL;
5784 /* Loop around copying the entrie(s) out. */
5788 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
5791 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
5793 txdr_hyper(cookie2, tl); tl += 2;
5795 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
5802 * eof is set true/false by nfsvno_listxattr(), but if we
5803 * can't copy all entries returned by nfsvno_listxattr(),
5804 * we are not at eof.
5809 /* *tl is set above. */
5810 *tl = txdr_unsigned(cnt);
5811 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5817 nd->nd_repstat = NFSERR_TOOSMALL;
5822 if (nd->nd_repstat == 0)
5823 nd->nd_repstat = error;
5825 NFSEXITCODE2(0, nd);
5830 * nfsv4 service not supported
5833 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
5834 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5837 nd->nd_repstat = NFSERR_NOTSUPP;
5838 NFSEXITCODE2(0, nd);